home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / INFO / C / DMAKE37S.ZIP / DMAKE / SYSINTF.C < prev    next >
Encoding:
C/C++ Source or Header  |  1991-05-06  |  14.3 KB  |  661 lines

  1. /* RCS      -- $Header: /u2/dvadura/src/generic/dmake/src/RCS/sysintf.c,v 1.1 91/05/06 15:23:35 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) 1990 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  91/05/06  15:23:35  dvadura
  67.  * dmake Release Version 3.7
  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 _strdup the name and return make the
  81. ** pointer pointed at by sym point at it.  Not handled for now!
  82. */
  83. PUBLIC time_t
  84. Do_stat(name, lib, member)
  85. char *name;
  86. char *lib;
  87. char **member;
  88. {
  89.    struct stat buf;
  90.    time_t seek_arch();
  91.  
  92.    if( member != NIL(char *) )
  93.       Fatal("Library symbol names not supported");
  94.  
  95.    buf.st_mtime = (time_t)0L;
  96.    if( lib != NIL(char) )
  97.       return( seek_arch(basename(name), lib) );
  98.    else
  99.       return( (STAT(name,&buf)==-1 || (Augmake && (buf.st_mode & S_IFDIR)))
  100.           ? (time_t)0L
  101.           : (time_t) buf.st_mtime
  102.         );
  103. }
  104.  
  105.  
  106.  
  107. /* Touch existing file to force modify time to present.
  108.  */
  109. PUBLIC int
  110. Do_touch(name, lib, member)
  111. char *name;
  112. char *lib;
  113. char **member;
  114. {
  115.    if( member != NIL(char *) )
  116.       Fatal("Library symbol names not supported");
  117.  
  118.    if (lib != NIL(char))
  119.       return( touch_arch(basename(name), lib) );
  120.    else
  121.       return( utime(name, NIL(time_t)) );
  122. }
  123.  
  124.  
  125.  
  126. PUBLIC void
  127. Void_lib_cache( lib_name, member_name )/*
  128. =========================================
  129.    Void the library cache for lib lib_name, and member member_name. */
  130. char *lib_name;
  131. char *member_name;
  132. {
  133.    VOID_LCACHE( lib_name, member_name );
  134. }
  135.  
  136.  
  137.  
  138. /*
  139. ** return the current time
  140. */
  141. PUBLIC time_t
  142. Do_time()
  143. {
  144.    extern time_t time();
  145.    return (time((time_t*)0));
  146. }
  147.  
  148.  
  149.  
  150. /*
  151. ** Execute the string passed in as a command and return
  152. ** the return code. The command line arguments are
  153. ** assumed to be separated by spaces or tabs.  The first
  154. ** such argument is assumed to be the command.
  155. **
  156. ** If group is true then this is a group of commands to be fed to the
  157. ** the shell as a single unit.  In this case cmd is of the form
  158. ** "file" indicating the file that should be read by the shell
  159. ** in order to execute the command group.
  160. */
  161. PUBLIC int
  162. Do_cmnd(cmd, group, do_it, target, ignore, shell, last)
  163. char   *cmd;
  164. int     group;
  165. int    do_it;
  166. CELLPTR target;
  167. int     ignore;
  168. int     shell;
  169. int    last;
  170. {
  171.    int  i;
  172.  
  173.    if( !do_it ) {
  174.       if( last && !Doing_bang ) {
  175.          Update_time_stamp( target );
  176.       }
  177.       return(0);
  178.    }
  179.  
  180.    if( Max_proc == 1 ) Wait_for_completion = TRUE;
  181.  
  182.    if( (i = runargv(target, ignore, group, last, shell, cmd)) == -1 )
  183.       Quit();
  184.  
  185.    /* NOTE:  runargv must return either 0 or 1, 0 ==> command executed, and
  186.     * we waited for it to return, 1 ==> command started and is running
  187.     * concurrently with make process. */
  188.    return(i);
  189. }
  190.  
  191.  
  192. #define MINARGV 64
  193. /* Take a command and pack it into an argument vector to be executed. */
  194. PUBLIC char **
  195. Pack_argv( group, shell, cmd )
  196. int    group;
  197. int    shell;
  198. char  *cmd;
  199. {
  200.    static char **av = NIL(char *);
  201.    static int   avs = 0;
  202.    int i = 0;
  203.  
  204.    if( av == NIL(char *) ) {
  205.       TALLOC(av, MINARGV, char*);
  206.       avs = MINARGV;
  207.    }
  208.  
  209.    if( (Packed_shell = shell||group||(*_strpbrk(cmd, Shell_metas)!='\0')) ) {
  210.       char* sh = group ? GShell : Shell;
  211.  
  212.       if( sh != NIL(char) ) {
  213.          av[i++] = sh;
  214.          if( (av[i] = (group?GShell_flags:Shell_flags)) != NIL(char) ) i++;
  215.  
  216.      av[i++] = cmd;
  217.      av[i]   = NIL(char);
  218.       }
  219.       else
  220.      Fatal("%sSHELL macro not defined", group?"GROUP":"");
  221.    }
  222.    else {
  223.       do {
  224.          while( iswhite(*cmd) ) ++cmd;
  225.          if( *cmd ) av[i++] = cmd;
  226.  
  227.          while( *cmd != '\0' && !iswhite(*cmd) ) ++cmd;
  228.          if( *cmd ) *cmd++ = '\0';
  229.  
  230.      if( i == avs ) {
  231.         avs += MINARGV;
  232.         av = (char **) realloc( av, avs*sizeof(char *) );
  233.      }
  234.       } while( *cmd );
  235.  
  236.       av[i] = NIL(char);
  237.    }
  238.  
  239.    return(av);
  240. }
  241.  
  242.  
  243. /*
  244. ** Return the value of ename from the environment
  245. ** if ename is not defined in the environment then
  246. ** NIL(char) should be returned
  247. */
  248. PUBLIC char *
  249. Read_env_string(ename)
  250. char *ename;
  251. {
  252. #if !defined(_MSC_VER) || _MSC_VER < 600
  253.    extern char *getenv();
  254. #endif
  255.    return( getenv(ename) );
  256. }
  257.  
  258.  
  259.  
  260. /*
  261. ** Set the value of the environment string ename to value.
  262. **  Returns 0 if success, non-zero if failure
  263. */
  264. PUBLIC int
  265. Write_env_string(ename, value)
  266. char *ename;
  267. char *value;
  268. {
  269.    extern int putenv();
  270.    char*   p;
  271.    char*   envstr = _stradd(ename, value, FALSE);
  272.  
  273.    p = envstr+strlen(ename);    /* Don't change this code, _stradd does not */
  274.    *p++ = '=';            /* add the space if *value is 0, it does    */
  275.    if( !*value ) *p = '\0';    /* allocate enough memory for one though.   */
  276.  
  277.    return( putenv(envstr) );
  278. }
  279.  
  280.  
  281.  
  282. PUBLIC void
  283. ReadEnvironment()
  284. {
  285.    extern char **Rule_tab;
  286. #if !defined(_MSC_VER)
  287.    extern char **environ;
  288. #endif
  289.    char **rsave;
  290.  
  291.    rsave    = Rule_tab;
  292.    Rule_tab = environ;
  293.    Readenv  = TRUE;
  294.  
  295.    Parse( NIL(FILE) );
  296.  
  297.    Readenv  = FALSE;
  298.    Rule_tab = rsave;
  299. }
  300.  
  301.  
  302.  
  303. /*
  304. ** All we have to catch is SIG_INT
  305. */
  306. PUBLIC void
  307. Catch_signals(fn)
  308. void (*fn)();
  309. {
  310.    if( signal(SIGINT, SIG_IGN) != SIG_IGN )
  311.       signal( SIGINT, fn );
  312.    if( signal(SIGQUIT, SIG_IGN) != SIG_IGN )
  313.       signal( SIGQUIT, fn );
  314. }
  315.  
  316.  
  317.  
  318. /*
  319. ** Clear any previously set signals
  320. */
  321. PUBLIC void
  322. Clear_signals()
  323. {
  324.    if( signal(SIGINT, SIG_IGN) != SIG_IGN )
  325.       signal( SIGINT, SIG_DFL );
  326.    if( signal(SIGQUIT, SIG_IGN) != SIG_IGN )
  327.       signal( SIGQUIT, SIG_DFL );
  328. }
  329.  
  330.  
  331.  
  332. /*
  333. ** Set program name
  334. */
  335. PUBLIC void
  336. Prolog(argc, argv)
  337. int   argc;
  338. char* argv[];
  339. {
  340.    char buf[50];
  341.  
  342.    Pname = (argc == 0) ? DEF_MAKE_PNAME : argv[0];
  343.    sprintf( buf, "dmake-%d-root", GETPID );
  344.    Root = Def_cell( buf );
  345.    tzset();
  346. }
  347.  
  348.  
  349.  
  350. /*
  351. ** Do any clean up for exit.
  352. */
  353. PUBLIC void
  354. Epilog(ret_code)
  355. int ret_code;
  356. {
  357.    Write_state();
  358.    Unlink_temp_files(Root);
  359.    Hook_std_writes(NIL(char));        /* For MSDOS tee (-F option) */
  360.    exit( ret_code );
  361. }
  362.  
  363.  
  364.  
  365. /*
  366. ** Use the built-in functions of the operating system to get the current
  367. ** working directory.
  368. */
  369. PUBLIC char *
  370. Get_current_dir()
  371. {
  372.    static char buf[MAX_PATH_LEN+1];
  373.  
  374.    return( getcwd(buf, sizeof(buf)) );
  375. }
  376.  
  377.  
  378.  
  379. /*
  380. ** change working directory
  381. */
  382. PUBLIC int
  383. Set_dir(path)
  384. char*   path;
  385. {
  386.    return( chdir(path) );
  387. }
  388.  
  389.  
  390.  
  391. /*
  392. ** return switch char
  393. */
  394. PUBLIC char
  395. Get_switch_char()
  396. {
  397.    return( getswitchar() );
  398. }
  399.  
  400.  
  401.  
  402. /*
  403. ** Generate a temporary file name and open the file for writing.
  404. ** If a name cannot be generated or the file cannot be opened
  405. ** return -1, else return the fileno of the open file.
  406. ** and update the source file pointer to point at the new file name.
  407. ** Note that the new name should be freed when the file is removed.
  408. */
  409. PUBLIC FILE*
  410. Get_temp(path, suff, op)
  411. char **path;
  412. char *suff;
  413. int  op;
  414. {
  415.    extern char *tempnam();
  416.  
  417.    *path = _strjoin( tempnam(NIL(char), "mk"), suff, -1, TRUE );
  418.    Def_macro( "TMPFILE", *path, M_MULTI|M_EXPANDED );
  419.  
  420.    return( op?fopen(*path, "w"):NIL(FILE) );
  421. }
  422.  
  423.  
  424. /*
  425. ** Open a new temporary file and set it up for writing.
  426. */
  427. PUBLIC FILE *
  428. Start_temp( suffix, cp, fname )
  429. char     *suffix;
  430. CELLPTR   cp;
  431. char    **fname;
  432. {
  433.    FILE           *fp;
  434.    char        *tmpname;
  435.    char           *name;
  436.  
  437.    name = (cp != NIL(CELL))?cp->CE_NAME:"makefile text";
  438.  
  439.    if( (fp = Get_temp(&tmpname, suffix, TRUE)) == NIL(FILE) )
  440.       Open_temp_error( tmpname, name );
  441.  
  442.    Link_temp( cp, fp, tmpname );
  443.    *fname = tmpname;
  444.  
  445.    return( fp );
  446. }
  447.  
  448.  
  449. /*
  450. ** Issue an error on failing to open a temporary file
  451. */
  452. PUBLIC void
  453. Open_temp_error( tmpname, name )
  454. char *tmpname;
  455. char *name;
  456. {
  457.    Fatal("Cannot open temp file `%s' while processing `%s'", tmpname, name );
  458. }
  459.  
  460.  
  461. /*
  462. ** Link a temp file onto the list of files.
  463. */
  464. PUBLIC void
  465. Link_temp( cp, fp, fname )
  466. CELLPTR cp;
  467. FILE   *fp;
  468. char   *fname;
  469. {
  470.    FILELISTPTR new;
  471.  
  472.    if( cp == NIL(CELL) ) cp = Root;
  473.  
  474.    TALLOC( new, 1, FILELIST );
  475.  
  476.    new->fl_next = cp->ce_files;
  477.    new->fl_name = fname;
  478.    new->fl_file = fp;        /* indicates temp file is open */
  479.  
  480.    cp->ce_files = new;
  481. }
  482.  
  483.  
  484. /*
  485. ** Close a previously used temporary file.
  486. */
  487. PUBLIC void
  488. Close_temp(cp, file)
  489. CELLPTR cp;
  490. FILE    *file;
  491. {
  492.    FILELISTPTR fl;
  493.    if( cp == NIL(CELL) ) cp = Root;
  494.  
  495.    for( fl=cp->ce_files; fl && fl->fl_file != file; fl=fl->fl_next );
  496.    if( fl ) {
  497.       fl->fl_file = NIL(FILE);
  498.       fclose(file);
  499.    }
  500. }
  501.  
  502.  
  503. /*
  504. ** Clean-up, and close all temporary files associated with a target.
  505. */
  506. PUBLIC void
  507. Unlink_temp_files( cp )/*
  508. ==========================
  509.    Unlink the tempfiles if any exist.  Make sure you close the files first
  510.    though.  This ensures that under DOS there is no disk space lost. */
  511. CELLPTR cp;
  512. {
  513.    FILELISTPTR cur, next;
  514.  
  515.    if( cp == NIL(CELL) || cp->ce_files == NIL(FILELIST) ) return;
  516.  
  517.    for( cur=cp->ce_files; cur != NIL(FILELIST); cur=next ) {
  518.       next = cur->fl_next;
  519.  
  520.       if( cur->fl_file ) fclose( cur->fl_file );
  521.  
  522.       if( Verbose & V_LEAVE_TMP )
  523.          printf( "%s:  Left temp file [%s]\n", Pname, cur->fl_name );
  524.       else
  525.          (void) unlink( cur->fl_name );
  526.  
  527.       FREE(cur->fl_name);
  528.       FREE(cur);
  529.    }
  530.  
  531.    cp->ce_files = NIL(FILELIST);
  532. }
  533.  
  534.  
  535. PUBLIC void
  536. Handle_result(status, ignore, abort_flg, target)
  537. int    status;
  538. int    ignore;
  539. int    abort_flg;
  540. CELLPTR target;
  541. {
  542.    status = ((status&0xff)==0 ? status>>8
  543.         : (status & 0xff)==SIGTERM ? -1
  544.         : (status & 0x7f)+128);
  545.  
  546.    if( status )
  547.       if( !abort_flg ) {
  548.      fprintf( stderr, "%s:  Error code %d, while making '%s'",
  549.           Pname, status, target->ce_fname );
  550.  
  551.      if( ignore || Continue ) {
  552.         fputs( " (Ignored)\n", stderr );
  553.      }
  554.      else {
  555.         fputc( '\n', stderr );
  556.  
  557.         if( !(target->ce_attr & A_PRECIOUS) )
  558.            if( unlink( target->ce_fname ) == 0 )
  559.           fprintf(stderr,"%s:  '%s' removed.\n",Pname,target->ce_fname);
  560.  
  561.         Quit();
  562.      }
  563.       }
  564.       else if( !(target->ce_attr & A_PRECIOUS) )
  565.      unlink( target->ce_fname );
  566. }
  567.  
  568.  
  569. PUBLIC void
  570. Update_time_stamp( cp )
  571. CELLPTR cp;
  572. {
  573.    HASHPTR hp;
  574.    CELLPTR tcp;
  575.    int     tmpflg; 
  576.    int     phony = ((cp->ce_attr&A_PHONY) != 0);
  577.  
  578.    tcp = cp;
  579.    do {
  580.       if( tcp->ce_attr & A_LIBRARY )
  581.      Void_lib_cache( tcp->ce_fname, NIL(char) );
  582.       else if( !Touch && (tcp->ce_attr & A_LIBRARYM) )
  583.      Void_lib_cache( tcp->ce_lib, tcp->ce_fname );
  584.  
  585.       if( !phony )
  586.      Stat_target(tcp, -1);
  587.  
  588.       if( tcp->ce_time == (time_t) 0L )
  589.      tcp->ce_time = Do_time();
  590.  
  591.       if( Trace )
  592.      tcp->ce_flag |= F_STAT;        /* pretend we stated ok */
  593.  
  594.       if( Verbose & V_MAKE )
  595.      printf( "%s:  <<<< Set [%s] time stamp to %ld\n",
  596.          Pname, tcp->CE_NAME, tcp->ce_time );
  597.  
  598.       Unlink_temp_files( tcp );
  599.       tcp->ce_flag |= F_MADE;
  600.       tcp->ce_attr |= A_UPDATED;
  601.       tcp = tcp->ce_all;
  602.    }
  603.    while( tcp != NIL(CELL) && tcp != cp );
  604.  
  605.  
  606.    /* Scan the list of prerequisites and if we find one that is
  607.     * marked as being removable, (ie. an inferred intermediate node
  608.     * then remove it.  We remove a prerequisite by running the recipe
  609.     * associated with the special target .REMOVE, with $< set to
  610.     * the list of prerequisites to remove. */
  611.  
  612.    /* Make sure we don't try to remove prerequisites for the .REMOVE
  613.     * target. */
  614.    if( strcmp(cp->CE_NAME,".REMOVE") != 0 &&
  615.        (hp = Get_name( ".REMOVE", Defs, FALSE )) != NIL(HASH) ) {
  616.       register LINKPTR dp;
  617.       int flag = FALSE;
  618.       int rem;
  619.       t_attr attr;
  620.  
  621.       tcp = hp->CP_OWNR;
  622.  
  623.       tcp->ce_flag |= F_TARGET;
  624.       Clear_prerequisites( tcp );
  625.  
  626.       for( dp = cp->ce_prq; dp != NIL(LINK); dp = dp->cl_next ) {
  627.      register CELLPTR prq = dp->cl_prq;
  628.  
  629.      attr = Glob_attr | prq->ce_attr;
  630.      rem  = (prq->ce_flag & F_REMOVE) &&
  631.         (prq->ce_flag & F_MADE  ) &&
  632.         !(prq->ce_attr & A_PHONY) &&
  633.         !(attr & A_PRECIOUS) &&
  634.         !Force;
  635.  
  636.      if( rem ) {
  637.         CELLPTR tmp = prq;
  638.         do {
  639.            (Add_prerequisite(tcp,prq,FALSE,FALSE))->cl_flag |= F_TARGET;
  640.            prq->ce_flag &= ~F_REMOVE;
  641.            prq = prq->ce_all;
  642.         }
  643.         while( prq != NIL(CELL) && prq != tmp );
  644.         flag = TRUE;
  645.      }
  646.       }
  647.  
  648.       if( flag ) {
  649.      Remove_prq( tcp );
  650.  
  651.      for( dp=tcp->ce_prq; dp != NIL(LINK); dp=dp->cl_next ) {
  652.         register CELLPTR prq = dp->cl_prq;
  653.  
  654.         prq->ce_flag &= ~(F_MADE|F_VISITED|F_STAT);
  655.         prq->ce_flag |= F_REMOVE;
  656.         prq->ce_time  = (time_t)0L;
  657.      }
  658.       }
  659.    }
  660. }
  661.