+++ /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 <string.h>
-#include <sys/stat.h> // mkdir
-#include <unistd.h> // unlink
-#include "include/build.h"
-#include "include/common.h"
-
-// === PROTOTYPES ===
-char *get_objfile(tIniFile *opts, const char *abi, const char *srcfile);
-char *get_udipropsfile(tIniFile *opts, const char *abi);
-
-// === 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, abi, 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_CreateUdiprops(tIniFile *opts, const char *abi, tUdiprops *udiprops)
-{
- const char *cc_prog = IniFile_Get(opts, abi, "CC", NULL);
-
- char *filename = get_udipropsfile(opts, abi);
- FILE *fp = fopen(filename, "w");
- fprintf(fp, "char udiprops[] __attribute__((section(\".udiprops\"))) = \n");
- for( int i = 0; i < udiprops->nLines; i ++ ) {
- // TODO: Escape " in string
- fprintf(fp, " \"%s\"\n", udiprops->Lines[i]);
- }
- fprintf(fp, " ;\n");
- fclose(fp);
-
- char *cmd = mkstr("%s %s -c %s -o %s.o",
- cc_prog, IniFile_Get(opts, abi, "CFLAGS", ""),
- filename, filename);
-
- int rv = system(cmd);
- free(cmd);
- unlink(filename);
- free(filename);
-
- return rv;
-}
-
-int Build_LinkObjects(tIniFile *opts, const char *abi, tUdiprops *udiprops)
-{
- const char *linker = IniFile_Get(opts, abi, "LD", NULL);
- if( !linker ) {
- fprintf(stderr, "No 'LD' defined for ABI %s\n", abi);
- return -1;
- }
-
- char *objfiles[udiprops->nSourceFiles];
- size_t objfiles_len = 0;
- for( int i = 0; i < udiprops->nSourceFiles; i ++ ) {
- objfiles[i] = get_objfile(opts, abi, udiprops->SourceFiles[i]->Filename);
- objfiles_len += strlen(objfiles[i])+1;
- }
-
- // Create command string
- char *objfiles_str = malloc(objfiles_len);
- objfiles_len = 0;
- for( int i = 0; i < udiprops->nSourceFiles; i ++ ) {
- strcpy(objfiles_str + objfiles_len, objfiles[i]);
- objfiles_len += strlen(objfiles[i])+1;
- objfiles_str[objfiles_len-1] = ' ';
- free( objfiles[i] );
- }
- objfiles_str[objfiles_len-1] = '\0';
-
- mkdir("bin", 0755);
- char *abidir = mkstr("bin/%s", abi);
- mkdir(abidir, 0755);
- free(abidir);
-
- char *udiprops_c = get_udipropsfile(opts, abi);
- char *cmd = mkstr("%s -r %s -o bin/%s/%s -s %s",// %s.o",
- linker, IniFile_Get(opts, abi, "LDFLAGS", ""),
- abi, udiprops->ModuleName, objfiles_str, udiprops_c
- );
- printf("--- Linking: bin/%s/%s\n", abi, udiprops->ModuleName);
- printf("%s\n", cmd);
- int rv = system(cmd);
- free(cmd);
- free(udiprops_c);
- free(objfiles_str);
-
- return rv;
-}
-
-char *get_objfile(tIniFile *opts, const char *abi, const char *srcfile)
-{
- return mkstr("%s.o", srcfile);
-}
-
-char *get_udipropsfile(tIniFile *opts, const char *abi)
-{
- return mkstr(".udiprops.c");
-}
-
+++ /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_CreateUdiprops(tIniFile *opts, const char *abi, tUdiprops *udiprops);
-extern int Build_LinkObjects(tIniFile *opts, const char *abi, tUdiprops *udiprops);
-
-#endif
-
+++ /dev/null
-/*
- * udibuild - UDI Compilation Utility
- * - By John Hodge (thePowersGang)
- *
- * common.h
- * - Common helpers
- */
-#ifndef _COMMON_H_
-#define _COMMON_H_
-
-#include <stdarg.h>
-
-#ifndef __GNUC__
-# define __attribute__(...)
-#endif
-
-extern char *mkstr(const char *fmt, ...) __attribute__((format(printf,1,2)));
-
-#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
-{
- const char *ModuleName;
- int nSourceFiles;
- tUdiprops_Srcfile **SourceFiles;
-
- int nLines;
- char **Lines;
-};
-
-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) )
- {
- if( strchr(buf, '#') )
- *strchr(buf, '#') = '\0';
- 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 <string.h> // strrchr
-#include <assert.h>
-#include "include/common.h"
-#include "include/build.h"
-#include "include/inifile.h"
-#include "include/udiprops.h"
-
-#define CONFIG_FILENAME "udibuild.ini"
-#ifdef __ACESS__
-#define RUNTIME_DIR "/Acess/Conf/UDI"
-#else
-#define RUNTIME_DIR "/etc/udi"
-#endif
-
-// === PROTOTYPES ===
- int main(int argc, char *argv[]);
- int ParseArguments(int argc, char *argv[]);
-void Usage(const char *progname);
-
-// === GLOBALS ===
-const char *gsRuntimeDir = RUNTIME_DIR;
-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
- // 1. Check CWD
- if( !gsOpt_ConfigFile ) {
- //if( file_exists("./udibuild.ini") )
- //{
- // gsOpt_ConfigFile = "udibuild.ini";
- //}
- }
- // 2. Check program dir (if not invoked from PATH)
- if( !gsOpt_ConfigFile && (argv[0][0] == '.' || argv[0][0] == '/') ) {
- char *last_slash = strrchr(argv[0], '/');
- if( last_slash ) {
- gsOpt_ConfigFile = mkstr("%.*s/%s",
- last_slash-argv[0], argv[0], CONFIG_FILENAME);
- }
- //if( !file_exists(gsOpt_ConfigFile) ) {
- // free(gsOpt_ConfigFile);
- // gsOpt_ConfigFile = NULL;
- //}
- }
- // 3. Check ~/.config/udi/udibuild.ini
- // 4. Check RUNTIME_DIR/udibuild.ini
-
- // #. Oh well
- if( !gsOpt_ConfigFile ) {
- fprintf(stderr, "Can't locate "CONFIG_FILENAME" file, please specify using '-c'\n");
- exit(2);
- }
-
- // Load udibuild.ini
- 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; i < gpUdipropsBuild->nSourceFiles; i ++ )
- {
- int rv = Build_CompileFile(gpOptions, gsOpt_ABIName, gpUdipropsBuild,
- gpUdipropsBuild->SourceFiles[i]);
- if( rv ) {
- fprintf(stderr, "*** Exit status: %i\n", rv);
- return rv;
- }
- }
- // Create file with `.udiprops` section
- // - udimkpkg's job
- //Build_CreateUdiprops(gpOptions, gsOpt_ABIName, gpUdipropsBuild);
- // Link
- 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");
-}
-
-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)
- *
- * 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;
-}
-
--- /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 <string.h>
+#include <sys/stat.h> // mkdir
+#include <unistd.h> // unlink
+#include "include/build.h"
+#include "include/common.h"
+
+// === PROTOTYPES ===
+char *get_objfile(tIniFile *opts, const char *abi, const char *srcfile);
+char *get_udipropsfile(tIniFile *opts, const char *abi);
+
+// === 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, abi, 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_CreateUdiprops(tIniFile *opts, const char *abi, tUdiprops *udiprops)
+{
+ const char *cc_prog = IniFile_Get(opts, abi, "CC", NULL);
+
+ char *filename = get_udipropsfile(opts, abi);
+ FILE *fp = fopen(filename, "w");
+ fprintf(fp, "char udiprops[] __attribute__((section(\".udiprops\"))) = \n");
+ for( int i = 0; i < udiprops->nLines; i ++ ) {
+ // TODO: Escape " in string
+ fprintf(fp, " \"%s\"\n", udiprops->Lines[i]);
+ }
+ fprintf(fp, " ;\n");
+ fclose(fp);
+
+ char *cmd = mkstr("%s %s -c %s -o %s.o",
+ cc_prog, IniFile_Get(opts, abi, "CFLAGS", ""),
+ filename, filename);
+
+ int rv = system(cmd);
+ free(cmd);
+ unlink(filename);
+ free(filename);
+
+ return rv;
+}
+
+int Build_LinkObjects(tIniFile *opts, const char *abi, tUdiprops *udiprops)
+{
+ const char *linker = IniFile_Get(opts, abi, "LD", NULL);
+ if( !linker ) {
+ fprintf(stderr, "No 'LD' defined for ABI %s\n", abi);
+ return -1;
+ }
+
+ char *objfiles[udiprops->nSourceFiles];
+ size_t objfiles_len = 0;
+ for( int i = 0; i < udiprops->nSourceFiles; i ++ ) {
+ objfiles[i] = get_objfile(opts, abi, udiprops->SourceFiles[i]->Filename);
+ objfiles_len += strlen(objfiles[i])+1;
+ }
+
+ // Create command string
+ char *objfiles_str = malloc(objfiles_len);
+ objfiles_len = 0;
+ for( int i = 0; i < udiprops->nSourceFiles; i ++ ) {
+ strcpy(objfiles_str + objfiles_len, objfiles[i]);
+ objfiles_len += strlen(objfiles[i])+1;
+ objfiles_str[objfiles_len-1] = ' ';
+ free( objfiles[i] );
+ }
+ objfiles_str[objfiles_len-1] = '\0';
+
+ mkdir("bin", 0755);
+ char *abidir = mkstr("bin/%s", abi);
+ mkdir(abidir, 0755);
+ free(abidir);
+
+ char *udiprops_c = get_udipropsfile(opts, abi);
+ char *cmd = mkstr("%s -r %s -o bin/%s/%s -s %s",// %s.o",
+ linker, IniFile_Get(opts, abi, "LDFLAGS", ""),
+ abi, udiprops->ModuleName, objfiles_str, udiprops_c
+ );
+ printf("--- Linking: bin/%s/%s\n", abi, udiprops->ModuleName);
+ printf("%s\n", cmd);
+ int rv = system(cmd);
+ free(cmd);
+ free(udiprops_c);
+ free(objfiles_str);
+
+ return rv;
+}
+
+char *get_objfile(tIniFile *opts, const char *abi, const char *srcfile)
+{
+ return mkstr("%s.o", srcfile);
+}
+
+char *get_udipropsfile(tIniFile *opts, const char *abi)
+{
+ return mkstr(".udiprops.c");
+}
+
--- /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_CreateUdiprops(tIniFile *opts, const char *abi, tUdiprops *udiprops);
+extern int Build_LinkObjects(tIniFile *opts, const char *abi, tUdiprops *udiprops);
+
+#endif
+
--- /dev/null
+/*
+ * udibuild - UDI Compilation Utility
+ * - By John Hodge (thePowersGang)
+ *
+ * common.h
+ * - Common helpers
+ */
+#ifndef _COMMON_H_
+#define _COMMON_H_
+
+#include <stdarg.h>
+
+#ifndef __GNUC__
+# define __attribute__(...)
+#endif
+
+extern char *mkstr(const char *fmt, ...) __attribute__((format(printf,1,2)));
+
+#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
+{
+ const char *ModuleName;
+ int nSourceFiles;
+ tUdiprops_Srcfile **SourceFiles;
+
+ int nLines;
+ char **Lines;
+};
+
+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) )
+ {
+ if( strchr(buf, '#') )
+ *strchr(buf, '#') = '\0';
+ 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 <string.h> // strrchr
+#include <assert.h>
+#include "include/common.h"
+#include "include/build.h"
+#include "include/inifile.h"
+#include "include/udiprops.h"
+
+#define CONFIG_FILENAME "udibuild.ini"
+#ifdef __ACESS__
+#define RUNTIME_DIR "/Acess/Conf/UDI"
+#else
+#define RUNTIME_DIR "/etc/udi"
+#endif
+
+// === PROTOTYPES ===
+ int main(int argc, char *argv[]);
+ int ParseArguments(int argc, char *argv[]);
+void Usage(const char *progname);
+
+// === GLOBALS ===
+const char *gsRuntimeDir = RUNTIME_DIR;
+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
+ // 1. Check CWD
+ if( !gsOpt_ConfigFile ) {
+ //if( file_exists("./udibuild.ini") )
+ //{
+ // gsOpt_ConfigFile = "udibuild.ini";
+ //}
+ }
+ // 2. Check program dir (if not invoked from PATH)
+ if( !gsOpt_ConfigFile && (argv[0][0] == '.' || argv[0][0] == '/') ) {
+ char *last_slash = strrchr(argv[0], '/');
+ if( last_slash ) {
+ gsOpt_ConfigFile = mkstr("%.*s/%s",
+ last_slash-argv[0], argv[0], CONFIG_FILENAME);
+ }
+ //if( !file_exists(gsOpt_ConfigFile) ) {
+ // free(gsOpt_ConfigFile);
+ // gsOpt_ConfigFile = NULL;
+ //}
+ }
+ // 3. Check ~/.config/udi/udibuild.ini
+ // 4. Check RUNTIME_DIR/udibuild.ini
+
+ // #. Oh well
+ if( !gsOpt_ConfigFile ) {
+ fprintf(stderr, "Can't locate "CONFIG_FILENAME" file, please specify using '-c'\n");
+ exit(2);
+ }
+
+ // Load udibuild.ini
+ 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; i < gpUdipropsBuild->nSourceFiles; i ++ )
+ {
+ int rv = Build_CompileFile(gpOptions, gsOpt_ABIName, gpUdipropsBuild,
+ gpUdipropsBuild->SourceFiles[i]);
+ if( rv ) {
+ fprintf(stderr, "*** Exit status: %i\n", rv);
+ return rv;
+ }
+ }
+ // Create file with `.udiprops` section
+ // - udimkpkg's job
+ //Build_CreateUdiprops(gpOptions, gsOpt_ABIName, gpUdipropsBuild);
+ // Link
+ 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");
+}
+
+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)
+ *
+ * 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;
+}
+