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.
This commit is contained in:
parent
cfbaf9c933
commit
305191454d
1 changed files with 120 additions and 54 deletions
142
dmake/function.c
142
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)
|
||||
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,14 +124,20 @@ char *buf;
|
|||
|
||||
case 'f':
|
||||
if(strncmp(fname,"foreach",7) == 0)
|
||||
if( mod_count == 2 )
|
||||
res = _exec_foreach(mod1,mod2,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)
|
||||
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;
|
||||
|
@ -123,7 +157,10 @@ char *buf;
|
|||
if(strncmp(fname,"!null",5) == 0)
|
||||
res = _exec_iseq(mod1,NIL(char),args,FALSE);
|
||||
else if(strncmp(fname,"!eq",3) ==0)
|
||||
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;
|
||||
|
@ -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)
|
||||
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) )
|
||||
/* Print the shell escape command. */
|
||||
if( !(rcp.st_attr & A_SILENT) ) {
|
||||
printf( "%s: Executing shell macro: %s\n", Pname, data );
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
if( (stdout_redir = Get_temp(&tmpnm, "", "w+")) == NIL(FILE) )
|
||||
Open_temp_error( tmpnm, cname.ht_name );
|
||||
|
||||
close(1);
|
||||
dup( fileno(tmp) );
|
||||
|
||||
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);
|
||||
fclose(stdout_redir);
|
||||
Remove_file(tmpnm);
|
||||
FREE(tmpnm);
|
||||
FREE(buffer);
|
||||
}
|
||||
else {
|
||||
if( (tmp = fopen(tmpnm, "w+")) == NIL(FILE) )
|
||||
Open_temp_error( tmpnm, cname.ht_name );
|
||||
|
||||
close(1);
|
||||
dup( fileno(tmp) );
|
||||
}
|
||||
stdout_redir = old_stdout_redir;
|
||||
|
||||
if ( mod1 ) {
|
||||
mod1 = Expand(res);
|
||||
|
|
Loading…
Reference in a new issue