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