/* TIGCC - A front-end for the compiler, assembler, linker and some other * stuffs. * Copyright (C) 2001 John David Ratliff * Copyright (C) 2001-2002 Romain Liévin * Copyright (C) 2002-2005 Kevin Kofler * Modified by Nils Gesbert, 2003 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #ifdef HAVE_CONFIG_H # include #endif #include "tigcc.h" /* The name the program was run with, stripped of any leading path. */ char *program_name; void print_version(void) { fprintf(stderr, "tigcc version %s built for TIGCC/*nix version %s\n", VERSION, TIGCC_VERSION); exit(0); } /* Display helping informations */ static void usage (int status) { printf ("%s - front-end for TIGCC\n", program_name); printf ("Usage: %s [OPTION]... [FILE]...\n", program_name); printf ("Options:\n" " -h, --help display this help and exit\n" " -V, --version output version information and exit\n" " -v, --verbose set verbosity on: show what the program is doing\n" " -q, --quiet display nothing\n" " -E, pre-process but don't compile or assemble\n" " -S, compile but don't assemble or link\n" " -c, compile/assemble, but don't link\n" " -g, --debug turns on debugging information (DWARF 2 format)\n" " -bsr ignored for backwards compatibility\n" " -o [outfile] output to file outfile\n" " -pack [varname] compress the program using ExePack technology\n" " -outputbin produce a pure binary file (as with ttstrip)\n" " -standalone does not link against the tigcc.a archive\n" " -r, --redirect redirect stdout to the tigcc.log file\n" " -Wa/WA,options pass options to as/a68k\n" " -ar create static library (function archive)\n" " -keep keep object files\n" " --all-relocs assemble files in all-relocs mode (for range cutting)\n" "Linker options are automatically passed on to ld-tigcc. See ld-tigcc --help for\n" "details.\n" "\n"); exit (status); } #define print_help() usage(0) /* Process cmdline args */ short int process_arg(short int arg, char *argv[], int argc) { char *cur_arg = argv[arg]; if (!strcmp("-h", cur_arg) || !strcmp("--help", cur_arg)) { print_help(); } else if (!strcmp("-V", cur_arg) || !strcmp("--version", cur_arg)) { print_version(); } else if (!strcmp("-v", cur_arg) || !strcmp("--verbose", cur_arg)) { ld_argv[ld_argc++] = cur_arg; gcc_argv[gcc_argc++] = cur_arg; verbose = TRUE; printcommands = TRUE; quiet = FALSE; } else if (!strcmp("-v0", cur_arg)) { printcommands = TRUE; } else if (!strcmp("-q", cur_arg) || !strcmp("--quiet", cur_arg)) { quiet = TRUE; verbose = FALSE; } else if(!strcmp("-E", cur_arg)) { delete = FALSE; patch = FALSE; do_compile = FALSE; do_link = FALSE; do_assemble = FALSE; } else if (!strcmp("-S", cur_arg)) { delete = FALSE; do_link = FALSE; do_assemble = FALSE; } else if (!strcmp("-c", cur_arg)) { do_link = FALSE; } else if (!strcmp("-g", cur_arg)) { debug = TRUE; } else if (!strcmp("--debug", cur_arg)) { debug = TRUE; } else if (!strcmp("-pack", cur_arg)) { char *next_arg; if(arg >= argc-1) { fprintf(stderr, "Error: you didn't specify a pack file\n"); exit(-1); } else { next_arg = argv[++arg]; if(next_arg[0] == '-') { fprintf(stderr, "Error: invalid pack filename\n"); exit(-1); } packfile[0] = 0; strncpy(packfile, next_arg, 8); do_pack = TRUE; } } else if(!strcmp("-bsr", cur_arg)) { /* Empty. Ignored for backwards compatibility. */ } else if (!strcmp("-outputbin", cur_arg) || !strcmp("--outputbin", cur_arg)) { outputbin = TRUE; } else if (!strcmp("-standalone", cur_arg) || !strcmp("--standalone", cur_arg)) { nostdlib = TRUE; } else if (!strcmp("-ar", cur_arg)) { staticlib = TRUE; nostdlib = TRUE; allrelocs = TRUE; optreturns = TRUE; } else if (!strcmp("-quill", cur_arg)) { char *quill_drv = malloc (strlen(tigcc_base) + 25); if (!quill_drv) { fprintf(stderr, "Fatal error: not enough free memory\n"); exit(-1); } sprintf(quill_drv, "%s/bin/quill.drv", tigcc_base); if(access(quill_drv, F_OK) != -1) goto quill_drv_found; sprintf(quill_drv, "%s/bin/Quill.drv", tigcc_base); if(access(quill_drv, F_OK) != -1) goto quill_drv_found; sprintf(quill_drv, "%s/include/c/quill.drv", tigcc_base); if(access(quill_drv, F_OK) != -1) goto quill_drv_found; sprintf(quill_drv, "%s/include/c/Quill.drv", tigcc_base); if(access(quill_drv, F_OK) != -1) goto quill_drv_found; sprintf(quill_drv, "%s/include/quill/quill.drv", tigcc_base); if(access(quill_drv, F_OK) != -1) goto quill_drv_found; sprintf(quill_drv, "%s/include/quill/Quill.drv", tigcc_base); if(access(quill_drv, F_OK) != -1) goto quill_drv_found; sprintf(quill_drv, "%s/include/Quill/quill.drv", tigcc_base); if(access(quill_drv, F_OK) != -1) goto quill_drv_found; sprintf(quill_drv, "%s/include/Quill/Quill.drv", tigcc_base); if(access(quill_drv, F_OK) != -1) goto quill_drv_found; sprintf(quill_drv, "%s/lib/quill.drv", tigcc_base); if(access(quill_drv, F_OK) != -1) goto quill_drv_found; sprintf(quill_drv, "%s/lib/Quill.drv", tigcc_base); if(access(quill_drv, F_OK) != -1) goto quill_drv_found; fprintf(stderr, "Quill installation problem: quill.drv file is missing.\n"); exit(-1); quill_drv_found: gcc_argv[gcc_argc++] = "-include"; gcc_argv[gcc_argc++] = quill_drv; gcc_argv[gcc_argc++] = "-x"; gcc_argv[gcc_argc++] = "c"; } else if (!strcmp("-o", cur_arg) || !strcmp("--output", cur_arg)) { if (++arg > argc) { fprintf(stderr, "Error: you didn't specify an output file\n"); } else { outfile = argv[arg]; } } else if (!strcmp("-r", cur_arg) || !strcmp("--redirect", cur_arg)) { freopen (REDIRECT, "wt", stdout); dup2 (STDOUT_FILENO, STDERR_FILENO); } else if (!strncmp("-Wa,", cur_arg, 4)) { as_args = strdup (cur_arg); if (!as_args) { fputs ("Fatal error: not enough free memory\n", stderr); exit (-1); } } else if (!strncmp("-WA,", cur_arg, 4)) { a68k_args = strdup (cur_arg); if (!a68k_args) { fputs ("Fatal error: not enough free memory\n", stderr); exit (-1); } } else if (!strcmp("-np", cur_arg)) { printf("Developer option: no patching enabled !\n"); patch = FALSE; } else if (!strcmp("-keep", cur_arg) || !strcmp("--keep", cur_arg)) { keepobj = TRUE; } else if (!strcmp("-save-temps", cur_arg) || !strcmp("--save-temps", cur_arg)) { savetemps = keepobj = TRUE; delete = FALSE; gcc_argv[gcc_argc++] = cur_arg; } else if (!strcmp("--fargo", cur_arg)) { fargo = TRUE; ld_argv[ld_argc++] = cur_arg; } else if (!strcmp("--flash-os", cur_arg)) { flashos = TRUE; ld_argv[ld_argc++] = cur_arg; } else if (!strcmp("--cut-ranges", cur_arg)) { allrelocs = TRUE; ld_argv[ld_argc++] = cur_arg; } else if (!strcmp("--all-relocs", cur_arg)) { allrelocs = TRUE; } else if (!strcmp("--optimize-code", cur_arg) || !strcmp("--optimize-returns", cur_arg)) { optreturns = TRUE; ld_argv[ld_argc++] = cur_arg; } else if (!strcmp("--native", cur_arg) || !strcmp("--remove-unused", cur_arg) || !strcmp("--optimize-relocs", cur_arg) || !strcmp("--optimize-nops", cur_arg) || !strcmp("--optimize-branches", cur_arg) || !strcmp("--optimize-moves", cur_arg) || !strcmp("--optimize-tests", cur_arg) || !strcmp("--optimize-calcs", cur_arg) || !strcmp("--reorder-sections", cur_arg) || !strcmp("--merge-constants", cur_arg) || !strcmp("--omit-bss-init", cur_arg) || !strcmp("--data-var-copy=never", cur_arg) || !strcmp("--data-var-copy=always", cur_arg) || !strcmp("--data-var-copy=archived", cur_arg) || !strcmp("--dump", cur_arg) || !strcmp("--dump0", cur_arg) || !strcmp("--dump1", cur_arg) || !strcmp("--dump2", cur_arg) || !strcmp("--dump3", cur_arg) || !strcmp("--dump4", cur_arg) || !strcmp("--dump5", cur_arg) || !strcmp("--dump6", cur_arg) || !strcmp("--dump7", cur_arg) || !strcmp("--dump8", cur_arg) || !strcmp("--dump9", cur_arg)) { ld_argv[ld_argc++] = cur_arg; } else if (!strcmp("-n", cur_arg) || !strcmp("--varname", cur_arg)) { if (++arg > argc) { fprintf(stderr, "Error: you didn't specify a variable name\n"); } else { ld_argv[ld_argc++] = cur_arg; ld_argv[ld_argc++] = argv[arg]; } } else if (!strcmp("-d", cur_arg) || !strcmp("--data-var", cur_arg)) { if (++arg > argc) { fprintf(stderr, "Error: you didn't specify a data variable name\n"); } else { ld_argv[ld_argc++] = cur_arg; ld_argv[ld_argc++] = argv[arg]; nomergesections = TRUE; } } return arg; } short int is_tigcc_arg(char *arg) { short int loop; for (loop = 0; tigcc_args[loop] != NULL; loop++) { if (strncmp(arg, tigcc_args[loop], 4) == 0) { return TRUE; } } return FALSE; } /* Return file type */ short int is_source_file(char *file) { char *ext = strrchr(file, '.'); short int filetype = BADFILE; if (ext == NULL) { return filetype; } if (strcasecmp(ext, ".c") == 0) { filetype = CFILE; } else if (strcasecmp(ext, ".asm") == 0) { filetype = ASMFILE; } else if (strcasecmp(ext, ".s") == 0) { filetype = SFILE; } else if (strcasecmp(ext, ".o") == 0) { filetype = OFILE; } else if (strcasecmp(ext, ".a") == 0) { filetype = AFILE; } else if (strcasecmp(ext, ".qll") == 0) { filetype = QLLFILE; } return filetype; } #define add_to_file_array(file,array) do {array->files[array->count++] = file;} while (0) void free_file_array(array_of_files *array) { /* (NG) Well, it doesn't work even if *all* the strings in the array are malloc-ated. I don't understand why... :( Anyway, it won't work if a68k() is called as it is now (see there). */ #if 0 short int loop; for (loop = 0; loop < array->count; loop++) { free(array->files[loop]); } #endif free(array); } /* Change filename extension and keep long filenames */ char *change_extension(char *file, char *newext) { char *start = (char *)strrchr(file, '.'); if(start == NULL) { start = file + strlen(file); } sprintf(start, "%s", newext); /* (NG) So to be safe file must be strlen(file) + strlen (newext) + 1 long... */ return file; } void parse_args(int *argc, char *argv[]) { static int firstsourcefile = 0; short int loop, filetype; array_of_files *array = NULL; for (loop = 1; loop < (*argc); loop++) { if ((!strcmp(argv[loop],"-include")||!strcmp(argv[loop],"-x")||!strcmp(argv[loop],"--param")||!strcmp(argv[loop],"-isystem")) && loop+1<*argc) { gcc_argv[gcc_argc++] = argv[loop++]; gcc_argv[gcc_argc++] = argv[loop]; } else if (is_tigcc_arg(argv[loop])) { loop = process_arg(loop, argv, *argc); } else if (argv[loop][0] == '-') { // if it's not one of our args, pass it to gcc gcc_argv[gcc_argc++] = argv[loop]; } else { filetype = is_source_file(argv[loop]); switch (filetype) { case CFILE: array = src_files; handle_outfile: if (!firstsourcefile) firstsourcefile = loop; break; case ASMFILE: array = a68k_files; goto handle_outfile; case SFILE: array = asm_files; goto handle_outfile; case OFILE: array = obj_files; goto handle_outfile; case AFILE: array = ar_files; break; case QLLFILE: /* Quill files are just C files which need a special -include switch to include the quill.drv header */ array = src_files; goto handle_outfile; default: fprintf(stderr, "Invalid option %s\n", argv[loop]); break; } if (array != NULL) { #if 0 /* Necessary if we want free_file_array not to crash, but it's a waste of memory... */ char *s = strdup(argv[loop]); if (!s) { fputs ("Fatal error: not enough free memory.\n", stderr); exit (1); } add_to_file_array(s, array); #else add_to_file_array(argv[loop], array); #endif } } } // If no output filename, first arg used as default name. // However, don't do this with -S or -c. Instead, let compile() or // assemble() guess an appropriate file name for each individual file. if (firstsourcefile && do_link && !outfile) { outfile = malloc(strlen(argv[firstsourcefile])+3); strcpy(outfile,argv[firstsourcefile]); change_extension(outfile,".o"); } } static inline void escape_arg(char *escaped_arg, const char *unescaped_arg) { char *p; strcpy(escaped_arg,unescaped_arg); for (p=escaped_arg; *p; p++) { switch(*p) { /* The following characters are shell characters and need to be escaped! */ case ' ': case '\\': case '\"': case '\'': case '$': case '!': case '^': case '&': case '*': case '(': case ')': case '~': case '[': case ']': case '|': case '{': case '}': case ';': case '<': case '>': case '?': memmove(p+1,p,strlen(p)+1); *(p++)='\\'; default: break; } } } /* Execute a program */ void execute(const char *program, char **argv) { pid_t pid; int status; if (printcommands) { char **ptr; fprintf(stderr, "tigcc: %s", program); for (ptr = argv + 1; *ptr; ptr++) { char escapedarg[((strlen(*ptr))<<1)+1]; escape_arg(escapedarg,*ptr); fprintf (stderr, " %s", escapedarg); } putc ('\n', stderr); } fflush (stdout); pid = fork(); if (pid == 0) { execv (program, argv); // execv only returns in case of an error fprintf (stderr, "Error executing %s\n", program); exit (1); } else if (pid < 0 || (waitpid (pid, &status, 0) != pid) || !WIFEXITED(status)) { fprintf (stderr, "Error executing %s\n", program); exit (1); } /* Fail silently if another program already showed an error message. */ if (WEXITSTATUS(status)) exit(1); } /* Execute GNU cc */ void compile(char *file) { unsigned short local_argc = gcc_argc; char gcc_name[9 + strlen (tigcc_base)]; char bindir[6 + strlen (tigcc_base)]; char includedir[13 + strlen (tigcc_base)]; sprintf (gcc_name, "%s/bin/gcc", tigcc_base); sprintf (bindir, "-B%s/bin/", tigcc_base); sprintf (includedir, "-I%s/include/c", tigcc_base); gcc_argv[0] = gcc_name; gcc_argv[local_argc++] = bindir; gcc_argv[local_argc++] = includedir; gcc_argv[local_argc++] = file; if (!do_compile) { // preprocess only gcc_argv[local_argc++] = "-E"; if (outfile) { gcc_argv[local_argc++] = "-o"; gcc_argv[local_argc++] = outfile; } gcc_argv[local_argc] = NULL; execute(gcc_name, gcc_argv); } else { char *tmpfile; if (!do_assemble && outfile) tmpfile = outfile; else { tmpfile = malloc (strlen (file) + 3); if (!tmpfile) { fprintf(stderr, "Fatal error: not enough free memory\n"); exit(-1); } strcpy(tmpfile, file); change_extension(tmpfile, ".s"); } if (debug) { gcc_argv[local_argc++] = "-gdwarf-2"; gcc_argv[local_argc++] = "-g3"; gcc_argv[local_argc++] = "-fasynchronous-unwind-tables"; } if (nomergesections) { gcc_argv[local_argc++] = "-mno-merge-sections"; } gcc_argv[local_argc++] = "-S"; if (fargo) gcc_argv[local_argc++] = "-DFARGO"; if (flashos) gcc_argv[local_argc++] = "-DFLASH_OS"; gcc_argv[local_argc++] = "-o"; gcc_argv[local_argc++] = tmpfile; add_to_file_array(tmpfile, asm_files); gcc_argv[local_argc] = NULL; execute(gcc_name, gcc_argv); // patch assembly file if(patch) { char patcher_name[strlen(tigcc_base) + 13]; char *argv[] = {patcher_name, tmpfile, "-o", tmpfile, NULL}; sprintf (patcher_name, "%s/bin/patcher", tigcc_base); execute (patcher_name, argv); } } } /* Execute GNU as */ void assemble(char *file) { char as_name[strlen(tigcc_base) + 8]; char includedir[strlen(tigcc_base) + 13]; char *tmpfile; char *argv[7 + (as_args ? strlen (as_args) / 2 : 0) + allrelocs + optreturns + debug]; char asargtokens[as_args?(strlen(as_args)+1):0]; int i = 6; argv[0] = as_name; argv[1] = "-mc68000"; argv[2] = includedir; argv[3] = file; argv[4] = "-o"; if (!do_link && outfile) tmpfile = outfile; else { tmpfile = malloc (strlen (file) + 3); if (!tmpfile) { fprintf(stderr, "Fatal error: not enough free memory\n"); exit(-1); } strcpy(tmpfile, file); change_extension(tmpfile, ".o"); } argv[5] = tmpfile; sprintf (as_name, "%s/bin/as", tigcc_base); sprintf (includedir, "-I%s/include/s", tigcc_base); // add the file to the list add_to_file_array(tmpfile, obj_files); if (allrelocs) argv[i++] = "--all-relocs"; if (optreturns) argv[i++] = "--keep-locals"; if (debug) argv[i++] = "--gdwarf2"; if (as_args) { strcpy (asargtokens, as_args); strtok (asargtokens, ","); while ((argv[i++] = strtok (NULL, ","))); } else argv[i] = NULL; execute(as_name, argv); } /* Execute ld-tigcc */ void ld(void) { short int loop; unsigned short local_argc = ld_argc; char ld_name[strlen(tigcc_base) + 14]; char tmpfile[strlen(outfile) + 1]; sprintf (ld_name, "%s/bin/ld-tigcc", tigcc_base); ld_argv[0] = ld_name; for (loop = 0; loop < obj_files->count; loop++) ld_argv[local_argc++] = obj_files->files[loop]; for (loop = 0; loop < ar_files->count; loop++) ld_argv[local_argc++] = ar_files->files[loop]; ld_argv[local_argc++] = "-o"; ld_argv[local_argc++] = tmpfile; strcpy(tmpfile, outfile); change_extension(tmpfile, ""); if(outputbin || do_pack) ld_argv[local_argc++] = "--outputbin"; ld_argv[local_argc] = NULL; execute(ld_name, ld_argv); } /* Execute A68K */ void a68k(char *file) { char *tmpfile; if (!do_link && outfile) { tmpfile = malloc (strlen (outfile) + 3); if (!tmpfile) { fprintf(stderr, "Fatal error: not enough free memory\n"); exit(-1); } sprintf(tmpfile, "-o%s", outfile); } else { tmpfile = malloc (strlen (file) + 5); if (!tmpfile) { fprintf(stderr, "Fatal error: not enough free memory\n"); exit(-1); } sprintf(tmpfile, "-o%s", file); change_extension(tmpfile, ".o"); } tmpfile += 2; /* Warning: this prevents free_file_array from working */ /* First, assemble file with A68k which produces AmigaOS files */ { char a68k_name[strlen(tigcc_base) + 10]; char includedir[strlen(tigcc_base) + 16]; char *argv[7 + (a68k_args ? strlen (a68k_args) / 2 : 0) + allrelocs + optreturns + quiet]; char a68kargtokens[a68k_args?(strlen(a68k_args)+1):0]; int i = 6; argv[0] = a68k_name; argv[1] = includedir; argv[2] = "-g"; argv[3] = "-t"; argv[4] = file; argv[5] = tmpfile; sprintf (a68k_name, "%s/bin/a68k", tigcc_base); sprintf (includedir, "-i%s/include/asm/", tigcc_base); // add the file to the list add_to_file_array(tmpfile, obj_files); if (allrelocs) argv[i++] = "-a"; if (optreturns) argv[i++] = "-d"; if (quiet) argv[i++] = "-q"; if (a68k_args) { strcpy (a68kargtokens, a68k_args); strtok (a68kargtokens, ","); while ((argv[i++] = strtok (NULL, ","))); } else argv[i] = NULL; execute(a68k_name, argv); } } /* Parse pstarter file and change internal varname */ static short int parse_pstarter(const char *input, const char *output, const char *packvar) { FILE *f; char array[65536]; char *token = "tempprog"; unsigned int i, n; unsigned int j, k; // open file in reading f = fopen(input, "rb"); if(f == NULL) { fprintf(stderr, "Unable to open pstarter.o\n"); exit(-1); } n = fread(array, sizeof(char), 65536*sizeof(char), f); fclose(f); // change varname for(i=0; icount + ar_files->count]; argv[0] = ar_name; argv[1] = "-o"; argv[2] = buffer; strcpy(buffer, outfile); change_extension(buffer, ".a"); unlink (buffer); sprintf(ar_name, "%s/bin/ar-tigcc", tigcc_base); i = 3; for (loop = 0; loop < obj_files->count; loop++) argv[i++] = obj_files->files[loop]; for (loop = 0; loop < ar_files->count; loop++) argv[i++] = ar_files->files[loop]; argv[i] = NULL; execute(ar_name, argv); } /* Compress TI executable */ void pack(void) { char pstarter_file[25 + strlen(tigcc_base)]; char tmpfile[strlen(outfile) + 14]; int ti89_targeted=0; // check for decompressor program sprintf(pstarter_file, "%s/lib/pstarter.o", tigcc_base); if(access(pstarter_file, F_OK) == -1) { fprintf(stderr, "TIGCC installation problem: pstarter.o file is missing.\n"); return; } strcpy(tmpfile, outfile); change_extension(tmpfile, ".z89"); if(access(tmpfile, F_OK) != -1) { ti89_targeted=1; // compress on calc variable { char ttpack_name[strlen (tigcc_base) + 12]; char *argv[5]; int i=1; *argv = ttpack_name; if (verbose) argv[i++] = "-v"; else if (quiet) argv[i++] = "-quiet"; argv[i++] = tmpfile; argv[i++] = TMP_PCK; argv[i] = NULL; sprintf (ttpack_name, "%s/bin/ttpack", tigcc_base); execute(ttpack_name, argv); } // encapsulate in var (.89y) { char ttbin2oth_name[strlen(tigcc_base) + 15]; char *argv[7]; int i=1; *argv = ttbin2oth_name; if (quiet) argv[i++] = "-quiet"; argv[i++] = "-89"; argv[i++] = "ppg"; argv[i++] = TMP_PCK; argv[i++] = packfile; argv[i] = NULL; sprintf(ttbin2oth_name, "%s/bin/ttbin2oth", tigcc_base); execute(ttbin2oth_name, argv); } unlink(tmpfile); unlink(TMP_PCK); } change_extension(tmpfile, ".zv2"); if(access(tmpfile, F_OK) != -1) { // compress on calc variable { char ttpack_name[strlen (tigcc_base) + 12]; char *argv[5]; int i=1; *argv = ttpack_name; if (verbose) argv[i++] = "-v"; else if (quiet) argv[i++] = "-quiet"; argv[i++] = tmpfile; argv[i++] = TMP_PCK; argv[i] = NULL; sprintf (ttpack_name, "%s/bin/ttpack", tigcc_base); execute(ttpack_name, argv); } // encapsulate in var (.v2y) { char ttbin2oth_name[strlen(tigcc_base) + 15]; char filename9x[strlen(packfile)+5]; char filenamev2[strlen(packfile)+5]; char *argv[7]; int i=1; *argv = ttbin2oth_name; if (quiet) argv[i++] = "-quiet"; argv[i++] = "-92"; argv[i++] = "ppg"; argv[i++] = TMP_PCK; argv[i++] = packfile; argv[i] = NULL; sprintf(ttbin2oth_name, "%s/bin/ttbin2oth", tigcc_base); execute(ttbin2oth_name, argv); strcpy(filename9x,packfile); strcat(filename9x,".9xy"); strcpy(filenamev2,packfile); strcat(filenamev2,".v2y"); rename(filename9x,filenamev2); } unlink(tmpfile); unlink(TMP_PCK); } change_extension(tmpfile, ".z9x"); if(access(tmpfile, F_OK) != -1) { // compress on calc variable { char ttpack_name[strlen (tigcc_base) + 12]; char *argv[5]; int i=1; *argv = ttpack_name; if (verbose) argv[i++] = "-v"; else if (quiet) argv[i++] = "-quiet"; argv[i++] = tmpfile; argv[i++] = TMP_PCK; argv[i] = NULL; sprintf (ttpack_name, "%s/bin/ttpack", tigcc_base); execute(ttpack_name, argv); } // encapsulate in var (.9xy) { char ttbin2oth_name[strlen(tigcc_base) + 15]; char *argv[7]; int i=1; *argv = ttbin2oth_name; if (quiet) argv[i++] = "-quiet"; argv[i++] = "-92"; argv[i++] = "ppg"; argv[i++] = TMP_PCK; argv[i++] = packfile; argv[i] = NULL; sprintf(ttbin2oth_name, "%s/bin/ttbin2oth", tigcc_base); execute(ttbin2oth_name, argv); } unlink(tmpfile); unlink(TMP_PCK); } // parse pstarter.o and change varname parse_pstarter(pstarter_file, "pstarter.o", packfile); // create decompressor (.??z) { char ld_tigcc_name[strlen(tigcc_base) + 14]; char *argv[] = {ld_tigcc_name, "pstarter.o", "-o", tmpfile, NULL}; sprintf (ld_tigcc_name, "%s/bin/ld-tigcc", tigcc_base); change_extension(tmpfile, ""); execute(ld_tigcc_name, argv); } unlink("pstarter.o"); if (!ti89_targeted) return; // no TI-89 -> no Titanium #if 1 // zap any leftover Titanium launchers strcat(tmpfile, "-titanium.89z"); unlink(tmpfile); strcpy(tmpfile, outfile); strcat(tmpfile, "-Titanium.89z"); unlink(tmpfile); #else // check for Titanium decompressor program sprintf(pstarter_file, "%s/lib/pstarter-titanium.o", tigcc_base); if(access(pstarter_file, F_OK) == -1) { fprintf(stderr, "TIGCC installation problem: pstarter-titanium.o file is missing.\n"); return; } // parse pstarter.o and change varname parse_pstarter(pstarter_file, "pstarter.o", packfile); // create decompressor (*-titanium.89z) { char ld_tigcc_name[strlen(tigcc_base) + 14]; char *argv[] = {ld_tigcc_name, "pstarter.o", "-o", tmpfile, NULL}; sprintf (ld_tigcc_name, "%s/bin/ld-tigcc", tigcc_base); strcat(tmpfile, "-titanium"); execute(ld_tigcc_name, argv); // zap non-TI-89 Titanium launchers change_extension(tmpfile, ".9xz"); unlink(tmpfile); change_extension(tmpfile, ".v2z"); unlink(tmpfile); } unlink("pstarter.o"); #endif } /* Destroy allocated resources */ void safe_exit(void) { free(gcc_argv); free(ld_argv); free_file_array(src_files); free_file_array(obj_files); free_file_array(asm_files); free_file_array(a68k_files); free_file_array(ar_files); free(as_args); free(a68k_args); } int main(int argc, char *argv[]) { short int loop; program_name = argv[0]; if (argc < 2) { fprintf(stderr, "tigcc: no input files\n"); exit(0); } if ((tigcc_base = getenv("TIGCC")) == NULL) { fprintf(stderr, "Fatal error: TIGCC is not defined in the environment. TIGCC must be defined before tigcc can run.\nFor (ba)sh, try: export TIGCC=/path/to/tigcc\nFor (t)csh, try: setenv TIGCC /path/to/tigcc\n"); exit(-1); } if (atexit(safe_exit) != 0) { fprintf(stderr, "Fatal error: unable to register safe exit callback\n"); exit(-1); } /* worst case (every arg is a gcc arg): argc + -Bprefix/bin/ + -Idir + -gdwarf-2 + -g3 + + -fasynchronous-unwind-tables + -mno-merge-sections + -S + -DFARGO/-DFLASH_OS + -include + quill.drv + -x + c + -o + filename */ gcc_argv = malloc((argc + 15) * sizeof (char*)); /* worst case: each arg is either a file to link or a linker switch; add tigcc.a/fargo.a/flashos.a, -o outfile, --outputbin, NULL */ ld_argv = malloc((argc + 5) * sizeof (char*)); src_files = malloc(sizeof (array_of_files) + MAX_ARRAY_FILES * sizeof (char*)); obj_files = malloc(sizeof (array_of_files) + MAX_ARRAY_FILES * sizeof (char*)); asm_files = malloc(sizeof (array_of_files) + MAX_ARRAY_FILES * sizeof (char*)); a68k_files = malloc(sizeof (array_of_files) + MAX_ARRAY_FILES * sizeof (char*)); ar_files = malloc(sizeof (array_of_files) + MAX_ARRAY_FILES * sizeof (char*)); if ((gcc_argv == NULL) || (ld_argv == NULL) || (src_files == NULL) || (obj_files == NULL) || (asm_files == NULL) || (a68k_files == NULL) || (ar_files == NULL)) { fprintf(stderr, "Fatal error: not enough free memory\n"); exit(-1); } src_files -> count = 0; obj_files -> count = 0; asm_files -> count = 0; a68k_files -> count = 0; ar_files -> count = 0; // parse the arguments parse_args(&argc, argv); // check there is at least one file to process if(!src_files->count && !asm_files->count && !a68k_files->count && !obj_files->count) { fprintf(stderr, "tigcc: no input files\n"); exit(0); } // set the archive file if(!nostdlib) { char *buffer = malloc(strlen(tigcc_base)+13); sprintf(buffer, flashos?"%s/lib/flashos.a":(fargo?"%s/lib/fargo.a":"%s/lib/tigcc.a"), tigcc_base); add_to_file_array(buffer, ar_files); } if(1) { for (loop = 0; loop < src_files->count; loop++) { compile(src_files->files[loop]); } } if (do_assemble) { for (loop = 0; loop < asm_files->count; loop++) { assemble(asm_files->files[loop]); } for (loop = 0; loop < a68k_files->count; loop++) { a68k(a68k_files->files[loop]); } } if (staticlib) ar(); else { if (do_link && obj_files->count > 0) { ld(); } } if(delete) { for (loop = 0; loop < src_files->count; loop++) { char tmpfile[strlen(src_files->files[loop]) + 3]; strcpy(tmpfile, src_files->files[loop]); change_extension(tmpfile, ".s"); unlink(tmpfile); } } if(do_link && !keepobj) { for (loop = 0; loop < src_files->count; loop++) { char tmpfile[strlen(src_files->files[loop]) + 3]; strcpy(tmpfile, src_files->files[loop]); change_extension(tmpfile, ".o"); unlink(tmpfile); } for (loop = 0; loop < asm_files->count; loop++) { char tmpfile[strlen(asm_files->files[loop]) + 3]; strcpy(tmpfile, asm_files->files[loop]); change_extension(tmpfile, ".o"); unlink(tmpfile); } for (loop = 0; loop < a68k_files->count; loop++) { char tmpfile[strlen(a68k_files->files[loop]) + 3]; strcpy(tmpfile, a68k_files->files[loop]); change_extension(tmpfile, ".o"); unlink(tmpfile); } } if (!staticlib && do_pack && do_link) { pack(); } return 0; }