home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / dmake40.zip / sysintf.c < prev    next >
C/C++ Source or Header  |  1994-10-23  |  17KB  |  749 lines

  1. /* RCS      -- $Header: /u5/dvadura/src/public/dmake/src/RCS/sysintf.c,v 1.1 1994/10/06 17:41:27 dvadura Exp $
  2. -- SYNOPSIS -- system independent interface
  3. -- 
  4. -- DESCRIPTION
  5. --    These are the routines constituting the system interface.
  6. --    The system is taken to be essentially POSIX conformant.
  7. --    The original code was extensively revised by T J Thompson at MKS,
  8. --    and the library cacheing was added by Eric Gisin at MKS.  I then
  9. --    revised the code yet again, to improve the lib cacheing, and to
  10. --    make it more portable.
  11. --
  12. --    The following is a list of routines that are required by this file
  13. --    in order to work.  These routines are provided as functions by the
  14. --    standard C lib of the target system or as #defines in system/sysintf.h
  15. --    or via appropriate C code in the system/ directory for the given
  16. --    system.
  17. --
  18. --    The first group must be provided by a file in the system/ directory
  19. --    the second group is ideally provided by the C lib.  However, there
  20. --    are instances where the C lib implementation of the specified routine
  21. --    does not exist, or is incorrect.  In these instances the routine
  22. --    must be provided by the the user in the system/ directory of dmake.
  23. --    (For example, the bsd/ dir contains code for putenv(), and tempnam())
  24. --
  25. --    DMAKE SPECIFIC:
  26. --        seek_arch()
  27. --        touch_arch()
  28. --        void_lcache()
  29. --        runargv()
  30. --        STAT()
  31. --        Remove_prq()
  32. --
  33. --    C-LIB SPECIFIC:  (should be present in your C-lib)
  34. --        utime()
  35. --        time()
  36. --        getenv()
  37. --        putenv()
  38. --        getcwd()
  39. --        signal()
  40. --        chdir()
  41. --        tempnam()
  42. -- 
  43. -- AUTHOR
  44. --      Dennis Vadura, dvadura@watdragon.uwaterloo.ca
  45. --      CS DEPT, University of Waterloo, Waterloo, Ont., Canada
  46. --
  47. -- COPYRIGHT
  48. --      Copyright (c) 1992,1994 by Dennis Vadura.  All rights reserved.
  49. -- 
  50. --      This program is free software; you can redistribute it and/or
  51. --      modify it under the terms of the GNU General Public License
  52. --      (version 1), as published by the Free Software Foundation, and
  53. --      found in the file 'LICENSE' included with this distribution.
  54. -- 
  55. --      This program is distributed in the hope that it will be useful,
  56. --      but WITHOUT ANY WARRANTY; without even the implied warrant of
  57. --      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  58. --      GNU General Public License for more details.
  59. -- 
  60. --      You should have received a copy of the GNU General Public License
  61. --      along with this program;  if not, write to the Free Software
  62. --      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  63. --
  64. -- LOG
  65. --     $Log: sysintf.c,v $
  66.  * Revision 1.1  1994/10/06  17:41:27  dvadura
  67.  * dmake Release Version 4.0, Initial revision
  68.  *
  69. */
  70.  
  71. #include "extern.h"
  72. #include "sysintf.h"
  73.  
  74. /*
  75. ** Tries to stat the file name.  Returns 0 if the file
  76. ** does not exist.  Note that if lib is not null it tries to stat
  77. ** the name found inside lib.
  78. **
  79. ** If member is NOT nil then look for the library object which defines the
  80. ** symbol given by name.  If found DmStrDup the name and return make the
  81. ** pointer pointed at by sym point at it.  Not handled for now!
  82. */
  83. static really_dostat(name, buf)
  84. char *name;
  85. struct stat *buf;
  86. {
  87.    return( (STAT(name,buf)==-1 || (Augmake && (buf->st_mode & S_IFDIR)))
  88.        ? (time_t)0L
  89.        : (time_t) buf->st_mtime
  90.      );
  91. }
  92.  
  93.  
  94. PUBLIC time_t
  95. Do_stat(name, lib, member, force)
  96. char *name;
  97. char *lib;
  98. char **member;
  99. int  force;
  100. {
  101.    struct stat buf;
  102.    time_t seek_arch();
  103.  
  104.    if( member != NIL(char *) )
  105.       Fatal("Library symbol names not supported");
  106.  
  107.    buf.st_mtime = (time_t)0L;
  108.    if( lib != NIL(char) )
  109.       return( seek_arch(Basename(name), lib) );
  110.    else if( UseDirCache && (*UseDirCache == 'y' || *UseDirCache == 'Y') )
  111.       return(CacheStat(name,force));
  112.    else if( strlen(Basename(name)) > NameMax )
  113.       return((time_t)0L);
  114.    else
  115.       return(really_dostat(name,&buf));
  116. }
  117.  
  118.  
  119. /* Touch existing file to force modify time to present.
  120.  */
  121. PUBLIC int
  122. Do_touch(name, lib, member)
  123. char *name;
  124. char *lib;
  125. char **member;
  126. {
  127.    if( member != NIL(char *) )
  128.       Fatal("Library symbol names not supported");
  129.  
  130.    if (lib != NIL(char))
  131.       return( touch_arch(Basename(name), lib) );
  132.    else
  133.       return( utime(name, NIL(time_t)) );
  134. }
  135.  
  136.  
  137.  
  138. PUBLIC void
  139. Void_lib_cache( lib_name, member_name )/*
  140. =========================================
  141.    Void the library cache for lib lib_name, and member member_name. */
  142. char *lib_name;
  143. char *member_name;
  144. {
  145.    VOID_LCACHE( lib_name, member_name );
  146. }
  147.  
  148.  
  149.  
  150. /*
  151. ** return the current time
  152. */
  153. PUBLIC time_t
  154. Do_time()
  155. {
  156.    extern time_t time();
  157.    return (time((time_t*)0));
  158. }
  159.  
  160.  
  161.  
  162. /*
  163. ** Execute the string passed in as a command and return
  164. ** the return code. The command line arguments are
  165. ** assumed to be separated by spaces or tabs.  The first
  166. ** such argument is assumed to be the command.
  167. **
  168. ** If group is true then this is a group of commands to be fed to the
  169. ** the shell as a single unit.  In this case cmd is of the form
  170. ** "file" indicating the file that should be read by the shell
  171. ** in order to execute the command group.
  172. */
  173. PUBLIC int
  174. Do_cmnd(cmd, group, do_it, target, ignore, shell, last)
  175. char   *cmd;
  176. int     group;
  177. int    do_it;
  178. CELLPTR target;
  179. int     ignore;
  180. int     shell;
  181. int    last;
  182. {
  183.    int  i;
  184.  
  185.    if( !do_it ) {
  186.       if( last && !Doing_bang ) {
  187.          Update_time_stamp( target );
  188.       }
  189.       return(0);
  190.    }
  191.  
  192.    if ( target->ce_attr & A_ERROR ) {
  193.       if ( last ) {
  194.      Update_time_stamp( target );
  195.       }
  196.       return(0);
  197.    }
  198.  
  199.    if( Max_proc == 1 ) Wait_for_completion = TRUE;
  200.  
  201.    if( (i = runargv(target, ignore, group, last, shell, cmd)) == -1 )
  202.       Quit();
  203.  
  204.    /* NOTE:  runargv must return either 0 or 1, 0 ==> command executed, and
  205.     * we waited for it to return, 1 ==> command started and is running
  206.     * concurrently with make process. */
  207.    return(i);
  208. }
  209.  
  210.  
  211. #define MINARGV 64
  212. /* Take a command and pack it into an argument vector to be executed. */
  213. PUBLIC char **
  214. Pack_argv( group, shell, cmd )
  215. int    group;
  216. int    shell;
  217. char  *cmd;
  218. {
  219.    static char **av = NIL(char *);
  220.    static int   avs = 0;
  221.    int i = 0;
  222.  
  223.    if( av == NIL(char *) ) {
  224.       TALLOC(av, MINARGV, char*);
  225.       avs = MINARGV;
  226.    }
  227.    av[0] = NIL(char);
  228.  
  229.    if (*cmd) {
  230.       Packed_shell = shell||group||(*DmStrPbrk(cmd, Shell_metas)!='\0');
  231.  
  232.       if( Packed_shell ){
  233.      char* sh = group ? GShell : Shell;
  234.  
  235.      if( sh != NIL(char) ) {
  236.         av[i++] = sh;
  237.         if( (av[i] = (group?GShell_flags:Shell_flags)) != NIL(char) ) i++;
  238.  
  239.         av[i++] = cmd;
  240.         av[i]   = NIL(char);
  241.      }
  242.      else
  243.         Fatal("%sSHELL macro not defined", group?"GROUP":"");
  244.       }
  245.       else {
  246.      do {
  247.         while( iswhite(*cmd) ) ++cmd;
  248.         if( *cmd ) av[i++] = cmd;
  249.  
  250.         while( *cmd != '\0' && !iswhite(*cmd) ) ++cmd;
  251.         if( *cmd ) *cmd++ = '\0';
  252.  
  253.         if( i == avs ) {
  254.            avs += MINARGV;
  255.            av = (char **) realloc( av, avs*sizeof(char *) );
  256.         }
  257.      } while( *cmd );
  258.  
  259.      av[i] = NIL(char);
  260.       }
  261.    }
  262.  
  263.    return(av);
  264. }
  265.  
  266.  
  267. /*
  268. ** Return the value of ename from the environment
  269. ** if ename is not defined in the environment then
  270. ** NIL(char) should be returned
  271. */
  272. PUBLIC char *
  273. Read_env_string(ename)
  274. char *ename;
  275. {
  276. #if !defined(_MSC_VER) || _MSC_VER < 600
  277.    extern char *getenv();
  278. #endif
  279.    return( getenv(ename) );
  280. }
  281.  
  282.  
  283.  
  284. /*
  285. ** Set the value of the environment string ename to value.
  286. **  Returns 0 if success, non-zero if failure
  287. */
  288. PUBLIC int
  289. Write_env_string(ename, value)
  290. char *ename;
  291. char *value;
  292. {
  293.    extern int putenv();
  294.    char*   p;
  295.    char*   envstr = DmStrAdd(ename, value, FALSE);
  296.  
  297.    p = envstr+strlen(ename);    /* Don't change this code, DmStrAdd does not */
  298.    *p++ = '=';            /* add the space if *value is 0, it does    */
  299.    if( !*value ) *p = '\0';    /* allocate enough memory for one though.   */
  300.  
  301.    return( putenv(envstr) );
  302. }
  303.  
  304.  
  305.  
  306. PUBLIC void
  307. ReadEnvironment()
  308. {
  309.    extern char **Rule_tab;
  310. #if !defined(_MSC_VER)
  311.    extern char **environ;
  312. #endif
  313.    char **rsave;
  314.  
  315. #if !defined(__ZTC__) && !defined(_MPW)
  316. # define make_env()
  317. # define free_env()
  318. #else
  319.    void make_env();
  320.    void free_env();
  321. #endif
  322.  
  323.    make_env();
  324.  
  325.    rsave    = Rule_tab;
  326.    Rule_tab = environ;
  327.    Readenv  = TRUE;
  328.  
  329.    Parse( NIL(FILE) );
  330.  
  331.    Readenv  = FALSE;
  332.    Rule_tab = rsave;
  333.  
  334.    free_env();
  335. }
  336.  
  337.  
  338.  
  339. /*
  340. ** All we have to catch is SIG_INT
  341. */
  342. PUBLIC void
  343. Catch_signals(fn)
  344. void (*fn)();
  345. {
  346.    if( (void (*)()) signal(SIGINT, SIG_IGN) != SIG_IGN )
  347.       signal( SIGINT, fn );
  348.    if( (void (*)()) signal(SIGQUIT, SIG_IGN) != SIG_IGN )
  349.       signal( SIGQUIT, fn );
  350. }
  351.  
  352.  
  353.  
  354. /*
  355. ** Clear any previously set signals
  356. */
  357. PUBLIC void
  358. Clear_signals()
  359. {
  360.    if( (void (*)())signal(SIGINT, SIG_IGN) != (void (*)())SIG_IGN )
  361.       signal( SIGINT, SIG_DFL );
  362.    if( (void (*)())signal(SIGQUIT, SIG_IGN) != (void (*)())SIG_IGN )
  363.       signal( SIGQUIT, SIG_DFL );
  364. }
  365.  
  366.  
  367.  
  368. /*
  369. ** Set program name
  370. */
  371. PUBLIC void
  372. Prolog(argc, argv)
  373. int   argc;
  374. char* argv[];
  375. {
  376.    Pname = (argc == 0) ? DEF_MAKE_PNAME : argv[0];
  377.    Root = Def_cell( ".ROOT" );
  378.    Targets = Def_cell( ".TARGETS" );
  379.    Add_prerequisite(Root, Targets, FALSE, FALSE);
  380.  
  381.    Targets->ce_flag = Root->ce_flag = F_RULES|F_TARGET|F_STAT;
  382.    Targets->ce_attr = Root->ce_attr = A_NOSTATE|A_PHONY;
  383.  
  384.    Root->ce_flag |= F_MAGIC;
  385.    Root->ce_attr |= A_SEQ;
  386.  
  387.    tzset();
  388. }
  389.  
  390.  
  391.  
  392. /*
  393. ** Do any clean up for exit.
  394. */
  395. PUBLIC void
  396. Epilog(ret_code)
  397. int ret_code;
  398. {
  399.    Write_state();
  400.    Unlink_temp_files(Root);
  401.    Hook_std_writes(NIL(char));        /* For MSDOS tee (-F option) */
  402.    exit( ret_code );
  403. }
  404.  
  405.  
  406.  
  407. /*
  408. ** Use the built-in functions of the operating system to get the current
  409. ** working directory.
  410. */
  411. PUBLIC char *
  412. Get_current_dir()
  413. {
  414.    static char buf[PATH_MAX+2];
  415.    return(getcwd(buf, sizeof(buf)));
  416. }
  417.  
  418.  
  419.  
  420. /*
  421. ** change working directory
  422. */
  423. PUBLIC int
  424. Set_dir(path)
  425. char*   path;
  426. {
  427.    return( chdir(path) );
  428. }
  429.  
  430.  
  431.  
  432. /*
  433. ** return switch char
  434. */
  435. PUBLIC char
  436. Get_switch_char()
  437. {
  438.    return( getswitchar() );
  439. }
  440.  
  441.  
  442.  
  443. /*
  444. ** Generate a temporary file name and open the file for writing.
  445. ** If a name cannot be generated or the file cannot be opened
  446. ** return -1, else return the fileno of the open file.
  447. ** and update the source file pointer to point at the new file name.
  448. ** Note that the new name should be freed when the file is removed.
  449. */
  450. PUBLIC FILE*
  451. Get_temp(path, suff, op)
  452. char **path;
  453. char *suff;
  454. int  op;
  455. {
  456.    extern char *tempnam();
  457.  
  458.    *path = DmStrJoin( tempnam(NIL(char), "mk"), suff, -1, TRUE );
  459.    Def_macro( "TMPFILE", *path, M_MULTI|M_EXPANDED );
  460.  
  461.    return( op?fopen(*path, "w"):NIL(FILE) );
  462. }
  463.  
  464.  
  465. /*
  466. ** Open a new temporary file and set it up for writing.
  467. */
  468. PUBLIC FILE *
  469. Start_temp( suffix, cp, fname )
  470. char     *suffix;
  471. CELLPTR   cp;
  472. char    **fname;
  473. {
  474.    FILE           *fp;
  475.    char        *tmpname;
  476.    char           *name;
  477.  
  478.    name = (cp != NIL(CELL))?cp->CE_NAME:"makefile text";
  479.  
  480.    if( (fp = Get_temp(&tmpname, suffix, TRUE)) == NIL(FILE) )
  481.       Open_temp_error( tmpname, name );
  482.  
  483.    Link_temp( cp, fp, tmpname );
  484.    *fname = tmpname;
  485.  
  486.    return( fp );
  487. }
  488.  
  489.  
  490. /*
  491. ** Issue an error on failing to open a temporary file
  492. */
  493. PUBLIC void
  494. Open_temp_error( tmpname, name )
  495. char *tmpname;
  496. char *name;
  497. {
  498.    Fatal("Cannot open temp file `%s' while processing `%s'", tmpname, name );
  499. }
  500.  
  501.  
  502. /*
  503. ** Link a temp file onto the list of files.
  504. */
  505. PUBLIC void
  506. Link_temp( cp, fp, fname )
  507. CELLPTR cp;
  508. FILE   *fp;
  509. char   *fname;
  510. {
  511.    FILELISTPTR new;
  512.  
  513.    if( cp == NIL(CELL) ) cp = Root;
  514.  
  515.    TALLOC( new, 1, FILELIST );
  516.  
  517.    new->fl_next = cp->ce_files;
  518.    new->fl_name = fname;
  519.    new->fl_file = fp;        /* indicates temp file is open */
  520.  
  521.    cp->ce_files = new;
  522. }
  523.  
  524.  
  525. /*
  526. ** Close a previously used temporary file.
  527. */
  528. PUBLIC void
  529. Close_temp(cp, file)
  530. CELLPTR cp;
  531. FILE    *file;
  532. {
  533.    FILELISTPTR fl;
  534.    if( cp == NIL(CELL) ) cp = Root;
  535.  
  536.    for( fl=cp->ce_files; fl && fl->fl_file != file; fl=fl->fl_next );
  537.    if( fl ) {
  538.       fl->fl_file = NIL(FILE);
  539.       fclose(file);
  540.    }
  541. }
  542.  
  543.  
  544. /*
  545. ** Clean-up, and close all temporary files associated with a target.
  546. */
  547. PUBLIC void
  548. Unlink_temp_files( cp )/*
  549. ==========================
  550.    Unlink the tempfiles if any exist.  Make sure you close the files first
  551.    though.  This ensures that under DOS there is no disk space lost. */
  552. CELLPTR cp;
  553. {
  554.    FILELISTPTR cur, next;
  555.  
  556.    if( cp == NIL(CELL) || cp->ce_files == NIL(FILELIST) ) return;
  557.  
  558.    for( cur=cp->ce_files; cur != NIL(FILELIST); cur=next ) {
  559.       next = cur->fl_next;
  560.  
  561.       if( cur->fl_file ) fclose( cur->fl_file );
  562.  
  563.       if( Verbose & V_LEAVE_TMP )
  564.          fprintf( stderr, "%s:  Left temp file [%s]\n", Pname, cur->fl_name );
  565.       else
  566.          (void) Remove_file( cur->fl_name );
  567.  
  568.       FREE(cur->fl_name);
  569.       FREE(cur);
  570.    }
  571.  
  572.    cp->ce_files = NIL(FILELIST);
  573. }
  574.  
  575.  
  576. PUBLIC void
  577. Handle_result(status, ignore, abort_flg, target)
  578. int    status;
  579. int    ignore;
  580. int    abort_flg;
  581. CELLPTR target;
  582. {
  583.    status = ((status&0xff)==0 ? status>>8
  584.         : (status & 0xff)==SIGTERM ? -1
  585.         : (status & 0x7f)+128);
  586.  
  587.    if( status )
  588.       if( !abort_flg ) {
  589.      char buf[512];
  590.  
  591.      sprintf(buf, "%s:  Error code %d, while making '%s'",
  592.          Pname, status, target->ce_fname );
  593.  
  594.      if( ignore || Continue ) {
  595.         if (!(Glob_attr & A_SILENT)) {
  596.            strcat(buf, " (Ignored" );
  597.  
  598.            if ( Continue ) {
  599.           strcat(buf,",Continuing");
  600.           target->ce_attr |= A_ERROR;
  601.            }
  602.            strcat(buf,")");
  603.            fprintf(stderr, "%s\n", buf);
  604.         }
  605.      }
  606.      else {
  607.         fprintf(stderr, "%s\n",buf);
  608.  
  609.         if( !(target->ce_attr & A_PRECIOUS) )
  610.            if( Remove_file( target->ce_fname ) == 0 )
  611.           fprintf(stderr,"%s:  '%s' removed.\n", Pname,
  612.               target->ce_fname);
  613.  
  614.         Quit();
  615.      }
  616.       }
  617.       else if( !(target->ce_attr & A_PRECIOUS) )
  618.      Remove_file( target->ce_fname );
  619. }
  620.  
  621.  
  622. PUBLIC void
  623. Update_time_stamp( cp )
  624. CELLPTR cp;
  625. {
  626.    HASHPTR hp;
  627.    LINKPTR dp;
  628.    CELLPTR tcp;
  629.    time_t  phonytime = (time_t)0L;
  630.    int     phony = ((cp->ce_attr&A_PHONY) != 0);
  631.  
  632.    /* Compute phony time as either the current time, or the most recent time
  633.     * from the list of prerequisites if there are any. */
  634.    if ( cp->ce_prq != NIL(LINK) ) {
  635.       for(dp=cp->ce_prq; dp; dp=dp->cl_next)
  636.      if ( dp->cl_prq->ce_time > phonytime )
  637.         phonytime = dp->cl_prq->ce_time;
  638.    }
  639.    else
  640.       phonytime = Do_time();
  641.  
  642.    for(dp=CeMeToo(cp); dp; dp=dp->cl_next) {
  643.       tcp=dp->cl_prq;
  644.  
  645.       if( tcp->ce_attr & A_LIBRARY )
  646.      Void_lib_cache( tcp->ce_fname, NIL(char) );
  647.       else if( !Touch && (tcp->ce_attr & A_LIBRARYM) )
  648.      Void_lib_cache( tcp->ce_lib, tcp->ce_fname );
  649.  
  650.       if( phony ) {
  651.      tcp->ce_time = phonytime;
  652.       }
  653.       else if (Trace) {
  654.      tcp->ce_time = Do_time();
  655.       }
  656.       else {
  657.      Stat_target(tcp, -1, TRUE);
  658.  
  659.      if( tcp->ce_time == (time_t) 0L )
  660.         tcp->ce_time = Do_time();
  661.       }
  662.  
  663.       if( Trace ) {
  664.      tcp->ce_flag |= F_STAT;        /* pretend we stated ok */
  665.       }
  666.  
  667.       if( Verbose & V_MAKE )
  668.      printf( "%s:  <<<< Set [%s] time stamp to %ld\n",
  669.          Pname, tcp->CE_NAME, tcp->ce_time );
  670.  
  671.       Unlink_temp_files( tcp );
  672.       tcp->ce_flag |= F_MADE;
  673.       tcp->ce_attr |= A_UPDATED;
  674.    }
  675.  
  676.    /* Scan the list of prerequisites and if we find one that is
  677.     * marked as being removable, (ie. an inferred intermediate node
  678.     * then remove it.  We remove a prerequisite by running the recipe
  679.     * associated with the special target .REMOVE, with $< set to
  680.     * the list of prerequisites to remove. */
  681.  
  682.    /* Make sure we don't try to remove prerequisites for the .REMOVE
  683.     * target. */
  684.    if( strcmp(cp->CE_NAME,".REMOVE") != 0 &&
  685.        (hp = Get_name(".REMOVE", Defs, FALSE)) != NIL(HASH) ) {
  686.       register LINKPTR dp;
  687.       int flag = FALSE;
  688.       int rem;
  689.       t_attr attr;
  690.  
  691.       tcp = hp->CP_OWNR;
  692.  
  693.       tcp->ce_flag |= F_TARGET;
  694.       Clear_prerequisites( tcp );
  695.  
  696.       for(dp=cp->ce_prq; dp != NIL(LINK); dp=dp->cl_next) {
  697.      register CELLPTR prq = dp->cl_prq;
  698.  
  699.      attr = Glob_attr | prq->ce_attr;
  700.      rem  = (prq->ce_flag & F_REMOVE) &&
  701.         (prq->ce_flag & F_MADE  ) &&
  702.         !(prq->ce_attr & A_PHONY) &&
  703.         !(attr & A_PRECIOUS);
  704.  
  705.      if(rem) {
  706.         LINKPTR tdp;
  707.  
  708.         for(tdp=CeMeToo(prq); tdp; tdp=tdp->cl_next) {
  709.            CELLPTR tmpcell=tdp->cl_prq;
  710.  
  711.            (Add_prerequisite(tcp,tmpcell,FALSE,FALSE))->cl_flag|=F_TARGET;
  712.            tmpcell->ce_flag &= ~F_REMOVE;
  713.         }
  714.         flag = TRUE;
  715.      }
  716.       }
  717.  
  718.       if( flag ) {
  719.      int sv_force = Force;
  720.  
  721.      Force = FALSE;
  722.      Remove_prq( tcp );
  723.      Force = sv_force;
  724.  
  725.      for(dp=tcp->ce_prq; dp != NIL(LINK); dp=dp->cl_next) {
  726.         register CELLPTR prq = dp->cl_prq;
  727.  
  728.         prq->ce_flag &= ~(F_MADE|F_VISITED|F_STAT);
  729.         prq->ce_flag |= F_REMOVE;
  730.         prq->ce_time  = (time_t)0L;
  731.      }
  732.       }
  733.    }
  734. }
  735.  
  736.  
  737. PUBLIC int
  738. Remove_file( name )
  739. char *name;
  740. {
  741.    struct stat buf;
  742.  
  743.    if( stat(name, &buf) != 0 )
  744.       return 1;
  745.    if( (buf.st_mode & S_IFMT) == S_IFDIR )
  746.       return 1;
  747.    return(unlink(name));
  748. }
  749.