#include #include #include #include #include #include #include #include #include #include #include #include #include "global.h" bool usage_only, multiple, include_strings; bool abs_paths = false, report_structs = true, pseudo_code = false; bool halt_on_error = false; char *sourcefile, *preprocfile = PREPROCESSOR_OUTPUT, *cwd; static char **ncc_key; static bool issource (char *f) { char *e = f + strlen (f) - 1; if (*(e-1) == '.') return *e == 'c' || *e == 'h' || *e == 'C' || *e == 'i'; return *(e-3) == '.' && (*(e-2) == 'c' || *(e-2) == 'C'); } static bool isobj (char *f) { int i = strlen (f); return (f [i-1] == 'o' || f [i-1] == 'a') && f [i-2] == '.'; } static char *objfile (char *f) { char *r = strdup (f); char *p = rindex (r, '.'); if (p) strcpy (p, ".o"); return r; } static void openout (char *f, char *mode = "w") { if (!f) return; char *c = (char*) alloca (strlen (f) + sizeof OUTPUT_EXT); freopen (strcat (strcpy (c, f), OUTPUT_EXT), mode, stdout); fprintf (stderr, "ncc: output file is ["COLS"%s"COLE"]\n", c); } static void LINK (char **obj, int objn) { int i; for (i = 0; i < objn; i++) { char *ncobj = (char*) alloca (strlen (obj [i]) + 10 + sizeof OUTPUT_EXT); strcat (strcpy (ncobj, obj [i]), OUTPUT_EXT); load_file L (ncobj); if (L.success == ZC_OK) { fprintf (stderr, "ncc: Linking object file ["COLS"%s"COLE"]\n", ncobj); fwrite (L.data, 1, L.len, stdout); } } } static void RUN (char *outfile, char **argv) { int i; fprintf (stderr, "Running: "); for (i = 0; argv [i]; i++) fprintf (stderr, "%s ", argv [i]); fprintf (stderr, "\n"); int pid = fork (); if (pid == 0) { if (outfile) if(!freopen (outfile, "w", stdout)) exit (127); execvp (argv [0], argv); exit (127); } int status; waitpid (pid, &status, 0); if (WEXITSTATUS (status) != 0) { fprintf (stderr, "[%s] Program failed..\n", argv[0]); exit (1); } } /************************************************************* # # binutils emulation mode. # happens to work in some cases... # *************************************************************/ static void nccar (int argc, char **argv) { /* * we take the simple usage: * ar [max-four-options] archive-file.[ao] obj1.o obj2.o ... */ int i; for (i = 1; i < 5 && i < argc; i++) if (isobj (argv [i])) { openout (argv [i], "a"); LINK (&argv [i + 1], argc - i - 1); return; } fprintf (stderr, "nccar: Nothing to do\n"); } static void nccld (int argc, char **argv) { /* * 'c++'/'g++' is sometimes used as a linker * we only do the job if there are object files */ int i, objfileno = 0; char *ofile = 0, **objfiles = (char**) alloca (argc * sizeof *objfiles); for (i = 1; i < argc; i++) if (argv [i][0] == '-') { if (argv [i][1] == 'o' && argv [i][2] == 0) ofile = argv [++i]; } else if (isobj (argv [i])) objfiles [objfileno++] = argv [i]; if (ofile && objfileno) { openout (ofile); LINK (objfiles, objfileno); } else fprintf (stderr, "%s: Nothing to do\n", argv [0]); } static void emubinutils (int argc, char **argv) { if (0); #define PROGNAME(x, y) else if (!strcmp (argv [0] + strlen (argv [0]) + 1 - sizeof x, x)) {\ argv [0] = x;\ RUN (NULL, argv);\ ncc ## y (argc, argv);\ } #define SPROGNAME(x) PROGNAME(#x,x) SPROGNAME(ar) SPROGNAME(ld) PROGNAME("c++", ld) PROGNAME("g++", ld) else return; exit (0); } const char help [] = "ncc "NCC_VERSION" - The new/next generation C compiler\n" "The user is the only one responsible for any damages\n" "Written by Stelios Xanthakis\n" "Homepage: http://students.ceid.upatras.gr/~sxanth/ncc/\n" "\n" "Options starting with '-nc' are ncc options, while the rest gcc:\n" " -ncgcc : also run gcc compiler (produces useful object file)\n" " -ncgcc=PROG : use PROG instead of \"gcc\"\n" " Files:\n" " -ncld : emulate object file output: write the output to "OUTPUT_EXT"\n" " -ncoo : write the output to sourcefile.c"OUTPUT_EXT"\n" " -ncspp : keep sourcefile.i preprocessor output instead of " PREPROCESSOR_OUTPUT"\n" " Output:\n" " -nccc : compile and produce virtual bytecode\n" " -ncmv : display multiple uses of functions and variables\n" " -ncpc : like -ncmv but also produce pseudo-code data\n" " -ncnrs : do not report structure declaration locations (lots of data)\n" " -ncerr : halt ncc on the first expression error detected\n" " Switches:\n" " -nc00 : do not include constant values (faster/less memory)\n" " Extras:\n" " -nckey : scan source file for additional output (see doc)\n" " Filenames:\n" " -ncfabs : report absolute pathnames in the output\n" "\nncc can also be called as 'nccar', 'nccld', 'nccc++', 'nccg++'\n" "In these cases it will invoke the programs 'ar', 'ld', 'c++' and 'g++'\n" "and then attempt to collect and link object files with the extension "OUTPUT_EXT"\n" ; void preproc (int argc, char**argv) { int i; if (1) { fprintf (stderr, "Invoked: "); for (i = 0; i < argc; i++) fprintf (stderr, "%s ", argv [i]); fprintf (stderr, "\n"); } /* emulate ar, ld, ... */ emubinutils (argc, argv); bool spp = false, dontdoit = false, mkobj = false, ncclinker = false; char *keys [10]; char **gccopt, **cppopt, **nccopt, **files, **objfiles, **nofileopt; char *ofile = 0; int gccno, cppno, nccno, filesno, objfileno, nofileno, keyno; cppopt = (char**) alloca ((8 + argc) * sizeof (char*)); nccopt = (char**) alloca ((3 + argc) * sizeof (char*)); gccopt = (char**) alloca ((3 + argc) * sizeof (char*)); files = (char**) alloca (argc * sizeof (char*)); objfiles = (char**) alloca (argc * sizeof (char*)); nofileopt = (char**) alloca ((3 + argc) * sizeof (char*)); cppopt [0] = gccopt [0] = "gcc"; cppopt [1] = "-E"; cppopt [2] = "-D__NCC__"; cppopt [3] = "-imacros"; cppopt [4] = NOGNU; nofileopt [0] = "ncc"; files [0] = NULL; cppno = 5; gccno = 1; keyno = filesno = nccno = objfileno = 0; nofileno = 1; for (i = 1; i < argc; i++) if (argv [i][0] == '-' && argv [i][1] == 'n' && argv [i][2] == 'c') { nccopt [nccno++] = (nofileopt [nofileno++] = argv[i]) + 3; if (!strcmp (argv [i], "-ncld")) ncclinker = true; } else { gccopt [gccno++] = argv [i]; if (issource (argv [i])) cppopt [cppno++] = files [filesno++] = argv [i]; else { nofileopt [nofileno++] = argv [i]; if (isobj (argv [i])) objfiles [objfileno++] = argv [i]; if (argv [i][0] == '-') if (argv [i][1] == 'O') goto addit; else if (argv [i][1] == 'D' || argv [i][1] == 'I') if (argv [i][2] == 0) goto separate; else addit: cppopt [cppno++] = argv [i]; else if (argv [i][1] == 'i') { separate: cppopt [cppno++] = argv [i++]; gccopt [gccno++] = cppopt [cppno++] = argv [i]; } else if (argv [i][1] == 'E') dontdoit = true; } if (!strcmp (argv [i], "-o")) gccopt [gccno++] = ofile = argv [++i]; else if (!strcmp (argv [i], "-c")) mkobj = 1; } if (!mkobj && ncclinker) nofileopt [nofileno++] = "-c"; nccopt [nccno] = gccopt [gccno] = cppopt [cppno] = nofileopt [nofileno + 1] = NULL; if (!ofile) ofile = mkobj ? filesno > 1 ? 0 : objfile (files [0]) : (char*) "a.out"; if (filesno > 1) { fprintf (stderr, "Multiple files. Forking\n"); for (i = 0; i < filesno; i++) { nofileopt [nofileno] = files [i]; RUN (NULL, nofileopt); if (ncclinker) objfiles [objfileno++] = objfile (files [i]); } if (ncclinker) { if (ofile) openout (ofile); LINK (objfiles, objfileno); } exit (0); } include_values = usage_only = true; multiple = false; for (i = 0; i < nccno; i++) if (0); #define NCCOPT(x) else if (!strcmp (nccopt [i], x)) #define NCCPOPT(x) else if (!strncmp (nccopt [i], x, sizeof x - 1)) NCCPOPT("gcc=") { gccopt [0] = nccopt [i] + 4; RUN (NULL, gccopt); } NCCOPT ("gcc") RUN (NULL, gccopt); NCCOPT ("cc") usage_only = false; NCCOPT ("err") halt_on_error = true; NCCOPT ("mv") multiple = true; NCCOPT ("pc") multiple = pseudo_code = true; NCCOPT ("oo") openout (files [0]); NCCOPT ("ld") openout (ofile); NCCOPT ("00") include_values = false; NCCOPT ("spp") spp = true; NCCOPT ("fabs") abs_paths = true; NCCOPT ("nrs") report_structs = false; NCCPOPT ("key") keys [keyno++] = nccopt [i] + 3; else { fputs (help, stderr); exit (strcmp (nccopt [i], "help") != 0); } if (!(sourcefile = files [0])) { if (objfileno) LINK (objfiles, objfileno); else fprintf (stderr, "ncc: No C source file\n"); exit (0); } if (dontdoit) { fprintf (stderr, "ncc: '-E'. Won't do it...\n"); exit (0); } if (spp) { preprocfile = StrDup (sourcefile); preprocfile [strlen (preprocfile) - 1] = 'i'; } if (keyno) { ncc_key = new char* [keyno + 1]; for (i = 0; i < keyno; i++) ncc_key [i] = keys [i]; ncc_key [i] = NULL; } if (usage_only) set_usage_report (); else set_compilation (); include_strings = include_values || ncc_key; if (objfileno) LINK (objfiles, objfileno); RUN (preprocfile, cppopt); } void ncc_keys () { #define KSZ (sizeof NCC_INFILE_KEY - 1) int i, j; if (ncc_key) for (i = 0; i < C_Nstrings; i++) if (!strncmp (C_Strings [i], NCC_INFILE_KEY, KSZ)) { for (j = 0; ncc_key [j]; j++) if (!strncmp (C_Strings [i] + KSZ, ncc_key [j], strlen (ncc_key [j]))) break; if (ncc_key [j]) printf ("%s", C_Strings [i] + KSZ + strlen (ncc_key [j])); } }