From 305191454de4b8775045fe791239e7fb658996a4 Mon Sep 17 00:00:00 2001
From: Jens-Heiner Rechtien
Date: Thu, 20 Apr 2006 11:00:12 +0000
Subject: INTEGRATION: CWS dmake43p01 (1.7.6); FILE MERGED 2006/03/13 23:21:27
vq 1.7.6.10: #i61390# Make dmake (gcc) build -Wall warning free. 2006/02/01
23:28:55 vq 1.7.6.9: #i60948# Add -m option family to generate timing
information for targets and/or recipes. (Autotools files were regenerated.)
2005/10/25 17:19:43 vq 1.7.6.8: #i53148# Restore old behaviour for non-*NIX
dmake versions. 2005/10/11 17:39:38 vq 1.7.6.7: #i54938# Fix problem when
building infered .INCLUDE makefiles and doing parallel builds. 2005/09/05
20:56:45 vq 1.7.6.6: #i53148# Move redirection of stdout from parent to child
and avoid capturing spurious output from other process queues. 2005/09/05
17:23:44 vq 1.7.6.5: #i53148# Additional patch to make sure that the shell
escapes is executed after all previous recipe lines from the same target have
finished. 2005/09/04 19:38:14 vq 1.7.6.4: #i53148# Fix $(shell ...) handling
for parallel builds with MAXPROCESS > 1. This certainly includes the -P#
switch with # > 1. 2005/06/01 23:48:57 vq 1.7.6.3: #i50091# Echo shell
function macro commands. 2004/11/25 16:09:31 vq 1.7.6.2: #i36027# Fix MSVC
compilation problem. 2004/11/21 17:40:17 vq 1.7.6.1: #i36027# Improve parsing
for dmake function macros.
---
dmake/function.c | 172 ++++++++++++++++++++++++++++++++++++++-----------------
1 file changed, 119 insertions(+), 53 deletions(-)
(limited to 'dmake/function.c')
diff --git a/dmake/function.c b/dmake/function.c
index 1638dae80122..82c8ef7e1ee0 100644
--- a/dmake/function.c
+++ b/dmake/function.c
@@ -1,6 +1,6 @@
/* $RCSfile: function.c,v $
--- $Revision: 1.7 $
--- last change: $Author: rt $ $Date: 2004-09-08 16:06:20 $
+-- $Revision: 1.8 $
+-- last change: $Author: hr $ $Date: 2006-04-20 12:00:12 $
--
-- SYNOPSIS
-- GNU style functions for dmake.
@@ -58,23 +58,48 @@ char *buf;
char *args;
char *mod1;
char *mod2 = NIL(char);
+ int mod_count = 0;
char *res = NIL(char);
/* This must succeed since the presence of ' ', \t or \n is what
- * determines if this function is called in the first place. */
+ * determines if this function is called in the first place.
+ * Unfortunately this prohibits the use of whitespaces in parameters
+ * for macro functions. */
+ /* ??? Using ScanToken to find the next ' ', \t or \n and discarding
+ * the returned, evaluated result is a misuse of that function. */
FREE(ScanToken(buf, &args, FALSE));
fname = DmSubStr(buf, args);
+ /* args points to the whitespace after the found token, this leads
+ * to leading whitespaces. */
+ if( *args ) {
+ args = DmStrSpn(args," \t"); /* strip whitespace before */
+ if( *args ) { /* ... and after value */
+ char *q;
+ for(q=args+strlen(args)-1; ((*q == ' ')||(*q == '\t')); q--);
+ *++q = '\0';
+ }
+ }
+ /* ??? Some function macros expect comma seperated parameters, but
+ * no decent parser is included. The desirable solution would be
+ * to parse fname for the correct number of parameters in fname
+ * when a function is recognized. We only count the parameters
+ * at the moment. Note "" is a valid parameter. */
if( (mod1 = strchr(fname,',')) != NIL(char) ){
*mod1 = '\0';
mod1++;
+ mod_count++;
if( (mod2 = strchr(mod1,',')) != NIL(char) ){
*mod2 = '\0';
mod2++;
+ mod_count++;
}
}
+ /* ??? At the moment only the leading part of fname compared if it
+ * matches a known function macro. For example assignXXX or even
+ * assign,,,, is also erroneously accepted. */
switch( *fname ) {
case 'a':
if(strncmp(fname,"assign",6) == 0)
@@ -87,7 +112,10 @@ char *buf;
case 'e':
if(strncmp(fname,"eq",2) == 0)
- res = _exec_iseq(mod1,mod2,args,TRUE);
+ if( mod_count == 2 )
+ res = _exec_iseq(mod1,mod2,args,TRUE);
+ else
+ Fatal( "Two comma-seperated arguments expected in [%s].\n", buf );
else if (strncmp(fname,"echo",4) == 0)
res = _exec_echo(args);
else
@@ -96,16 +124,22 @@ char *buf;
case 'f':
if(strncmp(fname,"foreach",7) == 0)
+ if( mod_count == 2 )
res = _exec_foreach(mod1,mod2,args);
- else
- res = _exec_call(fname,args);
+ else
+ Fatal( "Two comma-seperated arguments expected in [%s].\n", buf );
+ else
+ res = _exec_call(fname,args);
break;
case 'm':
if(strncmp(fname,"mktmp",5) == 0)
- res = _exec_mktmp(mod1,mod2,args);
- else
- res = _exec_call(fname,args);
+ if( mod_count < 3 )
+ res = _exec_mktmp(mod1,mod2,args);
+ else
+ Fatal( "Maximal two comma-seperated arguments expected in [%s].\n", buf );
+ else
+ res = _exec_call(fname,args);
break;
case 'n':
@@ -123,9 +157,12 @@ char *buf;
if(strncmp(fname,"!null",5) == 0)
res = _exec_iseq(mod1,NIL(char),args,FALSE);
else if(strncmp(fname,"!eq",3) ==0)
- res = _exec_iseq(mod1,mod2,args,FALSE);
- else
- res = _exec_call(fname,args);
+ if( mod_count == 2 )
+ res = _exec_iseq(mod1,mod2,args,FALSE);
+ else
+ Fatal( "Two comma-seperated arguments expected in [%s].\n", buf );
+ else
+ res = _exec_call(fname,args);
break;
case 'o':
@@ -142,8 +179,12 @@ char *buf;
res = _exec_shell(args,mod1);
else if(strncmp(fname,"strip",5)==0)
res = Tokenize(Expand(args)," ",'t',TRUE);
- else if(strncmp(fname,"subst",5)==0)
- res = _exec_subst(mod1,mod2,args);
+ else if(strncmp(fname,"subst",5)==0) {
+ if( mod_count == 2 )
+ res = _exec_subst(mod1,mod2,args);
+ else
+ Fatal( "Two comma-seperated arguments expected in [%s].\n", buf );
+ }
else
res = _exec_call(fname,args);
break;
@@ -286,14 +327,13 @@ char *data;
name = Current_target ? Current_target->CE_NAME:"makefile text";
if( file && *file ) {
- char *newtmp;
-
/* This call to Get_temp sets TMPFILE for subsequent expansion of file.
* The contents file variable passed may include TMPFILE to be expanded. */
/* Using TMPFILE as an argument to mktmp is no longer supported because it is not
* safe to create a random filename and assume the file does not exist. Howver,
* we still allow Expand() to do its job for fixed filenames */
- /* Get_temp( &newtmp, "", FALSE ); FREE(newtmp); */
+ /* char *newtmp;
+ * Get_temp( &newtmp, "", FALSE ); FREE(newtmp); */
tmpname = Expand(file);
if( *tmpname ) {
@@ -455,6 +495,8 @@ char *data;
pat = Expand(pat);
subst = Expand(subst);
+
+ /* This implies FREE(Expand(data)) */
res = Apply_edit( Expand(data), pat, subst, TRUE, FALSE );
FREE(pat);
FREE(subst);
@@ -464,19 +506,24 @@ char *data;
static char *
-_exec_shell( data, mod1 )
+_exec_shell( data, mod1 )/*
+===========================
+ Capture the stdout of an execuded command. */
char *data;
char *mod1;
{
extern char *tempnam();
- static int nestlevel = 0;
- static int org_out;
- static int bsize;
- static char *buffer;
- static char *tmpnm;
- static FILE *tmp;
+ int bsize;
+ char *buffer;
+ char *tmpnm;
+ FILE *old_stdout_redir = stdout_redir;
+#if !defined(USE_SANE_EXEC_SHELL_REDIR)
+ int old_stdout;
+#endif
int wait = Wait_for_completion;
+ int old_is_exec_shell = Is_exec_shell;
+ CELLPTR old_Shell_exec_target = Shell_exec_target;
uint16 vflag = Verbose;
int tflag = Trace;
char *res = NIL(char);
@@ -505,62 +552,81 @@ char *mod1;
cell.ce_fname = cname.ht_name;
cell.ce_recipe = &rcp;
cell.ce_flag = F_TARGET|F_RULES;
- cell.ce_attr = A_PHONY|A_SILENT;
+ /* Setting A_SILENT supresses the recipe output from Print_cmnd(). */
+ cell.ce_attr = A_PHONY|A_SILENT|A_SHELLESC;
- if( nestlevel == 0 ) {
- org_out = dup(1);
+ if( Measure & M_TARGET )
+ Do_profile_output( "s", M_TARGET, &cell );
- if( (tmp = Get_temp(&tmpnm, "", "w+")) == NIL(FILE) )
- Open_temp_error( tmpnm, cname.ht_name );
+ /* Print the shell escape command. */
+ if( !(rcp.st_attr & A_SILENT) ) {
+ printf( "%s: Executing shell macro: %s\n", Pname, data );
+ fflush(stdout);
+ }
- close(1);
- dup( fileno(tmp) );
+ if( (stdout_redir = Get_temp(&tmpnm, "", "w+")) == NIL(FILE) )
+ Open_temp_error( tmpnm, cname.ht_name );
- bsize = (Buffer_size < BUFSIZ)?BUFSIZ:Buffer_size;
- buffer = MALLOC(bsize,char);
- }
+ bsize = (Buffer_size < BUFSIZ)?BUFSIZ:Buffer_size;
+ buffer = MALLOC(bsize,char);
+ /* As this function redirects the output of stdout we have to make sure
+ * that only this single command is executed and all previous recipe lines
+ * that belong to the same target have finished. With Shell_exec_target and
+ * Wait_for_completion set this is realized. Current_target being NIL(CELL)
+ * outside of recipe lines makes sure that no waiting for previous recipe
+ * lines has to be done. */
Wait_for_completion = TRUE;
+ Is_exec_shell = TRUE;
+ Shell_exec_target = Current_target;
Verbose &= V_LEAVE_TMP;
Trace = FALSE;
- nestlevel++;
+
+ /* Only unix type builds define the redirection of stdout in the forked
+ * child process. Other OSs have to do it here, in the parent process.
+ * Note! This is not save for parallel builds, see #iz53148#, but parallel
+ * builds are not supported for non-unix like builds anyway. */
+#if !defined(USE_SANE_EXEC_SHELL_REDIR)
+ old_stdout = dup(1);
+ close(1);
+ dup( fileno(stdout_redir) );
+#endif
Exec_commands( &cell );
+#if !defined(USE_SANE_EXEC_SHELL_REDIR)
+ close(1);
+ dup(old_stdout);
+#endif
Unlink_temp_files( &cell );
- nestlevel--;
+
Trace = tflag;
Verbose = vflag;
Wait_for_completion = wait;
+ Is_exec_shell = old_is_exec_shell;
+ Shell_exec_target = old_Shell_exec_target;
/* Now we have to read the temporary file, get the tokens and return them
* as a string. */
- rewind(tmp);
- while( fgets(buffer, bsize, tmp) ) {
+ rewind(stdout_redir);
+ while( fgets(buffer, bsize, stdout_redir) ) {
char *p = strchr(buffer, '\n');
if( p == NIL(char) )
res = DmStrJoin(res,buffer,-1,TRUE);
else {
*p = '\0';
+ /* You might encounter '\r\n' on windows, handle it. */
+ if( p > buffer && *(p-1) == '\r')
+ *(p-1) = '\0';
res = DmStrApp(res,buffer);
}
}
- fclose(tmp);
- if( nestlevel == 0 ) {
- close(1);
- dup(org_out);
- close(org_out);
- Remove_file(tmpnm);
- FREE(tmpnm);
- FREE(buffer);
- }
- else {
- if( (tmp = fopen(tmpnm, "w+")) == NIL(FILE) )
- Open_temp_error( tmpnm, cname.ht_name );
+ fclose(stdout_redir);
+ Remove_file(tmpnm);
+ FREE(tmpnm);
+ FREE(buffer);
- close(1);
- dup( fileno(tmp) );
- }
+ stdout_redir = old_stdout_redir;
if ( mod1 ) {
mod1 = Expand(res);
--
cgit