--- /dev/null
+/*
+ * udibuild - UDI Compilation Utility
+ * - By John Hodge (thePowersGang)
+ *
+ * udiprops.c
+ * - udiprops.txt parsing (for udibuild only)
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include "include/udiprops.h"
+
+// === CODE ===
+static int _get_token_sym(const char *str, const char **outstr, ...)
+{
+ va_list args;
+ va_start(args, outstr);
+ const char *sym;
+ for( int idx = 0; (sym = va_arg(args, const char *)); idx ++ )
+ {
+ size_t len = strlen(sym);
+ if( memcmp(str, sym, len) != 0 )
+ continue ;
+ if( str[len] && !isspace(str[len]) )
+ continue ;
+
+ // Found it!
+ *outstr = str + len;
+ while( isspace(**outstr) )
+ (*outstr) ++;
+ return idx;
+ }
+ va_end(args);
+
+ const char *end = str;
+ while( !isspace(*end) )
+ end ++;
+// fprintf(stderr, "udiprops: Unknown token '%.*s'\n", end-str, str);
+
+ *outstr = NULL;
+ return -1;
+}
+
+static void rtrim(char *str)
+{
+ char *pos = str;
+ while( *pos )
+ pos ++;
+ while( pos != str && isspace(pos[-1]) )
+ *--pos = '\0';
+}
+
+static char *my_strdup(const char *str)
+{
+ char *ret = malloc(strlen(str)+1);
+ return strcpy(ret, str);
+}
+
+tUdiprops *Udiprops_LoadBuild(const char *Filename)
+{
+ FILE *fp = fopen(Filename, "r");
+ if( !fp ) {
+ perror("Udiprops_LoadBuild");
+ return NULL;
+ }
+
+ char *current_compile_opts = NULL;
+ int n_srcfiles = 0;
+ tUdiprops *ret = calloc( 1, sizeof(tUdiprops) );
+
+ char buf[512];
+ while( fgets(buf, sizeof(buf)-1, fp) )
+ {
+ char *str = buf;
+ {
+ char *hash = strchr(str, '#');
+ if( hash ) *hash = '\0';
+ }
+ rtrim(str);
+ if( !str[0] ) continue ;
+
+ ret->nLines ++;
+ ret->Lines = realloc(ret->Lines, ret->nLines*sizeof(void*));
+ ret->Lines[ret->nLines-1] = my_strdup(str);
+
+ int sym = _get_token_sym(str, (const char**)&str,
+ "source_files", "compile_options", "source_requires",
+ "module",
+ NULL);
+ switch(sym)
+ {
+ case 0: // source_files
+ for(char *file = strtok(str, " \t"); file; file = strtok(NULL, " \t") )
+ {
+ tUdiprops_Srcfile *srcfile = malloc(sizeof(tUdiprops_Srcfile)+strlen(file)+1);
+ srcfile->CompileOpts = current_compile_opts;
+ srcfile->Filename = (void*)(srcfile+1);
+ strcpy((char*)srcfile->Filename, file);
+
+ n_srcfiles ++;
+ ret->SourceFiles = realloc(ret->SourceFiles, n_srcfiles*sizeof(void*));
+ ret->SourceFiles[n_srcfiles-1] = srcfile;
+ }
+ break;
+ case 1: // compile_options
+ current_compile_opts = my_strdup(str);
+ break;
+ case 2: // source_requires
+ // TODO: Use source_requires
+ break;
+ case 3: // module
+ ret->ModuleName = my_strdup(str);
+ break;
+ }
+ }
+
+ ret->nSourceFiles = n_srcfiles;
+
+ // "Intentional" memory leak
+ // - current_compile_opts not freed, and shared between srcfiles
+ // - If two compile_options statements appear in a row, one is definitely leaked
+
+ fclose(fp);
+ return ret;
+}
+