--- /dev/null
+
+OBJS = main.o inifile.o build.o udiprops.o
+BIN = ../udibuild
+CFLAGS = -std=c99 -MMD -MP -g
+
+OBJS := $(OBJS:%=obj/%)
+
+.PHONY: all clean
+
+all: $(BIN)
+
+clean:
+ $(RM) $(BIN) $(OBJS) $(OBJS:%.o=%.d)
+
+$(BIN): $(OBJS)
+ @echo --- [CC] $@
+ @$(CC) -o $(BIN) $(OBJS) $(LDFLAGS)
+
+obj/%.o: %.c Makefile
+ @mkdir -p $(dir $@)
+ @echo --- [CC] $@
+ @$(CC) -o $@ -c $< $(CFLAGS)
+
+-include $(OBJS:%.o=%.d)
+
--- /dev/null
+/*
+ * udibuild - UDI Compilation Utility
+ * - By John Hodge (thePowersGang)
+ *
+ * build.c
+ * - Compilation functions
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include "include/build.h"
+
+#ifndef __GNUC__
+# define __attribute__(...)
+#endif
+
+// === PROTOTYPES ===
+char *get_objfile(tIniFile *opts, const char *srcfile);
+char *mkstr(const char *fmt, ...) __attribute__((format(printf,1,2)));
+
+// === CODE ===
+int Build_CompileFile(tIniFile *opts, const char *abi, tUdiprops *udiprops, tUdiprops_Srcfile *srcfile)
+{
+ // Select compiler from opts [abi]
+ const char *cc_prog = IniFile_Get(opts, abi, "CC", NULL);
+ if( !cc_prog ) {
+ fprintf(stderr, "No 'CC' defined for ABI %s\n", abi);
+ return 1;
+ }
+
+ // Build up compiler's command line
+ // - Include CFLAGS from .ini file
+ // - defines from udiprops
+ // - Object file is srcfile with .o appended
+ // > Place in 'obj/' dir?
+ char *objfile = get_objfile(opts, srcfile->Filename);
+ char *cmd = mkstr("%s -DUDI_ABI_is_%s %s %s -c %s -o %s",
+ cc_prog,
+ abi,
+ IniFile_Get(opts, abi, "CFLAGS", ""),
+ srcfile->CompileOpts ? srcfile->CompileOpts : "",
+ srcfile->Filename, objfile);
+ printf("--- Compiling: %s\n", srcfile->Filename);
+ int rv = system(cmd);
+ free(cmd);
+ free(objfile);
+
+ return rv;
+}
+
+int Build_LinkObjects(tIniFile *opts, const char *abi, tUdiprops *udiprops)
+{
+ return 0;
+}
+
+char *get_objfile(tIniFile *opts, const char *srcfile)
+{
+ return mkstr("%s.o", srcfile);
+}
+
+char *mkstr(const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ size_t len = vsnprintf(NULL, 0, fmt, args);
+ va_end(args);
+ va_start(args, fmt);
+ char *ret = malloc(len+1);
+ vsnprintf(ret, len+1, fmt, args);
+ va_end(args);
+ return ret;
+}
+
--- /dev/null
+/*
+ * udibuild - UDI Compilation Utility
+ * - By John Hodge (thePowersGang)
+ *
+ * build.h
+ * - Actual build steps (exposed functions)
+ */
+#ifndef _BUILD_H_
+#define _BUILD_H_
+
+#include "inifile.h"
+#include "udiprops.h"
+
+extern int Build_CompileFile(tIniFile *opts, const char *abi, tUdiprops *udiprops, tUdiprops_Srcfile *srcfile);
+extern int Build_LinkObjects(tIniFile *opts, const char *abi, tUdiprops *udiprops);
+
+#endif
+
--- /dev/null
+/*
+ * udibuild - UDI Compilation Utility
+ * - By John Hodge (thePowersGang)
+ *
+ * inifile.h
+ * - .ini file parsing
+ */
+#ifndef _INIFILE_H_
+#define _INIFILE_H_
+
+typedef struct sInifile tIniFile;
+
+extern tIniFile *IniFile_Load(const char *Path);
+extern const char *IniFile_Get(tIniFile *File, const char *Sect, const char *Key, const char *Default);
+extern void IniFile_Free(tIniFile *File);
+
+#endif
+
--- /dev/null
+/*
+ * udibuild - UDI Compilation Utility
+ * - By John Hodge (thePowersGang)
+ *
+ * udiprops.h
+ * - udiprops.txt parsing for udibuild
+ */
+#ifndef _UDIPROPS_H_
+#define _UDIPROPS_H_
+
+typedef struct sUdiprops tUdiprops;
+
+typedef struct sUdiprops_Srcfile tUdiprops_Srcfile;
+
+struct sUdiprops_Srcfile
+{
+ const char *Filename;
+ const char *CompileOpts;
+};
+
+struct sUdiprops
+{
+ tUdiprops_Srcfile **SourceFiles;
+};
+
+extern tUdiprops *Udiprops_LoadBuild(const char *Filename);
+
+#endif
+
--- /dev/null
+/*
+ * udibuild - UDI Compilation Utility
+ * - By John Hodge (thePowersGang)
+ *
+ * inifile.c
+ * - .ini file parsing
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+#include "include/inifile.h"
+
+typedef struct sInifile_Section tIniFile_Section;
+typedef struct sInifile_Value tIniFile_Value;
+
+struct sInifile_Value
+{
+ tIniFile_Value *Next;
+ const char *Key;
+ const char *Value;
+};
+
+struct sInifile_Section
+{
+ tIniFile_Section *Next;
+ const char *Name;
+ tIniFile_Value *FirstValue;
+};
+
+struct sInifile
+{
+ tIniFile_Section RootSection;
+};
+
+// === CODE ===
+static void rtrim(char *str)
+{
+ char *pos = str;
+ while( *pos )
+ pos ++;
+ while( pos != str && isspace(pos[-1]) )
+ *--pos = '\0';
+}
+
+tIniFile *IniFile_Load(const char *Path)
+{
+ FILE *fp = fopen(Path, "r");
+ if( !fp )
+ return NULL;
+
+ tIniFile *ret = malloc( sizeof(tIniFile) );
+ assert(ret);
+
+ ret->RootSection.Name = "";
+ ret->RootSection.FirstValue = NULL;
+
+ tIniFile_Section *curSect = &ret->RootSection;
+ char buf[512];
+ while( fgets(buf, sizeof(buf)-1, fp) )
+ {
+ rtrim(buf);
+ char name[64];
+ size_t ofs = 0;
+ if( sscanf(buf, "[%[^]]]", name) == 1 ) {
+ //printf("section %s\n", name);
+ // new section
+ tIniFile_Section *new_sect = malloc(sizeof(tIniFile_Section)+strlen(name)+1);
+ new_sect->Next = NULL;
+ new_sect->Name = (const char*)(new_sect+1);
+ new_sect->FirstValue = NULL;
+ strcpy( (char*)new_sect->Name, name );
+ curSect->Next = new_sect;
+ curSect = new_sect;
+ }
+ else if( sscanf(buf, "%[^=]=%n", name, &ofs) >= 1 ) {
+ //printf("key %s equals %s\n", name, value);
+ const char *value = buf + ofs;
+ tIniFile_Value *val = malloc(sizeof(tIniFile_Value)+strlen(name)+1+strlen(value)+1);
+ val->Next = curSect->FirstValue;
+ curSect->FirstValue = val;
+
+ val->Key = (char*)(val+1);
+ strcpy((char*)val->Key, name);
+ val->Value = val->Key + strlen(val->Key) + 1;
+ strcpy((char*)val->Value, value);
+ }
+ else {
+ //printf("ignore %s\n", buf);
+ // ignore
+ }
+ }
+
+ fclose(fp);
+
+ return ret;
+}
+
+const char *IniFile_Get(tIniFile *File, const char *Sect, const char *Key, const char *Default)
+{
+ tIniFile_Section *sect;
+ for( sect = &File->RootSection; sect; sect = sect->Next )
+ {
+ if( strcmp(sect->Name, Sect) == 0 )
+ break;
+ }
+ if( !sect )
+ return Default;
+
+ tIniFile_Value *val;
+ for( val = sect->FirstValue; val; val = val->Next )
+ {
+ if( strcmp(val->Key, Key) == 0 )
+ break;
+ }
+ if( !val )
+ return Default;
+
+ return val->Value;
+}
+
+void IniFile_Free(tIniFile *File)
+{
+ // TODO:
+}
--- /dev/null
+/*
+ * udibuild - UDI Compilation Utility
+ * - By John Hodge (thePowersGang)
+ *
+ * main.c
+ * - Core
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h> // getopt
+#include <getopt.h>
+#include <assert.h>
+#include "include/build.h"
+#include "include/inifile.h"
+#include "include/udiprops.h"
+
+#ifdef __ACESS__
+#define CONFIG_FILE "/Acess/Conf/UDI/udibuild.ini"
+#else
+#define CONFIG_FILE "/etc/udi/udibuild.ini"
+#endif
+
+// === PROTOTYPES ===
+ int main(int argc, char *argv[]);
+ int ParseArguments(int argc, char *argv[]);
+void Usage(const char *progname);
+
+// === GLOBALS ===
+const char *gsOpt_ConfigFile;
+const char *gsOpt_WorkingDir;
+const char *gsOpt_UdipropsFile;
+const char *gsOpt_ABIName = "ia32";
+tIniFile *gpOptions;
+tUdiprops *gpUdipropsBuild;
+
+// === CODE ===
+int main(int argc, char *argv[])
+{
+ if( ParseArguments(argc, argv) ) {
+ return 1;
+ }
+
+ // Locate udibuild.ini
+ if( NULL == gsOpt_ConfigFile )
+ {
+ // 1. Check CWD
+ //if( file_exists("./udibuild.ini") )
+ //{
+ // gsOpt_ConfigFile = "udibuild.ini";
+ //}
+ // 2. Check program dir (if not invoked from PATH)
+ // 3. Check ~/.config/udi/udibuild.ini
+ // 4. Check CONFIGNAME
+
+ exit(2);
+ }
+ gpOptions = IniFile_Load(gsOpt_ConfigFile);
+ assert(gpOptions);
+
+ // Change to working directory (-C <dir>)
+ if( gsOpt_WorkingDir )
+ {
+ chdir(gsOpt_WorkingDir);
+ }
+
+ // Load udiprops
+ gpUdipropsBuild = Udiprops_LoadBuild( gsOpt_UdipropsFile ? gsOpt_UdipropsFile : "udiprops.txt" );
+ assert(gpUdipropsBuild);
+ assert(gpUdipropsBuild->SourceFiles);
+
+ // Do build
+ for( int i = 0; gpUdipropsBuild->SourceFiles[i]; i ++ )
+ {
+ int rv = Build_CompileFile(gpOptions, gsOpt_ABIName, gpUdipropsBuild,
+ gpUdipropsBuild->SourceFiles[i]);
+ if( rv ) {
+ fprintf(stderr, "*** Exit status: %i\n", rv);
+ return rv;
+ }
+ }
+ Build_LinkObjects(gpOptions, gsOpt_ABIName, gpUdipropsBuild);
+
+ return 0;
+}
+
+int ParseArguments(int argc, char *argv[])
+{
+ int opt;
+ while( (opt = getopt(argc, argv, "hC:c:f:a:")) != -1 )
+ {
+ switch(opt)
+ {
+ case 'h':
+ Usage(argv[0]);
+ exit(0);
+ case 'C':
+ gsOpt_WorkingDir = optarg;
+ break;
+ case 'c':
+ gsOpt_ConfigFile = optarg;
+ break;
+ case 'f':
+ gsOpt_UdipropsFile = optarg;
+ break;
+ case 'a':
+ gsOpt_ABIName = optarg;
+ break;
+ case '?':
+ Usage(argv[0]);
+ return 1;
+ default:
+ fprintf(stderr, "BUG: Unhandled optarg %i '%c'\n", opt, opt);
+ break;
+ }
+ }
+ return 0;
+}
+
+void Usage(const char *progname)
+{
+ fprintf(stderr, "Usage: %s [-C workingdir] [-c udibuild.ini] [-f udiprops.txt] [-a abiname]\n",
+ progname);
+ fprintf(stderr, "\n"
+ "-C workingdir : Change to the specified directory before looking for udiprops.txt\n"
+ "-c udibuild.ini : Override the default udibuild config file\n"
+ "-f udiprops.txt : Override the default udiprops file\n"
+ "-a abiname : Select a different ABI\n"
+ "\n");
+}
+
--- /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';
+}
+
+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 ;
+
+ int sym = _get_token_sym(str, (const char**)&str,
+ "source_files", "compile_options", "source_requires", 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+1)*sizeof(void*));
+ ret->SourceFiles[n_srcfiles-1] = srcfile;
+ ret->SourceFiles[n_srcfiles] = NULL;
+ }
+ break;
+ case 1: // compile_options
+ current_compile_opts = malloc(strlen(str)+1);
+ strcpy(current_compile_opts, str);
+ break;
+ case 2: // source_requires
+ // TODO: Use source_requires
+ break;
+ }
+ }
+
+ // "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;
+}
+
--- /dev/null
+[COMMON]
+
+[ia32]
+CFLAGS=-ffreestanding -I/home/tpg/Projects/GitClones/acess2/KernelLand/Modules/Interfaces/UDI/include/
+CC=i586-elf-gcc
+LD=i586-elf-ld