1 /* RCS $Id: sysintf.c,v 1.13 2008-03-05 18:30:58 kz Exp $
4 -- System independent interface
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
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())
35 -- C-LIB SPECIFIC: (should be present in your C-lib)
46 -- Dennis Vadura, dvadura@dmake.wticorp.com
49 -- http://dmake.wticorp.com/
52 -- Copyright (c) 1996,1997 by WTI Corp. All rights reserved.
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.
59 -- Use cvs log to obtain detailed change logs.
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>
72 /* for cygwin_conv_to_posix_path() in Prolog() and for cygdospath()*/
74 # include <sys/cygwin.h>
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!
94 really_dostat(name
, buf
)
98 return( ( DMSTAT(name
,buf
)==-1
99 || (STOBOOL(Augmake
) && (buf
->st_mode
& S_IFDIR
)))
101 : (time_t) buf
->st_mtime
107 Do_stat(name
, lib
, member
, force
)
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
);
127 else if( STOBOOL(UseDirCache
) )
128 return(CacheStat(name
,force
));
130 return(really_dostat(name
,&buf
));
134 /* Touch existing file to force modify time to present.
137 Do_touch(name
, lib
, 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
);
153 #ifdef HAVE_UTIME_NULL
154 return( utime(name
, NULL
) );
156 # error "Utime NULL not supported"
163 Void_lib_cache( lib_name
, member_name
)/*
164 =========================================
165 Void the library cache for lib lib_name, and member member_name. */
169 VOID_LCACHE( lib_name
, member_name
);
175 ** return the current time
180 return (time( NIL(time_t) ));
186 ** Print profiling information
189 Do_profile_output( text
, mtype
, target
)
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;
206 #if defined(_MSC_VER) || defined(__MINGW32__)
207 struct _timeb timebuffer
;
208 _ftime( &timebuffer
);
209 time_sec
= timebuffer
.time
;
210 time_msec
= timebuffer
.millitm
;
212 time_sec
= time( NIL(time_t) );
217 tname
= target
->CE_NAME
;
218 if( mtype
& M_TARGET
) {
220 /* Don't print special targets .TARGETS and .ROOT */
221 if( tname
[0] == '.' && (strcmp(".TARGETS", tname
) == 0 || \
222 strcmp(".ROOT", tname
) == 0) ) {
229 /* Don't print shell escape targets if not especially requested. */
230 if( (target
->ce_attr
& A_SHELLESC
) && !(Measure
& M_SHELLESC
) ) {
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
);
238 printf("%s %s %lu.%.3u %s\n",text
, tstrg
, time_sec
, time_msec
, tname
);
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
260 char **cmd
; /* Simulate a reference to *cmd. */
261 int group
; /* if set cmd contains the filename of a (group-)shell
263 int do_it
; /* Only execute cmd if not set to null. */
265 t_attr cmnd_attr
; /* Attributes for current cmnd. */
266 int last
; /* Last recipe line in target. */
270 DB_ENTER( "Do_cmnd" );
273 if( last
&& !Doing_bang
) {
274 /* Don't execute, just update the target when using '-t'
276 Update_time_stamp( target
);
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
) {
285 Update_time_stamp( target
);
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
) ) {
298 if( (p
= DmStrSpn(*cmd
," \t") ) != *cmd
)
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
309 i
= runargv(target
, group
, last
, cmnd_attr
, cmd
);
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.
325 char **cmd
; /* Simulate a reference to *cmd. */
327 static char **av
= NIL(char *);
330 char *s
; /* Temporary string pointer. */
332 if( av
== NIL(char *) ) {
333 TALLOC(av
, MINARGV
, char*);
340 char* sh
= group
? GShell
: Shell
;
342 if( sh
!= NIL(char) ) {
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
);
350 *cmd
= DmStrJoin(s
, Shell_quote
, -1, TRUE
);
354 #if defined(USE_CREATEPROCESS)
355 /* CreateProcess() needs one long command line. */
356 av
[0] = DmStrAdd(av
[0], av
[1], FALSE
);
358 /* i == 3 means Shell_flags are given. */
361 av
[0] = DmStrAdd(s
, av
[2], FALSE
);
365 /* The final free of cmd will free the concated command line. */
372 Fatal("%sSHELL macro not defined", group
?"GROUP":"");
377 #if defined(USE_CREATEPROCESS)
378 /* CreateProcess() needs one long command line, fill *cmd
380 while( iswhite(*tcmd
) ) ++tcmd
;
381 if( *tcmd
) av
[i
++] = tcmd
;
383 /* All other exec/spawn functions need the parameters separated
384 * in the argument vector. */
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. */
397 av
= (char **) realloc( av
, avs
*sizeof(char *) );
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
416 Read_env_string(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
429 Write_env_string(ename
, value
)
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
) );
448 extern char **Rule_tab
;
449 #if !defined(_MSC_VER)
450 #if defined(__BORLANDC__) && __BORLANDC__ >= 0x500
451 extern char ** _RTLENTRY _EXPDATA environ
;
453 extern char **environ
;
458 #if !defined(__ZTC__) && !defined(_MPW)
483 ** All we have to catch is SIGINT
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
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
);
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));
531 /* Get the drive letter prefix used by cygwin. */
532 if ( (CygDrvPre
= MALLOC( PATH_MAX
, char)) == NIL(char) )
535 int err
= cygwin_conv_to_posix_path("c:", CygDrvPre
);
537 Fatal( "error converting \"%s\" - %s\n",
538 CygDrvPre
, strerror (errno
));
539 if( (CygDrvPreLen
= strlen(CygDrvPre
)) == 2 ) {
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
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. */
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
;
574 ** Do any clean up for exit.
581 Unlink_temp_files(Root
);
582 Hook_std_writes(NIL(char)); /* For MSDOS tee (-F option) */
589 ** Use the built-in functions of the operating system to get the current
590 ** working directory.
595 static char buf
[PATH_MAX
+2];
597 if( !getcwd(buf
, sizeof(buf
)) )
598 Fatal("Internal Error: Error when calling getcwd()!");
603 while( (slash
=strchr(slash
,'/')) )
613 ** change working directory
619 return( chdir(path
) );
625 ** return 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
644 int fd
; /* file descriptor */
646 #if defined(HAVE_MKSTEMP)
649 *path
= DmStrJoin( tmpdir
, DirSepStr
, -1, FALSE
);
650 *path
= DmStrJoin( *path
, "mkXXXXXX", -1, TRUE
);
653 fd
= mkstemp( *path
);
656 #elif defined(HAVE_TEMPNAM)
659 /* Create more unique filename for .NET2003 and newer. */
664 nticks
= GetTickCount() & 0xfff;
665 sprintf(pidbuff
,"mk%d_%d_",npid
,nticks
);
667 sprintf(pidbuff
,"mk");
669 *path
= tempnam(tmpdir
, pidbuff
);
670 fd
= open(*path
, O_CREAT
| O_EXCL
| O_TRUNC
| O_RDWR
, 0600);
673 #error mkstemp() or tempnam() is needed
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.
699 tmpdir
= Read_env_string( "TMPDIR" );
700 if( tmpdir
== NIL(char) )
705 /* This sets path to the name of the created temp file. */
706 if( (fd
= Create_temp(tmpdir
, path
)) != -1)
709 free(*path
); /* free var if creating temp failed. */
714 Def_macro( "TMPFILE", DO_WINPATH(*path
), M_MULTI
|M_EXPANDED
);
715 /* associate stream with file descriptor */
716 fp
= fdopen(fd
, mode
);
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.
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
);
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
) {
763 /* Only use umask if we are also using mkstemp - this basically
764 * avoids using the incompatible implementation from MSVC. */
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
);
781 /* Don't free fname_suff. */
782 Link_temp( cp
, fp2
, fname_suff
);
792 ** Issue an error on failing to open a temporary file
795 Open_temp_error( tmpname
, name
)
799 Fatal("Cannot open temp file `%s' while processing `%s'", tmpname
, name
);
804 ** Link a temp file onto the list of files.
807 Link_temp( cp
, fp
, fname
)
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 */
827 ** Close a previously used temporary file.
835 if( cp
== NIL(CELL
) ) cp
= Root
;
837 for( fl
=cp
->ce_files
; fl
&& fl
->fl_file
!= file
; fl
=fl
->fl_next
);
839 fl
->fl_file
= NIL(FILE);
846 ** Clean-up, and close all temporary files associated with a target.
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. */
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
) {
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
);
867 (void) Remove_file( cur
->fl_name
);
873 cp
->ce_files
= NIL(FILELIST
);
878 Handle_result(status
, ignore
, abort_flg
, target
)/*
879 ==================================================
880 Handle return value of recipe.
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
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" );
904 /* Continue after error if '-k' was used. */
905 strcat(buf
,",Continuing");
906 target
->ce_attr
|= A_ERROR
;
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
);
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
,
929 else if(!(target
->ce_attr
& A_PRECIOUS
)||(target
->ce_attr
& A_ERRREMOVE
))
930 Remove_file( target
->ce_fname
);
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. */
947 int phony
= ((cp
->ce_attr
&A_PHONY
) != 0);
949 for(dp
=CeMeToo(cp
); dp
; dp
=dp
->cl_next
) {
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
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. */
965 tcp
->ce_time
= Do_time();
968 tcp
->ce_time
= Do_time();
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
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
;
985 tcp
->ce_time
= Do_time();
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
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].",
1000 if( newtime
> tcp
->ce_time
)
1001 tcp
->ce_time
= mintime
;
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.",
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
1043 if( strcmp(cp
->CE_NAME
,".REMOVE") != 0 &&
1044 (hp
= Get_name(".REMOVE", Defs
, FALSE
)) != NIL(HASH
) ) {
1045 register LINKPTR dp
;
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 */
1074 /* Add the target plus all that are linked to it with the .UPDATEALL
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
;
1087 int sv_force
= 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;
1111 if( stat(name
, &buf
) != 0 )
1113 if( (buf
.st_mode
& S_IFMT
) == S_IFDIR
)
1115 return(unlink(name
));
1119 #if defined(__CYGWIN__)
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) ) )
1132 DB_PRINT( "cygdospath", ("converting [%s] with winpath [%d]", src
, winpath
) );
1134 /* Return immediately on NULL pointer or when .WINPATH is
1136 if( !src
|| !winpath
)
1139 if( *src
&& src
[0] == '/' ) {
1141 int err
= cygwin_conv_to_win32_path(src
, buf
);
1143 Fatal( "error converting \"%s\" - %s\n",
1144 src
, strerror (errno
));
1147 while ((tmp
= strchr (tmp
, '\\')) != NULL
) {