home *** CD-ROM | disk | FTP | other *** search
/ ftp.cs.arizona.edu / ftp.cs.arizona.edu.tar / ftp.cs.arizona.edu / icon / historic / v941.tgz / icon.v941src.tar / icon.v941src / src / icont / tunix.c < prev    next >
C/C++ Source or Header  |  2002-03-19  |  12KB  |  393 lines

  1. /*
  2.  * tunix.c - user interface for Unix.
  3.  */
  4.  
  5. #include "../h/gsupport.h"
  6. #include "../h/version.h"
  7. #include "tproto.h"
  8. #include "tglobals.h"
  9.  
  10. static void execute (char *ofile, char *efile, char *args[]);
  11. static void usage (void);
  12. static char *libpath (char *prog, char *envname);
  13.  
  14. static void txrun(char *(*func)(FILE*, char*), char *source, char *args[]);
  15. static char *copyfile(FILE *f, char *srcfile);
  16. static char *savefile(FILE *f, char *srcprog);
  17. static void cleanup(void);
  18.  
  19. static char **rfiles;        /* list of files removed by cleanup() */
  20.  
  21. /*
  22.  * for old method of hardwiring iconx path; not normally used.
  23.  */
  24. static char patchpath[MaxPath+18] = "%PatchStringHere->";
  25.  
  26. /*
  27.  * getopt() variables
  28.  */
  29. extern int optind;        /* index into parent argv vector */
  30. extern int optopt;        /* character checked for validity */
  31. extern char *optarg;        /* argument associated with option */
  32.  
  33. /*
  34.  *  main program
  35.  */
  36. int main(int argc, char *argv[]) {
  37.    int nolink = 0;            /* suppress linking? */
  38.    int errors = 0;            /* translator and linker errors */
  39.    char **tfiles, **tptr;        /* list of files to translate */
  40.    char **lfiles, **lptr;        /* list of files to link */
  41.    char **rptr;                /* list of files to remove */
  42.    char *efile = NULL;            /* stderr file */
  43.    char buf[MaxFileName];        /* file name construction buffer */
  44.    int c, n;
  45.    char ch;
  46.    struct fileparts *fp;
  47.  
  48.    /*
  49.     * Initialize globals.
  50.     */
  51.    initglob();                /* general global initialization */
  52.    ipath = libpath(argv[0], "IPATH");    /* set library search paths */
  53.    lpath = libpath(argv[0], "LPATH");
  54.    if (strlen(patchpath) > 18)
  55.       iconxloc = patchpath + 18;    /* use stated iconx path if patched */
  56.    else
  57.       iconxloc = relfile(argv[0], "/../iconx");    /* otherwise infer it */
  58.  
  59.    /*
  60.     * Process options.
  61.     * IMPORTANT:  When making changes here, also update usage() function.
  62.     */
  63.    while ((c = getopt(argc, argv, "+ce:f:o:stuv:ELP:VX:")) != EOF)
  64.       switch (c) {
  65.          case 'c':            /* -c: compile only (no linking) */
  66.             nolink = 1;
  67.             break;
  68.          case 'e':            /* -e file: [undoc] redirect stderr */
  69.             efile = optarg;
  70.             break;
  71.          case 'f':            /* -f features: enable features */
  72.             if (strchr(optarg, 's') || strchr(optarg, 'a'))
  73.                strinv = 1;        /* this is the only icont feature */
  74.             break;
  75.          case 'o':            /* -o file: name output file */
  76.             ofile = optarg;
  77.             break;
  78.          case 's':            /* -s: suppress informative messages */
  79.             silent = 1;
  80.             verbose = 0;
  81.             break;
  82.          case 't':            /* -t: turn on procedure tracing */
  83.             trace = -1;
  84.             break;
  85.          case 'u':            /* -u: warn about undeclared ids */
  86.             uwarn = 1;
  87.             break;
  88.          case 'v':            /* -v n: set verbosity level */
  89.             if (sscanf(optarg, "%d%c", &verbose, &ch) != 1)
  90.                quitf("bad operand to -v option: %s", optarg);
  91.             if (verbose == 0)
  92.                silent = 1;
  93.             break;
  94.          case 'E':            /* -E: preprocess only */
  95.             pponly = 1;
  96.             nolink = 1;
  97.             break;
  98.          case 'P':            /* -P program: execute from argument */
  99.             txrun(savefile, optarg, &argv[optind]);
  100.             break;            /*NOTREACHED*/
  101.          case 'V':
  102.             fprintf(stderr, "%s  (%s, %s)\n", Version, Config, __DATE__);
  103.             if (optind == argc)
  104.                exit(0);
  105.             break;
  106.          case 'X':            /* -X srcfile: execute single srcfile */
  107.             txrun(copyfile, optarg, &argv[optind]);
  108.             break;            /*NOTREACHED*/
  109.  
  110. #ifdef DeBugLinker
  111.          case 'L':            /* -L: enable linker debugging */
  112.             Dflag = 1;
  113.             break;
  114. #endif                    /* DeBugLinker */
  115.  
  116.          default:
  117.          case 'x':            /* -x illegal until after file list */
  118.             usage();
  119.          }
  120.  
  121.    /*
  122.     * If argv[0] ends in "icon" (instead of "icont" or anything else),
  123.     * process as "icon [options] sourcefile [arguments]" scripting shortcut.
  124.     */
  125.    n = strlen(argv[0]);
  126.    if (n >= 4 && strcmp(argv[0]+n-4, "icon") == 0) {
  127.       if (optind < argc)
  128.          txrun(copyfile, argv[optind], &argv[optind+1]);
  129.       else
  130.          usage();
  131.       }
  132.  
  133.    /*
  134.     * Allocate space for lists of file names.
  135.     */
  136.    n = argc - optind + 1;
  137.    tptr = tfiles = alloc(n * sizeof(char *));
  138.    lptr = lfiles = alloc(n * sizeof(char *));
  139.    rptr = rfiles = alloc(2 * n * sizeof(char *));
  140.  
  141.    /*
  142.     * Scan file name arguments.
  143.     */
  144.    while (optind < argc)  {
  145.       if (strcmp(argv[optind], "-x") == 0)    /* stop at -x */
  146.          break;
  147.       else if (strcmp(argv[optind], "-") == 0) {
  148.          *tptr++ = "-";                /* "-" means standard input */
  149.          *lptr++ = *rptr++ = "stdin.u1";
  150.          *rptr++ = "stdin.u2";
  151.          }
  152.       else {
  153.          fp = fparse(argv[optind]);        /* parse file name */
  154.          if (*fp->ext == '\0' || smatch(fp->ext, SourceSuffix)) {
  155.             makename(buf, SourceDir, argv[optind], SourceSuffix);
  156.             *tptr++ = salloc(buf);        /* translate the .icn file */
  157.             makename(buf, TargetDir, argv[optind], U1Suffix);
  158.             *lptr++ = *rptr++ = salloc(buf);    /* link & remove .u1 */
  159.             makename(buf, TargetDir, argv[optind], U2Suffix);
  160.             *rptr++ = salloc(buf);        /* also remove .u2 */
  161.             }
  162.          else if (smatch(fp->ext, U1Suffix) || smatch(fp->ext, U2Suffix)
  163.                || smatch(fp->ext, USuffix)) {
  164.             makename(buf, TargetDir, argv[optind], U1Suffix);
  165.             *lptr++ = salloc(buf);
  166.             }
  167.          else
  168.             quitf("bad argument %s", argv[optind]);
  169.          }
  170.       optind++;
  171.       }
  172.  
  173.    *tptr = *lptr = *rptr = NULL;    /* terminate filename lists */
  174.    if (lptr == lfiles)
  175.       usage();                /* error -- no files named */
  176.  
  177.    /*
  178.     * Translate .icn files to make .u1 and .u2 files.
  179.     */
  180.    if (tptr > tfiles) {
  181.       if (!pponly)
  182.          report("Translating");
  183.       errors = trans(tfiles, TargetDir);
  184.       if (errors > 0)            /* exit if errors seen */
  185.          exit(EXIT_FAILURE);
  186.       }
  187.  
  188.    /*
  189.     * Link .u1 and .u2 files to make an executable.
  190.     */
  191.    if (nolink)                /* exit if no linking wanted */
  192.       exit(EXIT_SUCCESS);
  193.  
  194.    if (ofile == NULL)  {        /* if no -o file, synthesize a name */
  195.       ofile = salloc(makename(buf, TargetDir, lfiles[0], IcodeSuffix));
  196.       }
  197.    else {                /* add extension in necessary */
  198.       fp = fparse(ofile);
  199.       if (*fp->ext == '\0' && *IcodeSuffix != '\0') /* if no ext given */
  200.          ofile = salloc(makename(buf, NULL, ofile, IcodeSuffix));
  201.    }
  202.  
  203.    report("Linking");
  204.    errors = ilink(lfiles, ofile);    /* link .u files to make icode file */
  205.  
  206.    /*
  207.     * Finish by removing intermediate files.
  208.     *  Execute the linked program if so requested and if there were no errors.
  209.     */
  210.    cleanup();                /* delete intermediate files */
  211.    if (errors > 0) {            /* exit if linker errors seen */
  212.       remove(ofile);
  213.       exit(EXIT_FAILURE);
  214.       }
  215.    if (optind < argc)  {
  216.       report("Executing");
  217.       execute (ofile, efile, argv + optind + 1);
  218.       }
  219.    exit(EXIT_SUCCESS);
  220.    return 0;
  221.    }
  222.  
  223. /*
  224.  * execute - execute iconx to run the icon program
  225.  */
  226. static void execute(char *ofile, char *efile, char *args[]) {
  227.    int n;
  228.    char **argv, **p;
  229.  
  230.    for (n = 0; args[n] != NULL; n++)    /* count arguments */
  231.       ;
  232.    p = argv = alloc((n + 5) * sizeof(char *));
  233.  
  234.    *p++ = ofile;            /* pass icode file name */
  235.    while ((*p++ = *args++) != 0)    /* copy args into argument vector */
  236.       ;
  237.    *p = NULL;
  238.  
  239.    /*
  240.     * Redirect stderr if requested, then execute the file.
  241.     * It knows how to find iconx.
  242.     */
  243.    if (efile != NULL) {
  244.       close(fileno(stderr));
  245.       if (strcmp(efile, "-") == 0)
  246.          dup(fileno(stdout));
  247.       else if (freopen(efile, "w", stderr) == NULL)
  248.          quitf("could not redirect stderr to %s\n", efile);
  249.       }
  250.    execv(ofile, argv);
  251.    quitf("could not execute %s", ofile);
  252.    }
  253.  
  254. void report(char *s) {
  255.    char *c = (strchr(s, '\n') ? "" : ":\n") ;
  256.    if (!silent)
  257.       fprintf(stderr, "%s%s", s, c);
  258.    }
  259.  
  260. /*
  261.  * Print a usage message and abort the run.
  262.  */
  263. static void usage(void) {
  264.    fprintf(stderr, "usage: icon  sourcefile   [args]\n");
  265.    fprintf(stderr, "       icon  -P 'program' [args]\n");
  266.    fprintf(stderr, "       icont %s\n",
  267.       "[-cstuEV] [-f s] [-o ofile] [-v i] file ... [-x args]");
  268.    exit(EXIT_FAILURE);
  269.    }
  270.  
  271. /*
  272.  * Return path after appending lib directory.
  273.  */
  274. static char *libpath(char *prog, char *envname) {
  275.    char buf[1000], *s;
  276.  
  277.    s = getenv(envname);
  278.    if (s != NULL)
  279.       strcpy(buf, s);
  280.    else
  281.       strcpy(buf, ".");
  282.    strcat(buf, ":");
  283.    strcat(buf, relfile(prog, "/../../lib"));
  284.    return salloc(buf);
  285.    }
  286.  
  287. /*
  288.  * Translate, link, and execute a source file.
  289.  * Does not return under any circumstances.
  290.  */
  291. static void txrun(char *(*func)(FILE*, char*), char *source, char *args[]) {
  292.    int omask;
  293.    char c1, c2;
  294.    char *flist[2], *progname;
  295.    char srcfile[MaxFileName], u1[MaxFileName], u2[MaxFileName];
  296.    char icode[MaxFileName], buf[MaxFileName + 20];
  297.    static char abet[] = "abcdefghijklmnopqrstuvwxyz";
  298.    FILE *f;
  299.  
  300.    silent = 1;            /* don't issue commentary while translating */
  301.    uwarn = 1;            /* do diagnose undeclared identifiers */
  302.    omask = umask(0077);        /* remember umask; keep /tmp files private */
  303.  
  304.    /*
  305.     * Invent a file named /tmp/innnnnxx.icn.
  306.     */
  307.    srand(time(NULL));
  308.    c1 = abet[rand() % (sizeof(abet) - 1)];
  309.    c2 = abet[rand() % (sizeof(abet) - 1)];
  310.    sprintf(srcfile, "/tmp/i%d%c%c.icn", getpid(), c1, c2);
  311.  
  312.    /*
  313.     * Copy the source code to the temporary file.
  314.     */
  315.    f = fopen(srcfile, "w");
  316.    if (f == NULL)
  317.       quitf("cannot open for writing: %s", srcfile);
  318.    progname = func(f, source);
  319.    fclose(f);
  320.  
  321.    /*
  322.     * Derive other names and arrange for cleanup on exit.
  323.     */
  324.    rfiles = alloc(5 * sizeof(char *));
  325.    rfiles[0] = srcfile;
  326.    makename(rfiles[1] = u1, NULL, srcfile, U1Suffix);
  327.    makename(rfiles[2] = u2, NULL, srcfile, U2Suffix);
  328.    makename(rfiles[3] = icode, NULL, srcfile, IcodeSuffix);
  329.    rfiles[4] = NULL;
  330.    atexit(cleanup);
  331.  
  332.    /*
  333.     * Translate to produce .u1 and .u2 files.
  334.     */
  335.    flist[0] = srcfile;
  336.    flist[1] = NULL;
  337.    if (trans(flist, SourceDir) > 0)
  338.       exit(EXIT_FAILURE);
  339.  
  340.    /*
  341.     * Link to make an icode file.
  342.     */
  343.    flist[0] = u1;
  344.    if (ilink(flist, icode) > 0)
  345.       exit(EXIT_FAILURE);
  346.  
  347.    /*
  348.     * Execute the icode file.
  349.     */
  350.    rfiles[3] = NULL;            /* don't delete icode yet */
  351.    cleanup();                /* but delete the others */
  352.    sprintf(buf, "ICODE_TEMP=%s:%s", icode, progname);
  353.    putenv(buf);                /* tell iconx to delete icode */
  354.    umask(omask);            /* reset original umask */
  355.    execute(icode, NULL, args);        /* execute the program */
  356.    quitf("could not execute %s", icode);
  357.    }
  358.  
  359. /*
  360.  * Dump a string to a file, prefixed by  $line 0 "[inline]".
  361.  */
  362. static char *savefile(FILE *f, char *srcprog) {
  363.    static char *progname = "[inline]";
  364.    fprintf(f, "$line 0 \"%s\"\n", progname);
  365.    fwrite(srcprog, 1, strlen(srcprog), f);
  366.    return progname;
  367.    }
  368.  
  369. /*
  370.  * Copy a source file for later translation, adding  $line 0 "filename".
  371.  */
  372. static char *copyfile(FILE *f, char *srcfile) {
  373.    int c;
  374.    FILE *e = fopen(srcfile, "r");
  375.    if (e == NULL)
  376.       quitf("cannot open: %s", srcfile);
  377.    fprintf(f, "$line 0 \"%s\"\n", srcfile);
  378.    while ((c = getc(e)) != EOF)
  379.       putc(c, f);
  380.    fclose(e);
  381.    return srcfile;
  382.    }
  383.  
  384. /*
  385.  * Deletes the files listed in rfiles[].
  386.  */
  387. static void cleanup(void) {
  388.    char **p;
  389.  
  390.    for (p = rfiles; *p; p++)
  391.       remove(*p);
  392. }
  393.