diff options
Diffstat (limited to 'dmake/expand.c')
-rw-r--r-- | dmake/expand.c | 1202 |
1 files changed, 0 insertions, 1202 deletions
diff --git a/dmake/expand.c b/dmake/expand.c deleted file mode 100644 index 4256f17d49fb..000000000000 --- a/dmake/expand.c +++ /dev/null @@ -1,1202 +0,0 @@ -/* --- --- SYNOPSIS --- Macro expansion code. --- --- DESCRIPTION --- --- This routine handles all the necessary junk that deals with macro --- expansion. It understands the following syntax. If a macro is --- not defined it expands to NULL, and {} are synonyms for (). --- --- $$ - expands to $ --- {{ - expands to { --- }} - expands to } --- $A - expands to whatever the macro A is defined as --- $(AA) - expands to whatever the macro AA is defined as --- $($(A)) - represents macro indirection --- <+...+> - get mapped to $(mktmp ...) --- --- following macro is recognized --- --- string1{ token_list }string2 --- --- and expands to string1 prepended to each element of token_list and --- string2 appended to each of the resulting tokens from the first --- operation. If string2 is of the form above then the result is --- the cross product of the specified (possibly modified) token_lists. --- --- The folowing macro modifiers are defined and expanded: --- --- $(macro:modifier_list:modifier_list:...) --- --- where modifier_list a combination of: --- --- D or d - Directory portion of token including separator --- F or f - File portion of token including suffix --- B or b - basename portion of token not including suffix --- E or e - Suffix portion of name --- L or l - translate to lower case --- U or u - translate to upper case --- I or i - return inferred names --- N or n - return normalized paths --- 1 - return the first white space separated token --- --- or a single one of: --- M or m - map escape codes --- S or s - pattern substitution (simple) --- T or t - for tokenization --- ^ - prepend a prefix to each token --- + - append a suffix to each token --- --- NOTE: Modifiers are applied once the macro value has been found. --- Thus the construct $($(test):s/joe/mary/) is defined and --- modifies the value of $($(test)) --- --- Also the construct $(m:d:f) is not the same as $(m:df) --- the first applies d to the value of $(m) and then --- applies f to the value of that whereas the second form --- applies df to the value of $(m). --- --- AUTHOR --- Dennis Vadura, dvadura@dmake.wticorp.com --- --- WWW --- http://dmake.wticorp.com/ --- --- COPYRIGHT --- Copyright (c) 1996,1997 by WTI Corp. All rights reserved. --- --- This program is NOT free software; you can redistribute it and/or --- modify it under the terms of the Software License Agreement Provided --- in the file <distribution-root>/readme/license.txt. --- --- LOG --- Use cvs log to obtain detailed change logs. -*/ - -#include "extern.h" - -/* Microsoft BRAINDAMAGE ALERT!!!! - * This #ifdef is here only to satisfy stupid bugs in MSC5.0 and MSC5.1 - * it isn't needed for anything else. It turns loop optimization off. */ -#if defined(_MSV_VER) && _MSC_VER < 600 -#include "optoff.h" -#endif - -static char* _scan_macro ANSI((char*, char**, int)); -static char* _scan_brace ANSI((char*, char**, int*)); -static char* _cross_prod ANSI((char*, char*)); - -#if !defined(__GNUC__) && !defined(__IBMC__) -static char* _scan_ballanced_parens ANSI((char*, char)); -#else -static char* _scan_ballanced_parens ANSI((char*, int)); -#endif - - -PUBLIC char * -Expand( src )/* -=============== - This is the driver routine for the expansion, it identifies non-white - space tokens and gets the ScanToken routine to figure out if they should - be treated in a special way. */ - -char *src; /* pointer to source string */ -{ - char *tmp; /* pointer to temporary str */ - char *res; /* pointer to result string */ - char *start; /* pointer to start of token */ - - DB_ENTER( "Expand" ); - DB_PRINT( "exp", ("Expanding [%s]", src) ); - - res = DmStrDup( "" ); - if( src == NIL(char) ) DB_RETURN( res ); - - while( *src ) { - char *ks, *ke; - - /* Here we find the next non white space token in the string - * and find it's end, with respect to non-significant white space. */ - -#if !defined( _MPW) && !defined(__EMX__) - start = DmStrSpn( src, " \t\n" ); -#else - start = DmStrSpn( src, " \t\r\n" ); -#endif - - res = DmStrJoin( res, src, start-src, TRUE ); - if( !(*start) ) break; - - /* START <+...+> KLUDGE */ - if( (ks=DmStrStr(start,"<+")) != NIL(char) - && (ke=DmStrStr(ks,"+>")) != NIL(char) ) { - char *t1, *t2; - - res = DmStrJoin( res, t2=Expand(t1=DmSubStr(start,ks)), -1, TRUE); - FREE(t1); FREE(t2); - - t1 = DmSubStr(ks+2, ke+1); t1[ke-ks-2] = ')'; - t2 = DmStrJoin( "$(mktmp ", t1, -1,FALSE); - FREE(t1); - res = DmStrJoin( res, t1=Expand(t2), -1, TRUE); - FREE(t1); FREE(t2); - src = ke+2; - } - /* END <+...+> KLUDGE */ - else { - res = DmStrJoin( res, tmp = ScanToken(start,&src,TRUE), -1, TRUE ); - FREE( tmp ); - } - } - - DB_PRINT( "exp", ("Returning [%s]", res) ); - DB_RETURN( res ); -} - - -PUBLIC char * -Apply_edit( src, pat, subst, fr, anchor )/* -=========================================== - Take the src string and apply the pattern substitution. ie. look for - occurrences of pat in src and replace each occurrence with subst. This is - NOT a regular expressions pattern substitution, it's just not worth it. - - if anchor == TRUE then the src pattern match must be at the end of a token. - ie. this is for SYSV compatibility and is only used for substitutions of - the caused by $(macro:pat=sub). So if src = "fre.o.k june.o" then - $(src:.o=.a) results in "fre.o.k june.a", and $(src:s/.o/.a) results in - "fre.a.k june.a" */ - -char *src; /* the source string */ -char *pat; /* pattern to find */ -char *subst; /* substitute string */ -int fr; /* if TRUE free src */ -int anchor; /* if TRUE anchor */ -{ - char *res; - char *p; - char *s; - int l; - - DB_ENTER( "Apply_edit" ); - - /* do nothing if pat is NULL or pat and subst are equal */ - if( !*pat || !strcmp(pat,subst) ) DB_RETURN( src ); - - DB_PRINT( "mod", ("Source str: [%s]", src) ); - DB_PRINT( "mod", ("Replacing [%s], with [%s]", pat, subst) ); - - /* FIXME: This routine is used frequently and has room for optimizations */ - s = src; - l = strlen( pat ); - if( (p = DmStrStr( s, pat )) != NIL(char) ) { - res = DmStrDup( "" ); - do { - if( anchor ) - if( !*(p+l) || (strchr(" \t", *(p+l)) != NIL(char)) ) - res = DmStrJoin( DmStrJoin(res,s,p-s,TRUE), subst, -1, TRUE ); - else - res = DmStrJoin( res, s, p+l-s, TRUE ); - else - res = DmStrJoin( DmStrJoin(res,s,p-s,TRUE), subst, -1, TRUE ); - - s = p + l; - } - while( (p = DmStrStr( s, pat )) != NIL(char) ); - - res = DmStrJoin( res, s, -1, TRUE ); - if( fr ) FREE( src ); - } - else - res = src; - - - DB_PRINT( "mod", ("Result [%s]", res) ); - DB_RETURN( res ); -} - - -PUBLIC void -Map_esc( tok )/* -================ - Map an escape sequence and replace it by it's corresponding character - value. It is assumed that tok points at the initial \, the esc - sequence in the original string is replaced and the value of tok - is not modified. */ -char *tok; -{ - if( strchr( "\"\\vantbrf01234567", tok[1] ) ) { - size_t len; - switch( tok[1] ) { - case 'a' : *tok = 0x07; break; - case 'b' : *tok = '\b'; break; - case 'f' : *tok = '\f'; break; - case 'n' : *tok = '\n'; break; - case 'r' : *tok = '\r'; break; - case 't' : *tok = '\t'; break; - case 'v' : *tok = 0x0b; break; - case '\\': *tok = '\\'; break; - case '\"': *tok = '\"'; break; - - default: { - register int i = 0; - register int j = 0; - for( ; i<2 && isdigit(tok[2]); i++ ) { - j = (j << 3) + (tok[1] - '0'); - len = strlen(tok+2)+1; - memmove( tok+1, tok+2, len ); - } - j = (j << 3) + (tok[1] - '0'); - *tok = j; - } - } - len = strlen(tok+2)+1; - memmove( tok+1, tok+2, len ); - } -} - - -PUBLIC char* -Apply_modifiers( mod, src )/* -============================= - This routine applies the appropriate modifiers to the string src - and returns the proper result string */ - -int mod; -char *src; -{ - char *s; - char *e; - char *res; - TKSTR str; - - DB_ENTER( "Apply_modifiers" ); - - if ( mod & INFNAME_FLAG ) { - SET_TOKEN( &str, src ); - e = NIL(char); - - while( *(s = Get_token( &str, "", FALSE )) != '\0' ) { - HASHPTR hp; - - if ( (hp = Get_name(normalize_path(s), Defs, FALSE)) != NIL(HASH) - && hp->CP_OWNR - && hp->CP_OWNR->ce_fname - ) { - res = hp->CP_OWNR->ce_fname; - } - else - res = s; - - if(str.tk_quote == 0) { - /* Add leading quote. */ - e = DmStrApp(e, "\""); - e = DmStrJoin(e, res, -1, TRUE); - /* Append the trailing quote. */ - e = DmStrJoin(e, "\"", 1, TRUE); - } else { - e = DmStrApp(e, res); - } - - } - - FREE(src); - src = e; - mod &= ~INFNAME_FLAG; - } - - if ( mod & NORMPATH_FLAG ) { - e = exec_normpath(src); - - FREE(src); - src = e; - mod &= ~NORMPATH_FLAG; - } - - if(mod & (TOLOWER_FLAG|TOUPPER_FLAG) ) { - int lower; - lower = mod & TOLOWER_FLAG; - - for (s=src; *s; s++) - if ( isalpha(*s) ) - *s = ((lower) ? tolower(*s) : toupper(*s)); - - mod &= ~(TOLOWER_FLAG|TOUPPER_FLAG); - } - - if (mod & JUST_FIRST_FLAG) { - SET_TOKEN(&str, src); - if ((s = Get_token(&str,"",FALSE)) != '\0') { - /* Recycle the quote at the beginning. */ - if(str.tk_quote == 0) { - s--; - } - e = DmStrDup(s); - /* Add trailing quote. */ - if(str.tk_quote == 0) { - e = DmStrJoin(e, "\"", 1, TRUE); - } - - CLEAR_TOKEN(&str); - FREE(src); - src = e; - } - else { - CLEAR_TOKEN(&str); - } - mod &= ~JUST_FIRST_FLAG; - } - - if( !mod || mod == (SUFFIX_FLAG | DIRECTORY_FLAG | FILE_FLAG) ) - DB_RETURN( src ); - - SET_TOKEN( &str, src ); - DB_PRINT( "mod", ("Source string [%s]", src) ); - res = DmStrDup(""); - - while( *(s = Get_token( &str, "", FALSE )) != '\0' ) { - char *tokstart = s; - - /* search for the directory portion of the filename. If the - * DIRECTORY_FLAG is set, then we want to keep the directory portion - * othewise throw it away and blank out to the end of the token */ - - if( (e = Basename(s)) != s) { - if( !(mod & DIRECTORY_FLAG) ) { - /* Move the basename to the start. */ - size_t len = strlen(e)+1; - memmove(s, e, len); - } - else - s = e; - } - /* s now points to the start of the basename. */ - - - /* search for the suffix, if there is none, treat it as a NULL suffix. - * if no file name treat it as a NULL file name. same copy op as - * for directory case above */ - - e = strrchr( s, '.' ); /* NULL suffix if e=0 */ - if( e == NIL(char) ) e = s+strlen(s); - - if( !(mod & FILE_FLAG) ) { - /* Move the suffix to the start. */ - size_t len = strlen(e)+1; - memmove(s, e, len); - } - else - s = e; - - /* s now points to the start of the suffix. */ - - - /* The last and final part. This is the suffix case, if we don't want - * it then just erase it. */ - - if( s != NIL(char) ) - if( !(mod & SUFFIX_FLAG) && s != str.tk_str ) - *s = '\0'; - - - /* only keep non-empty tokens. (This also discards empty quoted "" - * tokens.) */ - if( strlen(tokstart) ) { - /* Recycle the quote at the beginning. */ - if(str.tk_quote == 0) { - tokstart--; - } - res = DmStrApp(res, tokstart); - /* Add trailing quote. */ - if(str.tk_quote == 0) { - res = DmStrJoin(res, "\"", 1, TRUE); - } - } - } - - FREE(src); - src = res; - - - DB_PRINT( "mod", ("Result string [%s]", src) ); - DB_RETURN( src ); -} - - -PUBLIC char* -Tokenize( src, separator, op, mapesc )/* -======================================== - Tokenize the input of src and join each token found together with - the next token separated by the separator string. - - When doing the tokenization, <sp>, <tab>, <nl>, and \<nl> all - constitute white space. */ - -char *src; -char *separator; -char op; -int mapesc; -{ - TKSTR tokens; - char *tok; - char *res; - int first = (op == 't' || op == 'T'); - - DB_ENTER( "Tokenize" ); - - /* map the escape codes in the separator string first */ - if ( mapesc ) - for(tok=separator; (tok = strchr(tok,ESCAPE_CHAR)) != NIL(char); tok++) - Map_esc( tok ); - - DB_PRINT( "exp", ("Separator [%s]", separator) ); - - /* By default we return an empty string */ - res = DmStrDup( "" ); - - /* Build the token list */ - SET_TOKEN( &tokens, src ); - while( *(tok = Get_token( &tokens, "", FALSE )) != '\0' ) { - char *x; - - if( first ) { - FREE( res ); - res = DmStrDup( tok ); - first = FALSE; - } - else if (op == '^') { - res = DmStrAdd(res, DmStrJoin(separator, tok, -1, FALSE), TRUE); - } - else if (op == '+') { - res = DmStrAdd(res, DmStrJoin(tok, separator, -1, FALSE), TRUE); - } - else { - res = DmStrJoin(res, x =DmStrJoin(separator, tok, -1, FALSE), - -1, TRUE); - FREE( x ); - } - - DB_PRINT( "exp", ("Tokenizing [%s] --> [%s]", tok, res) ); - } - - FREE( src ); - DB_RETURN( res ); -} - - -static char* -_scan_ballanced_parens(p, delim) -char *p; -char delim; -{ - int pcount = 0; - int bcount = 0; - - if ( p ) { - do { - if (delim) - if( !(bcount || pcount) && *p == delim) { - return(p); - } - - if ( *p == '(' ) pcount++; - else if ( *p == '{' ) bcount++; - else if ( *p == ')' && pcount ) pcount--; - else if ( *p == '}' && bcount ) bcount--; - - p++; - } - while (*p && (pcount || bcount || delim)); - } - - return(p); -} - - -PUBLIC char* -ScanToken( s, ps, doexpand )/* -============================== - This routine scans the token characters one at a time and identifies - macros starting with $( and ${ and calls _scan_macro to expand their - value. the string1{ token_list }string2 expansion is also handled. - In this case a temporary result is maintained so that we can take it's - cross product with any other token_lists that may possibly appear. */ - -char *s; /* pointer to start of src string */ -char **ps; /* pointer to start pointer */ -int doexpand; -{ - char *res; /* pointer to result */ - char *start; /* pointer to start of prefix */ - int crossproduct = 0; /* if 1 then computing X-prod */ - - start = s; - res = DmStrDup( "" ); - while( 1 ) { - switch( *s ) { - /* Termination, We halt at seeing a space or a tab or end of string. - * We return the value of the result with any new macro's we scanned - * or if we were computing cross_products then we return the new - * cross_product. - * NOTE: Once we start computing cross products it is impossible to - * stop. ie. the semantics are such that once a {} pair is - * seen we compute cross products until termination. */ - - case ' ': - case '\t': - case '\n': - case '\r': - case '\0': - { - char *tmp; - - *ps = s; - if( !crossproduct ) - tmp = DmStrJoin( res, start, (s-start), TRUE ); - else - { - tmp = DmSubStr( start, s ); - tmp = _cross_prod( res, tmp ); - } - return( tmp ); - } - - case '$': - case '{': - { - /* Handle if it's a macro or if it's a {} construct. - * The results of a macro expansion are handled differently based - * on whether we have seen a {} beforehand. */ - - char *tmp; - tmp = DmSubStr( start, s ); /* save the prefix */ - - if( *s == '$' ) { - start = _scan_macro( s+1, &s, doexpand ); - - if( crossproduct ) { - res = _cross_prod( res, DmStrJoin( tmp, start, -1, TRUE ) ); - } - else { - res = DmStrJoin(res,tmp=DmStrJoin(tmp,start,-1,TRUE),-1,TRUE); - FREE( tmp ); - } - FREE( start ); - } - else if( strchr("{ \t",s[1]) == NIL(char) ){ - int ok; - start = _scan_brace( s+1, &s, &ok ); - - if( ok ) { - if ( crossproduct ) { - res = _cross_prod(res,_cross_prod(tmp,start)); - } - else { - char *freeres; - res = Tokenize(start, - freeres=DmStrJoin(res,tmp,-1,TRUE), - '^', FALSE); - FREE(freeres); - FREE(tmp); - } - crossproduct = TRUE; - } - else { - res =DmStrJoin(res,tmp=DmStrJoin(tmp,start,-1,TRUE),-1,TRUE); - FREE( start ); - FREE( tmp ); - } - } - else { /* handle the {{ case */ - res = DmStrJoin( res, start, (s-start+1), TRUE ); - s += (s[1]=='{')?2:1; - FREE( tmp ); - } - - start = s; - } - break; - - case '}': - if( s[1] != '}' ) { - /* error malformed macro expansion */ - s++; - } - else { /* handle the }} case */ - res = DmStrJoin( res, start, (s-start+1), TRUE ); - s += 2; - start = s; - } - break; - - default: s++; - } - } -} - - -static char* -_scan_macro( s, ps, doexpand )/* -================================ - This routine scans a macro use and expands it to the value. It - returns the macro's expanded value and modifies the pointer into the - src string to point at the first character after the macro use. - The types of uses recognized are: - - $$ and $<sp> - expands to $ - $(name) - expands to value of name - ${name} - same as above - $($(name)) - recurses on macro names (any level) - and - $(func[,args ...] [data]) - and - $(name:modifier_list:modifier_list:...) - - see comment for Expand for description of valid modifiers. - - NOTE that once a macro name bounded by ( or { is found only - the appropriate terminator (ie. ( or } is searched for. */ - -char *s; /* pointer to start of src string */ -char **ps; /* pointer to start pointer */ -int doexpand; /* If TRUE enables macro expansion */ -{ - char sdelim; /* start of macro delimiter */ - char edelim; /* corresponding end macro delim */ - char *start; /* start of prefix */ - char *macro_name; /* temporary macro name */ - char *recurse_name; /* recursive macro name */ - char *result; /* result for macro expansion */ - int bflag = 0; /* brace flag, ==0 => $A type macro */ - int done = 0; /* != 0 => done macro search */ - int lev = 0; /* brace level */ - int mflag = 0; /* != 0 => modifiers present in mac */ - int fflag = 0; /* != 0 => GNU style function */ - HASHPTR hp; /* hash table pointer for macros */ - - DB_ENTER( "_scan_macro" ); - - /* Check for $ at end of line, or $ followed by white space */ - /* FIXME: Shouldn't a single '$' be an error? */ - if( !*s || strchr(" \t", *s) != NIL(char)) { - *ps = s; - DB_RETURN( DmStrDup("") ); - } - - if( *s == '$' ) { /* Take care of the simple $$ case. */ - *ps = s+1; - DB_RETURN( DmStrDup("$") ); - } - - sdelim = *s; /* set and remember start/end delim */ - if( sdelim == '(' ) - edelim = ')'; - else - edelim = '}'; - - start = s; /* build up macro name, find its end */ - while( !done ) { - switch( *s ) { - case '(': /* open macro brace */ - case '{': - if( *s == sdelim ) { - lev++; - bflag++; - } - break; - - case ':': /* halt at modifier */ - if( lev == 1 && !fflag && doexpand ) { - done = TRUE; - mflag = 1; - } - else if( !lev ) /* must be $: */ - Fatal( "Syntax error in macro [$%s]. A colon [:] cannot be a macro name.\n", start ); - - /* continue if a colon is found but lev > 1 */ - break; - - case '\n': /* Not possible because of the - * following case. */ - Fatal( "DEBUG: No standalone '\n' [%s].\n", start ); - break; - - case '\\': /* Transform \<nl> -> ' '. */ - if( s[1] != '\n' ) { - done = !lev; - break; - } else { - size_t len; - s[1] = ' '; - len = strlen(s+1)+1; - memmove( s, s+1, len ); - } - /*FALLTHRU*/ - case ' ': - case '\t': - if ( lev == 1 ) fflag = 1; - break; - - case '\0': /* check for null */ - *ps = s; - done = TRUE; - if( lev ) { /* catch $( or ${ without closing bracket */ - Fatal( "Syntax error in macro [$%s]. The closing bracket [%c] is missing.\n", start, edelim ); - } else - Fatal( "DEBUG: This cannot occur! [%s].\n", start ); - break; - - case ')': /* close macro brace */ - case '}': - if( !lev ) /* A closing bracket without an .. */ - Fatal("Syntax error in macro [$%s]. Closing bracket [%c] cannot be a macro name.\n", start, *s ); - else if( *s == edelim ) --lev; - /*FALLTHRU*/ - - default: /* Done when lev == 0. This means either no */ - done = !lev; /* opening bracket (single letter macro) or */ - /* a fully enclosed $(..) or ${..} macro */ - /* was found. */ - } - s++; - } - - /* Check if this is a $A type macro. If so then we have to - * handle it a little differently. */ - if( bflag ) - macro_name = DmSubStr( start+1, s-1 ); - else - macro_name = DmSubStr( start, s ); - - /* If we don't have to expand the macro we're done. */ - if (!doexpand) { - *ps = s; - DB_RETURN(macro_name); - } - - /* Check to see if the macro name contains spaces, if so then treat it - * as a GNU style function invocation and call the function mapper to - * deal with it. We do not call the function expander if the function - * invocation begins with a '$' */ - if( fflag && *macro_name != '$' ) { - result = Exec_function(macro_name); - } - else { - /* Check if the macro is a recursive macro name, if so then - * EXPAND the name before expanding the value */ - if( strchr( macro_name, '$' ) != NIL(char) ) { - recurse_name = Expand( macro_name ); - FREE( macro_name ); - macro_name = recurse_name; - } - - /* Code to do value expansion goes here, NOTE: macros whose assign bit - is one have been evaluated and assigned, they contain no further - expansions and thus do not need their values expanded again. */ - - if( (hp = GET_MACRO( macro_name )) != NIL(HASH) ) { - if( hp->ht_flag & M_MARK ) - Fatal( "Detected circular macro [%s]", hp->ht_name ); - - if( !(hp->ht_flag & M_EXPANDED) ) { - hp->ht_flag |= M_MARK; - result = Expand( hp->ht_value ); - hp->ht_flag ^= M_MARK; - } - else if( hp->ht_value != NIL(char) ) - result = DmStrDup( hp->ht_value ); - else - result = DmStrDup( "" ); - - } - else { - /* The use of an undefined macro implicitly defines it but - * leaves its value to NIL(char). */ - hp = Def_macro( macro_name, NIL(char), M_EXPANDED ); - /* Setting M_INIT assures that this macro is treated unset like - * default internal macros. (Necessary for *= and *:=) */ - hp->ht_flag |= M_INIT; - - result = DmStrDup( "" ); - } - /* Mark macros as used only if we are not expanding them for - * the purpose of a .IF test, so we can warn about redef after use*/ - if( !If_expand ) hp->ht_flag |= M_USED; - - } - - if( mflag ) { - char separator; - int modifier_list = 0; - int aug_mod = FALSE; - char *pat1; - char *pat2; - char *p; - - /* We are inside of a macro expansion. The "build up macro name, - * find its while loop above should have caught all \<nl> and - * converted them to a real space. Let's verify this. */ - for( p=s; *p && *p != edelim && *p; p++ ) { - if( p[0] == '\\' && p[1] == '\n' ) { - size_t len; - p[1] = ' '; - len = strlen(p+1)+1; - memmove( p, p+1, len ); - } - } - if( !*p ) - Fatal( "Syntax error in macro modifier pattern [$%s]. The closing bracket [%c] is missing.\n", start, edelim ); - - /* Yet another brain damaged AUGMAKE kludge. We should accept the - * AUGMAKE bullshit of $(f:pat=sub) form of macro expansion. In - * order to do this we will forgo the normal processing if the - * AUGMAKE solution pans out, otherwise we will try to process the - * modifiers ala dmake. - * - * So we look for = in modifier string. - * If found we process it and not do the normal stuff */ - - for( p=s; *p && *p != '=' && *p != edelim; p++ ); - - if( *p == '=' ) { - char *tmp; - - pat1 = Expand(tmp = DmSubStr(s,p)); FREE(tmp); - s = p+1; - p = _scan_ballanced_parens(s+1, edelim); - - if ( !*p ) { - Fatal( "Incomplete macro expression [%s]", s ); - p = s+1; - } - pat2 = Expand(tmp = DmSubStr(s,p)); FREE(tmp); - - result = Apply_edit( result, pat1, pat2, TRUE, TRUE ); - FREE( pat1 ); - FREE( pat2 ); - s = p; - aug_mod = TRUE; - } - - if( !aug_mod ) - while( *s && *s != edelim ) { /* while not at end of macro */ - char switch_char; - - switch( switch_char = *s++ ) { - case '1': modifier_list |= JUST_FIRST_FLAG; break; - - case 'b': - case 'B': modifier_list |= FILE_FLAG; break; - - case 'd': - case 'D': modifier_list |= DIRECTORY_FLAG; break; - - case 'f': - case 'F': modifier_list |= FILE_FLAG | SUFFIX_FLAG; break; - - case 'e': - case 'E': modifier_list |= SUFFIX_FLAG; break; - - case 'l': - case 'L': modifier_list |= TOLOWER_FLAG; break; - - case 'i': - case 'I': modifier_list |= INFNAME_FLAG; break; - - case 'u': - case 'U': modifier_list |= TOUPPER_FLAG; break; - - case 'm': - case 'M': - if( modifier_list || ( (*s != edelim) && (*s != ':') ) ) { - Warning( "Map escape modifier must appear alone, ignored"); - modifier_list = 0; - } - else { - /* map the escape codes in the separator string first */ - for(p=result; (p = strchr(p,ESCAPE_CHAR)) != NIL(char); p++) - Map_esc( p ); - } - /* find the end of the macro spec, or the start of a new - * modifier list for further processing of the result */ - - for( ; (*s != edelim) && (*s != ':') && *s; s++ ); - if( !*s ) - Fatal( "Syntax error in macro. [$%s].\n", start ); - if( *s == ':' ) s++; - break; - - case 'n': - case 'N': modifier_list |= NORMPATH_FLAG; break; - - case 'S': - case 's': - if( modifier_list ) { - Warning( "Edit modifier must appear alone, ignored"); - modifier_list = 0; - } - else { - separator = *s++; - for( p=s; *p != separator && *p; p++ ); - - if( !*p ) - Fatal( "Syntax error in subst macro. [$%s].\n", start ); - else { - char *t1, *t2; - pat1 = DmSubStr( s, p ); - for(s=p=p+1; (*p != separator) && *p; p++ ); - /* Before the parsing fixes in iz36027 the :s macro modifier - * erroneously worked with patterns with missing pattern - * separator, i.e. $(XXX:s#pat#sub). This is an error because - * it prohibits the use of following macro modifiers. - * I.e. $(XXX:s#pat#sub:u) falsely replaces with "sub:u". - * ??? Remove this special case once OOo compiles without - * any of this warnings. */ - if( !*p ) { - if( *(p-1) == edelim ) { - p--; - Warning( "Syntax error in subst macro. Bracket found, but third delimiter [%c] missing in [$%s].\n", separator, start ); - } - else { - Fatal( "Syntax error in subst macro. Third delimiter [%c] missing in [$%s].\n", separator, start ); - } - } - pat2 = DmSubStr( s, p ); - t1 = Expand(pat1); FREE(pat1); - t2 = Expand(pat2); FREE(pat2); - result = Apply_edit( result, t1, t2, TRUE, FALSE ); - FREE( t1 ); - FREE( t2 ); - } - s = p; - } - /* find the end of the macro spec, or the start of a new - * modifier list for further processing of the result */ - - for( ; (*s != edelim) && (*s != ':') && *s; s++ ); - if( !*s ) - Fatal( "Syntax error in macro. [$%s].\n", start ); - if( *s == ':' ) s++; - break; - - case 'T': - case 't': - case '^': - case '+': - if( modifier_list ) { - Warning( "Tokenize modifier must appear alone, ignored"); - modifier_list = 0; - } - else { - separator = *s++; - - if( separator == '$' ) { - p = _scan_ballanced_parens(s,'\0'); - - if ( *p ) { - char *tmp; - pat1 = Expand(tmp = DmSubStr(s-1,p)); - FREE(tmp); - result = Tokenize(result, pat1, switch_char, TRUE); - FREE(pat1); - } - else { - Warning( "Incomplete macro expression [%s]", s ); - } - s = p; - } - else if ( separator == '\"' ) { - /* we change the semantics to allow $(v:t")") */ - for (p = s; *p && *p != separator; p++) - if (*p == '\\') - if (p[1] == '\\' || p[1] == '"') - p++; - - if( *p == 0 ) - Fatal( "Unterminated separator string" ); - else { - pat1 = DmSubStr( s, p ); - result = Tokenize( result, pat1, switch_char, TRUE); - FREE( pat1 ); - } - s = p; - } - else { - Warning( - "Separator must be a quoted string or macro expression"); - } - - /* find the end of the macro spec, or the start of a new - * modifier list for further processing of the result */ - - for( ; (*s != edelim) && (*s != ':'); s++ ); - if( *s == ':' ) s++; - } - break; - - case ':': - if( modifier_list ) { - result = Apply_modifiers( modifier_list, result ); - modifier_list = 0; - } - break; - - default: - Warning( "Illegal modifier in macro, ignored" ); - break; - } - } - - if( modifier_list ) /* apply modifier */ - result = Apply_modifiers( modifier_list, result ); - - s++; - } - - *ps = s; - FREE( macro_name ); - DB_RETURN( result ); -} - - -static char* -_scan_brace( s, ps, flag )/* -============================ - This routine scans for { token_list } pairs. It expands the value of - token_list by calling Expand on it. Token_list may be anything at all. - Note that the routine count's ballanced parentheses. This means you - cannot have something like { fred { joe }, if that is what you really - need the write it as { fred {{ joe }, flag is set to 1 if all ok - and to 0 if the braces were unballanced. */ - -char *s; -char **ps; -int *flag; -{ - char *t; - char *start; - char *res; - int lev = 1; - int done = 0; - - DB_ENTER( "_scan_brace" ); - - start = s; - while( !done ) - switch( *s++ ) { - case '{': - if( *s == '{' ) break; /* ignore {{ */ - lev++; - break; - - case '}': - if( *s == '}' ) break; /* ignore }} */ - if( lev ) - if( --lev == 0 ) done = TRUE; - break; - - case '$': - if( *s == '{' || *s == '}' ) { - if( (t = strchr(s,'}')) != NIL(char) ) - s = t; - s++; - } - break; - - case '\0': - if( lev ) { - done = TRUE; - s--; - /* error malformed macro expansion */ - } - break; - } - - start = DmSubStr( start, (lev) ? s : s-1 ); - - if( lev ) { - /* Braces were not ballanced so just return the string. - * Do not expand it. */ - - res = DmStrJoin( "{", start, -1, FALSE ); - *flag = 0; - } - else { - *flag = 1; - res = Expand( start ); - - if( (t = DmStrSpn( res, " \t" )) != res ) { - size_t len = strlen(t)+1; - memmove( res, t, len ); - } - } - - FREE( start ); /* this is ok! start is assigned a DmSubStr above */ - *ps = s; - - DB_RETURN( res ); -} - - -static char* -_cross_prod( x, y )/* -===================== - Given two strings x and y compute the cross-product of the tokens found - in each string. ie. if x = "a b" and y = "c d" return "ac ad bc bd". - - NOTE: buf will continue to grow until it is big enough to handle - all cross product requests. It is never freed! (maybe I - will fix this someday) */ - -char *x; -char *y; -{ - static char *buf = NULL; - static int buf_siz = 0; - char *brkx; - char *brky; - char *cy; - char *cx; - char *res; - int i; - - if( *x && *y ) { - res = DmStrDup( "" ); cx = x; - while( *cx ) { - cy = y; - brkx = DmStrPbrk( cx, " \t\n" ); - if( (brkx-cx == 2) && *cx == '\"' && *(cx+1) == '\"' ) cx = brkx; - - while( *cy ) { - brky = DmStrPbrk( cy, " \t\n" ); - if( (brky-cy == 2) && *cy == '\"' && *(cy+1) == '\"' ) cy = brky; - i = brkx-cx + brky-cy + 2; - - if( i > buf_siz ) { /* grow buf to the correct size */ - if( buf != NIL(char) ) FREE( buf ); - if( (buf = MALLOC( i, char )) == NIL(char)) No_ram(); - buf_siz = i; - } - - strncpy( buf, cx, (i = brkx-cx) ); - buf[i] = '\0'; - if (brky-cy > 0) strncat( buf, cy, brky-cy ); - buf[i+(brky-cy)] = '\0'; - strcat( buf, " " ); - res = DmStrJoin( res, buf, -1, TRUE ); - cy = DmStrSpn( brky, " \t\n" ); - } - cx = DmStrSpn( brkx, " \t\n" ); - } - - FREE( x ); - res[ strlen(res)-1 ] = '\0'; - } - else - res = DmStrJoin( x, y, -1, TRUE ); - - FREE( y ); - return( res ); -} |