home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / files / language / sozobon2 / cc.c < prev    next >
C/C++ Source or Header  |  1993-10-23  |  15KB  |  749 lines

  1. /* Copyright (c) 1988 by Sozobon, Limited.  Author: Tony Andrews
  2.  *
  3.  * Permission is granted to anyone to use this software for any purpose
  4.  * on any computer system, and to redistribute it freely, with the
  5.  * following restrictions:
  6.  * 1) No charge may be made other than reasonable charges for reproduction.
  7.  * 2) Modified versions must be clearly marked as such.
  8.  * 3) The authors are not responsible for any harmful consequences
  9.  *    of using this software, even if they result from defects in it.
  10.  */
  11.  
  12. static    char    Version[] =
  13. "cc: version 1.01  Copyright (c) 1988 by Sozobon, Limited.";
  14.  
  15. /*
  16.  * cc - C compiler driver program
  17.  *
  18.  * Parses command line for options and file names. Then calls the
  19.  * various passes of the compiler as needed.
  20.  */
  21.  
  22. #include <stdio.h>
  23. #include <fcntl.h>
  24. #include <osbind.h>
  25.  
  26. /*
  27.  * This is the amount of space to grab from TOS at a time for
  28.  * malloc(). The default is 64K which wastes space if you don't
  29.  * need much. Since we spawn sub-programs from cc, it's important
  30.  * to leave as much memory for them as possible.
  31.  */
  32. long    _BLKSIZ = 4096;
  33.  
  34. #ifndef    TRUE
  35. #define    FALSE    (0)
  36. #define    TRUE    !FALSE
  37. #endif
  38.  
  39. #define    MAXOPT    16    /* max. number of options to any one pass */
  40.  
  41. /*
  42.  * Standard filename extensions
  43.  */
  44. #define    EXSUF    ".ttp,.tos,.prg"    /* suffixes for executables */
  45. #define    LIBSUF    ".a,.lib"        /* libraries */
  46.  
  47. /*
  48.  * Compiler pass information
  49.  */
  50. #define    CC    "hcc"
  51.  
  52. char    *hccopt[MAXOPT];
  53. int    hcc_cnt = 0;        /* number of options to hcc */
  54.  
  55. /*
  56.  * Optimizer information
  57.  */
  58. #define    OPT    "top"
  59. #define    OTMP    "top_tmp.s"
  60.  
  61. /*
  62.  * Assembler information
  63.  */
  64. #define    ASM    "jas"            /* default assembler */
  65. #define    ASMD    "as68symb.dat"        /* assembler data file (as68 only) */
  66.  
  67. /*
  68.  * Loader information
  69.  */
  70. #define    LD    "ld"
  71. #define    LTMP    "ldfile.tmp"        /* loader command file */
  72.  
  73. #define    CSU    "dstart.o"        /* C startup code */
  74. #define    PCSU    "pdstart.o"        /* profiling startup code */
  75.  
  76. #define    LIBC    "dlibs"            /* C runtime library */
  77. #define    PLIBC    "pdlibs"        /* profiled runtime library */
  78.  
  79. #define    LIBM    "libm"            /* math library */
  80. #define    PLIBM    "plibm"            /* profiled math library */
  81.  
  82. /*
  83.  * Path information
  84.  */
  85.  
  86. char    *path;        /* where to find executables */
  87. char    *lib;        /* where to find library stuff */
  88. char    *tmp;        /* where to put temporary files */
  89.  
  90. /*
  91.  * Default paths for executables and libraries
  92.  *
  93.  * Always check the root of the current drive first.
  94.  */
  95. #define    DEFPATH        "\\bin,\\sozobon\\bin"
  96. #define    DEFLIB        "\\lib,\\sozobon\\lib"
  97. #define    DEFTMP        ""
  98.  
  99. /*
  100.  * Boolean options
  101.  */
  102. int    mflag = 0;    /* generate a load map */
  103. int    vflag = 0;    /* show what we're doing w/ version numbers */
  104. int    nflag = 0;    /* ...but don't really do it */
  105. int    Sflag = 0;    /* generate assembly files */
  106. int    cflag = 0;    /* generate ".s" files only */
  107. int    Oflag = 0;    /* run the optimizer */
  108. int    tflag = 0;    /* generate a symbol table in executables */
  109. int    pflag = 0;    /* enable execution profiling */
  110. int    fflag = 0;    /* enable floating point */
  111.  
  112. /*
  113.  * We build lists of the various file types we're given. Within each
  114.  * type, MAXF says how many we can deal with.
  115.  */
  116. #define    MAXF    30
  117.  
  118. int    ncfiles = 0;    /* .c files */
  119. char    *cfiles[MAXF];
  120. int    nsfiles = 0;    /* .s files */
  121. char    *sfiles[MAXF];
  122. int    nofiles = 0;    /* .o files */
  123. char    *ofiles[MAXF];
  124. int    nlfiles = 0;    /* .a or .lib files (or files with no suffix) */
  125. char    *lfiles[MAXF];
  126.  
  127. char    *output = NULL;    /* output file */
  128.  
  129. char    cmdln[512];
  130.  
  131. usage()
  132. {
  133.     fprintf(stderr,
  134.         "Sozobon C Compiler Options:\n");
  135.     fprintf(stderr,
  136.         "-c        compile, but don't link\n");
  137.     fprintf(stderr,
  138.         "-O        run the assembly code optimizer\n");
  139.     fprintf(stderr,
  140.         "-S        don't assemble, leave .s files around\n");
  141.     fprintf(stderr,
  142.         "-v (or -V)    show the passes and versions as they run\n");
  143.     fprintf(stderr,
  144.         "-n        like -v, but don't really run anything\n");
  145.     fprintf(stderr,
  146.         "-m        tell the loader to generate a load map\n");
  147.     fprintf(stderr,
  148.         "-t        tell the loader to generate a symbol table\n");
  149.     fprintf(stderr,
  150.         "-f        link the floating point library\n");
  151.     fprintf(stderr,
  152.         "-p        enable execution profiling\n");
  153.     fprintf(stderr,
  154.         "-o f        use the file 'f' for the loader output\n");
  155.     fprintf(stderr,
  156.         "-Ilib        add dir. 'lib' to the header search list\n");
  157.     fprintf(stderr,
  158.         "-Dsym        define the pre-processor symbol 'sym' as 1\n");
  159.     fprintf(stderr,
  160.         "-Dsym=val    or as 'val'\n");
  161.     fprintf(stderr,
  162.         "-Usym        un-define the built-in symbol 'sym'\n");
  163.  
  164.     exit(1);
  165. }
  166.  
  167. main(argc, argv)
  168. int    argc;
  169. char    *argv[];
  170. {
  171.     extern    char    *chsuf();
  172.     register int    i;
  173.     register char    *s;
  174.     register int    endopt;
  175.     int    domsg = FALSE;
  176.  
  177.     if (argc == 1)
  178.         usage();
  179.  
  180.     for (i=1; i < argc ;i++) {
  181.         if (argv[i][0] == '-') {    /* option */
  182.             endopt = FALSE;
  183.             for (s = &argv[i][1]; *s && !endopt ;s++) {
  184.                 switch (*s) {
  185.                 case 'c':
  186.                     cflag = TRUE; break;
  187.                 case 'O':
  188.                     Oflag = TRUE; break;
  189.                 case 'S':
  190.                     Sflag = TRUE; break;
  191.                 case 'v':
  192.                 case 'V':
  193.                     vflag = TRUE; break;
  194.                 case 'n':
  195.                     nflag = TRUE; break;
  196.                 case 'm':
  197.                     mflag = TRUE; break;
  198.                 case 't':
  199.                     tflag = TRUE; break;
  200.                 case 'f':
  201.                     fflag = TRUE; break;
  202.                 case 'p':
  203.                     pflag = TRUE; break;
  204.                 case 'o':
  205.                     output = argv[++i];
  206.                     endopt = TRUE;
  207.                     break;
  208.                 /*
  209.                  * Options for other passes.
  210.                  */
  211.                 case 'I':    /* compiler options */
  212.                 case 'D':
  213.                 case 'U':
  214.                     hccopt[hcc_cnt++] = argv[i];
  215.                     endopt = TRUE;
  216.                     break;
  217.                 default:
  218.                     usage();
  219.                 }
  220.             }
  221.         } else {        /* input file */
  222.             if (output == NULL)
  223.                 output = chsuf(argv[i], ".ttp");
  224.  
  225.             keepfile(argv[i]);
  226.         }
  227.     }
  228.  
  229.     if ((ncfiles + nsfiles) > 1)
  230.         domsg = TRUE;
  231.  
  232.     doinit();
  233.  
  234.     if (vflag)
  235.         printf("%s\n", Version);
  236.  
  237.     for (i = 0; i < ncfiles ;i++) {
  238.         if (domsg)
  239.             printf("%s:\n", cfiles[i]);
  240.         docomp(cfiles[i]);
  241.         doopt(cfiles[i]);
  242.         doasm(cfiles[i], TRUE);
  243.     }
  244.  
  245.     for (i = 0; i < nsfiles ;i++) {
  246.         if (domsg)
  247.             printf("%s:\n", sfiles[i]);
  248.         doasm(sfiles[i], FALSE);
  249.     }
  250.  
  251.     dold();        /* run the loader */
  252.  
  253.     exit(0);
  254. }
  255.  
  256. /*
  257.  * doinit() - set up some variables before getting started
  258.  */
  259. doinit()
  260. {
  261.     char    *getenv();
  262.  
  263.     if ((path = getenv("PATH")) == NULL)
  264.         path = DEFPATH;
  265.  
  266.     if ((lib = getenv("LIB")) == NULL)
  267.         lib = DEFLIB;
  268.  
  269.     if ((tmp = getenv("TMP")) == NULL)
  270.         tmp = DEFTMP;
  271. }
  272.  
  273. /*
  274.  * keepfile(f) - remember the filename 'f' in the appropriate place
  275.  */
  276. keepfile(f)
  277. char    *f;
  278. {
  279.     char    *p, *strchr();
  280.  
  281.     if ((p = strchr(f, '.')) == NULL) {    /* no suffix */
  282.         lfiles[nlfiles++] = f;
  283.         return;
  284.     }
  285.  
  286.     if (strcmp(p, ".c") == 0) {
  287.         cfiles[ncfiles++] = f;
  288.         return;
  289.     }
  290.     if (strcmp(p, ".s") == 0) {
  291.         sfiles[nsfiles++] = f;
  292.         return;
  293.     }
  294.     if (strcmp(p, ".o") == 0) {
  295.         ofiles[nofiles++] = f;
  296.         return;
  297.     }
  298.     if (strcmp(p, ".a") == 0) {
  299.         lfiles[nlfiles++] = f;
  300.         return;
  301.     }
  302.     if (strcmp(p, ".lib") == 0) {
  303.         lfiles[nlfiles++] = f;
  304.         return;
  305.     }
  306.     fprintf(stderr, "cc: unknown file suffix '%s'\n", f);
  307.     exit(1);
  308. }
  309.  
  310. /*
  311.  * chsuf(f, suf) - change the suffix of file 'f' to 'suf'.
  312.  *
  313.  * Space for the new string is obtained using malloc().
  314.  */
  315. char *
  316. chsuf(f, suf)
  317. char    *f;
  318. char    *suf;
  319. {
  320.     char    *malloc();
  321.     char    *s, *p;
  322.  
  323.     p = s = malloc(strlen(f) + strlen(suf) + 1);
  324.  
  325.     strcpy(p, f);
  326.  
  327.     for (; *p ; p++) {
  328.         if (*p == '.')
  329.             break;
  330.     }
  331.  
  332.     while (*suf)
  333.         *p++ = *suf++;
  334.  
  335.     *suf = '\0';
  336.  
  337.     return s;
  338. }
  339.  
  340. /*
  341.  * isfile(f) - return true if the given file exists
  342.  */
  343. int
  344. isfile(f)
  345. char    *f;
  346. {
  347.     int    fd;
  348.  
  349.     if ((fd = open(f, O_RDONLY)) < 0)
  350.         return FALSE;
  351.  
  352.     close(fd);
  353.     return TRUE;
  354. }
  355.  
  356. /*
  357.  * findfile(e, b, s, chknul)
  358.  *
  359.  * Finds a file in one of the directories given in the environment
  360.  * variable whose value is pointed to by 'e'. Looks for the file
  361.  * given by 'b' with one of the suffixes listed in 's'. The suffix
  362.  * string should contain suffixes delimited by commas.
  363.  *
  364.  * e.g.  findfile("env stuff", "hcc", ".tos,.ttp,.prg")
  365.  *
  366.  * Returns a pointer to a static area containing the pathname of the
  367.  * file, if found, NULL otherwise.
  368.  *
  369.  * If 'chknul' is set, try the base name without any suffix as well.
  370.  */
  371. char *
  372. findfile(e, b, s, chknul)
  373. char    *e;
  374. char    *b;
  375. char    *s;
  376. int    chknul;
  377. {
  378.     static    char    file[256];
  379.     char    env[256];
  380.     char    suf[128];
  381.     char    *eptr, *sptr;
  382.     char    *p;
  383.  
  384.     /*
  385.      * Make a copy of the value of the env. variable. Convert all
  386.      * delimiters to nulls.
  387.      */
  388.     if (e != NULL) {
  389.         strcpy(env, e);
  390.         for (p = env; *p ;p++) {
  391.             if (*p == ';' || *p == ',')
  392.                 *p = '\0';
  393.         }
  394.         p[1] = '\0';        /* double null terminator */
  395.     } else
  396.         env[1] = env[0] = '\0';
  397.  
  398.     strcpy(suf, s);
  399.     for (p = suf; *p ;p++) {
  400.         if (*p == ',')
  401.             *p = '\0';
  402.     }
  403.     p[1] = '\0';        /* double null terminator */
  404.  
  405.     /*
  406.      * Always check the root of the current drive and the
  407.      * current directory first. If that doesn't work, then
  408.      * start looking in the usual places...
  409.      */
  410.     for (sptr = suf; *sptr ;) {
  411.  
  412.         sprintf(file, "%s%s", b, sptr);
  413.  
  414.         if (isfile(file))
  415.             return file;
  416.  
  417.         sprintf(file, "\\%s%s", b, sptr);
  418.  
  419.         if (isfile(file))
  420.             return file;
  421.  
  422.         while (*sptr++ != '\0')
  423.             ;
  424.     }
  425.  
  426.     for (eptr = env; *eptr ;) {
  427.         if (chknul) {
  428.             sprintf(file, "%s\\%s", eptr, b);
  429.             if (isfile(file))
  430.                 return file;
  431.         }
  432.  
  433.         for (sptr = suf; *sptr ;) {
  434.  
  435.             sprintf(file, "%s\\%s%s", eptr, b, sptr);
  436.  
  437.             if (isfile(file))
  438.                 return file;
  439.  
  440.             while (*sptr++ != '\0')
  441.                 ;
  442.         }
  443.         while (*eptr++ != '\0')
  444.             ;
  445.     }
  446.     return NULL;        /* give up */
  447. }
  448.  
  449. /*
  450.  * docmd(path, cmdline) - run a command
  451.  */
  452. int
  453. docmd(path, cmdline)
  454. char    *path;
  455. char    *cmdline;
  456. {
  457.     int    i;
  458.     char    cmd[150];
  459.  
  460.     strcpy(&cmd[1], cmdline);
  461.     cmd[0] = strlen(cmdline);
  462.  
  463.     i = Pexec(0, path, cmd, 0L);
  464.  
  465.     return i;
  466. }
  467.  
  468. /*
  469.  * docomp(f) - run the compiler on the given .c file
  470.  */
  471. docomp(f)
  472. char    *f;
  473. {
  474.     int    i;
  475.     char    *cpath, *sf;
  476.  
  477.     if ((cpath = findfile(path, CC, EXSUF, FALSE)) == NULL) {
  478.         fprintf(stderr, "cc: can't find compiler program '%s'\n", CC);
  479.         exit(1);
  480.     }
  481.  
  482.     strcpy(cmdln, pflag ? "-P " : "");
  483.  
  484.     for (i=0; i < hcc_cnt ;i++) {
  485.         strcat(cmdln, hccopt[i]);
  486.         strcat(cmdln, " ");
  487.     }
  488.     strcat(cmdln, f);
  489.  
  490.     if (nflag || vflag)
  491.         fprintf(stderr, "%s %s\n", cpath, cmdln);
  492.  
  493.     if (!nflag) {
  494.         if (docmd(cpath, cmdln)) {
  495.             sf = chsuf(f, ".s");
  496.             unlink(sf);
  497.             free(sf);
  498.             fprintf(stderr, "cc: compiler failed\n");
  499.             exit(1);
  500.         }
  501.     }
  502. }
  503.  
  504. /*
  505.  * doopt(f) - run the optimizer
  506.  *
  507.  * Only optimize files that were produced by the compiler.
  508.  */
  509. doopt(f)
  510. char    *f;
  511. {
  512.     int    i;
  513.     char    *opath;
  514.     char    *sf;
  515.  
  516.     if (!Oflag)
  517.         return;
  518.  
  519.     if ((opath = findfile(path, OPT, EXSUF, FALSE)) == NULL) {
  520.         fprintf(stderr, "cc: can't find optimizer program '%s'\n", OPT);
  521.         exit(1);
  522.     }
  523.  
  524.     sf = chsuf(f, ".s");
  525.  
  526.     if (nflag || vflag)
  527.         fprintf(stderr, "%s %s %s\n",
  528.             opath, sf, OTMP);
  529.  
  530.     if (!nflag) {
  531.         sprintf(cmdln, "%s %s", sf, OTMP);
  532.         if (docmd(opath, cmdln)) {
  533.             unlink(OTMP);
  534.             fprintf(stderr, "cc: optimizer failed (continuing)\n");
  535.             unlink(OTMP);
  536.         } else {
  537.             unlink(sf);
  538.             rename(OTMP, sf);
  539.         }
  540.     }
  541.     free(sf);
  542. }
  543.  
  544. /*
  545.  * doasm() - run the assembler
  546.  *
  547.  * If 'istmp' is TRUE, the file we were given is a temporary
  548.  */
  549. doasm(f, istmp)
  550. char    *f;
  551. int    istmp;
  552. {
  553.     char    *strrchr(), *getenv();
  554.     int    i;
  555.     char    apath[128], *dpath;
  556.     char    *s;
  557.     char    *aname;        /* assembler to use */
  558.     char    *sf;
  559.  
  560.     if (Sflag)
  561.         return;
  562.  
  563.     if ((aname = getenv("ASM")) == NULL)
  564.         aname = ASM;
  565.  
  566.     if ((dpath = findfile(path, aname, EXSUF, FALSE)) == NULL) {
  567.         fprintf(stderr, "cc: can't find assembler program '%s'\n", aname);
  568.         exit(1);
  569.     }
  570.     strcpy(apath, dpath);
  571.  
  572.     if (strcmp(aname, "as68") == 0) {
  573.         if ((dpath = findfile(lib, ASMD, "", TRUE)) == NULL) {
  574.             fprintf(stderr, "cc: can't find assembler data file\n");
  575.             exit(1);
  576.         }
  577.         if ((s = strrchr(dpath, '\\')) == NULL) {
  578.             fprintf(stderr, "cc: can't find assembler data file\n");
  579.             exit(1);
  580.         }
  581.         s[1] = '\0';
  582.     } else
  583.         dpath = NULL;
  584.  
  585.     sf = chsuf(f, ".s");
  586.  
  587.     if (nflag || vflag)
  588.         fprintf(stderr, "%s -l -u%s%s %s\n",
  589.             apath,
  590.             (dpath != NULL) ? " -s " : "",
  591.             (dpath != NULL) ? dpath : "",
  592.             sf);
  593.  
  594.     if (!nflag) {
  595.         sprintf(cmdln, "%s%s %s",
  596.             (dpath != NULL) ? "-l -u -s " : "",
  597.             (dpath != NULL) ? dpath : "",
  598.             sf);
  599.  
  600.         if (docmd(apath, cmdln)) {
  601.             fprintf(stderr, "cc: assembler failed '%s'\n",
  602.                 sf);
  603.             if (istmp)
  604.                 unlink(sf);
  605.             free(sf);
  606.             exit(1);
  607.         }
  608.     }
  609.  
  610.     if (nflag) {
  611.         free(sf);
  612.         return;
  613.     }
  614.  
  615.     if (istmp)
  616.         unlink(sf);
  617.  
  618.     free(sf);
  619. }
  620.  
  621. /*
  622.  * dold() - run the loader
  623.  */
  624. dold()
  625. {
  626.     FILE    *fp, *fopen();
  627.     int    i;
  628.     char    tfile[128];
  629.     char    *lpath;
  630.     char    *s;
  631.     char    *l;
  632.  
  633.     if (cflag || Sflag)
  634.         return;
  635.  
  636.     /*
  637.      * Construct the name of the loader data file.
  638.      */
  639.     if (*tmp != '\0') {
  640.         strcpy(tfile, tmp);
  641.         if (tfile[strlen(tfile)-1] != '\\')
  642.             strcat(tfile, "\\");
  643.     } else
  644.         tfile[0] = '\0';
  645.  
  646.     strcat(tfile, LTMP);
  647.  
  648.     unlink(tfile);
  649.     /*
  650.      * Construct loader command file
  651.      */
  652.     if ((fp = fopen(tfile, "w")) == NULL) {
  653.         fprintf(stderr, "cc: can't open loader temp file\n");
  654.         exit(1);
  655.     }
  656.  
  657.     l = pflag ? PCSU : CSU;
  658.     if ((lpath = findfile(lib, l, "", TRUE)) == NULL) {
  659.         fprintf(stderr, "cc: can't find C startup code '%s'\n", l);
  660.         exit(1);
  661.     }
  662.     fprintf(fp, "%s\n", lpath);
  663.  
  664.     for (i = 0; i < ncfiles ;i++) {
  665.         s = chsuf(cfiles[i], ".o");
  666.         fprintf(fp, "%s\n", s);
  667.         free(s);
  668.     }
  669.     for (i = 0; i < nsfiles ;i++) {
  670.         s = chsuf(sfiles[i], ".o");
  671.         fprintf(fp, "%s\n", s);
  672.         free(s);
  673.     }
  674.     for (i = 0; i < nofiles ;i++)
  675.         fprintf(fp, "%s\n", ofiles[i]);
  676.  
  677.     for (i = 0; i < nlfiles ;i++) {
  678.         if (isfile(lfiles[i])) {
  679.             fprintf(fp, "%s\n", lfiles[i]);
  680.         } else {
  681.             lpath = findfile(lib, lfiles[i], LIBSUF, TRUE);
  682.             if (lpath == NULL) {
  683.                 fprintf(stderr, "cc: can't find library '%s'\n", lfiles[i]);
  684.                 exit(1);
  685.             }
  686.             fprintf(fp, "%s\n", lpath);
  687.         }
  688.     }
  689.  
  690.     if (fflag) {
  691.         l = pflag ? PLIBM : LIBM;
  692.         if ((lpath = findfile(lib, l, LIBSUF, TRUE)) == NULL) {
  693.             fprintf(stderr, "cc: can't find floating point library '%s'\n",l);
  694.             exit(1);
  695.         }
  696.         fprintf(fp, "%s\n", lpath);
  697.     }
  698.  
  699.     l = pflag ? PLIBC : LIBC;
  700.     if ((lpath = findfile(lib, l, LIBSUF, TRUE)) == NULL) {
  701.         fprintf(stderr, "cc: can't find C runtime library '%s'\n", l);
  702.         exit(1);
  703.     }
  704.     fprintf(fp, "%s\n", lpath);
  705.  
  706.     fclose(fp);
  707.  
  708.     if ((lpath = findfile(path, LD, EXSUF, FALSE)) == NULL) {
  709.         fprintf(stderr, "cc: can't find loader program '%s'\n", LD);
  710.         exit(1);
  711.     }
  712.  
  713.     sprintf(cmdln, "%s%s-p -u _main %s -o %s -f %s",
  714.         mflag ? "-m " : "",
  715.         tflag ? "-t " : "",
  716.         fflag ? "-u __printf -u __scanf " : "",
  717.         output,
  718.         tfile);
  719.  
  720.     if (nflag || vflag)
  721.         fprintf(stderr, "%s %s\n", lpath, cmdln);
  722.  
  723.     if (!nflag) {
  724.         if (docmd(lpath, cmdln)) {
  725.             fprintf(stderr, "cc: loader failed\n");
  726.             unlink(tfile);
  727.             unlink(output);
  728.             exit(1);
  729.         }
  730.     }
  731.  
  732.     if (nflag)
  733.         return;
  734.  
  735.     for (i = 0; i < ncfiles ;i++) {
  736.         s = chsuf(cfiles[i], ".o");
  737.         unlink(s);
  738.         free(s);
  739.     }
  740.  
  741.     for (i = 0; i < nsfiles ;i++) {
  742.         s = chsuf(sfiles[i], ".o");
  743.         unlink(s);
  744.         free(s);
  745.     }
  746.  
  747.     unlink(tfile);
  748. }
  749.