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 occurred
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
) );
424 ** Set the value of the environment string ename to value.
425 ** Returns 0 if success, non-zero if failure
428 Write_env_string(ename
, value
)
432 #if defined(HAVE_SETENV)
434 return( setenv(ename
, value
, 1) );
436 #else /* !HAVE_SETENV */
439 char* envstr
= DmStrAdd(ename
, value
, FALSE
);
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. */
445 return( putenv(envstr
) ); /* Possibly leaking 'envstr' */
447 #endif /* !HAVE_SETENV */
454 extern char **Rule_tab
;
455 #if !defined(_MSC_VER)
456 #if defined(__BORLANDC__) && __BORLANDC__ >= 0x500
457 extern char ** _RTLENTRY _EXPDATA environ
;
459 extern char **environ
;
464 #if !defined(__ZTC__) && !defined(_MPW)
489 ** All we have to catch is SIGINT
495 /* FIXME: Check this and add error handling. */
496 if( (void (*)(int)) signal(SIGINT
, SIG_IGN
) != (void (*)(int))SIG_IGN
)
497 signal( SIGINT
, fn
);
498 if( (void (*)(int)) signal(SIGQUIT
, SIG_IGN
) != (void (*)(int))SIG_IGN
)
499 signal( SIGQUIT
, fn
);
505 ** Clear any previously set signals
510 if( (void (*)())signal(SIGINT
, SIG_IGN
) != (void (*)())SIG_IGN
)
511 signal( SIGINT
, SIG_DFL
);
512 if( (void (*)())signal(SIGQUIT
, SIG_IGN
) != (void (*)())SIG_IGN
)
513 signal( SIGQUIT
, SIG_DFL
);
526 Pname
= (argc
== 0) ? DEF_MAKE_PNAME
: argv
[0];
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));
537 /* Get the drive letter prefix used by cygwin. */
538 if ( (CygDrvPre
= MALLOC( PATH_MAX
, char)) == NIL(char) )
541 int err
= cygwin_conv_to_posix_path("c:", CygDrvPre
);
543 Fatal( "error converting \"%s\" - %s\n",
544 CygDrvPre
, strerror (errno
));
545 if( (CygDrvPreLen
= strlen(CygDrvPre
)) == 2 ) {
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
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. */
564 Root
= Def_cell( ".ROOT" );
565 Targets
= Def_cell( ".TARGETS" );
566 Add_prerequisite(Root
, Targets
, FALSE
, FALSE
);
568 Targets
->ce_flag
= Root
->ce_flag
= F_RULES
|F_TARGET
|F_STAT
;
569 Targets
->ce_attr
= Root
->ce_attr
= A_NOSTATE
|A_PHONY
;
571 Root
->ce_flag
|= F_MAGIC
;
572 Root
->ce_attr
|= A_SEQ
;
580 ** Do any clean up for exit.
587 Unlink_temp_files(Root
);
588 Hook_std_writes(NIL(char)); /* For MSDOS tee (-F option) */
595 ** Use the built-in functions of the operating system to get the current
596 ** working directory.
601 static char buf
[PATH_MAX
+2];
603 if( !getcwd(buf
, sizeof(buf
)) )
604 Fatal("Internal Error: Error when calling getcwd()!");
609 while( (slash
=strchr(slash
,'/')) )
619 ** change working directory
625 return( chdir(path
) );
631 ** return switch char
636 return( getswitchar() );
640 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
650 int fd
; /* file descriptor */
652 #if defined(HAVE_MKSTEMP)
655 *path
= DmStrJoin( tmpdir
, DirSepStr
, -1, FALSE
);
656 *path
= DmStrJoin( *path
, "mkXXXXXX", -1, TRUE
);
659 fd
= mkstemp( *path
);
662 #elif defined(HAVE_TEMPNAM)
665 /* Create more unique filename for .NET2003 and newer. */
670 nticks
= GetTickCount() & 0xfff;
671 sprintf(pidbuff
,"mk%d_%d_",npid
,nticks
);
673 sprintf(pidbuff
,"mk");
675 *path
= tempnam(tmpdir
, pidbuff
);
676 fd
= open(*path
, O_CREAT
| O_EXCL
| O_TRUNC
| O_RDWR
, 0600);
679 #error mkstemp() or tempnam() is needed
688 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.
705 tmpdir
= Read_env_string( "TMPDIR" );
706 if( tmpdir
== NIL(char) )
711 /* This sets path to the name of the created temp file. */
712 if( (fd
= Create_temp(tmpdir
, path
)) != -1)
715 free(*path
); /* free var if creating temp failed. */
720 Def_macro( "TMPFILE", DO_WINPATH(*path
), M_MULTI
|M_EXPANDED
);
721 /* associate stream with file descriptor */
722 fp
= fdopen(fd
, mode
);
732 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.
754 name
= (cp
!= NIL(CELL
))?cp
->CE_NAME
:"makefile text";
756 /* This sets tmpname to the name that was used. */
757 if( (fp
= Get_temp(&tmpname
, "w")) == NIL(FILE) )
758 Open_temp_error( tmpname
, name
);
760 /* Don't free tmpname, it's stored in a FILELIST member in Link_temp(). */
761 Link_temp( cp
, fp
, tmpname
);
764 /* As Get_temp() doesn't provide a definable suffix (anymore) we create an
765 * additional temporary file with that suffix. */
766 if ( suffix
&& *suffix
) {
769 /* Only use umask if we are also using mkstemp - this basically
770 * avoids using the incompatible implementation from MSVC. */
776 fname_suff
= DmStrJoin( tmpname
, suffix
, -1, FALSE
);
778 /* Overwrite macro, Get_temp didn't know of the suffix. */
779 Def_macro( "TMPFILE", DO_WINPATH(fname_suff
), M_MULTI
|M_EXPANDED
);
781 if( (fp2
= fopen(fname_suff
, "w" )) == NIL(FILE) )
782 Open_temp_error( fname_suff
, name
);
787 /* Don't free fname_suff. */
788 Link_temp( cp
, fp2
, fname_suff
);
798 ** Issue an error on failing to open a temporary file
801 Open_temp_error( tmpname
, name
)
805 Fatal("Cannot open temp file `%s' while processing `%s'", tmpname
, name
);
810 ** Link a temp file onto the list of files.
813 Link_temp( cp
, fp
, fname
)
820 if( cp
== NIL(CELL
) ) cp
= Root
;
822 TALLOC( new, 1, FILELIST
);
824 new->fl_next
= cp
->ce_files
;
825 new->fl_name
= fname
;
826 new->fl_file
= fp
; /* indicates temp file is open */
833 ** Close a previously used temporary file.
841 if( cp
== NIL(CELL
) ) cp
= Root
;
843 for( fl
=cp
->ce_files
; fl
&& fl
->fl_file
!= file
; fl
=fl
->fl_next
);
845 fl
->fl_file
= NIL(FILE);
852 ** Clean-up, and close all temporary files associated with a target.
855 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. */
861 FILELISTPTR cur
, next
;
863 if( cp
== NIL(CELL
) || cp
->ce_files
== NIL(FILELIST
) ) return;
865 for( cur
=cp
->ce_files
; cur
!= NIL(FILELIST
); cur
=next
) {
868 if( cur
->fl_file
) fclose( cur
->fl_file
);
870 if( Verbose
& V_LEAVE_TMP
)
871 fprintf( stderr
, "%s: Left temp file [%s]\n", Pname
, cur
->fl_name
);
873 (void) Remove_file( cur
->fl_name
);
879 cp
->ce_files
= NIL(FILELIST
);
884 Handle_result(status
, ignore
, abort_flg
, target
)/*
885 ==================================================
886 Handle return value of recipe.
893 status
= ((status
&0xff)==0 ? status
>>8 /* return from exit() */
894 : (status
& 0xff)==SIGTERM
? -1 /* terminated from SIGTERM */
895 : (status
& 0x7f)+128); /* terminated from signal
902 sprintf(buf
, "%s: Error code %d, while making '%s'",
903 Pname
, status
, target
->ce_fname
);
905 if( ignore
|| Continue
) {
906 if (!(Glob_attr
& A_SILENT
)) {
907 strcat(buf
, " (Ignored" );
910 /* Continue after error if '-k' was used. */
911 strcat(buf
,",Continuing");
912 target
->ce_attr
|= A_ERROR
;
916 fprintf(stderr
, "%s\n", buf
);
919 if( target
->ce_attr
& A_ERRREMOVE
920 && Remove_file( target
->ce_fname
) == 0
921 && !(Glob_attr
& A_SILENT
))
922 fprintf(stderr
,"%s: '%s' removed.\n", Pname
, target
->ce_fname
);
925 fprintf(stderr
, "%s\n",buf
);
927 if(!(target
->ce_attr
& A_PRECIOUS
)||(target
->ce_attr
& A_ERRREMOVE
))
928 if( Remove_file( target
->ce_fname
) == 0 )
929 fprintf(stderr
,"%s: '%s' removed.\n", Pname
,
935 else if(!(target
->ce_attr
& A_PRECIOUS
)||(target
->ce_attr
& A_ERRREMOVE
))
936 Remove_file( target
->ce_fname
);
942 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. */
953 int phony
= ((cp
->ce_attr
&A_PHONY
) != 0);
955 for(dp
=CeMeToo(cp
); dp
; dp
=dp
->cl_next
) {
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
961 mintime
= tcp
->ce_time
;
963 if( tcp
->ce_attr
& A_LIBRARY
)
964 Void_lib_cache( tcp
->ce_fname
, NIL(char) );
965 else if( !Touch
&& (tcp
->ce_attr
& A_LIBRARYM
) )
966 Void_lib_cache( tcp
->ce_lib
, tcp
->ce_fname
);
968 /* phony targets are treated as if they were recently made
969 * and get the current time assigned. */
971 tcp
->ce_time
= Do_time();
974 tcp
->ce_time
= Do_time();
977 Stat_target(tcp
, -1, TRUE
);
979 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
985 * Targets with recipes are treated as if they were recently
986 * made and get the current time assigned. */
987 if( cp
->ce_recipe
== NIL(STRING
) && mintime
> 1 ) {
988 tcp
->ce_time
= mintime
;
991 tcp
->ce_time
= Do_time();
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
999 if( cp
->ce_recipe
== NIL(STRING
) ) {
1000 time_t newtime
= ( mintime
> 1 ? mintime
: Do_time() );
1002 if( !(tcp
->ce_attr
& A_SILENT
) )
1003 Warning( "Found file corresponding to virtual target [%s].",
1006 if( newtime
> tcp
->ce_time
)
1007 tcp
->ce_time
= mintime
;
1013 tcp
->ce_flag
|= F_STAT
; /* pretend we stated ok */
1016 if( Verbose
& V_MAKE
)
1017 printf( "%s: <<<< Set [%s] time stamp to %lu\n",
1018 Pname
, tcp
->CE_NAME
, tcp
->ce_time
);
1020 if( Measure
& M_TARGET
)
1021 Do_profile_output( "e", M_TARGET
, tcp
);
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 if( tcp
->ce_time
< mintime
&& !(tcp
->ce_attr
& A_SILENT
) ) {
1028 Warning( "Target [%s] was made but the time stamp has not been updated.",
1032 /* The target was made, remove the temp files now. */
1033 Unlink_temp_files( tcp
);
1034 tcp
->ce_flag
|= F_MADE
;
1035 tcp
->ce_attr
|= A_UPDATED
;
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 $< .) */
1047 /* Make sure we don't try to remove prerequisites for the .REMOVE
1049 if( strcmp(cp
->CE_NAME
,".REMOVE") != 0 &&
1050 (hp
= Get_name(".REMOVE", Defs
, FALSE
)) != NIL(HASH
) ) {
1051 register LINKPTR dp
;
1058 /* The .REMOVE target is re-used. Remove old prerequisites. */
1059 tcp
->ce_flag
|= F_TARGET
;
1060 Clear_prerequisites( tcp
);
1062 for(dp
=cp
->ce_prq
; dp
!= NIL(LINK
); dp
=dp
->cl_next
) {
1063 register CELLPTR prq
= dp
->cl_prq
;
1065 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 rem
= (prq
->ce_flag
& F_REMOVE
) &&
1071 (prq
->ce_flag
& F_MADE
) &&
1072 !(prq
->ce_count
) && /* Don't remove F_MULTI subtargets. */
1073 !(prq
->ce_attr
& A_PHONY
) &&
1074 !(attr
& A_PRECIOUS
);
1076 /* remove if rem is != 0 */
1080 /* Add the target plus all that are linked to it with the .UPDATEALL
1082 for(tdp
=CeMeToo(prq
); tdp
; tdp
=tdp
->cl_next
) {
1083 CELLPTR tmpcell
=tdp
->cl_prq
;
1085 (Add_prerequisite(tcp
,tmpcell
,FALSE
,FALSE
))->cl_flag
|=F_TARGET
;
1086 tmpcell
->ce_flag
&= ~F_REMOVE
;
1093 int sv_force
= Force
;
1099 for(dp
=tcp
->ce_prq
; dp
!= NIL(LINK
); dp
=dp
->cl_next
) {
1100 register CELLPTR prq
= dp
->cl_prq
;
1102 prq
->ce_flag
&= ~(F_MADE
|F_VISITED
|F_STAT
);
1103 prq
->ce_flag
|= F_REMOVE
;
1104 prq
->ce_time
= (time_t)0L;
1117 if( stat(name
, &buf
) != 0 )
1119 if( (buf
.st_mode
& S_IFMT
) == S_IFDIR
)
1121 return(unlink(name
));
1125 #if defined(__CYGWIN__)
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.
1133 static char *buf
= NIL(char);
1135 if ( !buf
&& ( (buf
= MALLOC( PATH_MAX
, char)) == NIL(char) ) )
1138 DB_PRINT( "cygdospath", ("converting [%s] with winpath [%d]", src
, winpath
) );
1140 /* Return immediately on NULL pointer or when .WINPATH is
1142 if( !src
|| !winpath
)
1145 if( *src
&& src
[0] == '/' ) {
1147 int err
= cygwin_conv_to_win32_path(src
, buf
);
1149 Fatal( "error converting \"%s\" - %s\n",
1150 src
, strerror (errno
));
1153 while ((tmp
= strchr (tmp
, '\\')) != NULL
) {