git.y1.nz

gbdk-2020

GameBoy Development Kit
download: https://git.y1.nz/archives/gbdk.tar.gz
README | Files | Log | Refs | LICENSE

gbdk-support/lcc/lcc.c

      1 /*
      2  * lcc [ option ]... [ file | -llib ]...
      3  * front end for the ANSI C compiler
      4  */
      5 static char rcsid[] = "$Id: lcc.c,v 2.0 " BUILDDATE " " BUILDTIME " gbdk-2020 Exp $";
      6 
      7 #include <stdio.h>
      8 #include <stdarg.h>
      9 #include <stdlib.h>
     10 #include <stdbool.h>
     11 #include <string.h>
     12 #include <assert.h>
     13 #include <ctype.h>
     14 #include <signal.h>
     15 
     16 #ifdef _WIN32
     17 # include <io.h>
     18 # include <process.h>
     19 #else
     20 # include <unistd.h>
     21 # include <sys/types.h>
     22 # include <sys/wait.h>
     23 #endif
     24 
     25 #include "gb.h"
     26 #include "list.h"
     27 #include "targets.h"
     28 
     29 #ifndef TEMPDIR
     30 #define TEMPDIR "/tmp"
     31 #endif
     32 
     33 void *alloc(int);
     34 extern char *basepath(char *);
     35 extern char *path_stripext(char *);
     36 extern char *path_newext(char *, char *);
     37 static int callsys(char *[]);
     38 extern char *concat(const char *, const char *);
     39 static void compose(char *[], List, List, List);
     40 static void error(char *, char *);
     41 static char *exists(char *);
     42 static char *first(char *);
     43 static int filename(char *, char *);
     44 static void help(void);
     45 static void initinputs(void);
     46 static void interrupt(int);
     47 static void opt(char *);
     48 extern int main(int, char *[]);
     49 extern char *replace(const char *, int, int);
     50 static void rm(List);
     51 extern char *strsave(const char *);
     52 extern char *stringf(const char *, ...);
     53 extern int suffix(char *, char *[], int);
     54 extern char *tempname(char *);
     55 
     56 static bool arg_has_searchkey(char *, char *);
     57 
     58 // Adds linker default required vars if not present (defined by user)
     59 static void Fixllist();
     60 
     61 static void handle_autobanking(void);
     62 static int handle_file_preprocess_only(char *name, char *base);
     63 
     64 static void warn_obsolete_option(char * arg);
     65 
     66 // These get populated from _class using finalise() in gb.c
     67 extern char *cpp[], *include[], *com[], *as[], *bankpack[], *ld[], *ihxcheck[], *mkbin[], *postproc[], inputs[], *suffixes[], *rom_extension;
     68 extern bool has_postproc_stage;
     69 extern arg_entry *llist0_defaults;
     70 extern int llist0_defaults_len;
     71 
     72 extern int option(char *);
     73 extern void set_gbdk_dir(char*);
     74 
     75 void finalise(void);
     76 
     77 static int errcnt;		/* number of errors */
     78 static int Eflag;		/* -E specified */
     79 static int Eflag_preproc_to_file;	// --save-procroc specified
     80 static int Sflag;		/* -S specified */
     81 static int cflag;		/* -c specified */
     82 static int Kflag;		/* -K specified */
     83 static int autobankflag;	/* -K specified */
     84 int verbose;		/* incremented for each -v */
     85 static List bankpack_flags;	/* bankpack flags */
     86 static List ihxchecklist;	/* ihxcheck flags */
     87 static List postproclist;	/* postproc flags */
     88 static List mkbinlist;		/* loader files, flags */
     89 
     90 // Index entries for llist[]
     91 #define L_ARGS 0
     92 #define L_FILES 1
     93 #define L_LKFILES 2
     94 static List llist[3];	   /* [2] = .lkfiles, [1] = linker object file list, [0] = linker flags */
     95 
     96 static List alist;		/* assembler flags */
     97 List clist;		/* compiler flags */
     98 static List plist;		/* preprocessor flags */
     99 static List ilist;		/* list of additional includes from LCCINPUTS */
    100 static List rmlist;		/* list of files to remove */
    101 static char *outfile;		/* ld output file or -[cS] object file */
    102 static int ac;			/* argument count */
    103 static char **av;		/* argument vector */
    104 char *tempdir = TEMPDIR;	/* directory for temporary files */
    105 char *progname;
    106 static List lccinputs;		/* list of input directories */
    107 char bankpack_newext[1024] = {'\0'};
    108 static int ihx_inputs = 0;  // Number of ihx files present in input list
    109 static char ihxFile[256] = {'\0'};
    110 static char binFile[256] = {'\0'};
    111 
    112 
    113 int main(int argc, char *argv[]) {
    114 	int i, j, nf;
    115 
    116 	progname = argv[0];
    117 	ac = argc + 50;
    118 	av = alloc(ac * sizeof(char *));
    119 	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
    120 		signal(SIGINT, interrupt);
    121 	if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
    122 		signal(SIGTERM, interrupt);
    123 #ifdef SIGHUP
    124 	if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
    125 		signal(SIGHUP, interrupt);
    126 #endif
    127 	if (getenv("TMP"))
    128 		tempdir = getenv("TMP");
    129 	else if (getenv("TEMP"))
    130 		tempdir = getenv("TEMP");
    131 	else if (getenv("TMPDIR"))
    132 		tempdir = getenv("TMPDIR");
    133 	assert(tempdir);
    134 
    135 	// Remove trailing slashes
    136 	i = strlen(tempdir);
    137 	for (; (i > 0) && ((tempdir[i - 1] == '/') || (tempdir[i - 1] == '\\')); i--)
    138 		tempdir[i - 1] = '\0';
    139 	if (argc <= 1) {
    140 		help();
    141 		exit(0);
    142 	}
    143 //	clist = append("-D__LCC__", 0);
    144 	initinputs();
    145 	if (getenv("GBDKDIR"))
    146 		option(stringf("--prefix=%s", getenv("GBDKDIR")));
    147 	else
    148 		set_gbdk_dir(argv[0]);
    149 	for (nf = 0, i = j = 1; i < argc; i++) {
    150 		if (strcmp(argv[i], "-o") == 0) {
    151 			if (++i < argc) {
    152 				// Don't allow output file to have ".c" or ".i" extension (first two in suffixes[])
    153 				if (suffix(argv[i], suffixes, 2) != SUFX_NOMATCH) {
    154 					error("-o would overwrite %s", argv[i]);
    155 					exit(8);
    156 				}
    157 				// Valid output file found
    158 				outfile = argv[i];
    159 				continue;
    160 			}
    161 			else {
    162 				error("unrecognized option `%s'", argv[i - 1]);
    163 				exit(8);
    164 			}
    165 		}
    166         // This option is obsolete
    167         // -----------------------------------------
    168 		else if (strcmp(argv[i], "-target") == 0) {
    169             // -target name   is ignored
    170             warn_obsolete_option(argv[i]);
    171             // Skip past argument second param if present
    172 			if (argv[i + 1] && *argv[i + 1] != '-')
    173 				i++;
    174 			continue;
    175 		}
    176         // -----------------------------------------
    177 		else if (*argv[i] == '-' && argv[i][1] != 'l') {
    178 			opt(argv[i]);
    179 			continue;
    180 		}
    181 		else if (*argv[i] != '-') {
    182 			// Count number of (.ihx) files
    183 			if (suffix(argv[i], (char * []){EXT_IHX}, 1) != SUFX_NOMATCH)
    184 				ihx_inputs++;
    185 			// Count number of (.c, .i, .asm, .s) files
    186 			else if (suffix(argv[i], suffixes, 3) != SUFX_NOMATCH)
    187 				nf++;
    188 		}
    189 		argv[j++] = argv[i];
    190 	}
    191 
    192 	// Ignore -o output request if:
    193 	// * compile only (-c) *OR* compile to ASM (-S) is specified
    194 	// * and there are 2 or more source files (.c, .i, .asm, .s) in the input list (what "nf" seems to count)
    195 	// Instead, it will generate output matching each input filename
    196 	if ((cflag || Sflag) && outfile && nf != 1) {
    197 		fprintf(stderr, "%s: -o %s ignored\n", progname, outfile);
    198 		outfile = 0;
    199 	}
    200 
    201 	// When .ihx is an input only ihxcheck and makebin will be called.
    202 	// Warn that all source files won't be processed
    203 	if ((ihx_inputs > 0) && (nf > 0)) {
    204 		fprintf(stderr, "%s: Warning: .ihx file present as input, all other input files ignored\n", progname);
    205 	}
    206 
    207 	// Add includes
    208 	argv[j] = 0;
    209 
    210 	// This copies settings from port:platform "class" structure
    211 	// into command strings used for compose()
    212 	finalise();
    213 
    214 	for (i = 0; include[i]; i++)
    215 		clist = append(include[i], clist);
    216 	if (ilist) {
    217 		List b = ilist;
    218 		do {
    219 			b = b->link;
    220 			clist = append(b->str, clist);
    221 		} while (b != ilist);
    222 	}
    223 	ilist = 0;
    224 	for (i = 1; argv[i]; i++)
    225 		// Process arguments
    226 		if (*argv[i] == '-')
    227 			opt(argv[i]);
    228 		else {
    229 			// Process filenames
    230 			char *name = exists(argv[i]);
    231 			if (name) {
    232 				if (strcmp(name, argv[i]) != 0
    233 					|| ((nf > 1) && (suffix(name, suffixes, 3) != SUFX_NOMATCH)) ) // Does it match: .c, .i, .asm, .s
    234 
    235 					fprintf(stderr, "%s:\n", name);
    236 				// Send input filename argument to "filename processor"
    237 				// which will add them to llist[n] in some form most of the time
    238 				filename(name, 0);
    239 			}
    240 			else
    241 				error("can't find `%s'", argv[i]);
    242 		}
    243 
    244 
    245 	// Perform Link / ihxcheck / makebin stages
    246 	//
    247 	// Don't perform these stages if any of the following were requested:
    248 	// -E : Preprocessor only
    249 	// -c : Compile only
    250 	// -S : Compile to Assembly
    251 	if (errcnt == 0 && !Eflag && !cflag && !Sflag &&
    252 		(llist[L_FILES] || llist[L_LKFILES] || ((ihxFile[0] != '\0') && ihx_inputs))) {
    253 
    254 		int target_is_ihx = 0;
    255 
    256 		// if outfile is not specified, set it to default rom extension for active port:platform
    257 		if(!outfile)
    258 			outfile = concat("a", rom_extension);
    259 
    260 		// If an .ihx file is present as input skip link related stages
    261 		if (ihx_inputs > 0) {
    262 
    263 			// Only one .ihx can be used for input, warn that others will be ignored
    264 			if (ihx_inputs > 1)
    265 				fprintf(stderr, "%s: Warning: Multiple (%d) .ihx files present as input, only one (%s) will be used\n", progname, ihx_inputs, ihxFile);
    266 		}
    267 		else {
    268 
    269 			//file.gb to file.ihx (don't use tmpfile because maps and other stuffs are created there)
    270 			// Check to see if output target is a .ihx file
    271 			target_is_ihx = (suffix(outfile, (char *[]){EXT_IHX}, 1) != SUFX_NOMATCH);
    272 
    273 			// Build ihx file name from output name
    274 			sprintf(ihxFile, "%s%s", path_stripext(outfile), EXT_IHX);
    275 
    276 			// Only remove .ihx from the delete-list if it's not the final target
    277 			if (!target_is_ihx)
    278 				append(ihxFile, rmlist);
    279 
    280 			// If auto bank assignment is enabled, modify obj files before linking
    281 			// Will alter: llist[L_FILES] and llist[L_LKFILES]
    282 			if (autobankflag)
    283 				handle_autobanking();
    284 
    285 			// Copy any pending linkerfiles into the linker list (with "-f" as preceding arg)
    286 			llist[L_FILES] = list_add_to_another(llist[L_FILES], llist[L_LKFILES], NULL, "-f");
    287 			// Call linker (add output ihxfile in compose $3)
    288 			Fixllist();   // Fixlist adds required default linker vars if not added by user
    289 			compose(ld, llist[L_ARGS], llist[L_FILES], append(ihxFile, 0));
    290 
    291 			if (callsys(av))
    292 				errcnt++;
    293 		} // end: non-ihx input file handling
    294 
    295 		// ihxcheck (test for multiple writes to the same ROM address)
    296 		if (!Kflag) {
    297 			compose(ihxcheck, ihxchecklist, append(ihxFile, 0), 0);
    298 			if (callsys(av))
    299 				errcnt++;
    300 		}
    301 
    302 		// No need to makebin (.ihx -> .gb [or other rom_extension]) if .ihx is final target
    303 		if (!target_is_ihx)
    304 		{
    305 			if(errcnt == 0)
    306 			{
    307 				// makebin - use output filename unless there is a post-process step
    308 				if (has_postproc_stage == false)
    309 					sprintf(binFile, "%s", outfile);
    310 				else
    311 					sprintf(binFile, "%s", path_newext(outfile, EXT_ROM));
    312 
    313 				// makebin - if autobanking and no ROM bank size specified (-yo *) then add ROM auto-size (-yo A)
    314 				if ((autobankflag) && (find("-yo", mkbinlist) == 0)) {
    315 					mkbinlist = append("-yo", mkbinlist);
    316 					mkbinlist = append("A", mkbinlist);
    317 				}
    318 
    319 				compose(mkbin, mkbinlist, append(ihxFile, 0), append(binFile, 0));
    320 				if (callsys(av))
    321 					errcnt++;
    322 
    323 				// Post-process step (such as makecom, makenes), if applicable
    324 				// This won't apply if the targets .postproc template entry is empty ("")
    325 				if (has_postproc_stage && (errcnt == 0)) {
    326 					compose(postproc, postproclist, append(binFile, 0), append(outfile, 0));
    327 					if (callsys(av))
    328 						errcnt++;
    329 				}
    330 			}
    331 		}
    332 	}
    333 	rm(rmlist);
    334 	if (verbose > 0)
    335 		fprintf(stderr, "\n");
    336 	return errcnt ? EXIT_FAILURE : EXIT_SUCCESS;
    337 }
    338 
    339 
    340 
    341 // Check whether string "arg" has "searchkey" at the first possible
    342 // occurrence of searchkey's starting character in arg (typically "." or "_")
    343 static bool arg_has_searchkey(char * arg, char * searchkey) {
    344 	char * str_start = strchr(arg, searchkey[0]);
    345 
    346 	if (str_start)
    347 		return (strncmp(str_start, searchkey, strlen(searchkey)) == 0);
    348 	else
    349 		return false;
    350 }
    351 
    352 
    353 // Adds linker default required vars if not present (defined by user)
    354 // Uses data from targets.c for per port/platform defaults
    355 static void Fixllist()
    356 {
    357 	int c;
    358 
    359 	// Iterate through linker list entries
    360 	if(llist[L_ARGS]) {
    361 		List b = llist[L_ARGS];
    362 		do {
    363 			b = b->link;
    364 			// Only -g and -b settings are supported at this time
    365 			if(b->str[1] == 'g' || b->str[1] == 'b')
    366 			{
    367 				// '-g' and '-b' now have their values separated by a space.
    368 				// That splits them into two consecutive llist items,
    369 				// so try advancing to the next item to access it's value.
    370 				// Example:  b = "-g", next = ".STACK=0xE000"
    371 				if (b != llist[L_ARGS])
    372 					b = b->link;
    373 				else
    374 					break; // end of list
    375 
    376 				// Check current linker arg to see if any default settings are present
    377 				// If they do, flag them as present so they don't need to be added later
    378 				for (c = 0; c < llist0_defaults_len; c++)
    379 					if (arg_has_searchkey(b->str, llist0_defaults[c].searchkey))
    380 						llist0_defaults[c].found = true;
    381 			}
    382 		} while (b != llist[L_ARGS]);
    383 	}
    384 
    385 	// Add required default settings to the linker list if they weren't found
    386 	for (c = 0; c < llist0_defaults_len; c++)
    387 		if (llist0_defaults[c].found == false) {
    388 			// Add the entry to the linker llist[L_ARGS], flag first then value
    389 			llist[L_ARGS] = append(llist0_defaults[c].addflag,  llist[L_ARGS]);
    390 			llist[L_ARGS] = append(llist0_defaults[c].addvalue, llist[L_ARGS]);
    391 		}
    392 }
    393 
    394 
    395 /* alloc - allocate n bytes or die */
    396 void *alloc(int n) {
    397 	static char *avail, *limit;
    398 
    399 	n = (n + sizeof(char *) - 1)&~(sizeof(char *) - 1);
    400 	if (n >= limit - avail) {
    401 		avail = malloc(n + 4 * 1024);
    402 		assert(avail);
    403 		limit = avail + n + 4 * 1024;
    404 	}
    405 	avail += n;
    406 	return avail - n;
    407 }
    408 
    409 
    410 /* basepath - return base name for name, e.g. /usr/drh/foo.c => foo */
    411 char *basepath(char *name) {
    412 	char *s, *b, *t = 0;
    413 
    414 	for (b = s = name; *s; s++)
    415 		if (*s == '/' || *s == '\\') {
    416 			b = s + 1;
    417 			t = 0;
    418 		}
    419 		else if (*s == '.')
    420 			t = s;
    421 	s = strsave(b);
    422 	if (t)
    423 		s[t - b] = 0;
    424 	return s;
    425 }
    426 
    427 // path_stripext - return a new string of path [name] with extension removed
    428 //			  e.g. /usr/drh/foo.c => /usr/drh/foo
    429 char *path_stripext(char *name) {
    430 	char * copy_str = strsave(name);
    431 	char * end_str = copy_str + strlen(copy_str);
    432 
    433 	// Work from end of string backward,
    434 	// truncate string at first "." char
    435 	while (end_str > copy_str) {
    436 		if (*end_str == '.') {
    437 			*end_str = '\0';
    438 			break;
    439 		}
    440 		end_str--;
    441 	}
    442 	return copy_str;
    443 }
    444 
    445 
    446 // path_newext - return a new string of path [name] with extension replaced
    447 //			  e.g. /usr/drh/foo.c => /usr/drh/foo
    448 char *path_newext(char *name, char *new_ext) {
    449 	 return stringf("%s%s", path_stripext(name), new_ext);
    450 }
    451 
    452 
    453 // Check if an extension matches the end of a filename
    454 int matches_ext(const char * filename, const char * ext)
    455 {
    456 	// Only test match if filename is larger than extension
    457 	// Then check the end of the filename for [ext] length of chars
    458 	if (strlen(filename) >= strlen(ext))
    459 		return strncmp(filename + strlen(filename) - strlen(ext), ext, strlen(ext)) == 0;
    460 	else return 0;
    461 }
    462 
    463 
    464 #ifndef WIN32
    465 #define _P_WAIT 0
    466 
    467 static int _spawnvp(int mode, const char *cmdname, char *argv[]) {
    468 	int status;
    469 	pid_t pid, n;
    470 
    471 	switch (pid = fork()) {
    472 	case -1:
    473 		fprintf(stderr, "%s: no more processes\n", progname);
    474 		return 100;
    475 	case 0:
    476 		execv(cmdname, argv);
    477 		fprintf(stderr, "%s: ", progname);
    478 		perror(cmdname);
    479 		fflush(stdout);
    480 		exit(100);
    481 	}
    482 	while ((n = wait(&status)) != pid && n != -1)
    483 		;
    484 	if (n == -1)
    485 		status = -1;
    486 	if (status & 0377) {
    487 		fprintf(stderr, "%s: fatal error in %s\n", progname, cmdname);
    488 		status |= 0400;
    489 	}
    490 	return (status >> 8) & 0377;
    491 }
    492 #endif
    493 
    494 /* removes quotes from src and stores it on dst */
    495 void removeQuotes(char* src, char* dst)
    496 {
    497 	while(*src != '\0')
    498 	{
    499 		if(*src != '\"')
    500 	{
    501 	  if(*dst != *src)
    502 				*(dst) = *src;
    503 	  dst ++;
    504 	}
    505 		src ++;
    506 	}
    507   if(*dst != '\0')
    508 	  *dst = '\0';
    509 }
    510 
    511 /* turns "C:\Users\Zalo\Desktop\gb\gbdk 2020\build\gbdk\"bin/sdcpp
    512    into  "C:\Users\Zalo\Desktop\gb\gbdk 2020\build\gbdk\bin/sdcpp" */
    513 void fixQuotes(char* str)
    514 {
    515 	while(*str != '\"' && *str != '\0')
    516 		str ++;
    517 
    518 	char* src = str;
    519 	if(*src == '\"')
    520 	{
    521 		*(str ++) = '\"';
    522 		while(*src != '\0')
    523 		{
    524 			if(*src != '\"')
    525 				*(str ++) = *src;
    526 			src ++;
    527 		}
    528 		*(str ++) = '\"';
    529 		*(str ++) = '\0';
    530 	}
    531 }
    532 
    533 /* callsys - execute the command described by av[0...], return status */
    534 static int callsys(char **av) {
    535 	int i, status = 0;
    536 	static char **argv;
    537 	static int argc;
    538 
    539 	for (i = 0; av[i] != NULL; i++)
    540 		;
    541 	if (i + 1 > argc) {
    542 		argc = i + 1;
    543 		if (argv == NULL)
    544 			argv = malloc(argc * sizeof *argv);
    545 		else {
    546 			char **argv0 = argv;
    547 			argv = realloc(argv0, argc * sizeof *argv);
    548 			if (argv == NULL)
    549 				free(argv0);
    550 		}
    551 		assert(argv);
    552 	}
    553 	for (i = 0; status == 0 && av[i] != NULL; ) {
    554 		int j = 0;
    555 		char *s;
    556 		for (; av[i] != NULL && (s = strchr(av[i], '\n')) == NULL; i++)
    557 			argv[j++] = av[i];
    558 		if (s != NULL) {
    559 			if (s > av[i])
    560 				argv[j++] = stringf("%.*s", s - av[i], av[i]);
    561 			if (s[1] != '\0')
    562 				av[i] = s + 1;
    563 			else
    564 				i++;
    565 		}
    566 		argv[j] = NULL;
    567 		if (verbose > 0) {
    568 			int k;
    569 			fprintf(stderr, "%s", argv[0]);
    570 			for (k = 1; argv[k] != NULL; k++)
    571 				fprintf(stderr, " %s", argv[k]);
    572 			fprintf(stderr, "\n");
    573 		}
    574 		if (verbose < 2)
    575 		{
    576 			char argv_0_no_quotes[256];
    577 			removeQuotes(argv[0], argv_0_no_quotes);
    578 			for(char** it = argv; *it != 0; it ++)
    579 			{
    580 #ifdef __WIN32__
    581 				fixQuotes(*it); //On windows quotes must be kept, and fixed
    582 #else
    583 		removeQuotes(*it, *it); //On macos, quotes must be fully removed from args
    584 #endif
    585 			}
    586 			//For future reference:
    587 			//_spawnvp requires _FileName to not have quotes
    588 			//_Arguments must have quotes on windows, but not in macos
    589 			//Quoted strings must begin and end with quotes, no quotes in the middle
    590 			status = _spawnvp(_P_WAIT, argv_0_no_quotes, argv);
    591 		}
    592 		if (status == -1) {
    593 			fprintf(stderr, "%s: ", progname);
    594 			perror(argv[0]);
    595 		}
    596 	}
    597 	return status;
    598 }
    599 
    600 /* concat - return concatenation of strings s1 and s2 */
    601 char *concat(const char *s1, const char *s2) {
    602 	int n = strlen(s1);
    603 	char *s = alloc(n + strlen(s2) + 1);
    604 
    605 	strcpy(s, s1);
    606 	strcpy(s + n, s2);
    607 	return s;
    608 }
    609 
    610 /* compose - compose cmd into av substituting a, b, c for $1, $2, $3, resp. */
    611 static void compose(char *cmd[], List a, List b, List c) {
    612 	int i, j;
    613 	List lists[3];
    614 
    615 	lists[0] = a;
    616 	lists[1] = b;
    617 	lists[2] = c;
    618 	for (i = j = 0; cmd[i]; i++) {
    619 		char *s = strchr(cmd[i], '$');
    620 		if (s && isdigit(s[1])) {
    621 			int k = s[1] - '0';
    622 			assert(k >= 1 && k <= 3);
    623 			b = lists[k - 1];
    624 			if (b) {
    625 				b = b->link;
    626 				av[j] = alloc(strlen(cmd[i]) + strlen(b->str) - 1);
    627 				strncpy(av[j], cmd[i], s - cmd[i]);
    628 				av[j][s - cmd[i]] = '\0';
    629 				strcat(av[j], b->str);
    630 				strcat(av[j++], s + 2);
    631 				while (b != lists[k - 1]) {
    632 					b = b->link;
    633 					assert(j < ac);
    634 					av[j++] = b->str;
    635 				};
    636 			}
    637 		}
    638 		else if (*cmd[i]) {
    639 			assert(j < ac);
    640 			av[j++] = cmd[i];
    641 		}
    642 	}
    643 	av[j] = NULL;
    644 }
    645 
    646 /* error - issue error msg according to fmt, bump error count */
    647 static void error(char *fmt, char *msg) {
    648 	fprintf(stderr, "%s: ", progname);
    649 	fprintf(stderr, fmt, msg);
    650 	fprintf(stderr, "\n");
    651 	errcnt++;
    652 }
    653 
    654 /* exists - if `name' readable return its path name or return null */
    655 static char *exists(char *name) {
    656 	List b;
    657 
    658 	if ((name[0] == '/' || name[0] == '\\' || name[2] == ':')
    659 		&& access(name, 4) == 0)
    660 		return name;
    661 	if (!(name[0] == '/' || name[0] == '\\' || name[2] == ':')
    662 		&& (b = lccinputs))
    663 		do {
    664 			b = b->link;
    665 			if (b->str[0]) {
    666 				char buf[1024];
    667 				sprintf(buf, "%s/%s", b->str, name);
    668 				if (access(buf, 4) == 0)
    669 					return strsave(buf);
    670 			}
    671 			else if (access(name, 4) == 0)
    672 				return name;
    673 		} while (b != lccinputs);
    674 		if (verbose > 1)
    675 			return name;
    676 		return 0;
    677 }
    678 
    679 /* first - return first component in semicolon separated list */
    680 static char *first(char *list) {
    681 	char *s = strchr(list, ';');
    682 
    683 	if (s) {
    684 		char buf[1024];
    685 		size_t len = s - list;
    686 		if(len >= sizeof(buf)) len = sizeof(buf)-1;
    687 		strncpy(buf, list, len);
    688 		buf[len] = '\0';
    689 		return strsave(buf);
    690 	}
    691 	else
    692 		return list;
    693 }
    694 
    695 /* filename - process file name argument `name', return status */
    696 static int filename(char *name, char *base) {
    697 	int status = 0;
    698 	static char *stemp, *itemp;
    699 
    700 	if (base == 0)
    701 		base = basepath(name);
    702 
    703 	// Handle all available suffixes except .gb (last in list)
    704 	switch (suffix(name, suffixes, 5)) {
    705 	case 0:	/* C source files */
    706 		if (Eflag) {
    707 			// If Preprocess only was requested
    708 			status = handle_file_preprocess_only(name, base);
    709 		}
    710 		else {
    711 			char *ofile;
    712 			if ((cflag || Sflag) && outfile)
    713 				ofile = outfile;
    714 			else if (cflag)
    715 				ofile = concat(base, EXT_O);
    716 			else if (Sflag) {
    717 				// When compiling to asm only, set outfile as .asm
    718 				ofile = concat(base, EXT_ASM);
    719 			}
    720 			else
    721 			{
    722 				ofile = tempname(EXT_O);
    723 
    724 				// Remove generated files of these extensions upon completion
    725 				char* ofileBase = basepath(ofile);
    726 				rmlist = append(stringf("%s/%s%s", tempdir, ofileBase, EXT_ASM), rmlist);
    727 				rmlist = append(stringf("%s/%s%s", tempdir, ofileBase, EXT_LST), rmlist);
    728 				rmlist = append(stringf("%s/%s%s", tempdir, ofileBase, EXT_SYM), rmlist);
    729 				rmlist = append(stringf("%s/%s%s", tempdir, ofileBase, EXT_ADB), rmlist);
    730 			}
    731 
    732 			compose(com, clist, append(name, 0), append(ofile, 0));
    733 			status = callsys(av);
    734 			if (!find(ofile, llist[L_FILES]))
    735 				llist[L_FILES] = append(ofile, llist[L_FILES]);
    736 		}
    737 		break;
    738 	case 2:	/* assembly language files */
    739 		if (Eflag)
    740 			break; // Skip asm files if pre-process only specified
    741 		if (!Sflag) {
    742 			char *ofile;
    743 			if (cflag && outfile)
    744 				ofile = outfile;
    745 			else if (cflag)
    746 				ofile = concat(base, EXT_O);
    747 			else
    748 				ofile = tempname(EXT_O);
    749 			compose(as, alist, append(name, 0), append(ofile, 0));
    750 			status = callsys(av);
    751 			if (!find(ofile, llist[L_FILES]))
    752 				llist[L_FILES] = append(ofile, llist[L_FILES]);
    753 		}
    754 		break;
    755 	case 3:	/* object files */
    756 		if (!find(name, llist[L_FILES]))
    757 			llist[L_FILES] = append(name, llist[L_FILES]);
    758 		break;
    759 	case 4: // .ihx files
    760 		// Apply "name" as .ihx file (there can be only one as input)
    761 		strncpy(ihxFile, name, sizeof(ihxFile) - 1);
    762 		break;
    763 	default: // Files with unmatched or no extension
    764 
    765 		// If Preprocess only was requested and it's a .h file
    766 		if ((Eflag) && matches_ext(name, EXT_H))  {
    767 			status = handle_file_preprocess_only(name, base);
    768 			break;
    769 		}
    770 		llist[L_FILES] = append(name, llist[L_FILES]);
    771 		break;
    772 	}
    773 	if (status)
    774 		errcnt++;
    775 	return status;
    776 }
    777 
    778 /* help - print help message */
    779 static void help(void) {
    780 	static char *msgs[] = {
    781 "", " [ option | file ]...\n",
    782 "    except for -l, options are processed left-to-right before files\n",
    783 "    unrecognized options are taken to be linker options\n",
    784 "-c             compile only\n",
    785 "-debug         Turns on --debug for compiler, -y (.cdb), -j (.noi), -w (wide .map format) for linker\n",
    786 "                       -Wa-l (assembler .lst), -Wl-u (.lst -> .rst address update)\n",
    787 "-Dname=def     define the preprocessor symbol `name'\n",
    788 "-E             only run preprocessor on named .c and .h files files -> stdout\n",
    789 "--save-preproc Use with -E for output to *.i files instead of stdout\n",
    790 "-help or -?    print this message\n",
    791 "-Idir          add `dir' to the beginning of the list of #include directories\n",
    792 "-K             don't run ihxcheck test on linker ihx output\n",
    793 "-lx            search library `x'\n",
    794 "-m             select port and platform: \"-m[port]:[plat]\" ports:sm83,z80,mos6502 plats:ap,duck,gb,sms,gg,nes\n",
    795 "-N             do not search the standard directories for #include files\n",
    796 "-no-crt        do not auto-include the gbdk crt0.o runtime in linker list\n",
    797 "-no-libs       do not auto-include the gbdk libs in linker list\n",
    798 "-o file        leave the output in `file'\n",
    799 "-S             compile to assembly language\n",
    800 "-autobank      auto-assign banks set to 255 (bankpack)\n"
    801 "-tempdir=dir   place temporary files in `dir/'", "\n"
    802 "-Uname         undefine the preprocessor symbol `name'\n",
    803 "-v             show commands as they are executed; 2nd -v suppresses execution\n",
    804 "-Woarg         specify system-specific `arg'\n",
    805 "-W[pfablimnc]arg pass `arg' to the (p)preprocessor, (f)compiler, (a)assembler, (b)bankpack,\n"
    806 "                                   (l)linker, (i)ihxcheck, (m)makebin, (n)makenes, (c)makecom\n",
    807 	0 };
    808 	int i;
    809 	char *s;
    810 
    811 	msgs[0] = progname;
    812 	for (i = 0; msgs[i]; i++) {
    813 		fprintf(stderr, "%s", msgs[i]);
    814 		if (strncmp("-tempdir", msgs[i], 8) == 0 && tempdir)
    815 			fprintf(stderr, "; default=%s", tempdir);
    816 	}
    817 #define xx(v) if ((s = getenv(#v))) fprintf(stderr, #v "=%s\n", s)
    818 	xx(LCCINPUTS);
    819 	xx(LCCDIR);
    820 #ifdef WIN32
    821 	xx(include);
    822 	xx(lib);
    823 #endif
    824 #undef xx
    825 }
    826 
    827 /* initinputs - if LCCINPUTS or include is defined, use them to initialize various lists */
    828 static void initinputs(void) {
    829 	char *s = getenv("LCCINPUTS");
    830 	List list, b;
    831 
    832 	if (s == 0 || (s = inputs)[0] == 0)
    833 		s = ".";
    834 	if (s) {
    835 		lccinputs = path2list(s);
    836 		b = lccinputs;
    837 		if (b)
    838 			do {
    839 				b = b->link;
    840 				if (strcmp(b->str, ".") != 0) {
    841 					ilist = append(concat("-I", b->str), ilist);
    842 					if (strstr(com[1], "win32") == NULL)
    843 						llist[L_ARGS] = append(concat("-L", b->str), llist[L_ARGS]);
    844 				}
    845 				else
    846 					b->str = "";
    847 			} while (b != lccinputs);
    848 	}
    849 #ifdef WIN32
    850 	if (list = b = path2list(getenv("include")))
    851 		do {
    852 			b = b->link;
    853 			ilist = append(stringf("-I\"%s\"", b->str), ilist);
    854 		} while (b != list);
    855 #endif
    856 }
    857 
    858 /* interrupt - catch interrupt signals */
    859 static void interrupt(int n) {
    860 	rm(rmlist);
    861 	exit(n = 100);
    862 }
    863 
    864 /* opt - process option in arg */
    865 static void opt(char *arg) {
    866 	switch (arg[1]) {	/* multi-character options */
    867 
    868     // Obsolete (multi-character) options that just emit a warning
    869     // -----------------------------------------
    870     case 'p': // -p -pg         emit profiling code; see prof(1) and gprof(1)
    871     case 'B': // -Bdir/         use the compiler named `dir/rcc' (Also -Bstatic -Bdynamic)
    872         warn_obsolete_option(arg);
    873         return;
    874 
    875     case 's': // -static        specify static libraries (default is dynamic)
    876         if (strcmp(arg, "-static") == 0) {
    877             warn_obsolete_option(arg);
    878         }
    879         return;
    880     // -----------------------------------------
    881 
    882 	case '-':	// --* options
    883 		if (strcmp(arg, "--save-preproc") == 0) {
    884 			Eflag_preproc_to_file = true;
    885 			return;
    886 		}
    887 		// If no match for "--*" options here then break instead of
    888 		// return in case they need to get processed in option() below
    889 		break;
    890 	case 'W':	/* -Wxarg */
    891 		if (arg[2] && arg[3])
    892 			switch (arg[2]) {
    893 			case 'o':
    894 				if (option(&arg[3]))
    895 					return;
    896 				break;
    897 			case 'p': /* Preprocessor */
    898 				clist = append(&arg[3], clist);
    899 				return;
    900 			case 'f': /* Compiler */
    901 				if (strcmp(&arg[3], "-C") || option("-b")) {
    902 					clist = append(&arg[3], clist);
    903 					return;
    904 				}
    905 				break; /* and fall thru */
    906 			case 'a': /* Assembler */
    907 				alist = append(&arg[3], alist);
    908 				return;
    909 			case 'i': /* ihxcheck arg list */
    910 				ihxchecklist = append(&arg[3], ihxchecklist);
    911 				return;
    912 			case 'n': /* makenes arg list */
    913 				postproclist = append(&arg[3], postproclist);
    914 				return;
    915 			case 'c': /* makecom arg list */
    916 				postproclist = append(&arg[3], postproclist);
    917 				return;
    918 			case 'b': /* auto bankpack_flags arg list */
    919 				bankpack_flags = append(&arg[3], bankpack_flags);
    920 				// -Wb-ext=[.some-extension]
    921 				// If bankpack is going to rewrite input object files to a new extension
    922 				// then save that extension for rewriting the linker list (llist[L_FILES])
    923 				if (strstr(&arg[3], "-ext=") != NULL) {
    924 					if (arg[8]) {
    925 						sprintf(bankpack_newext, "%s", &arg[8]);
    926 					}
    927 				}
    928 				return;
    929 			case 'l': /* Linker */
    930 				if(arg[4] == 'y' && (arg[5] == 't' || arg[5] == 'o' || arg[5] == 'a' || arg[5] == 'p') && (arg[6] != '\0' && arg[6] != ' '))
    931 					goto makebinoption; //automatically pass -yo -ya -yt -yp options to makebin (backwards compatibility)
    932 				{
    933 					// If using linker file for sdldgb (-f file[.lk]).
    934 					// Starting at arg[5] should be name of the linkerfile
    935 					if ((arg[4] == 'f') && (arg[5])) {
    936 						// Items in llist[L_LKFILES] get added to llist[L_FILES] right before the linker is called.
    937 						// That avoids sending to bankpack with the "-f" flag mixed in with the names of the .o object files.
    938 						llist[L_LKFILES] = append(stringf(&arg[5]), llist[L_LKFILES]);
    939 					} else {
    940 						//sdldgb requires spaces between -k and the path
    941 						llist[L_ARGS] = append(stringf("%c%c", arg[3], arg[4]), llist[L_ARGS]);	 //splitting the args into 2 works on Win and Linux
    942 						if (arg[5]) {
    943 							llist[L_ARGS] = append(&arg[5], llist[L_ARGS]);  // Add filename separately if present
    944 						}
    945 					}
    946 				}
    947 				return;
    948 			case 'm': /* Makebin */
    949 			makebinoption:{
    950 				char *tmp = malloc(256);
    951 				char *tmp2 = malloc(256);
    952 				tmp2[0] = '\0'; // Zero out second arg by default
    953 				if (arg[4] == 'y') {
    954 					sprintf(tmp, "%c%c%c", arg[3], arg[4], arg[5]); //-yo -ya -yt -yl -yk -yn -yp
    955 					if (!(arg[5] == 'c' || arg[5] == 'C' || arg[5] == 's'  || arg[5] == 'S' || arg[5] == 'j' || arg[5] == 'p')) // Don't add second arg for -yc -yC -ys -yS -yj
    956 						sprintf(tmp2, "%s", &arg[6]);
    957 					// -yp of SDCC 4.1.0's makebin erroneously does not use a space between flag and it's value
    958 					// So append trailing values to first arg that would otherwise go in the second arg
    959 					if (arg[5] == 'p')
    960 						sprintf(tmp, "%s", &arg[3]);
    961 
    962 					// If MBC option is present for makebin (-Wl-yt <n> or -Wm-yt <n>) then make a copy for bankpack to use
    963 					if (arg[5] == 't')
    964 						bankpack_flags = append(&arg[3], bankpack_flags);
    965 				} else if ((arg[4] == 'x') && arg[5] && arg[6]) {
    966 					// SMS options
    967 					// Print "-" plus first two option chars into first arg
    968 					// and any trailing option chars into a separate arg
    969 					sprintf(tmp, "%c%c%c", arg[3], arg[4], arg[5]);  //-xo -xj -xv
    970 					if(arg[6])
    971 						sprintf(tmp2, "%s", &arg[6]);
    972 				} else {
    973 					sprintf(tmp, "%c%c", arg[3], arg[4]); //-s
    974 					if(arg[5])
    975 						sprintf(tmp2, "%s", &arg[5]);
    976 				}
    977 				mkbinlist = append(tmp, mkbinlist);
    978 				if (tmp2[0] != '\0')  // Only append second argument if it's populated
    979 					mkbinlist = append(tmp2, mkbinlist);
    980 				}return;
    981 			}
    982 		fprintf(stderr, "%s: %s ignored\n", progname, arg);
    983 		return;
    984 	case 'd':
    985 		if (strcmp(arg, "-debug") == 0) {
    986 			// Load default debug options
    987 			clist	= append("--debug", clist);  // Debug for sdcc compiler
    988 			llist[L_ARGS] = append("-y", llist[L_ARGS]);	// linker: .cdb output for sdldgb
    989 			llist[L_ARGS] = append("-j", llist[L_ARGS]);	// linker: .noi output
    990 
    991 			alist         = append("-l", alist);            // assembler: .lst output
    992 			// -Wl-u currently requires a patch to SDCC so it warns instead errors out and
    993 			// build fails if no matching .lst file is present for an object file.
    994 			// For example: When the user includes a pre-built object file for a music driver
    995 			llist[L_ARGS] = append("-u", llist[L_ARGS]);    // linker: .lst -> .rst address update
    996 			llist[L_ARGS] = append("-w", llist[L_ARGS]);    // linker: wide listing in .map file
    997 			return;
    998 		}
    999 
   1000         // This option is obsolete
   1001         // -----------------------------------------
   1002         // -dn            set switch statement density to `n'
   1003         warn_obsolete_option(arg);
   1004         // -----------------------------------------
   1005 		return;
   1006 	case 't':	/* -t -tname -tempdir=dir */
   1007 		if (strncmp(arg, "-tempdir=", 9) == 0)
   1008 			tempdir = arg + 9;
   1009 		else
   1010 			clist = append(arg, clist);
   1011 		return;
   1012 	case 'D':	/* -Dname -Dname=def */
   1013 	case 'U':	/* -Uname */
   1014 	case 'I':	/* -Idir */
   1015 		clist = append(arg, clist);
   1016 		return;
   1017 	case 'K':
   1018 		Kflag++;
   1019 		return;
   1020 	case 'a':
   1021 		if (strcmp(arg, "-autobank") == 0) {
   1022 			autobankflag++;
   1023 			return;
   1024 		}
   1025 	case 'n':
   1026 		if (strcmp(arg, "-no-crt") == 0) {
   1027 			option(arg);  // Clear crt0 entry in linker compose string
   1028 			return;
   1029 		}
   1030 		else if (strcmp(arg, "-no-libs") == 0) {
   1031 			option(arg);  // Clear libs entry in linker compose string
   1032 			return;
   1033 		}
   1034 	case 'h':
   1035 		if (strcmp(arg, "-help") == 0) {
   1036 			static int printed = 0;
   1037 	case '?':
   1038 		if (!printed)
   1039 			help();
   1040 		printed = 1;
   1041 		return;
   1042 		}
   1043 	}
   1044 	if (arg[2] == 0)
   1045 		switch (arg[1]) {	/* single-character options */
   1046 
   1047         // Obsolete (single character) options that just emit a warning
   1048         // -----------------------------------------
   1049         case 'A': // -A             warn about nonANSI usage; 2nd -A warns more
   1050         case 'b': // -b             emit expression-level profiling code; see bprint(1)
   1051         case 'g': // -g             produce symbol table information for debuggers
   1052         case 'G': // -G             append("-g3", clist); append("-N", llist[L_ARGS]);
   1053         case 'n': // -n             emit code to check for dereferencing zero pointers
   1054         case 'O': // -O             is ignored
   1055         case 'P': // -P             print ANSI-style declarations for globals
   1056         case 't': // -t -tname      emit function tracing calls to printf or to `name'
   1057         case 'w': // -w             suppress warnings
   1058             warn_obsolete_option(arg);
   1059             return;
   1060         // -----------------------------------------
   1061 
   1062 		case 'S':		// Requested compile to assembly only
   1063 			Sflag++;
   1064 			option(arg); // Update composing the compile stage, use of -S instead of -c
   1065 			return;
   1066 		case 'E':
   1067 			Eflag++; // Preprocess files only
   1068 			return;
   1069 		case 'c':
   1070 			cflag++;
   1071 			return;
   1072 		case 'N':
   1073 			if (strcmp(basepath(cpp[0]), "gcc-cpp") == 0)
   1074 				clist = append("-nostdinc", clist);
   1075 			include[0] = 0;
   1076 			ilist = 0;
   1077 			return;
   1078 		case 'v':
   1079 			if (verbose++ == 0) {
   1080 				fprintf(stderr, "%s %s\n", progname, rcsid);
   1081 			}
   1082 			return;
   1083 		}
   1084 	if (option(arg))
   1085 		return;
   1086 	if (cflag || Sflag || Eflag)
   1087 		fprintf(stderr, "%s: %s ignored\n", progname, arg);
   1088 	else
   1089 		llist[L_FILES] = append(arg, llist[L_FILES]);
   1090 }
   1091 
   1092 
   1093 /* replace - copy str, then replace occurrences of from with to, return the copy */
   1094 char *replace(const char *str, int from, int to) {
   1095 	char *s = strsave(str), *p = s;
   1096 
   1097 	for (; (p = strchr(p, from)) != NULL; p++)
   1098 		*p = to;
   1099 	return s;
   1100 }
   1101 
   1102 /* rm - remove files in list */
   1103 static void rm(List list) {
   1104 	if (list) {
   1105 		List b = list;
   1106 		if (verbose)
   1107 			fprintf(stderr, "rm");
   1108 		do {
   1109 			if (verbose)
   1110 				fprintf(stderr, " %s", b->str);
   1111 			if (verbose < 2)
   1112 				remove(b->str);
   1113 		} while ((b = b->link) != list);
   1114 		if (verbose)
   1115 			fprintf(stderr, "\n");
   1116 	}
   1117 }
   1118 
   1119 /* strsave - return a saved copy of string str */
   1120 char *strsave(const char *str) {
   1121 	return strcpy(alloc(strlen(str) + 1), str);
   1122 }
   1123 
   1124 /* stringf - format and return a string */
   1125 char *stringf(const char *fmt, ...) {
   1126 	char buf[1024];
   1127 	va_list ap;
   1128 	int n;
   1129 
   1130 	va_start(ap, fmt);
   1131 	n = vsnprintf(buf, sizeof(buf), fmt, ap);
   1132 	va_end(ap);
   1133 	return strsave(buf);
   1134 }
   1135 
   1136 /* suffix - if one of tails[0..n-1] holds a proper suffix of name, return its index */
   1137 int suffix(char *name, char *tails[], int n) {
   1138 	int i, len = strlen(name);
   1139 
   1140 	for (i = 0; i < n; i++) {
   1141 		char *s = tails[i], *t;
   1142 		for (; (t = strchr(s, ';')); s = t + 1) {
   1143 			int m = t - s;
   1144 			if (len > m && strncmp(&name[len - m], s, m) == 0)
   1145 				return i;
   1146 		}
   1147 		if (*s) {
   1148 			int m = strlen(s);
   1149 			if (len > m && strncmp(&name[len - m], s, m) == 0)
   1150 				return i;
   1151 		}
   1152 	}
   1153 	return SUFX_NOMATCH;
   1154 }
   1155 
   1156 /* tempname - generate a temporary file name in tempdir with given suffix */
   1157 char *tempname(char *suffix) {
   1158 	static int n;
   1159 	char *name = stringf("%s/lcc%d%d%s", tempdir, getpid(), n++, suffix);
   1160 
   1161 	if (strstr(com[1], "win32") != NULL)
   1162 		name = replace(name, '/', '\\');
   1163 	rmlist = append(name, rmlist);
   1164 	return name;
   1165 }
   1166 
   1167 
   1168 // Performs the autobanking stage
   1169 //
   1170 // Should be called prior to doing compose() for the linker
   1171 //
   1172 static void handle_autobanking(void) {
   1173 
   1174 	// bankpack will be populated if supported by active port:platform
   1175 	if (bankpack[0][0] != '\0') {
   1176 
   1177 		char * bankpack_linkerfile_name = tempname(EXT_LK);
   1178 		rmlist = append(bankpack_linkerfile_name, rmlist); // Delete the linkerfile when done
   1179 		// Always use a linkerfile when using bankpack through lcc
   1180 		// Writes all input object files out to [bankpack_linkerfile_name]
   1181 		bankpack_flags = append(stringf("%s%s","-lkout=", bankpack_linkerfile_name), bankpack_flags);
   1182 
   1183 		// Add linkerfile entries (usually *.lk) to the bankpack arg list if any are present
   1184 		bankpack_flags = list_add_to_another(bankpack_flags, llist[L_LKFILES], "-lkin=", NULL);
   1185 
   1186 		// Prepare the bankpack command line, then execute it
   1187 		compose(bankpack, bankpack_flags, llist[L_FILES], 0);
   1188 		if (callsys(av))
   1189 			errcnt++;
   1190 
   1191 		// Clear out the objects file and linkerfiles from their lists
   1192 		// Then replace them with the filename passed to bankpack for "-lkout="
   1193 		llist[L_FILES]   = list_remove_all(llist[L_FILES]);
   1194 		llist[L_LKFILES] = list_remove_all(llist[L_LKFILES]);
   1195 		llist[L_LKFILES] = append(stringf("%s", bankpack_linkerfile_name), llist[L_LKFILES]);
   1196 	}
   1197 	else
   1198 		fprintf(stderr, "Warning: bankpack enabled but not supported by active port:platform\n");
   1199 }
   1200 
   1201 // Triggered by -E flag
   1202 // Called for files with .c, unmatched extension, or no extension
   1203 // Output with -o > <somefile>.i is blocked earlier (same as is for output to .c)
   1204 //
   1205 // Note: This follows the existing convention for -c and -S where the output file
   1206 //       is just the input file with the path stripped off and placed into the working dir.
   1207 //       Not actually sure that's what anyone wants, but not gonna rock that boat for now.
   1208 //       Otherwise using "name" instead of base would use the full path for output.
   1209 static int handle_file_preprocess_only(char *name, char *base) {
   1210 
   1211 	// Default for preprocess only is to stdout with no output file
   1212 	char *ofile;
   1213 
   1214 	// Save preprocessor output to a file if requested
   1215 	if (Eflag_preproc_to_file) {
   1216 		ofile = concat("-o", concat(base, EXT_I));
   1217 		compose(cpp, clist, append(name, 0), append(ofile, 0));
   1218 	}
   1219 	else
   1220 		compose(cpp, clist, append(name, 0), 0);
   1221 
   1222 	return callsys(av); // return call status
   1223 }
   1224 
   1225 
   1226 static void warn_obsolete_option(char * arg) {
   1227     fprintf(stderr, "lcc: Warning: argument \"%s\" ignored, no longer supported\n", arg);
   1228 }

This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.