update dev300-m58
[ooovba.git] / dmake / sysintf.c
blob528178a4928d035d788e3e1062b042ff7a0b8c7d
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.
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.
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())
27 -- DMAKE SPECIFIC:
28 -- seek_arch()
29 -- touch_arch()
30 -- void_lcache()
31 -- runargv()
32 -- DMSTAT()
33 -- Remove_prq()
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
48 -- WWW
49 -- http://dmake.wticorp.com/
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.
58 -- LOG
59 -- Use cvs log to obtain detailed change logs.
62 #include "extern.h"
64 /* The following definition controls the use of GetModuleFileName() */
65 #if defined(_MSC_VER) || defined(__MINGW32__)
66 # define HAVE_GETMODULEFILENAMEFUNC 1
68 /* this is needed for the _ftime call below. Only needed here. */
69 # include <sys/timeb.h>
70 #endif
72 /* for cygwin_conv_to_posix_path() in Prolog() and for cygdospath()*/
73 #if __CYGWIN__
74 # include <sys/cygwin.h>
75 #endif
77 #include "sysintf.h"
78 #if HAVE_ERRNO_H
79 # include <errno.h>
80 #else
81 extern int errno;
82 #endif
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.
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!
93 static time_t
94 really_dostat(name, buf)
95 char *name;
96 struct stat *buf;
98 return( ( DMSTAT(name,buf)==-1
99 || (STOBOOL(Augmake) && (buf->st_mode & S_IFDIR)))
100 ? (time_t)0L
101 : (time_t) buf->st_mtime
106 PUBLIC time_t
107 Do_stat(name, lib, member, force)
108 char *name;
109 char *lib;
110 char **member;
111 int force;
113 struct stat buf;
114 time_t seek_arch();
116 if( member != NIL(char *) )
117 Fatal("Library symbol names not supported");
119 buf.st_mtime = (time_t)0L;
120 if( lib != NIL(char) )
121 return( seek_arch(Basename(name), lib) );
122 else if( strlen(Basename(name)) > NameMax ) {
123 Warning( "Filename [%s] longer than value of NAMEMAX [%d].\n\
124 Assume unix time 0.\n", Basename(name), NameMax );
125 return((time_t)0L);
127 else if( STOBOOL(UseDirCache) )
128 return(CacheStat(name,force));
129 else
130 return(really_dostat(name,&buf));
134 /* Touch existing file to force modify time to present.
136 PUBLIC int
137 Do_touch(name, lib, member)
138 char *name;
139 char *lib;
140 char **member;
142 if( member != NIL(char *) )
143 Fatal("Library symbol names not supported");
145 if (lib != NIL(char))
146 return( touch_arch(Basename(name), lib) );
147 else if( strlen(Basename(name)) > NameMax ) {
148 Warning( "Filename [%s] longer than value of NAMEMAX [%d].\n\
149 File timestamp not updated to present time.\n", Basename(name), NameMax );
150 return(-1);
152 else
153 #ifdef HAVE_UTIME_NULL
154 return( utime(name, NULL) );
155 #else
156 # error "Utime NULL not supported"
157 #endif
162 PUBLIC void
163 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;
169 VOID_LCACHE( lib_name, member_name );
175 ** return the current time
177 PUBLIC time_t
178 Do_time()
180 return (time( NIL(time_t) ));
186 ** Print profiling information
188 PUBLIC void
189 Do_profile_output( text, mtype, target )
190 char *text;
191 uint16 mtype;
192 CELLPTR target;
195 time_t time_sec;
196 uint32 time_msec;
197 char *tstrg;
198 char *tname;
200 #ifdef HAVE_GETTIMEOFDAY
201 struct timeval timebuffer;
202 gettimeofday(&timebuffer, NULL);
203 time_sec = timebuffer.tv_sec;
204 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
217 tname = target->CE_NAME;
218 if( mtype & M_TARGET ) {
219 tstrg = "target";
220 /* Don't print special targets .TARGETS and .ROOT */
221 if( tname[0] == '.' && (strcmp(".TARGETS", tname) == 0 || \
222 strcmp(".ROOT", tname) == 0) ) {
223 return;
225 } else {
226 tstrg = "recipe";
229 /* Don't print shell escape targets if not especially requested. */
230 if( (target->ce_attr & A_SHELLESC) && !(Measure & M_SHELLESC) ) {
231 return;
234 /* Print absolute path if requested. */
235 if( !(target->ce_attr & A_SHELLESC) && (Measure & M_ABSPATH) ) {
236 printf("%s %s %lu.%.3u %s%s%s\n",text, tstrg, time_sec, time_msec, Pwd, DirSepStr, tname);
237 } else {
238 printf("%s %s %lu.%.3u %s\n",text, tstrg, time_sec, time_msec, tname);
244 PUBLIC int
245 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.
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.
257 If Wait_for_completion is TRUE add the A_WFC attribute to the new
258 process.
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. */
268 int i;
270 DB_ENTER( "Do_cmnd" );
272 if( !do_it ) {
273 if( last && !Doing_bang ) {
274 /* Don't execute, just update the target when using '-t'
275 * switch. */
276 Update_time_stamp( target );
278 DB_RETURN( 0 );
281 /* Stop making the rest of the recipies for this target if an error occured
282 * but the Continue (-k) flag is set to build as much as possible. */
283 if ( target->ce_attr & A_ERROR ) {
284 if ( last ) {
285 Update_time_stamp( target );
287 DB_RETURN( 0 );
290 if( Max_proc == 1 ) Wait_for_completion = TRUE;
292 /* Tell runargv() to wait if needed. */
293 if( Wait_for_completion ) cmnd_attr |= A_WFC;
295 /* remove leading whitespace - This should never trigger! */
296 if( iswhite(**cmd) ) {
297 char *p;
298 if( (p = DmStrSpn(*cmd," \t") ) != *cmd )
299 strcpy(*cmd,p);
302 /* set shell if shell metas are found */
303 if( (cmnd_attr & A_SHELL) || group || (*DmStrPbrk(*cmd, Shell_metas)!='\0') )
304 cmnd_attr |= A_SHELL; /* If group is TRUE this doesn't hurt. */
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 i = runargv(target, group, last, cmnd_attr, cmd);
311 DB_RETURN( i );
315 #define MINARGV 64
317 PUBLIC char **
318 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.
323 int group;
324 int shell;
325 char **cmd; /* Simulate a reference to *cmd. */
327 static char **av = NIL(char *);
328 static int avs = 0;
329 int i = 0;
330 char *s; /* Temporary string pointer. */
332 if( av == NIL(char *) ) {
333 TALLOC(av, MINARGV, char*);
334 avs = MINARGV;
336 av[0] = NIL(char);
338 if (**cmd) {
339 if( shell||group ) {
340 char* sh = group ? GShell : Shell;
342 if( sh != NIL(char) ) {
343 av[i++] = sh;
344 if( (av[i] = (group?GShell_flags:Shell_flags)) != NIL(char) ) i++;
346 if( shell && Shell_quote && *Shell_quote ) {
347 /* Enclose the shell command with SHELLCMDQUOTE. */
348 s = DmStrJoin(Shell_quote, *cmd, -1, FALSE);
349 FREE(*cmd);
350 *cmd = DmStrJoin(s, Shell_quote, -1, TRUE);
352 av[i++] = *cmd;
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);
365 /* The final free of cmd will free the concated command line. */
366 FREE(*cmd);
367 *cmd = av[0];
368 #endif
369 av[i] = NIL(char);
371 else
372 Fatal("%sSHELL macro not defined", group?"GROUP":"");
374 else {
375 char *tcmd = *cmd;
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 while( iswhite(*tcmd) ) ++tcmd;
389 if( *tcmd ) av[i++] = tcmd;
391 while( *tcmd != '\0' && !iswhite(*tcmd) ) ++tcmd;
392 if( *tcmd ) *tcmd++ = '\0';
394 /* dynamically increase av size. */
395 if( i == avs ) {
396 avs += MINARGV;
397 av = (char **) realloc( av, avs*sizeof(char *) );
399 } while( *tcmd );
400 #endif
402 av[i] = NIL(char);
406 return(av);
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
415 PUBLIC char *
416 Read_env_string(ename)
417 char *ename;
419 return( getenv(ename) );
425 ** Set the value of the environment string ename to value.
426 ** Returns 0 if success, non-zero if failure
428 PUBLIC int
429 Write_env_string(ename, value)
430 char *ename;
431 char *value;
433 char* p;
434 char* envstr = DmStrAdd(ename, value, FALSE);
436 p = envstr+strlen(ename); /* Don't change this code, DmStrAdd does not */
437 *p++ = '='; /* add the space if *value is 0, it does */
438 if( !*value ) *p = '\0'; /* allocate enough memory for one though. */
440 return( putenv(envstr) );
445 PUBLIC void
446 ReadEnvironment()
448 extern char **Rule_tab;
449 #if !defined(_MSC_VER)
450 #if defined(__BORLANDC__) && __BORLANDC__ >= 0x500
451 extern char ** _RTLENTRY _EXPDATA environ;
452 #else
453 extern char **environ;
454 #endif
455 #endif
456 char **rsave;
458 #if !defined(__ZTC__) && !defined(_MPW)
459 # define make_env()
460 # define free_env()
461 #else
462 void make_env();
463 void free_env();
464 #endif
466 make_env();
468 rsave = Rule_tab;
469 Rule_tab = environ;
470 Readenv = TRUE;
472 Parse( NIL(FILE) );
474 Readenv = FALSE;
475 Rule_tab = rsave;
477 free_env();
483 ** All we have to catch is SIGINT
485 PUBLIC void
486 Catch_signals(fn)
487 void (*fn)(int);
489 /* FIXME: Check this and add error handling. */
490 if( (void (*)(int)) signal(SIGINT, SIG_IGN) != (void (*)(int))SIG_IGN )
491 signal( SIGINT, fn );
492 if( (void (*)(int)) signal(SIGQUIT, SIG_IGN) != (void (*)(int))SIG_IGN )
493 signal( SIGQUIT, fn );
499 ** Clear any previously set signals
501 PUBLIC void
502 Clear_signals()
504 if( (void (*)())signal(SIGINT, SIG_IGN) != (void (*)())SIG_IGN )
505 signal( SIGINT, SIG_DFL );
506 if( (void (*)())signal(SIGQUIT, SIG_IGN) != (void (*)())SIG_IGN )
507 signal( SIGQUIT, SIG_DFL );
513 ** Set program name
515 PUBLIC void
516 Prolog(argc, argv)
517 int argc;
518 char* argv[];
520 Pname = (argc == 0) ? DEF_MAKE_PNAME : argv[0];
522 /* Only some native Windows compilers provide this functionality. */
523 #ifdef HAVE_GETMODULEFILENAMEFUNC
524 if( (AbsPname = MALLOC( PATH_MAX, char)) == NIL(char) ) No_ram();
525 GetModuleFileName(NULL, AbsPname, PATH_MAX*sizeof(char));
526 #else
527 AbsPname = "";
528 #endif
530 #if __CYGWIN__
531 /* Get the drive letter prefix used by cygwin. */
532 if ( (CygDrvPre = MALLOC( PATH_MAX, char)) == NIL(char) )
533 No_ram();
534 else {
535 int err = cygwin_conv_to_posix_path("c:", CygDrvPre);
536 if (err)
537 Fatal( "error converting \"%s\" - %s\n",
538 CygDrvPre, strerror (errno));
539 if( (CygDrvPreLen = strlen(CygDrvPre)) == 2 ) {
540 /* No prefix */
541 *CygDrvPre = '\0';
542 CygDrvPreLen = 0;
543 } else {
544 /* Cut away the directory letter. */
545 CygDrvPre[CygDrvPreLen-2] = '\0';
546 /* Cut away the leading '/'. We don't free the pointer, i.e. choose
547 * the easy way. */
548 CygDrvPre++;
549 CygDrvPreLen -= 3;
552 #endif
554 /* DirSepStr is used from Clean_path() in Def_cell(). Set it preliminary
555 * here, it will be redefined later in Create_macro_vars() in imacs.c. */
556 DirSepStr = "/";
558 Root = Def_cell( ".ROOT" );
559 Targets = Def_cell( ".TARGETS" );
560 Add_prerequisite(Root, Targets, FALSE, FALSE);
562 Targets->ce_flag = Root->ce_flag = F_RULES|F_TARGET|F_STAT;
563 Targets->ce_attr = Root->ce_attr = A_NOSTATE|A_PHONY;
565 Root->ce_flag |= F_MAGIC;
566 Root->ce_attr |= A_SEQ;
568 tzset();
574 ** Do any clean up for exit.
576 PUBLIC void
577 Epilog(ret_code)
578 int ret_code;
580 Write_state();
581 Unlink_temp_files(Root);
582 Hook_std_writes(NIL(char)); /* For MSDOS tee (-F option) */
583 exit( ret_code );
589 ** Use the built-in functions of the operating system to get the current
590 ** working directory.
592 PUBLIC char *
593 Get_current_dir()
595 static char buf[PATH_MAX+2];
597 if( !getcwd(buf, sizeof(buf)) )
598 Fatal("Internal Error: Error when calling getcwd()!");
600 #ifdef __EMX__
601 char *slash;
602 slash = buf;
603 while( (slash=strchr(slash,'/')) )
604 *slash = '\\';
605 #endif
607 return buf;
613 ** change working directory
615 PUBLIC int
616 Set_dir(path)
617 char* path;
619 return( chdir(path) );
625 ** return switch char
627 PUBLIC char
628 Get_switch_char()
630 return( getswitchar() );
634 int Create_temp(tmpdir, path)/*
635 ===============================
636 Create a temporary file and open with exclusive access
637 Path is updated with the filename and the file descriptor
638 is returned. Note that the new name should be freed when
639 the file is removed.
641 char *tmpdir;
642 char **path;
644 int fd; /* file descriptor */
646 #if defined(HAVE_MKSTEMP)
647 mode_t mask;
649 *path = DmStrJoin( tmpdir, DirSepStr, -1, FALSE);
650 *path = DmStrJoin( *path, "mkXXXXXX", -1, TRUE );
652 mask = umask(0066);
653 fd = mkstemp( *path );
654 umask(mask);
656 #elif defined(HAVE_TEMPNAM)
657 char pidbuff[32];
658 #if _MSC_VER >= 1300
659 /* Create more unique filename for .NET2003 and newer. */
660 long npid;
661 long nticks;
663 npid = _getpid();
664 nticks = GetTickCount() & 0xfff;
665 sprintf(pidbuff,"mk%d_%d_",npid,nticks);
666 #else
667 sprintf(pidbuff,"mk");
668 #endif
669 *path = tempnam(tmpdir, pidbuff);
670 fd = open(*path, O_CREAT | O_EXCL | O_TRUNC | O_RDWR, 0600);
671 #else
673 #error mkstemp() or tempnam() is needed
675 #endif
677 return fd;
681 PUBLIC FILE*
682 Get_temp(path, mode)/*
683 ======================
684 Generate a temporary file name and open the file for writing.
685 If a name cannot be generated or the file cannot be opened
686 return -1, else return the fileno of the open file.
687 and update the source file pointer to point at the new file name.
688 Note that the new name should be freed when the file is removed.
689 The file stream is opened with the given mode.
691 char **path;
692 char *mode;
694 int fd;
695 FILE *fp;
696 char *tmpdir;
697 int tries = 20;
699 tmpdir = Read_env_string( "TMPDIR" );
700 if( tmpdir == NIL(char) )
701 tmpdir = "/tmp";
703 while( --tries )
705 /* This sets path to the name of the created temp file. */
706 if( (fd = Create_temp(tmpdir, path)) != -1)
707 break;
709 free(*path); /* free var if creating temp failed. */
712 if( fd != -1)
714 Def_macro( "TMPFILE", DO_WINPATH(*path), M_MULTI|M_EXPANDED );
715 /* associate stream with file descriptor */
716 fp = fdopen(fd, mode);
718 else
719 fp = NIL(FILE);
721 return fp;
725 PUBLIC FILE *
726 Start_temp( suffix, cp, fname )/*
727 =================================
728 Open a new temporary file and set it up for writing. The file is linked
729 to cp and will be removed if once the target is finished.
730 If a suffix for the temporary files is requested two temporary files are
731 created. This is done because the routines that create a save temporary
732 file do not provide a definable suffix. The first (provided by Get_temp())
733 is save and unique and the second file is generated by adding the desired
734 suffix the the first temporary file. The extra file is also linked to cp
735 so that it gets removed later.
736 The function returns the FILE pointer to the temporary file (with suffix
737 if specified) and leaves the file name in *fname.
739 char *suffix;
740 CELLPTR cp;
741 char **fname;
743 FILE *fp, *fp2;
744 char *tmpname;
745 char *name;
746 char *fname_suff;
748 name = (cp != NIL(CELL))?cp->CE_NAME:"makefile text";
750 /* This sets tmpname to the name that was used. */
751 if( (fp = Get_temp(&tmpname, "w")) == NIL(FILE) )
752 Open_temp_error( tmpname, name );
754 /* Don't free tmpname, it's stored in a FILELIST member in Link_temp(). */
755 Link_temp( cp, fp, tmpname );
756 *fname = tmpname;
758 /* As Get_temp() doesn't provide a definable suffix (anymore) we create an
759 * additional temporary file with that suffix. */
760 if ( suffix && *suffix ) {
762 #ifdef HAVE_MKSTEMP
763 /* Only use umask if we are also using mkstemp - this basically
764 * avoids using the incompatible implementation from MSVC. */
765 mode_t mask;
767 mask = umask(0066);
768 #endif
770 fname_suff = DmStrJoin( tmpname, suffix, -1, FALSE );
772 /* Overwrite macro, Get_temp didn't know of the suffix. */
773 Def_macro( "TMPFILE", DO_WINPATH(fname_suff), M_MULTI|M_EXPANDED );
775 if( (fp2 = fopen(fname_suff, "w" )) == NIL(FILE) )
776 Open_temp_error( fname_suff, name );
777 #ifdef HAVE_MKSTEMP
778 umask(mask);
779 #endif
781 /* Don't free fname_suff. */
782 Link_temp( cp, fp2, fname_suff );
783 fp = fp2;
784 *fname = fname_suff;
787 return( fp );
792 ** Issue an error on failing to open a temporary file
794 PUBLIC void
795 Open_temp_error( tmpname, name )
796 char *tmpname;
797 char *name;
799 Fatal("Cannot open temp file `%s' while processing `%s'", tmpname, name );
804 ** Link a temp file onto the list of files.
806 PUBLIC void
807 Link_temp( cp, fp, fname )
808 CELLPTR cp;
809 FILE *fp;
810 char *fname;
812 FILELISTPTR new;
814 if( cp == NIL(CELL) ) cp = Root;
816 TALLOC( new, 1, FILELIST );
818 new->fl_next = cp->ce_files;
819 new->fl_name = fname;
820 new->fl_file = fp; /* indicates temp file is open */
822 cp->ce_files = new;
827 ** Close a previously used temporary file.
829 PUBLIC void
830 Close_temp(cp, file)
831 CELLPTR cp;
832 FILE *file;
834 FILELISTPTR fl;
835 if( cp == NIL(CELL) ) cp = Root;
837 for( fl=cp->ce_files; fl && fl->fl_file != file; fl=fl->fl_next );
838 if( fl ) {
839 fl->fl_file = NIL(FILE);
840 fclose(file);
846 ** Clean-up, and close all temporary files associated with a target.
848 PUBLIC void
849 Unlink_temp_files( cp )/*
850 ==========================
851 Unlink the tempfiles if any exist. Make sure you close the files first
852 though. This ensures that under DOS there is no disk space lost. */
853 CELLPTR cp;
855 FILELISTPTR cur, next;
857 if( cp == NIL(CELL) || cp->ce_files == NIL(FILELIST) ) return;
859 for( cur=cp->ce_files; cur != NIL(FILELIST); cur=next ) {
860 next = cur->fl_next;
862 if( cur->fl_file ) fclose( cur->fl_file );
864 if( Verbose & V_LEAVE_TMP )
865 fprintf( stderr, "%s: Left temp file [%s]\n", Pname, cur->fl_name );
866 else
867 (void) Remove_file( cur->fl_name );
869 FREE(cur->fl_name);
870 FREE(cur);
873 cp->ce_files = NIL(FILELIST);
877 PUBLIC void
878 Handle_result(status, ignore, abort_flg, target)/*
879 ==================================================
880 Handle return value of recipe.
882 int status;
883 int ignore;
884 int abort_flg;
885 CELLPTR target;
887 status = ((status&0xff)==0 ? status>>8 /* return from exit() */
888 : (status & 0xff)==SIGTERM ? -1 /* terminated from SIGTERM */
889 : (status & 0x7f)+128); /* terminated from signal
890 * ( =status-128 ) */
892 if( status ) {
893 if( !abort_flg ) {
894 char buf[512];
896 sprintf(buf, "%s: Error code %d, while making '%s'",
897 Pname, status, target->ce_fname );
899 if( ignore || Continue ) {
900 if (!(Glob_attr & A_SILENT)) {
901 strcat(buf, " (Ignored" );
903 if ( Continue ) {
904 /* Continue after error if '-k' was used. */
905 strcat(buf,",Continuing");
906 target->ce_attr |= A_ERROR;
908 strcat(buf,")");
909 if (Verbose)
910 fprintf(stderr, "%s\n", buf);
913 if( target->ce_attr & A_ERRREMOVE
914 && Remove_file( target->ce_fname ) == 0
915 && !(Glob_attr & A_SILENT))
916 fprintf(stderr,"%s: '%s' removed.\n", Pname, target->ce_fname);
918 else {
919 fprintf(stderr, "%s\n",buf);
921 if(!(target->ce_attr & A_PRECIOUS)||(target->ce_attr & A_ERRREMOVE))
922 if( Remove_file( target->ce_fname ) == 0 )
923 fprintf(stderr,"%s: '%s' removed.\n", Pname,
924 target->ce_fname);
926 Quit(0);
929 else if(!(target->ce_attr & A_PRECIOUS)||(target->ce_attr & A_ERRREMOVE))
930 Remove_file( target->ce_fname );
935 PUBLIC void
936 Update_time_stamp( cp )/*
937 =========================
938 Update the time stamp of cp and scan the list of its prerequisites for
939 files being marked as removable (ie. an inferred intermediate node).
940 Remove them if there are any. */
941 CELLPTR cp;
943 HASHPTR hp;
944 LINKPTR dp;
945 CELLPTR tcp;
946 time_t mintime;
947 int phony = ((cp->ce_attr&A_PHONY) != 0);
949 for(dp=CeMeToo(cp); dp; dp=dp->cl_next) {
950 tcp=dp->cl_prq;
951 /* When calling Make() on this target ce_time was set to the minimal
952 * required time the target should have after building, i.e. the time
953 * stamp of the newest prerequisite or 1L if there is no
954 * prerequisite. */
955 mintime = tcp->ce_time;
957 if( tcp->ce_attr & A_LIBRARY )
958 Void_lib_cache( tcp->ce_fname, NIL(char) );
959 else if( !Touch && (tcp->ce_attr & A_LIBRARYM) )
960 Void_lib_cache( tcp->ce_lib, tcp->ce_fname );
962 /* phony targets are treated as if they were recently made
963 * and get the current time assigned. */
964 if( phony ) {
965 tcp->ce_time = Do_time();
967 else if (Trace) {
968 tcp->ce_time = Do_time();
970 else {
971 Stat_target(tcp, -1, TRUE);
973 if( tcp->ce_time == (time_t) 0L ) {
974 /* If the target does not exist after building set its
975 * time stamp depending if it has recipes or not. Virtual
976 * Targets (without recipes) get the newest time stamp of
977 * its prerequisites assigned. (This was conveniently stored
978 * in mintime.)
979 * Targets with recipes are treated as if they were recently
980 * made and get the current time assigned. */
981 if( cp->ce_recipe == NIL(STRING) && mintime > 1 ) {
982 tcp->ce_time = mintime;
984 else {
985 tcp->ce_time = Do_time();
988 else {
989 /* The target exist. If the target does not have recipe
990 * lines use the newest time stamp of either the target or
991 * the newest time stamp of its prerequisites and issue
992 * a warning. */
993 if( cp->ce_recipe == NIL(STRING) ) {
994 time_t newtime = ( mintime > 1 ? mintime : Do_time() );
996 if( !(tcp->ce_attr & A_SILENT) )
997 Warning( "Found file corresponding to virtual target [%s].",
998 tcp->CE_NAME );
1000 if( newtime > tcp->ce_time )
1001 tcp->ce_time = mintime;
1006 if( Trace ) {
1007 tcp->ce_flag |= F_STAT; /* pretend we stated ok */
1010 if( Verbose & V_MAKE )
1011 printf( "%s: <<<< Set [%s] time stamp to %lu\n",
1012 Pname, tcp->CE_NAME, tcp->ce_time );
1014 if( Measure & M_TARGET )
1015 Do_profile_output( "e", M_TARGET, tcp );
1017 /* At this point cp->ce_time is updated to either the actual file
1018 * time or the current time. */
1019 DB_PRINT( "make", ("time stamp: %ld, required mintime: %ld",
1020 cp->ce_time, mintime) );
1021 if( tcp->ce_time < mintime && !(tcp->ce_attr & A_SILENT) ) {
1022 Warning( "Target [%s] was made but the time stamp has not been updated.",
1023 tcp->CE_NAME );
1026 /* The target was made, remove the temp files now. */
1027 Unlink_temp_files( tcp );
1028 tcp->ce_flag |= F_MADE;
1029 tcp->ce_attr |= A_UPDATED;
1032 /* Scan the list of prerequisites and if we find one that is
1033 * marked as being removable, (ie. an inferred intermediate node)
1034 * then remove it. We remove a prerequisite by running the recipe
1035 * associated with the special target .REMOVE.
1036 * Typically .REMOVE is defined in the startup file as:
1037 * .REMOVE :; $(RM) $<
1038 * with $< being the list of prerequisites specified in the current
1039 * target. (Make() sets $< .) */
1041 /* Make sure we don't try to remove prerequisites for the .REMOVE
1042 * target. */
1043 if( strcmp(cp->CE_NAME,".REMOVE") != 0 &&
1044 (hp = Get_name(".REMOVE", Defs, FALSE)) != NIL(HASH) ) {
1045 register LINKPTR dp;
1046 int flag = FALSE;
1047 int rem;
1048 t_attr attr;
1050 tcp = hp->CP_OWNR;
1052 /* The .REMOVE target is re-used. Remove old prerequisites. */
1053 tcp->ce_flag |= F_TARGET;
1054 Clear_prerequisites( tcp );
1056 for(dp=cp->ce_prq; dp != NIL(LINK); dp=dp->cl_next) {
1057 register CELLPTR prq = dp->cl_prq;
1059 attr = Glob_attr | prq->ce_attr;
1060 /* We seem to have problems here that F_MULTI subtargets get removed
1061 * that even though they are still needed because the A_PRECIOUS
1062 * was not propagated correctly. Solution: Don't remove subtargets, the
1063 * master target will be removed if is not needed. */
1064 rem = (prq->ce_flag & F_REMOVE) &&
1065 (prq->ce_flag & F_MADE ) &&
1066 !(prq->ce_count ) && /* Don't remove F_MULTI subtargets. */
1067 !(prq->ce_attr & A_PHONY) &&
1068 !(attr & A_PRECIOUS);
1070 /* remove if rem is != 0 */
1071 if(rem) {
1072 LINKPTR tdp;
1074 /* Add the target plus all that are linked to it with the .UPDATEALL
1075 * attribute. */
1076 for(tdp=CeMeToo(prq); tdp; tdp=tdp->cl_next) {
1077 CELLPTR tmpcell=tdp->cl_prq;
1079 (Add_prerequisite(tcp,tmpcell,FALSE,FALSE))->cl_flag|=F_TARGET;
1080 tmpcell->ce_flag &= ~F_REMOVE;
1082 flag = TRUE;
1086 if( flag ) {
1087 int sv_force = Force;
1089 Force = FALSE;
1090 Remove_prq( tcp );
1091 Force = sv_force;
1093 for(dp=tcp->ce_prq; dp != NIL(LINK); dp=dp->cl_next) {
1094 register CELLPTR prq = dp->cl_prq;
1096 prq->ce_flag &= ~(F_MADE|F_VISITED|F_STAT);
1097 prq->ce_flag |= F_REMOVE;
1098 prq->ce_time = (time_t)0L;
1105 PUBLIC int
1106 Remove_file( name )
1107 char *name;
1109 struct stat buf;
1111 if( stat(name, &buf) != 0 )
1112 return 1;
1113 if( (buf.st_mode & S_IFMT) == S_IFDIR )
1114 return 1;
1115 return(unlink(name));
1119 #if defined(__CYGWIN__)
1120 char *
1121 cygdospath(char *src, int winpath)/*
1122 ====================================
1123 Convert to DOS path if winpath is true. The returned pointer is
1124 either the original pointer or a pointer to a static buffer.
1127 static char *buf = NIL(char);
1129 if ( !buf && ( (buf = MALLOC( PATH_MAX, char)) == NIL(char) ) )
1130 No_ram();
1132 DB_PRINT( "cygdospath", ("converting [%s] with winpath [%d]", src, winpath ) );
1134 /* Return immediately on NULL pointer or when .WINPATH is
1135 * not set. */
1136 if( !src || !winpath )
1137 return src;
1139 if( *src && src[0] == '/' ) {
1140 char *tmp;
1141 int err = cygwin_conv_to_win32_path(src, buf);
1142 if (err)
1143 Fatal( "error converting \"%s\" - %s\n",
1144 src, strerror (errno));
1146 tmp = buf;
1147 while ((tmp = strchr (tmp, '\\')) != NULL) {
1148 *tmp = '/';
1149 tmp++;
1152 return buf;
1154 else
1155 return src;
1157 #endif