LCOV - code coverage report
Current view: top level - libreoffice/dmake - sysintf.c (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 188 310 60.6 %
Date: 2012-12-17 Functions: 23 28 82.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* RCS  $Id: sysintf.c,v 1.13 2008-03-05 18:30:58 kz Exp $
       2             : --
       3             : -- SYNOPSIS
       4             : --      System independent interface
       5             : --
       6             : -- DESCRIPTION
       7             : --  These are the routines constituting the system interface.
       8             : --  The system is taken to be essentially POSIX conformant.
       9             : --  The original code was extensively revised by T J Thompson at MKS,
      10             : --  and the library cacheing was added by Eric Gisin at MKS.  I then
      11             : --  revised the code yet again, to improve the lib cacheing, and to
      12             : --  make it more portable.
      13             : --
      14             : --  The following is a list of routines that are required by this file
      15             : --  in order to work.  These routines are provided as functions by the
      16             : --  standard C lib of the target system or as #defines in system/sysintf.h
      17             : --  or via appropriate C code in the system/ directory for the given
      18             : --  system.
      19             : --
      20             : --  The first group must be provided by a file in the system/ directory
      21             : --  the second group is ideally provided by the C lib.  However, there
      22             : --  are instances where the C lib implementation of the specified routine
      23             : --  does not exist, or is incorrect.  In these instances the routine
      24             : --  must be provided by the the user in the system/ directory of dmake.
      25             : --  (For example, the bsd/ dir contains code for putenv(), and tempnam())
      26             : --
      27             : --  DMAKE SPECIFIC:
      28             : --      seek_arch()
      29             : --      touch_arch()
      30             : --      void_lcache()
      31             : --      runargv()
      32             : --      DMSTAT()
      33             : --      Remove_prq()
      34             : --
      35             : --  C-LIB SPECIFIC:  (should be present in your C-lib)
      36             : --      utime()
      37             : --      time()
      38             : --      getenv()
      39             : --      putenv()
      40             : --      getcwd()
      41             : --      signal()
      42             : --      chdir()
      43             : --      tempnam()
      44             : --
      45             : -- AUTHOR
      46             : --      Dennis Vadura, dvadura@dmake.wticorp.com
      47             : --
      48             : -- WWW
      49             : --      http://dmake.wticorp.com/
      50             : --
      51             : -- COPYRIGHT
      52             : --      Copyright (c) 1996,1997 by WTI Corp.  All rights reserved.
      53             : --
      54             : --      This program is NOT free software; you can redistribute it and/or
      55             : --      modify it under the terms of the Software License Agreement Provided
      56             : --      in the file <distribution-root>/readme/license.txt.
      57             : --
      58             : -- LOG
      59             : --      Use cvs log to obtain detailed change logs.
      60             : */
      61             : 
      62             : #include "extern.h"
      63             : 
      64             : /* The following definition controls the use of GetModuleFileName() */
      65             : #if defined(_MSC_VER) || defined(__MINGW32__)
      66             : #   define HAVE_GETMODULEFILENAMEFUNC 1
      67             : 
      68             : /* this is needed for the _ftime call below. Only needed here. */
      69             : #   include <sys/timeb.h>
      70             : #endif
      71             : 
      72             : /* for cygwin_conv_to_posix_path() in Prolog() and for cygdospath()*/
      73             : #if __CYGWIN__
      74             : #   include <sys/cygwin.h>
      75             : #endif
      76             : 
      77             : #include "sysintf.h"
      78             : #if HAVE_ERRNO_H
      79             : #  include <errno.h>
      80             : #else
      81             :    extern  int  errno;
      82             : #endif
      83             : 
      84             : /*
      85             : ** Tries to stat the file name.  Returns 0 if the file
      86             : ** does not exist.  Note that if lib is not null it tries to stat
      87             : ** the name found inside lib.
      88             : **
      89             : ** If member is NOT nil then look for the library object which defines the
      90             : ** symbol given by name.  If found DmStrDup the name and return make the
      91             : ** pointer pointed at by sym point at it.  Not handled for now!
      92             : */
      93             : static time_t
      94           0 : really_dostat(name, buf)
      95             : char *name;
      96             : struct stat *buf;
      97             : {
      98           0 :    return( (   DMSTAT(name,buf)==-1
      99           0 :             || (STOBOOL(Augmake) && (buf->st_mode & S_IFDIR)))
     100             :        ? (time_t)0L
     101           0 :        : (time_t) buf->st_mtime
     102             :      );
     103             : }
     104             : 
     105             : 
     106             : PUBLIC time_t
     107       37761 : Do_stat(name, lib, member, force)
     108             : char *name;
     109             : char *lib;
     110             : char **member;
     111             : int  force;
     112             : {
     113             :    struct stat buf;
     114             :    time_t seek_arch();
     115             : 
     116       37761 :    if( member != NIL(char *) )
     117           0 :       Fatal("Library symbol names not supported");
     118             : 
     119       37761 :    buf.st_mtime = (time_t)0L;
     120       37761 :    if( lib != NIL(char) )
     121           0 :       return( seek_arch(Basename(name), lib) );
     122       37761 :    else if( strlen(Basename(name)) > NameMax ) {
     123           0 :       Warning( "Filename [%s] longer than value of NAMEMAX [%d].\n\
     124             :       Assume unix time 0.\n", Basename(name), NameMax );
     125           0 :       return((time_t)0L);
     126             :    }
     127       37761 :    else if( STOBOOL(UseDirCache) )
     128       37761 :       return(CacheStat(name,force));
     129             :    else
     130           0 :       return(really_dostat(name,&buf));
     131             : }
     132             : 
     133             : 
     134             : /* Touch existing file to force modify time to present.
     135             :  */
     136             : PUBLIC int
     137           0 : Do_touch(name, lib, member)
     138             : char *name;
     139             : char *lib;
     140             : char **member;
     141             : {
     142           0 :    if( member != NIL(char *) )
     143           0 :       Fatal("Library symbol names not supported");
     144             : 
     145           0 :    if (lib != NIL(char))
     146           0 :       return( touch_arch(Basename(name), lib) );
     147           0 :    else if( strlen(Basename(name)) > NameMax ) {
     148           0 :       Warning( "Filename [%s] longer than value of NAMEMAX [%d].\n\
     149             :       File timestamp not updated to present time.\n", Basename(name), NameMax );
     150           0 :       return(-1);
     151             :    }
     152             :    else
     153             : #ifdef HAVE_UTIME_NULL
     154           0 :       return( utime(name, NULL) );
     155             : #else
     156             : #   error "Utime NULL not supported"
     157             : #endif
     158             : }
     159             : 
     160             : 
     161             : 
     162             : PUBLIC void
     163           0 : Void_lib_cache( lib_name, member_name )/*
     164             : =========================================
     165             :    Void the library cache for lib lib_name, and member member_name. */
     166             : char *lib_name;
     167             : char *member_name;
     168             : {
     169           0 :    VOID_LCACHE( lib_name, member_name );
     170           0 : }
     171             : 
     172             : 
     173             : 
     174             : /*
     175             : ** return the current time
     176             : */
     177             : PUBLIC time_t
     178        1672 : Do_time()
     179             : {
     180        1672 :    return (time( NIL(time_t) ));
     181             : }
     182             : 
     183             : 
     184             : 
     185             : /*
     186             : ** Print profiling information
     187             : */
     188             : PUBLIC void
     189           0 : Do_profile_output( text, mtype, target )
     190             : char *text;
     191             : uint16 mtype;
     192             : CELLPTR target;
     193             : {
     194             : 
     195             :    time_t time_sec;
     196             :    uint32 time_msec;
     197             :    char *tstrg;
     198             :    char *tname;
     199             : 
     200             : #ifdef HAVE_GETTIMEOFDAY
     201             :    struct timeval timebuffer;
     202           0 :    gettimeofday(&timebuffer, NULL);
     203           0 :    time_sec = timebuffer.tv_sec;
     204           0 :    time_msec = timebuffer.tv_usec/1000;
     205             : #else
     206             : #if defined(_MSC_VER) || defined(__MINGW32__)
     207             :    struct _timeb timebuffer;
     208             :    _ftime( &timebuffer );
     209             :    time_sec = timebuffer.time;
     210             :    time_msec = timebuffer.millitm;
     211             : #   else
     212             :    time_sec = time( NIL(time_t) );
     213             :    time_msec = 0;
     214             : #   endif
     215             : #endif
     216             : 
     217           0 :    tname = target->CE_NAME;
     218           0 :    if( mtype & M_TARGET ) {
     219           0 :       tstrg = "target";
     220             :       /* Don't print special targets .TARGETS and .ROOT */
     221           0 :       if( tname[0] == '.' && (strcmp(".TARGETS", tname) == 0 || \
     222           0 :                   strcmp(".ROOT", tname) == 0) ) {
     223             :      return;
     224             :       }
     225             :    } else {
     226           0 :       tstrg = "recipe";
     227             :    }
     228             : 
     229             :    /* Don't print shell escape targets if not especially requested. */
     230           0 :    if( (target->ce_attr & A_SHELLESC) && !(Measure & M_SHELLESC) ) {
     231             :       return;
     232             :    }
     233             : 
     234             :    /* Print absolute path if requested. */
     235           0 :    if( !(target->ce_attr & A_SHELLESC) && (Measure & M_ABSPATH) ) {
     236           0 :       printf("%s %s %lu.%.3u %s%s%s\n",text, tstrg, time_sec, time_msec, Pwd, DirSepStr, tname);
     237             :    } else {
     238           0 :       printf("%s %s %lu.%.3u %s\n",text, tstrg, time_sec, time_msec, tname);
     239             :    }
     240             : }
     241             : 
     242             : 
     243             : 
     244             : PUBLIC int
     245        2184 : Do_cmnd(cmd, group, do_it, target, cmnd_attr, last)/*
     246             : =====================================================
     247             :   Execute the string passed in as a command and return
     248             :   the return code. The command line arguments are
     249             :   assumed to be separated by spaces or tabs.  The first
     250             :   such argument is assumed to be the command.
     251             : 
     252             :   If group is true then this is a group of commands to be fed to the
     253             :   the shell as a single unit.  In this case cmd is of the form
     254             :   "file" indicating the file that should be read by the shell
     255             :   in order to execute the command group.
     256             : 
     257             :   If Wait_for_completion is TRUE add the A_WFC attribute to the new
     258             :   process.
     259             : */
     260             : char  **cmd; /* Simulate a reference to *cmd. */
     261             : int     group;  /* if set cmd contains the filename of a (group-)shell
     262             :          * script. */
     263             : int     do_it;  /* Only execute cmd if not set to null. */
     264             : CELLPTR target;
     265             : t_attr  cmnd_attr; /* Attributes for current cmnd. */
     266             : int     last;   /* Last recipe line in target. */
     267             : {
     268             :    int  i;
     269             : 
     270             :    DB_ENTER( "Do_cmnd" );
     271             : 
     272        2184 :    if( !do_it ) {
     273           0 :       if( last && !Doing_bang ) {
     274             :      /* Don't execute, just update the target when using '-t'
     275             :       * switch. */
     276           0 :          Update_time_stamp( target );
     277             :       }
     278           0 :       DB_RETURN( 0 );
     279             :    }
     280             : 
     281             :    /* Stop making the rest of the recipies for this target if an error occurred
     282             :     * but the Continue (-k) flag is set to build as much as possible. */
     283        2184 :    if ( target->ce_attr & A_ERROR ) {
     284           0 :       if ( last ) {
     285           0 :      Update_time_stamp( target );
     286             :       }
     287           0 :       DB_RETURN( 0 );
     288             :    }
     289             : 
     290        2184 :    if( Max_proc == 1 ) Wait_for_completion = TRUE;
     291             : 
     292             :    /* Tell runargv() to wait if needed. */
     293        2184 :    if( Wait_for_completion ) cmnd_attr |= A_WFC;
     294             : 
     295             :    /* remove leading whitespace - This should never trigger! */
     296        2184 :    if( iswhite(**cmd) ) {
     297             :       char *p;
     298           0 :       if( (p = DmStrSpn(*cmd," \t") ) != *cmd )
     299           0 :      strcpy(*cmd,p);
     300             :    }
     301             : 
     302             :    /* set shell if shell metas are found */
     303        2184 :    if( (cmnd_attr & A_SHELL) || group || (*DmStrPbrk(*cmd, Shell_metas)!='\0') )
     304         402 :       cmnd_attr |= A_SHELL; /* If group is TRUE this doesn't hurt. */
     305             : 
     306             :    /* runargv() returns either 0 or 1, 0 ==> command executed, and
     307             :     * we waited for it to return, 1 ==> command started and is still
     308             :     * running. */
     309        2184 :    i = runargv(target, group, last, cmnd_attr, cmd);
     310             : 
     311        2184 :    DB_RETURN( i );
     312             : }
     313             : 
     314             : 
     315             : #define MINARGV 64
     316             : 
     317             : PUBLIC char **
     318         412 : Pack_argv( group, shell, cmd )/*
     319             : ================================
     320             :   Take a command and pack it into an argument vector to be executed.
     321             :   If group is true cmd holds the group script file.
     322             : */
     323             : int    group;
     324             : int    shell;
     325             : char **cmd; /* Simulate a reference to *cmd. */
     326             : {
     327             :    static char **av = NIL(char *);
     328             :    static int   avs = 0;
     329         412 :    int i = 0;
     330             :    char *s; /* Temporary string pointer. */
     331             : 
     332         412 :    if( av == NIL(char *) ) {
     333         184 :       TALLOC(av, MINARGV, char*);
     334         184 :       avs = MINARGV;
     335             :    }
     336         412 :    av[0] = NIL(char);
     337             : 
     338         412 :    if (**cmd) {
     339         814 :       if( shell||group ) {
     340         402 :      char* sh = group ? GShell : Shell;
     341             : 
     342         402 :      if( sh != NIL(char) ) {
     343         402 :         av[i++] = sh;
     344         402 :         if( (av[i] = (group?GShell_flags:Shell_flags)) != NIL(char) ) i++;
     345             : 
     346         402 :         if( shell && Shell_quote && *Shell_quote ) {
     347             :            /* Enclose the shell command with SHELLCMDQUOTE. */
     348           0 :            s = DmStrJoin(Shell_quote, *cmd, -1, FALSE);
     349           0 :            FREE(*cmd);
     350           0 :            *cmd = DmStrJoin(s, Shell_quote, -1, TRUE);
     351             :         }
     352         402 :         av[i++] = *cmd;
     353             : 
     354             : #if defined(USE_CREATEPROCESS)
     355             :         /* CreateProcess() needs one long command line. */
     356             :         av[0] = DmStrAdd(av[0], av[1], FALSE);
     357             :         av[1] = NIL(char);
     358             :         /* i == 3 means Shell_flags are given. */
     359             :         if( i == 3 ) {
     360             :            s = av[0];
     361             :            av[0] = DmStrAdd(s, av[2], FALSE);
     362             :            FREE(s);
     363             :            av[2] = NIL(char);
     364             :         }
     365             :         /* The final free of cmd will free the concated command line. */
     366             :         FREE(*cmd);
     367             :         *cmd = av[0];
     368             : #endif
     369         402 :         av[i]   = NIL(char);
     370             :      }
     371             :      else
     372           0 :         Fatal("%sSHELL macro not defined", group?"GROUP":"");
     373             :       }
     374             :       else {
     375          10 :      char *tcmd = *cmd;
     376             : 
     377             : #if defined(USE_CREATEPROCESS)
     378             :      /* CreateProcess() needs one long command line, fill *cmd
     379             :       * into av[0]. */
     380             :      while( iswhite(*tcmd) ) ++tcmd;
     381             :      if( *tcmd ) av[i++] = tcmd;
     382             : #else
     383             :      /* All other exec/spawn functions need the parameters separated
     384             :       * in the argument vector. */
     385             :      do {
     386             :         /* Fill *cmd into av[]. Whitespace is converted into '\0' to
     387             :          * terminate each av[] member. */
     388          32 :         while( iswhite(*tcmd) ) ++tcmd;
     389          32 :         if( *tcmd ) av[i++] = tcmd;
     390             : 
     391          32 :         while( *tcmd != '\0' && !iswhite(*tcmd) ) ++tcmd;
     392          32 :         if( *tcmd ) *tcmd++ = '\0';
     393             : 
     394             :         /* dynamically increase av size. */
     395          32 :         if( i == avs ) {
     396           0 :            avs += MINARGV;
     397           0 :            av = (char **) realloc( av, avs*sizeof(char *) );
     398             :         }
     399          32 :      } while( *tcmd );
     400             : #endif
     401             : 
     402          10 :      av[i] = NIL(char);
     403             :       }
     404             :    }
     405             : 
     406         412 :    return(av);
     407             : }
     408             : 
     409             : 
     410             : /*
     411             : ** Return the value of ename from the environment
     412             : ** if ename is not defined in the environment then
     413             : ** NIL(char) should be returned
     414             : */
     415             : PUBLIC char *
     416        1298 : Read_env_string(ename)
     417             : char *ename;
     418             : {
     419        1298 :    return( getenv(ename) );
     420             : }
     421             : 
     422             : 
     423             : /*
     424             : ** Set the value of the environment string ename to value.
     425             : **  Returns 0 if success, non-zero if failure
     426             : */
     427             : PUBLIC int
     428        2600 : Write_env_string(ename, value)
     429             : char *ename;
     430             : char *value;
     431             : {
     432             : #if defined(HAVE_SETENV)
     433             : 
     434        2600 :   return( setenv(ename, value, 1) );
     435             : 
     436             : #else  /* !HAVE_SETENV */
     437             : 
     438             :   char*   p;
     439             :   char*   envstr = DmStrAdd(ename, value, FALSE);
     440             : 
     441             :   p = envstr+strlen(ename); /* Don't change this code, DmStrAdd does not */
     442             :   *p++ = '=';           /* add the space if *value is 0, it does    */
     443             :   if( !*value ) *p = '\0';  /* allocate enough memory for one though.   */
     444             : 
     445             :   return( putenv(envstr) ); /* Possibly leaking 'envstr' */
     446             : 
     447             : #endif /* !HAVE_SETENV */
     448             : }
     449             : 
     450             : 
     451             : PUBLIC void
     452         184 : ReadEnvironment()
     453             : {
     454             :    extern char **Rule_tab;
     455             : #if !defined(_MSC_VER)
     456             : #if defined(__BORLANDC__) && __BORLANDC__ >= 0x500
     457             :    extern char ** _RTLENTRY _EXPDATA environ;
     458             : #else
     459             :    extern char **environ;
     460             : #endif
     461             : #endif
     462             :    char **rsave;
     463             : 
     464             : #if !defined(__ZTC__) && !defined(_MPW)
     465             : # define make_env()
     466             : # define free_env()
     467             : #else
     468             :    void make_env();
     469             :    void free_env();
     470             : #endif
     471             : 
     472             :    make_env();
     473             : 
     474         184 :    rsave    = Rule_tab;
     475         184 :    Rule_tab = environ;
     476         184 :    Readenv  = TRUE;
     477             : 
     478         184 :    Parse( NIL(FILE) );
     479             : 
     480         184 :    Readenv  = FALSE;
     481         184 :    Rule_tab = rsave;
     482             : 
     483             :    free_env();
     484         184 : }
     485             : 
     486             : 
     487             : 
     488             : /*
     489             : ** All we have to catch is SIGINT
     490             : */
     491             : PUBLIC void
     492         188 : Catch_signals(fn)
     493             : void (*fn)(int);
     494             : {
     495             :    /* FIXME: Check this and add error handling. */
     496         188 :    if( (void (*)(int)) signal(SIGINT, SIG_IGN) != (void (*)(int))SIG_IGN )
     497         188 :       signal( SIGINT, fn );
     498         188 :    if( (void (*)(int)) signal(SIGQUIT, SIG_IGN) != (void (*)(int))SIG_IGN )
     499         188 :       signal( SIGQUIT, fn );
     500         188 : }
     501             : 
     502             : 
     503             : 
     504             : /*
     505             : ** Clear any previously set signals
     506             : */
     507             : PUBLIC void
     508         184 : Clear_signals()
     509             : {
     510         184 :    if( (void (*)())signal(SIGINT, SIG_IGN) != (void (*)())SIG_IGN )
     511         184 :       signal( SIGINT, SIG_DFL );
     512         184 :    if( (void (*)())signal(SIGQUIT, SIG_IGN) != (void (*)())SIG_IGN )
     513         184 :       signal( SIGQUIT, SIG_DFL );
     514         184 : }
     515             : 
     516             : 
     517             : 
     518             : /*
     519             : ** Set program name
     520             : */
     521             : PUBLIC void
     522         188 : Prolog(argc, argv)
     523             : int   argc;
     524             : char* argv[];
     525             : {
     526         188 :    Pname = (argc == 0) ? DEF_MAKE_PNAME : argv[0];
     527             : 
     528             :    /* Only some native Windows compilers provide this functionality. */
     529             : #ifdef HAVE_GETMODULEFILENAMEFUNC
     530             :    if( (AbsPname = MALLOC( PATH_MAX, char)) == NIL(char) ) No_ram();
     531             :    GetModuleFileName(NULL, AbsPname, PATH_MAX*sizeof(char));
     532             : #else
     533         188 :    AbsPname = "";
     534             : #endif
     535             : 
     536             : #if __CYGWIN__
     537             :    /* Get the drive letter prefix used by cygwin. */
     538             :    if ( (CygDrvPre = MALLOC( PATH_MAX, char)) == NIL(char) )
     539             :       No_ram();
     540             :    else {
     541             :       int err = cygwin_conv_to_posix_path("c:", CygDrvPre);
     542             :       if (err)
     543             :      Fatal( "error converting \"%s\" - %s\n",
     544             :         CygDrvPre, strerror (errno));
     545             :       if( (CygDrvPreLen = strlen(CygDrvPre)) == 2 ) {
     546             :      /* No prefix */
     547             :      *CygDrvPre = '\0';
     548             :      CygDrvPreLen = 0;
     549             :       } else {
     550             :      /* Cut away the directory letter. */
     551             :      CygDrvPre[CygDrvPreLen-2] = '\0';
     552             :      /* Cut away the leading '/'. We don't free the pointer, i.e. choose
     553             :       * the easy way. */
     554             :      CygDrvPre++;
     555             :      CygDrvPreLen -= 3;
     556             :       }
     557             :    }
     558             : #endif
     559             : 
     560             :    /* DirSepStr is used from Clean_path() in Def_cell(). Set it preliminary
     561             :     * here, it will be redefined later in Create_macro_vars() in imacs.c. */
     562         188 :    DirSepStr = "/";
     563             : 
     564         188 :    Root = Def_cell( ".ROOT" );
     565         188 :    Targets = Def_cell( ".TARGETS" );
     566         188 :    Add_prerequisite(Root, Targets, FALSE, FALSE);
     567             : 
     568         188 :    Targets->ce_flag = Root->ce_flag = F_RULES|F_TARGET|F_STAT;
     569         188 :    Targets->ce_attr = Root->ce_attr = A_NOSTATE|A_PHONY;
     570             : 
     571         188 :    Root->ce_flag |= F_MAGIC;
     572         188 :    Root->ce_attr |= A_SEQ;
     573             : 
     574         188 :    tzset();
     575         188 : }
     576             : 
     577             : 
     578             : 
     579             : /*
     580             : ** Do any clean up for exit.
     581             : */
     582             : PUBLIC void
     583         188 : Epilog(ret_code)
     584             : int ret_code;
     585             : {
     586         188 :    Write_state();
     587         188 :    Unlink_temp_files(Root);
     588             :    Hook_std_writes(NIL(char));      /* For MSDOS tee (-F option) */
     589         188 :    exit( ret_code );
     590             : }
     591             : 
     592             : 
     593             : 
     594             : /*
     595             : ** Use the built-in functions of the operating system to get the current
     596             : ** working directory.
     597             : */
     598             : PUBLIC char *
     599        4556 : Get_current_dir()
     600             : {
     601             :    static char buf[PATH_MAX+2];
     602             : 
     603        4556 :    if( !getcwd(buf, sizeof(buf)) )
     604           0 :       Fatal("Internal Error: Error when calling getcwd()!");
     605             : 
     606             : #ifdef __EMX__
     607             :    char *slash;
     608             :    slash = buf;
     609             :    while( (slash=strchr(slash,'/')) )
     610             :       *slash = '\\';
     611             : #endif
     612             : 
     613        4556 :    return buf;
     614             : }
     615             : 
     616             : 
     617             : 
     618             : /*
     619             : ** change working directory
     620             : */
     621             : PUBLIC int
     622        7228 : Set_dir(path)
     623             : char*   path;
     624             : {
     625        7228 :    return( chdir(path) );
     626             : }
     627             : 
     628             : 
     629             : 
     630             : /*
     631             : ** return switch char
     632             : */
     633             : PUBLIC char
     634         188 : Get_switch_char()
     635             : {
     636         188 :    return( getswitchar() );
     637             : }
     638             : 
     639             : 
     640         746 : int Create_temp(tmpdir, path)/*
     641             : ===============================
     642             :   Create a temporary file and open with exclusive access
     643             :   Path is updated with the filename and the file descriptor
     644             :   is returned.  Note that the new name should be freed when
     645             :   the file is removed.
     646             : */
     647             : char *tmpdir;
     648             : char **path;
     649             : {
     650             :    int fd; /* file descriptor */
     651             : 
     652             : #if defined(HAVE_MKSTEMP)
     653             :    mode_t       mask;
     654             : 
     655         746 :    *path = DmStrJoin( tmpdir, DirSepStr, -1, FALSE);
     656         746 :    *path = DmStrJoin( *path, "mkXXXXXX", -1, TRUE );
     657             : 
     658         746 :    mask = umask(0066);
     659         746 :    fd = mkstemp( *path );
     660         746 :    umask(mask);
     661             : 
     662             : #elif defined(HAVE_TEMPNAM)
     663             :    char pidbuff[32];
     664             : #if _MSC_VER >= 1300
     665             :    /* Create more unique filename for .NET2003 and newer. */
     666             :    long npid;
     667             :    long nticks;
     668             : 
     669             :    npid = _getpid();
     670             :    nticks = GetTickCount() & 0xfff;
     671             :    sprintf(pidbuff,"mk%d_%d_",npid,nticks);
     672             : #else
     673             :    sprintf(pidbuff,"mk");
     674             : #endif
     675             :    *path = tempnam(tmpdir, pidbuff);
     676             :    fd = open(*path, O_CREAT | O_EXCL | O_TRUNC | O_RDWR, 0600);
     677             : #else
     678             : 
     679             : #error mkstemp() or tempnam() is needed
     680             : 
     681             : #endif
     682             : 
     683         746 :    return fd;
     684             : }
     685             : 
     686             : 
     687             : PUBLIC FILE*
     688         746 : Get_temp(path, mode)/*
     689             : ======================
     690             :   Generate a temporary file name and open the file for writing.
     691             :   If a name cannot be generated or the file cannot be opened
     692             :   return -1, else return the fileno of the open file.
     693             :   and update the source file pointer to point at the new file name.
     694             :   Note that the new name should be freed when the file is removed.
     695             :   The file stream is opened with the given mode.
     696             : */
     697             : char **path;
     698             : char *mode;
     699             : {
     700             :    int          fd;
     701             :    FILE         *fp;
     702             :    char         *tmpdir;
     703         746 :    int          tries = 20;
     704             : 
     705         746 :    tmpdir = Read_env_string( "TMPDIR" );
     706         746 :    if( tmpdir == NIL(char) )
     707           0 :       tmpdir = "/tmp";
     708             : 
     709        1492 :    while( --tries )
     710             :    {
     711             :       /* This sets path to the name of the created temp file. */
     712         746 :       if( (fd = Create_temp(tmpdir, path)) != -1)
     713         746 :          break;
     714             : 
     715           0 :       free(*path); /* free var if creating temp failed. */
     716             :    }
     717             : 
     718         746 :    if( fd != -1)
     719             :    {
     720         746 :       Def_macro( "TMPFILE", DO_WINPATH(*path), M_MULTI|M_EXPANDED );
     721             :       /* associate stream with file descriptor */
     722         746 :       fp = fdopen(fd, mode);
     723             :    }
     724             :    else
     725           0 :       fp = NIL(FILE);
     726             : 
     727         746 :    return fp;
     728             : }
     729             : 
     730             : 
     731             : PUBLIC FILE *
     732         362 : Start_temp( suffix, cp, fname )/*
     733             : =================================
     734             :   Open a new temporary file and set it up for writing. The file is linked
     735             :   to cp and will be removed if once the target is finished.
     736             :   If a suffix for the temporary files is requested two temporary files are
     737             :   created. This is done because the routines that create a save temporary
     738             :   file do not provide a definable suffix. The first (provided by Get_temp())
     739             :   is save and unique and the second file is generated by adding the desired
     740             :   suffix the the first temporary file. The extra file is also linked to cp
     741             :   so that it gets removed later.
     742             :   The function returns the FILE pointer to the temporary file (with suffix
     743             :   if specified) and leaves the file name in *fname.
     744             : */
     745             : char     *suffix;
     746             : CELLPTR   cp;
     747             : char    **fname;
     748             : {
     749             :    FILE        *fp, *fp2;
     750             :    char        *tmpname;
     751             :    char        *name;
     752             :    char        *fname_suff;
     753             : 
     754         362 :    name = (cp != NIL(CELL))?cp->CE_NAME:"makefile text";
     755             : 
     756             :    /* This sets tmpname to the name that was used. */
     757         362 :    if( (fp = Get_temp(&tmpname, "w")) == NIL(FILE) )
     758           0 :       Open_temp_error( tmpname, name );
     759             : 
     760             :    /* Don't free tmpname, it's stored in a FILELIST member in Link_temp(). */
     761         362 :    Link_temp( cp, fp, tmpname );
     762         362 :    *fname = tmpname;
     763             : 
     764             :    /* As Get_temp() doesn't provide a definable suffix (anymore) we create an
     765             :     * additional temporary file with that suffix. */
     766         362 :    if ( suffix && *suffix ) {
     767             : 
     768             : #ifdef HAVE_MKSTEMP
     769             :       /* Only use umask if we are also using mkstemp - this basically
     770             :        * avoids using the incompatible implementation from MSVC. */
     771             :       mode_t mask;
     772             : 
     773           0 :       mask = umask(0066);
     774             : #endif
     775             : 
     776           0 :       fname_suff = DmStrJoin( tmpname, suffix, -1, FALSE );
     777             : 
     778             :       /* Overwrite macro, Get_temp didn't know of the suffix. */
     779           0 :       Def_macro( "TMPFILE", DO_WINPATH(fname_suff), M_MULTI|M_EXPANDED );
     780             : 
     781           0 :       if( (fp2 = fopen(fname_suff, "w" )) == NIL(FILE) )
     782           0 :          Open_temp_error( fname_suff, name );
     783             : #ifdef HAVE_MKSTEMP
     784           0 :       umask(mask);
     785             : #endif
     786             : 
     787             :       /* Don't free fname_suff. */
     788           0 :       Link_temp( cp, fp2, fname_suff );
     789           0 :       fp = fp2;
     790           0 :       *fname = fname_suff;
     791             :    }
     792             : 
     793         362 :    return( fp );
     794             : }
     795             : 
     796             : 
     797             : /*
     798             : ** Issue an error on failing to open a temporary file
     799             : */
     800             : PUBLIC void
     801           0 : Open_temp_error( tmpname, name )
     802             : char *tmpname;
     803             : char *name;
     804             : {
     805           0 :    Fatal("Cannot open temp file `%s' while processing `%s'", tmpname, name );
     806           0 : }
     807             : 
     808             : 
     809             : /*
     810             : ** Link a temp file onto the list of files.
     811             : */
     812             : PUBLIC void
     813         362 : Link_temp( cp, fp, fname )
     814             : CELLPTR cp;
     815             : FILE   *fp;
     816             : char   *fname;
     817             : {
     818             :    FILELISTPTR new;
     819             : 
     820         362 :    if( cp == NIL(CELL) ) cp = Root;
     821             : 
     822         362 :    TALLOC( new, 1, FILELIST );
     823             : 
     824         362 :    new->fl_next = cp->ce_files;
     825         362 :    new->fl_name = fname;
     826         362 :    new->fl_file = fp;       /* indicates temp file is open */
     827             : 
     828         362 :    cp->ce_files = new;
     829         362 : }
     830             : 
     831             : 
     832             : /*
     833             : ** Close a previously used temporary file.
     834             : */
     835             : PUBLIC void
     836         362 : Close_temp(cp, file)
     837             : CELLPTR cp;
     838             : FILE    *file;
     839             : {
     840             :    FILELISTPTR fl;
     841         362 :    if( cp == NIL(CELL) ) cp = Root;
     842             : 
     843         362 :    for( fl=cp->ce_files; fl && fl->fl_file != file; fl=fl->fl_next );
     844         362 :    if( fl ) {
     845         362 :       fl->fl_file = NIL(FILE);
     846         362 :       fclose(file);
     847             :    }
     848         362 : }
     849             : 
     850             : 
     851             : /*
     852             : ** Clean-up, and close all temporary files associated with a target.
     853             : */
     854             : PUBLIC void
     855        2430 : Unlink_temp_files( cp )/*
     856             : ==========================
     857             :    Unlink the tempfiles if any exist.  Make sure you close the files first
     858             :    though.  This ensures that under DOS there is no disk space lost. */
     859             : CELLPTR cp;
     860             : {
     861             :    FILELISTPTR cur, next;
     862             : 
     863        4860 :    if( cp == NIL(CELL) || cp->ce_files == NIL(FILELIST) ) return;
     864             : 
     865         534 :    for( cur=cp->ce_files; cur != NIL(FILELIST); cur=next ) {
     866         362 :       next = cur->fl_next;
     867             : 
     868         362 :       if( cur->fl_file ) fclose( cur->fl_file );
     869             : 
     870         362 :       if( Verbose & V_LEAVE_TMP )
     871           0 :          fprintf( stderr, "%s:  Left temp file [%s]\n", Pname, cur->fl_name );
     872             :       else
     873         362 :          (void) Remove_file( cur->fl_name );
     874             : 
     875         362 :       FREE(cur->fl_name);
     876         362 :       FREE(cur);
     877             :    }
     878             : 
     879         172 :    cp->ce_files = NIL(FILELIST);
     880             : }
     881             : 
     882             : 
     883             : PUBLIC void
     884        2184 : Handle_result(status, ignore, abort_flg, target)/*
     885             : ==================================================
     886             :   Handle return value of recipe.
     887             : */
     888             : int status;
     889             : int ignore;
     890             : int abort_flg;
     891             : CELLPTR target;
     892             : {
     893        4368 :    status = ((status&0xff)==0 ? status>>8   /* return from exit()      */
     894        2184 :          : (status & 0xff)==SIGTERM ? -1 /* terminated from SIGTERM */
     895           0 :          : (status & 0x7f)+128);         /* terminated from signal
     896             :                           *         ( =status-128 ) */
     897             : 
     898        2184 :    if( status ) {
     899           0 :       if( !abort_flg ) {
     900             :      char buf[512];
     901             : 
     902           0 :      sprintf(buf, "%s:  Error code %d, while making '%s'",
     903             :          Pname, status, target->ce_fname );
     904             : 
     905           0 :      if( ignore || Continue ) {
     906           0 :         if (!(Glob_attr & A_SILENT)) {
     907           0 :            strcat(buf, " (Ignored" );
     908             : 
     909           0 :            if ( Continue ) {
     910             :           /* Continue after error if '-k' was used. */
     911           0 :           strcat(buf,",Continuing");
     912           0 :           target->ce_attr |= A_ERROR;
     913             :            }
     914           0 :            strcat(buf,")");
     915           0 :            if (Verbose)
     916           0 :           fprintf(stderr, "%s\n", buf);
     917             :         }
     918             : 
     919           0 :         if( target->ce_attr & A_ERRREMOVE
     920           0 :         && Remove_file( target->ce_fname ) == 0
     921           0 :         && !(Glob_attr & A_SILENT))
     922           0 :            fprintf(stderr,"%s:  '%s' removed.\n", Pname, target->ce_fname);
     923             :      }
     924             :      else {
     925           0 :         fprintf(stderr, "%s\n",buf);
     926             : 
     927           0 :         if(!(target->ce_attr & A_PRECIOUS)||(target->ce_attr & A_ERRREMOVE))
     928           0 :            if( Remove_file( target->ce_fname ) == 0 )
     929           0 :           fprintf(stderr,"%s:  '%s' removed.\n", Pname,
     930             :               target->ce_fname);
     931             : 
     932           0 :         Quit(0);
     933             :      }
     934             :       }
     935           0 :       else if(!(target->ce_attr & A_PRECIOUS)||(target->ce_attr & A_ERRREMOVE))
     936           0 :      Remove_file( target->ce_fname );
     937             :    }
     938        2184 : }
     939             : 
     940             : 
     941             : PUBLIC void
     942        1858 : Update_time_stamp( cp )/*
     943             : =========================
     944             :    Update the time stamp of cp and scan the list of its prerequisites for
     945             :    files being marked as removable (ie. an inferred intermediate node).
     946             :    Remove them if there are any. */
     947             : CELLPTR cp;
     948             : {
     949             :    HASHPTR hp;
     950             :    LINKPTR dp;
     951             :    CELLPTR tcp;
     952             :    time_t  mintime;
     953        1858 :    int     phony = ((cp->ce_attr&A_PHONY) != 0);
     954             : 
     955        3716 :    for(dp=CeMeToo(cp); dp; dp=dp->cl_next) {
     956        1858 :       tcp=dp->cl_prq;
     957             :       /* When calling Make() on this target ce_time was set to the minimal
     958             :        * required time the target should have after building, i.e. the time
     959             :        * stamp of the newest prerequisite or 1L if there is no
     960             :        * prerequisite. */
     961        1858 :       mintime = tcp->ce_time;
     962             : 
     963        1858 :       if( tcp->ce_attr & A_LIBRARY )
     964           0 :      Void_lib_cache( tcp->ce_fname, NIL(char) );
     965        1858 :       else if( !Touch && (tcp->ce_attr & A_LIBRARYM) )
     966           0 :      Void_lib_cache( tcp->ce_lib, tcp->ce_fname );
     967             : 
     968             :       /* phony targets are treated as if they were recently made
     969             :        * and get the current time assigned. */
     970        1858 :       if( phony ) {
     971        1316 :      tcp->ce_time = Do_time();
     972             :       }
     973         542 :       else if (Trace) {
     974           0 :      tcp->ce_time = Do_time();
     975             :       }
     976             :       else {
     977         542 :      Stat_target(tcp, -1, TRUE);
     978             : 
     979         542 :      if( tcp->ce_time == (time_t) 0L ) {
     980             :         /* If the target does not exist after building set its
     981             :          * time stamp depending if it has recipes or not. Virtual
     982             :          * Targets (without recipes) get the newest time stamp of
     983             :          * its prerequisites assigned. (This was conveniently stored
     984             :          * in mintime.)
     985             :          * Targets with recipes are treated as if they were recently
     986             :          * made and get the current time assigned. */
     987         542 :         if( cp->ce_recipe == NIL(STRING) && mintime > 1 ) {
     988         186 :            tcp->ce_time = mintime;
     989             :         }
     990             :         else {
     991         356 :            tcp->ce_time = Do_time();
     992             :         }
     993             :      }
     994             :      else {
     995             :         /* The target exist. If the target does not have recipe
     996             :          * lines use the newest time stamp of either the target or
     997             :          * the newest time stamp of its prerequisites and issue
     998             :          * a warning. */
     999           0 :         if( cp->ce_recipe == NIL(STRING) ) {
    1000           0 :            time_t  newtime = ( mintime > 1 ? mintime : Do_time() );
    1001             : 
    1002           0 :            if( !(tcp->ce_attr & A_SILENT) )
    1003           0 :           Warning( "Found file corresponding to virtual target [%s].",
    1004           0 :                tcp->CE_NAME );
    1005             : 
    1006           0 :            if( newtime > tcp->ce_time )
    1007           0 :           tcp->ce_time = mintime;
    1008             :         }
    1009             :      }
    1010             :       }
    1011             : 
    1012        1858 :       if( Trace ) {
    1013           0 :      tcp->ce_flag |= F_STAT;        /* pretend we stated ok */
    1014             :       }
    1015             : 
    1016        1858 :       if( Verbose & V_MAKE )
    1017           0 :      printf( "%s:  <<<< Set [%s] time stamp to %lu\n",
    1018           0 :          Pname, tcp->CE_NAME, tcp->ce_time );
    1019             : 
    1020        1858 :       if( Measure & M_TARGET )
    1021           0 :      Do_profile_output( "e", M_TARGET, tcp );
    1022             : 
    1023             :       /* At this point cp->ce_time is updated to either the actual file
    1024             :        * time or the current time. */
    1025             :       DB_PRINT( "make", ("time stamp: %ld, required mintime: %ld",
    1026             :              cp->ce_time, mintime) );
    1027        1858 :       if( tcp->ce_time < mintime && !(tcp->ce_attr & A_SILENT) ) {
    1028           0 :      Warning( "Target [%s] was made but the time stamp has not been updated.",
    1029           0 :           tcp->CE_NAME );
    1030             :       }
    1031             : 
    1032             :       /* The target was made, remove the temp files now. */
    1033        1858 :       Unlink_temp_files( tcp );
    1034        1858 :       tcp->ce_flag |= F_MADE;
    1035        1858 :       tcp->ce_attr |= A_UPDATED;
    1036             :    }
    1037             : 
    1038             :    /* Scan the list of prerequisites and if we find one that is
    1039             :     * marked as being removable, (ie. an inferred intermediate node)
    1040             :     * then remove it.  We remove a prerequisite by running the recipe
    1041             :     * associated with the special target .REMOVE.
    1042             :     * Typically .REMOVE is defined in the startup file as:
    1043             :     *  .REMOVE :; $(RM) $<
    1044             :     * with $< being the list of prerequisites specified in the current
    1045             :     * target. (Make() sets $< .) */
    1046             : 
    1047             :    /* Make sure we don't try to remove prerequisites for the .REMOVE
    1048             :     * target. */
    1049        1858 :    if( strcmp(cp->CE_NAME,".REMOVE") != 0 &&
    1050             :        (hp = Get_name(".REMOVE", Defs, FALSE)) != NIL(HASH) ) {
    1051             :       register LINKPTR dp;
    1052        1858 :       int flag = FALSE;
    1053             :       int rem;
    1054             :       t_attr attr;
    1055             : 
    1056        1858 :       tcp = hp->CP_OWNR;
    1057             : 
    1058             :       /* The .REMOVE target is re-used. Remove old prerequisites. */
    1059        1858 :       tcp->ce_flag |= F_TARGET;
    1060        1858 :       Clear_prerequisites( tcp );
    1061             : 
    1062        4052 :       for(dp=cp->ce_prq; dp != NIL(LINK); dp=dp->cl_next) {
    1063        2194 :      register CELLPTR prq = dp->cl_prq;
    1064             : 
    1065        2194 :      attr = Glob_attr | prq->ce_attr;
    1066             :      /* We seem to have problems here that F_MULTI subtargets get removed
    1067             :       * that even though they are still needed because the A_PRECIOUS
    1068             :       * was not propagated correctly. Solution: Don't remove subtargets, the
    1069             :       * master target will be removed if is not needed. */
    1070        4392 :      rem  = (prq->ce_flag & F_REMOVE) &&
    1071           8 :         (prq->ce_flag & F_MADE  ) &&
    1072           8 :             !(prq->ce_count ) && /* Don't remove F_MULTI subtargets. */
    1073        2202 :         !(prq->ce_attr & A_PHONY) &&
    1074           4 :         !(attr & A_PRECIOUS);
    1075             : 
    1076             :      /* remove if rem is != 0 */
    1077        2194 :      if(rem) {
    1078             :         LINKPTR tdp;
    1079             : 
    1080             :         /* Add the target plus all that are linked to it with the .UPDATEALL
    1081             :          * attribute. */
    1082           0 :         for(tdp=CeMeToo(prq); tdp; tdp=tdp->cl_next) {
    1083           0 :            CELLPTR tmpcell=tdp->cl_prq;
    1084             : 
    1085           0 :            (Add_prerequisite(tcp,tmpcell,FALSE,FALSE))->cl_flag|=F_TARGET;
    1086           0 :            tmpcell->ce_flag &= ~F_REMOVE;
    1087             :         }
    1088           0 :         flag = TRUE;
    1089             :      }
    1090             :       }
    1091             : 
    1092        1858 :       if( flag ) {
    1093           0 :      int sv_force = Force;
    1094             : 
    1095           0 :      Force = FALSE;
    1096           0 :      Remove_prq( tcp );
    1097           0 :      Force = sv_force;
    1098             : 
    1099           0 :      for(dp=tcp->ce_prq; dp != NIL(LINK); dp=dp->cl_next) {
    1100           0 :         register CELLPTR prq = dp->cl_prq;
    1101             : 
    1102           0 :         prq->ce_flag &= ~(F_MADE|F_VISITED|F_STAT);
    1103           0 :         prq->ce_flag |= F_REMOVE;
    1104           0 :         prq->ce_time  = (time_t)0L;
    1105             :      }
    1106             :       }
    1107             :    }
    1108        1858 : }
    1109             : 
    1110             : 
    1111             : PUBLIC int
    1112         746 : Remove_file( name )
    1113             : char *name;
    1114             : {
    1115             :    struct stat buf;
    1116             : 
    1117         746 :    if( stat(name, &buf) != 0 )
    1118           0 :       return 1;
    1119         746 :    if( (buf.st_mode & S_IFMT) == S_IFDIR )
    1120           0 :       return 1;
    1121         746 :    return(unlink(name));
    1122             : }
    1123             : 
    1124             : 
    1125             : #if defined(__CYGWIN__)
    1126             : char *
    1127             : cygdospath(char *src, int winpath)/*
    1128             : ====================================
    1129             :    Convert to DOS path if winpath is true. The returned pointer is
    1130             :    either the original pointer or a pointer to a static buffer.
    1131             : */
    1132             : {
    1133             :    static char *buf = NIL(char);
    1134             : 
    1135             :    if ( !buf && ( (buf = MALLOC( PATH_MAX, char)) == NIL(char) ) )
    1136             :       No_ram();
    1137             : 
    1138             :    DB_PRINT( "cygdospath", ("converting [%s] with winpath [%d]", src, winpath ) );
    1139             : 
    1140             :    /* Return immediately on NULL pointer or when .WINPATH is
    1141             :     * not set. */
    1142             :    if( !src || !winpath )
    1143             :       return src;
    1144             : 
    1145             :    if( *src && src[0] == '/' ) {
    1146             :       char *tmp;
    1147             :       int err = cygwin_conv_to_win32_path(src, buf);
    1148             :       if (err)
    1149             :      Fatal( "error converting \"%s\" - %s\n",
    1150             :         src, strerror (errno));
    1151             : 
    1152             :       tmp = buf;
    1153             :       while ((tmp = strchr (tmp, '\\')) != NULL) {
    1154             :      *tmp = '/';
    1155             :      tmp++;
    1156             :       }
    1157             : 
    1158             :       return buf;
    1159             :    }
    1160             :    else
    1161             :       return src;
    1162             : }
    1163             : #endif

Generated by: LCOV version 1.10