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