gbdk-2020 | GameBoy Development Kit |
| download: https://git.y1.nz/archives/gbdk.tar.gz | |
| README | Files | Log | Refs | LICENSE |
commit ff84156ec329827ae0ff0d8cee1d4ad57144dd36 parent 290169e07229c6ffde21a0943fa3c5f65e673263 Author: bbbbbr <reg+github@roughhousing.com> Date: Tue, 24 Aug 2021 18:51:26 -0700 Merge pull request #236 from bbbbbr/bankpack_linkerfile Add linkerfile support to Bankpack + LCC integration Diffstat:
| M | gbdk-lib/examples/ap/linkerfile/Makefile | 6 | ++++-- |
| M | gbdk-lib/examples/gb/linkerfile/Makefile | 6 | ++++-- |
| M | gbdk-support/bankpack/bankpack.c | 6 | ++++++ |
| M | gbdk-support/bankpack/files.c | 67 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| M | gbdk-support/bankpack/files.h | 4 | ++++ |
| M | gbdk-support/lcc/Makefile | 2 | +- |
| M | gbdk-support/lcc/gb.h | 3 | +++ |
| M | gbdk-support/lcc/lcc.c | 247 | +++++++++++++++++++++++++------------------------------------------------------ |
| A | gbdk-support/lcc/list.c | 193 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | gbdk-support/lcc/list.h | 26 | ++++++++++++++++++++++++++ |
10 files changed, 387 insertions(+), 173 deletions(-)
diff --git a/gbdk-lib/examples/ap/linkerfile/Makefile b/gbdk-lib/examples/ap/linkerfile/Makefile @@ -51,8 +51,10 @@ $(OBJDIR)/%.s: $(SRCDIR)/%.c $(OBJDIR)/linkfile.lk: $(OBJS) - rm -f $(OBJDIR)/linkfile.lk - $(foreach O,$(OBJS),echo $O >>$@) + rm -f $@ + @for obj in $(OBJS); do \ + echo $$obj >>$@; \ + done # Link the compiled object files (via linkerfile) into a .pocket ROM file $(BINS): $(OBJDIR)/linkfile.lk diff --git a/gbdk-lib/examples/gb/linkerfile/Makefile b/gbdk-lib/examples/gb/linkerfile/Makefile @@ -50,8 +50,10 @@ $(OBJDIR)/%.s: $(SRCDIR)/%.c $(OBJDIR)/linkfile.lk: $(OBJS) - rm -f $(OBJDIR)/linkfile.lk - $(foreach O,$(OBJS),echo $O >>$@) + rm -f $@ + @for obj in $(OBJS); do \ + echo $$obj >>$@; \ + done # Link the compiled object files (via linkerfile) into a .gb ROM file $(BINS): $(OBJDIR)/linkfile.lk diff --git a/gbdk-support/bankpack/bankpack.c b/gbdk-support/bankpack/bankpack.c @@ -31,6 +31,8 @@ static void display_help(void) { "\n" "Options\n" "-h : Show this help\n" + "-lkin=<file> : Load object files specified in linker file <file>\n" + "-lkout=<file>: Write list of object files out to linker file <file>\n" "-yt<mbctype> : Set MBC type per ROM byte 149 in Decimal or Hex (0xNN) (see pandocs)\n" "-mbc=N : Similar to -yt, but sets MBC type directly to N instead\n" " of by intepreting ROM byte 149\n" @@ -105,6 +107,10 @@ static int handle_args(int argc, char * argv[]) { banks_set_platform(argv[i] + 6); } else if (strstr(argv[i], "-random") == argv[i]) { banks_set_random(true); + } else if (strstr(argv[i], "-lkin=") == argv[i]) { + files_read_linkerfile(argv[i] + strlen("-lkin=")); + } else if (strstr(argv[i], "-lkout=") == argv[i]) { + files_set_linkerfile_outname(argv[i] + strlen("-lkout=")); } else printf("BankPack: Warning: Ignoring unknown option %s\n", argv[i]); } else { diff --git a/gbdk-support/bankpack/files.c b/gbdk-support/bankpack/files.c @@ -22,6 +22,7 @@ list_type filelist; char g_out_ext[MAX_FILE_STR]; char g_out_path[MAX_FILE_STR]; +char g_out_linkerfile_name[MAX_FILE_STR] = {'\0'}; void files_set_out_ext(char * ext_str) { if (snprintf(g_out_ext, sizeof(g_out_ext), "%s", ext_str) > sizeof(g_out_ext)) @@ -45,6 +46,68 @@ void files_cleanup(void) { } +// Reads a list of object files from a linkerfile +// (one filename per line) and adds them +void files_read_linkerfile(char * filename_in) { + char strline_in[MAX_FILE_STR] = ""; + + FILE * in_file; + + // Open each object file and try to process all the lines + in_file = fopen(filename_in, "r"); + if (in_file) { + + // Read one line at a time into \0 terminated string + // Skip empty lines + // Strip newlines and carraige returns from end of filename + while ( fgets(strline_in, sizeof(strline_in), in_file) != NULL) { + if ((strline_in[0] != '\n') || (strline_in[0] != '\r')) { + strline_in[strcspn(strline_in, "\r\n")] = '\0'; + files_add(strline_in); + } + } + fclose(in_file); + + } // end: if valid file + else { + printf("BankPack: ERROR: failed to open input linkerfile: %s\n", filename_in); + exit(EXIT_FAILURE); + } +} + + +void files_set_linkerfile_outname(char * filename) { + + if (snprintf(g_out_linkerfile_name, sizeof(g_out_linkerfile_name), "%s", filename) > sizeof(g_out_linkerfile_name)) + printf("Warning: truncated output linkerfile name to:%s\n",g_out_linkerfile_name); +} + + +// Writes a list of loaded object filenames to +// a linkerfile (one filename per line) +void files_write_linkerfile(void) { + uint32_t c; + file_item * files = (file_item *)filelist.p_array; + FILE * out_file; + + // Open the linkerfile output and write all object filenames + out_file = fopen(g_out_linkerfile_name, "w"); + if (out_file) { + + // Process stored file names + for (c = 0; c < filelist.count; c++) + fprintf(out_file, "%s\n", files[c].name_out); + + fclose(out_file); + + } // end: if valid file + else { + printf("BankPack: ERROR: failed to open output linkerfile: %s\n", g_out_linkerfile_name); + exit(EXIT_FAILURE); + } +} + + void files_add(char * filename) { file_item newfile; @@ -175,6 +238,10 @@ void files_rewrite(void) { FILE * out_file = NULL; file_item * files = (file_item *)filelist.p_array; + // If linkerfile output is enabled, write it + if (g_out_linkerfile_name[0] != '\0') + files_write_linkerfile(); + // Process stored file names - (including unchanged ones since output may get new extensions or path) for (c = 0; c < filelist.count; c++) { diff --git a/gbdk-support/bankpack/files.h b/gbdk-support/bankpack/files.h @@ -19,6 +19,10 @@ void files_init(void); void files_cleanup(void); void files_add(char *); +void files_read_linkerfile(char *); +void files_set_linkerfile_outname(char *); +void files_write_linkerfile(void); + char * file_get_name_in_by_id(uint32_t); char * file_get_name_out_by_id(uint32_t); diff --git a/gbdk-support/lcc/Makefile b/gbdk-support/lcc/Makefile @@ -14,7 +14,7 @@ CFLAGS += -DBUILDDATE=\"$(BUILDDATE)\" -DBUILDTIME=\"$(BUILDTIME)\" ifdef BINDIR CFLAGS += -DGBDKBINDIR=\"$(BINDIR)\" endif -OBJ = lcc.o gb.o targets.o +OBJ = lcc.o gb.o targets.o list.o BIN = lcc all: $(BIN) diff --git a/gbdk-support/lcc/gb.h b/gbdk-support/lcc/gb.h @@ -12,6 +12,9 @@ #define EXT_O ".o" #define EXT_OBJ ".obj" #define EXT_IHX ".ihx" +#define EXT_LK ".lk" + +// ROM file extensions #define EXT_GB ".gb" #define EXT_AP ".pocket" #define EXT_SMS ".sms" diff --git a/gbdk-support/lcc/lcc.c b/gbdk-support/lcc/lcc.c @@ -23,20 +23,14 @@ static char rcsid[] = "$Id: lcc.c,v 2.0 " BUILDDATE " " BUILDTIME " gbdk-2020 Ex #endif #include "gb.h" +#include "list.h" #include "targets.h" #ifndef TEMPDIR #define TEMPDIR "/tmp" #endif -typedef struct list *List; -struct list { /* circular list nodes: */ - char *str; /* option or file name */ - List link; /* next list element */ -}; - -static void *alloc(int); -List append(char *, List); +void *alloc(int); extern char *basepath(char *); extern char *path_stripext(char *); static int callsys(char *[]); @@ -46,12 +40,10 @@ static void error(char *, char *); static char *exists(char *); static char *first(char *); static int filename(char *, char *); -static List find(char *, List); static void help(void); static void initinputs(void); static void interrupt(int); static void opt(char *); -static List path2list(const char *); extern int main(int, char *[]); extern char *replace(const char *, int, int); static void rm(List); @@ -64,8 +56,9 @@ static bool arg_has_searchkey(char *, char *); // Adds linker default required vars if not present (defined by user) static void Fixllist(); -static void list_rewrite_exts(List, char *, char *); -static void list_duplicate_to_new_exts(List, char *, char *); + +static void handle_autobanking(void); + // These get populated from _class using finalise() in gb.c extern char *cpp[], *include[], *com[], *as[], *bankpack[], *ld[], *ihxcheck[], *mkbin[], inputs[], *suffixes[], *rom_extension; @@ -83,11 +76,17 @@ static int Sflag; /* -S specified */ static int cflag; /* -c specified */ static int Kflag; /* -K specified */ static int autobankflag; /* -K specified */ -static int verbose; /* incremented for each -v */ +int verbose; /* incremented for each -v */ static List bankpack_flags; /* bankpack flags */ static List ihxchecklist; /* ihxcheck flags */ static List mkbinlist; /* loader files, flags */ -static List llist[2]; /* [1] = loader files, [0] = flags */ + +// Index entries for llist[] +#define L_ARGS 0 +#define L_FILES 1 +#define L_LKFILES 2 +static List llist[3]; /* [2] = .lkfiles, [1] = linker object file list, [0] = linker flags */ + static List alist; /* assembler flags */ List clist; /* compiler flags */ static List plist; /* preprocessor flags */ @@ -232,7 +231,7 @@ int main(int argc, char *argv[]) { // Perform Link / ihxcheck / makebin stages (unless some conditions prevent it) if (errcnt == 0 && !Eflag && !cflag && !Sflag && - (llist[1] || ((ihxFile[0] != '\0') && ihx_inputs))) { + (llist[L_FILES] || llist[L_LKFILES] || ((ihxFile[0] != '\0') && ihx_inputs))) { int target_is_ihx = 0; @@ -260,33 +259,16 @@ int main(int argc, char *argv[]) { if (!target_is_ihx) append(ihxFile, rmlist); - // if auto bank assignment is enabled, modify obj files before linking - if (autobankflag) { - - // bankpack will be populated if supported by active port:platform - if (bankpack[0][0] != '\0') - compose(bankpack, bankpack_flags, llist[1], 0); - else - fprintf(stderr, "Warning: bankpack enabled but not supported by active port:platform\n"); - - if (callsys(av)) { - errcnt++; - } else { - // If bankpack has -ext= flag set to write obj files - // out to a new extension then rewrite the - // linker list (llist[1]) and delete list (rmlist). - // The delete list likely only has temp obj files such - // as from a single-pass build: lcc -o out.gb in1.c in2.c - if (bankpack_newext[0]) { - list_rewrite_exts(llist[1], EXT_O, bankpack_newext); - list_duplicate_to_new_exts(rmlist, EXT_O, bankpack_newext); - } - } - } + // If auto bank assignment is enabled, modify obj files before linking + // Will alter: llist[L_FILES] and llist[L_LKFILES] + if (autobankflag) + handle_autobanking(); + // Copy any pending linkerfiles into the linker list (with "-f" as preceding arg) + llist[L_FILES] = list_add_to_another(llist[L_FILES], llist[L_LKFILES], NULL, "-f"); // Call linker (add output ihxfile in compose $3) Fixllist(); // Fixlist adds required default linker vars if not added by user - compose(ld, llist[0], llist[1], append(ihxFile, 0)); + compose(ld, llist[L_ARGS], llist[L_FILES], append(ihxFile, 0)); if (callsys(av)) errcnt++; @@ -312,6 +294,8 @@ int main(int argc, char *argv[]) { } } rm(rmlist); + if (verbose > 0) + fprintf(stderr, "\n"); return errcnt ? EXIT_FAILURE : EXIT_SUCCESS; } @@ -336,8 +320,8 @@ static void Fixllist() int c; // Iterate through linker list entries - if(llist[0]) { - List b = llist[0]; + if(llist[L_ARGS]) { + List b = llist[L_ARGS]; do { b = b->link; // Only -g and -b settings are supported at this time @@ -347,7 +331,7 @@ static void Fixllist() // That splits them into two consecutive llist items, // so try advancing to the next item to access it's value. // Example: b = "-g", next = ".STACK=0xE000" - if (b != llist[0]) + if (b != llist[L_ARGS]) b = b->link; else break; // end of list @@ -358,21 +342,21 @@ static void Fixllist() if (arg_has_searchkey(b->str, llist0_defaults[c].searchkey)) llist0_defaults[c].found = true; } - } while (b != llist[0]); + } while (b != llist[L_ARGS]); } // Add required default settings to the linker list if they weren't found for (c = 0; c < llist0_defaults_len; c++) if (llist0_defaults[c].found == false) { - // Add the entry to the linker llist[0], flag first then value - llist[0] = append(llist0_defaults[c].addflag, llist[0]); - llist[0] = append(llist0_defaults[c].addvalue, llist[0]); + // Add the entry to the linker llist[L_ARGS], flag first then value + llist[L_ARGS] = append(llist0_defaults[c].addflag, llist[L_ARGS]); + llist[L_ARGS] = append(llist0_defaults[c].addvalue, llist[L_ARGS]); } } /* alloc - allocate n bytes or die */ -static void *alloc(int n) { +void *alloc(int n) { static char *avail, *limit; n = (n + sizeof(char *) - 1)&~(sizeof(char *) - 1); @@ -385,19 +369,6 @@ static void *alloc(int n) { return avail - n; } -/* append - append a node with string str onto list, return new list */ -List append(char *str, List list) { - List p = alloc(sizeof *p); - - p->str = str; - if (list) { - p->link = list->link; - list->link = p; - } - else - p->link = p; - return p; -} /* basepath - return base name for name, e.g. /usr/drh/foo.c => foo */ char *basepath(char *name) { @@ -711,8 +682,8 @@ static int filename(char *name, char *base) { compose(com, clist, append(name, 0), append(ofile, 0)); status = callsys(av); - if (!find(ofile, llist[1])) - llist[1] = append(ofile, llist[1]); + if (!find(ofile, llist[L_FILES])) + llist[L_FILES] = append(ofile, llist[L_FILES]); } break; case 2: /* assembly language files */ @@ -728,13 +699,13 @@ static int filename(char *name, char *base) { ofile = tempname(EXT_O); compose(as, alist, append(name, 0), append(ofile, 0)); status = callsys(av); - if (!find(ofile, llist[1])) - llist[1] = append(ofile, llist[1]); + if (!find(ofile, llist[L_FILES])) + llist[L_FILES] = append(ofile, llist[L_FILES]); } break; case 3: /* object files */ - if (!find(name, llist[1])) - llist[1] = append(name, llist[1]); + if (!find(name, llist[L_FILES])) + llist[L_FILES] = append(name, llist[L_FILES]); break; case 4: // .ihx files // Apply "name" as .ihx file (there can be only one as input) @@ -745,7 +716,7 @@ static int filename(char *name, char *base) { compose(cpp, plist, append(name, 0), 0); status = callsys(av); } - llist[1] = append(name, llist[1]); + llist[L_FILES] = append(name, llist[L_FILES]); break; } if (status) @@ -753,19 +724,6 @@ static int filename(char *name, char *base) { return status; } -/* find - find 1st occurrence of str in list, return list node or 0 */ -static List find(char *str, List list) { - List b; - - b = list; - if (b) - do { - if (strcmp(str, b->str) == 0) - return b; - } while ((b = b->link) != list); - return 0; -} - /* help - print help message */ static void help(void) { static char *msgs[] = { @@ -846,7 +804,7 @@ static void initinputs(void) { if (strcmp(b->str, ".") != 0) { ilist = append(concat("-I", b->str), ilist); if (strstr(com[1], "win32") == NULL) - llist[0] = append(concat("-L", b->str), llist[0]); + llist[L_ARGS] = append(concat("-L", b->str), llist[L_ARGS]); } else b->str = ""; @@ -896,7 +854,7 @@ static void opt(char *arg) { bankpack_flags = append(&arg[3], bankpack_flags); // -Wb-ext=[.some-extension] // If bankpack is going to rewrite input object files to a new extension - // then save that extension for rewriting the linker list (llist[1]) + // then save that extension for rewriting the linker list (llist[L_FILES]) if (strstr(&arg[3], "-ext=") != NULL) { if (arg[8]) { sprintf(bankpack_newext, "%s", &arg[8]); @@ -910,14 +868,14 @@ static void opt(char *arg) { // If using linker file for sdldgb (-f file[.lk]). // Starting at arg[5] should be name of the linkerfile if ((arg[4] == 'f') && (arg[5])) { - llist[1] = append("-f", llist[1]); // Add -f to file link list - llist[1] = append(&arg[5], llist[1]); // Then add linkerfile as the very next parameter + // Items in llist[L_LKFILES] get added to llist[L_FILES] right before the linker is called. + // That avoids sending to bankpack with the "-f" flag mixed in with the names of the .o object files. + llist[L_LKFILES] = append(stringf(&arg[5]), llist[L_LKFILES]); } else { - char *tmp = malloc(256); - sprintf(tmp, "%c%c", arg[3], arg[4]); //sdldgb requires spaces between -k and the path - llist[0] = append(tmp, llist[0]); //splitting the args into 2 works on Win and Linux + //sdldgb requires spaces between -k and the path + llist[L_ARGS] = append(stringf("%c%c", arg[3], arg[4]), llist[L_ARGS]); //splitting the args into 2 works on Win and Linux if (arg[5]) { - llist[0] = append(&arg[5], llist[0]); // Add filename separately if present + llist[L_ARGS] = append(&arg[5], llist[L_ARGS]); // Add filename separately if present } } } @@ -955,8 +913,8 @@ static void opt(char *arg) { if (strcmp(arg, "-debug") == 0) { // Load default debug options clist = append("--debug", clist); // Debug for sdcc compiler - llist[0] = append("-y", llist[0]); // Enable .cdb output for sdldgb linker - llist[0] = append("-j", llist[0]); // Enable .noi output + llist[L_ARGS] = append("-y", llist[L_ARGS]); // Enable .cdb output for sdldgb linker + llist[L_ARGS] = append("-j", llist[L_ARGS]); // Enable .noi output return; } @@ -1000,7 +958,7 @@ static void opt(char *arg) { case 'B': /* -Bdir -Bstatic -Bdynamic */ #ifdef sparc if (strcmp(arg, "-Bstatic") == 0 || strcmp(arg, "-Bdynamic") == 0) - llist[1] = append(arg, llist[1]); + llist[L_FILES] = append(arg, llist[L_FILES]); else #endif { @@ -1055,7 +1013,7 @@ static void opt(char *arg) { case 'G': if (option(arg)) { clist = append("-g3", clist); - llist[0] = append("-N", llist[0]); + llist[L_ARGS] = append("-N", llist[L_ARGS]); } else fprintf(stderr, "%s: %s ignored\n", progname, arg); @@ -1089,39 +1047,9 @@ static void opt(char *arg) { if (cflag || Sflag || Eflag) fprintf(stderr, "%s: %s ignored\n", progname, arg); else - llist[1] = append(arg, llist[1]); + llist[L_FILES] = append(arg, llist[L_FILES]); } -/* path2list - convert a colon- or semicolon-separated list to a list */ -static List path2list(const char *path) { - List list = NULL; - char sep = ':'; - - if (path == NULL) - return NULL; - if (strchr(path, ';')) - sep = ';'; - while (*path) { - char *p, buf[512]; - p = strchr(path, sep); - if (p) { - size_t len = p - path; - if(len >= sizeof(buf)) len = sizeof(buf)-1; - strncpy(buf, path, len); - buf[len] = '\0'; - } - else { - strncpy(buf, path, sizeof(buf)); - buf[sizeof(buf)-1] = '\0'; - } - if (!find(buf, list)) - list = append(strsave(buf), list); - if (p == 0) - break; - path = p + 1; - } - return list; -} /* replace - copy str, then replace occurrences of from with to, return the copy */ char *replace(const char *str, int from, int to) { @@ -1198,53 +1126,35 @@ char *tempname(char *suffix) { } -// Replace extensions for filenames in a list -static void list_rewrite_exts(List list_in, char * ext_match, char * ext_new) -{ - char * filepath_old; +// Performs the autobanking stage +// +// Should be called prior to doing compose() for the linker +// +static void handle_autobanking(void) { - // Iterate through list and replace file extensions - if (list_in) { - List list_t = list_in; - do { - if (list_t->str) { - // Check to see if filname has desired extension - if (matches_ext(list_t->str, ext_match)) { - - // Save a copy to free after re-assignment - filepath_old = list_t->str; - // Create a new string with the replaced suffix (stringf() allocs) - list_t->str = stringf("%s%s", path_stripext(list_t->str), ext_new); - if (verbose > 0) fprintf(stderr,"lcc: rename link obj (from -autobank): %s -> %s\n", filepath_old, list_t->str); - } - } - // Move to next list item, exit if start of list is reached - list_t = list_t->link; - } while (list_t != list_in); - } -} + // bankpack will be populated if supported by active port:platform + if (bankpack[0][0] != '\0') { + char * bankpack_linkerfile_name = tempname(EXT_LK); + rmlist = append(bankpack_linkerfile_name, rmlist); // Delete the linkerfile when done + // Always use a linkerfile when using bankpack through lcc + // Writes all input object files out to [bankpack_linkerfile_name] + bankpack_flags = append(stringf("%s%s","-lkout=", bankpack_linkerfile_name), bankpack_flags); -// Replace extensions for filenames in a list -static void list_duplicate_to_new_exts(List list_in, char * ext_match, char * ext_new) -{ - // List may have entries appended, cache original start - List list_start = list_in; + // Add linkerfile entries (usually *.lk) to the bankpack arg list if any are present + bankpack_flags = list_add_to_another(bankpack_flags, llist[L_LKFILES], "-lkin=", NULL); - // Iterate through list and replace file extensions - if (list_in) { - List list_t = list_in; - do { - if (list_t->str) { - // Check to see if filname has desired extension - if (matches_ext(list_t->str, ext_match)) { + // Prepare the bankpack command line, then execute it + compose(bankpack, bankpack_flags, llist[L_FILES], 0); + if (callsys(av)) + errcnt++; - list_in = append(stringf("%s%s", path_stripext(list_t->str), ext_new), list_in); - if (verbose > 0) fprintf(stderr,"lcc: add to rmlist (from -autobank): %s -> %s\n", list_t->str, stringf("%s%s", path_stripext(list_t->str), ext_new)); - } - } - // Move to next list item, exit if start of list is reached - list_t = list_t->link; - } while (list_t != list_start); - } -} + // Clear out the objects file and linkerfiles from their lists + // Then replace them with the filename passed to bankpack for "-lkout=" + llist[L_FILES] = list_remove_all(llist[L_FILES]); + llist[L_LKFILES] = list_remove_all(llist[L_LKFILES]); + llist[L_LKFILES] = append(stringf("%s", bankpack_linkerfile_name), llist[L_LKFILES]); + } + else + fprintf(stderr, "Warning: bankpack enabled but not supported by active port:platform\n"); +} + diff --git a/gbdk-support/lcc/list.c b/gbdk-support/lcc/list.c @@ -0,0 +1,193 @@ +// list.c + +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#include <stdbool.h> +#include <string.h> +//#include <assert.h> +//#include <ctype.h> +//#include <signal.h> + +#include "list.h" + +// From lcc.c +extern void *alloc(int); +extern char *strsave(const char *str); +extern char *stringf(const char *fmt, ...); +extern char *path_stripext(char *name); +extern int matches_ext(const char * filename, const char * ext); +extern int verbose; + + + +/* append - append a node with string str onto list, return new list */ +List append(char *str, List list) { + List p = alloc(sizeof *p); + + p->str = str; + if (list) { + p->link = list->link; + list->link = p; + } + else + p->link = p; + return p; +} + + +/* find - find 1st occurrence of str in list, return list node or 0 */ +List find(char *str, List list) { + List b; + + b = list; + if (b) + do { + if (strcmp(str, b->str) == 0) + return b; + } while ((b = b->link) != list); + return 0; +} + + +/* path2list - convert a colon- or semicolon-separated list to a list */ +List path2list(const char *path) { + List list = NULL; + char sep = ':'; + + if (path == NULL) + return NULL; + if (strchr(path, ';')) + sep = ';'; + while (*path) { + char *p, buf[512]; + p = strchr(path, sep); + if (p) { + size_t len = p - path; + if(len >= sizeof(buf)) len = sizeof(buf)-1; + strncpy(buf, path, len); + buf[len] = '\0'; + } + else { + strncpy(buf, path, sizeof(buf)); + buf[sizeof(buf)-1] = '\0'; + } + if (!find(buf, list)) + list = append(strsave(buf), list); + if (p == 0) + break; + path = p + 1; + } + return list; +} + + +// Replace extensions for filenames in a list +void list_rewrite_exts(List list_in, char * ext_match, char * ext_new) +{ + char * filepath_old; + + // Iterate through list and replace file extensions + if (list_in) { + List list_t = list_in; + do { + if (list_t->str) { + // Check to see if filname has desired extension + if (matches_ext(list_t->str, ext_match)) { + + // Save a copy to free after re-assignment + filepath_old = list_t->str; + // Create a new string with the replaced suffix (stringf() allocs) + list_t->str = stringf("%s%s", path_stripext(list_t->str), ext_new); + if (verbose > 0) fprintf(stderr,"lcc: rename link obj (from -autobank): %s -> %s\n", filepath_old, list_t->str); + } + } + // Move to next list item, exit if start of list is reached + list_t = list_t->link; + } while (list_t != list_in); + } +} + + +// Duplicate items with [ext_match] into new list items with [ext_new] +void list_duplicate_to_new_exts(List list_in, char * ext_match, char * ext_new) +{ + // List may have entries appended, cache original start + List list_start = list_in; + + // Iterate through list and replace file extensions + if (list_in) { + List list_t = list_in; + do { + if (list_t->str) { + // Check to see if filname has desired extension + if (matches_ext(list_t->str, ext_match)) { + // Make a copy with the replaced extension into the list + list_in = append(stringf("%s%s", path_stripext(list_t->str), ext_new), list_in); + if (verbose > 0) fprintf(stderr,"lcc: add to rmlist (from -autobank): %s -> %s\n", list_t->str, stringf("%s%s", path_stripext(list_t->str), ext_new)); + } + } + // Move to next list item, exit if start of list is reached + list_t = list_t->link; + } while (list_t != list_start); + } +} + + +// Remove all items from a list +List list_remove_all(List list_in) { + + // Well... the custom alloc() used for lists makes it hard to free their memory. + // Instead just set the list to NULL to erase it and let cleanup happen on program exit. + return NULL; + + /* + List list_next; + // Iterate through list and free memory + if (list_in) { + List list_t = list_in->link; // Advance to next item + list_in->link = NULL; // Break list to create a stopping point + + do { + // Copy next link before freeing the current item + list_next = list_t->link; + if (list_t) { + free(list_t); + list_t = NULL; + } + // Move to next list item, exit if start of list is reached + list_t = list_next; + } while (list_t && list_t->link); + } + return NULL; + */ +} + + +// Copies all items from [list_src] to [list_dest] +// * optionally prefix items from [list_src] with [str_prefix] +// * optionally append() a separate [str_add_before] for each item in [list_src] (use for space separated flags) +List list_add_to_another(List list_dest, List list_src, char * str_prefix, char * str_add_before) { + + if (list_src) { + List list_t = list_src->link; // Start at first list item (list usually points to END) + + // Iterate through [list_src] and copy into to [list_dest], exit once start is reached again + do { + if (list_t->str) + // Add str_add_before string as a separate item if present + if (str_add_before) + list_dest = append( stringf("%s", str_add_before), list_dest); + + // pre-pend string prefix if present + if (str_prefix) + list_dest = append( stringf("%s%s", str_prefix, list_t->str), list_dest); + else + list_dest = append( stringf("%s", list_t->str), list_dest); + // Move to next list item + list_t = list_t->link; + } while (list_t != list_src); + } + + return list_dest; // Return updated list +} diff --git a/gbdk-support/lcc/list.h b/gbdk-support/lcc/list.h @@ -0,0 +1,26 @@ +// list.h + +#include <stdbool.h> + +#ifndef _LCC_LIST_H +#define _LCC_LIST_H + + +typedef struct list *List; +struct list { /* circular list nodes: */ + char *str; /* option or file name */ + List link; /* next list element */ +}; + +List append(char *, List); +List find(char *, List); + +List path2list(const char *); + +void list_rewrite_exts(List, char *, char *); +void list_duplicate_to_new_exts(List, char *, char *); +List list_remove_all(List); +List list_add_to_another(List, List, char *, char *); + + +#endif // _LCC_LIST_H
This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.