Version 3.6.0.4, tag libreoffice-3.6.0.4
[LibreOffice.git] / dmake / sysintf.c
blobc8cf756b19b97faf885744b9488eec48f4e0d37a
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()
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.
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 occurred
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) );
424 ** Set the value of the environment string ename to value.
425 ** Returns 0 if success, non-zero if failure
427 PUBLIC int
428 Write_env_string(ename, value)
429 char *ename;
430 char *value;
432 #if defined(HAVE_SETENV)
434 return( setenv(ename, value, 1) );
436 #else /* !HAVE_SETENV */
438 char* p;
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 */
451 PUBLIC void
452 ReadEnvironment()
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;
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
472 make_env();
474 rsave = Rule_tab;
475 Rule_tab = environ;
476 Readenv = TRUE;
478 Parse( NIL(FILE) );
480 Readenv = FALSE;
481 Rule_tab = rsave;
483 free_env();
489 ** All we have to catch is SIGINT
491 PUBLIC void
492 Catch_signals(fn)
493 void (*fn)(int);
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
507 PUBLIC void
508 Clear_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 );
519 ** Set program name
521 PUBLIC void
522 Prolog(argc, argv)
523 int argc;
524 char* argv[];
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));
532 #else
533 AbsPname = "";
534 #endif
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;
558 #endif
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 DirSepStr = "/";
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;
574 tzset();
580 ** Do any clean up for exit.
582 PUBLIC void
583 Epilog(ret_code)
584 int ret_code;
586 Write_state();
587 Unlink_temp_files(Root);
588 Hook_std_writes(NIL(char)); /* For MSDOS tee (-F option) */
589 exit( ret_code );
595 ** Use the built-in functions of the operating system to get the current
596 ** working directory.
598 PUBLIC char *
599 Get_current_dir()
601 static char buf[PATH_MAX+2];
603 if( !getcwd(buf, sizeof(buf)) )
604 Fatal("Internal Error: Error when calling getcwd()!");
606 #ifdef __EMX__
607 char *slash;
608 slash = buf;
609 while( (slash=strchr(slash,'/')) )
610 *slash = '\\';
611 #endif
613 return buf;
619 ** change working directory
621 PUBLIC int
622 Set_dir(path)
623 char* path;
625 return( chdir(path) );
631 ** return switch char
633 PUBLIC char
634 Get_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
645 the file is removed.
647 char *tmpdir;
648 char **path;
650 int fd; /* file descriptor */
652 #if defined(HAVE_MKSTEMP)
653 mode_t mask;
655 *path = DmStrJoin( tmpdir, DirSepStr, -1, FALSE);
656 *path = DmStrJoin( *path, "mkXXXXXX", -1, TRUE );
658 mask = umask(0066);
659 fd = mkstemp( *path );
660 umask(mask);
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;
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
679 #error mkstemp() or tempnam() is needed
681 #endif
683 return fd;
687 PUBLIC FILE*
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.
697 char **path;
698 char *mode;
700 int fd;
701 FILE *fp;
702 char *tmpdir;
703 int tries = 20;
705 tmpdir = Read_env_string( "TMPDIR" );
706 if( tmpdir == NIL(char) )
707 tmpdir = "/tmp";
709 while( --tries )
711 /* This sets path to the name of the created temp file. */
712 if( (fd = Create_temp(tmpdir, path)) != -1)
713 break;
715 free(*path); /* free var if creating temp failed. */
718 if( fd != -1)
720 Def_macro( "TMPFILE", DO_WINPATH(*path), M_MULTI|M_EXPANDED );
721 /* associate stream with file descriptor */
722 fp = fdopen(fd, mode);
724 else
725 fp = NIL(FILE);
727 return fp;
731 PUBLIC FILE *
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.
745 char *suffix;
746 CELLPTR cp;
747 char **fname;
749 FILE *fp, *fp2;
750 char *tmpname;
751 char *name;
752 char *fname_suff;
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 );
762 *fname = 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 ) {
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;
773 mask = umask(0066);
774 #endif
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 );
783 #ifdef HAVE_MKSTEMP
784 umask(mask);
785 #endif
787 /* Don't free fname_suff. */
788 Link_temp( cp, fp2, fname_suff );
789 fp = fp2;
790 *fname = fname_suff;
793 return( fp );
798 ** Issue an error on failing to open a temporary file
800 PUBLIC void
801 Open_temp_error( tmpname, name )
802 char *tmpname;
803 char *name;
805 Fatal("Cannot open temp file `%s' while processing `%s'", tmpname, name );
810 ** Link a temp file onto the list of files.
812 PUBLIC void
813 Link_temp( cp, fp, fname )
814 CELLPTR cp;
815 FILE *fp;
816 char *fname;
818 FILELISTPTR new;
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 */
828 cp->ce_files = new;
833 ** Close a previously used temporary file.
835 PUBLIC void
836 Close_temp(cp, file)
837 CELLPTR cp;
838 FILE *file;
840 FILELISTPTR fl;
841 if( cp == NIL(CELL) ) cp = Root;
843 for( fl=cp->ce_files; fl && fl->fl_file != file; fl=fl->fl_next );
844 if( fl ) {
845 fl->fl_file = NIL(FILE);
846 fclose(file);
852 ** Clean-up, and close all temporary files associated with a target.
854 PUBLIC void
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. */
859 CELLPTR cp;
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 ) {
866 next = cur->fl_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 );
872 else
873 (void) Remove_file( cur->fl_name );
875 FREE(cur->fl_name);
876 FREE(cur);
879 cp->ce_files = NIL(FILELIST);
883 PUBLIC void
884 Handle_result(status, ignore, abort_flg, target)/*
885 ==================================================
886 Handle return value of recipe.
888 int status;
889 int ignore;
890 int abort_flg;
891 CELLPTR target;
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
896 * ( =status-128 ) */
898 if( status ) {
899 if( !abort_flg ) {
900 char buf[512];
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" );
909 if ( Continue ) {
910 /* Continue after error if '-k' was used. */
911 strcat(buf,",Continuing");
912 target->ce_attr |= A_ERROR;
914 strcat(buf,")");
915 if (Verbose)
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);
924 else {
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,
930 target->ce_fname);
932 Quit(0);
935 else if(!(target->ce_attr & A_PRECIOUS)||(target->ce_attr & A_ERRREMOVE))
936 Remove_file( target->ce_fname );
941 PUBLIC void
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. */
947 CELLPTR cp;
949 HASHPTR hp;
950 LINKPTR dp;
951 CELLPTR tcp;
952 time_t mintime;
953 int phony = ((cp->ce_attr&A_PHONY) != 0);
955 for(dp=CeMeToo(cp); dp; dp=dp->cl_next) {
956 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 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. */
970 if( phony ) {
971 tcp->ce_time = Do_time();
973 else if (Trace) {
974 tcp->ce_time = Do_time();
976 else {
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
984 * in mintime.)
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;
990 else {
991 tcp->ce_time = Do_time();
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 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].",
1004 tcp->CE_NAME );
1006 if( newtime > tcp->ce_time )
1007 tcp->ce_time = mintime;
1012 if( Trace ) {
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.",
1029 tcp->CE_NAME );
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
1048 * target. */
1049 if( strcmp(cp->CE_NAME,".REMOVE") != 0 &&
1050 (hp = Get_name(".REMOVE", Defs, FALSE)) != NIL(HASH) ) {
1051 register LINKPTR dp;
1052 int flag = FALSE;
1053 int rem;
1054 t_attr attr;
1056 tcp = hp->CP_OWNR;
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 */
1077 if(rem) {
1078 LINKPTR tdp;
1080 /* Add the target plus all that are linked to it with the .UPDATEALL
1081 * attribute. */
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;
1088 flag = TRUE;
1092 if( flag ) {
1093 int sv_force = Force;
1095 Force = FALSE;
1096 Remove_prq( tcp );
1097 Force = sv_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;
1111 PUBLIC int
1112 Remove_file( name )
1113 char *name;
1115 struct stat buf;
1117 if( stat(name, &buf) != 0 )
1118 return 1;
1119 if( (buf.st_mode & S_IFMT) == S_IFDIR )
1120 return 1;
1121 return(unlink(name));
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.
1133 static char *buf = NIL(char);
1135 if ( !buf && ( (buf = MALLOC( PATH_MAX, char)) == NIL(char) ) )
1136 No_ram();
1138 DB_PRINT( "cygdospath", ("converting [%s] with winpath [%d]", src, winpath ) );
1140 /* Return immediately on NULL pointer or when .WINPATH is
1141 * not set. */
1142 if( !src || !winpath )
1143 return src;
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));
1152 tmp = buf;
1153 while ((tmp = strchr (tmp, '\\')) != NULL) {
1154 *tmp = '/';
1155 tmp++;
1158 return buf;
1160 else
1161 return src;
1163 #endif