home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / DMAKE38A.ZIP / SYSINTF.C < prev    next >
C/C++ Source or Header  |  1992-01-23  |  15KB  |  688 lines

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