char *GetMacroValue( const char *name ) /********************************************* * Now we need to check for string substitution * $(MACRONAME:oldstring=newstring) */ { char *InName; const char *beforeSub; char *afterSub; char *current; const char *new; const char *old; char *line; InName = StrDupSafe( name ); current = strchr( InName, COLON ); if( current == NULL ) { beforeSub = GetMacroValueProcess( InName ); if( beforeSub == NULL ) { afterSub = NULL; } else { afterSub = StrDupSafe( beforeSub ); } } else { *current++ = NULLCHAR; beforeSub = GetMacroValueProcess( InName ); if( beforeSub == NULL ) { afterSub = NULL; } else { line = NULL; // recursively expand so $(macro:sub) OK if macro contains another if( strchr( beforeSub, DOLLAR ) != NULL ) { UnGetCH( STRM_MAGIC ); InsString( beforeSub, FALSE ); beforeSub = line = DeMacro( TOK_MAGIC ); GetCHR(); // eat STRM_MAGIC } if( beforeSub == NULL ) { afterSub = NULL; } else { if( getOldNewString( current, &old, &new ) == RET_SUCCESS ) { afterSub = doStringSubstitute( beforeSub, old, new ); } else { afterSub = NULL; PrtMsg( ERR | LOC | INVALID_STRING_SUBSTITUTE ); } if( line ) { FreeSafe( line ); } } } }
RET_T InsFile( const char *name, BOOLEAN envsearch ) /********************************************************** * Open file named name, and push it into stream. If can't find name, it * tries an implicit suffix search (possibly using the env variable PATH) */ { SENT *tmp; int fh; char path[_MAX_PATH]; assert( name != NULL ); if( TrySufPath( path, name, NULL, envsearch ) == RET_SUCCESS ) { PrtMsg( DBG | INF | LOC | ENTERING_FILE, path ); fh = sopen3( path, O_RDONLY | O_BINARY, SH_DENYWR ); if( fh == -1 ) { return( RET_ERROR ); } tmp = getSENT( SENT_FILE ); tmp->free = TRUE; tmp->data.file.name = StrDupSafe( path ); pushFH( tmp, fh ); if( !Glob.overide ) { UnGetCH( EOL ); InsString( path, FALSE ); InsString( "$+$(__MAKEFILES__)$- ", FALSE ); DefMacro( "__MAKEFILES__" ); } return( RET_SUCCESS ); } return( RET_ERROR ); }
TOKEN_T LexParser( STRM_T s ) /************************************ * returns: next token for parser * remarks: possibly defines a macro */ { static BOOLEAN atstart = TRUE; char *p; for( ;; ) { if( atstart ) { /* atstart == TRUE if either of these succeed */ if( isws( s ) ) { /* cmd line */ return( lexCmd() ); } if( ismacc( s ) && checkMacro( s ) ) { /* check if macro = body */ s = PreGetCH(); continue; } atstart = FALSE; UnGetCH( s ); /* put back our probe */ s = STRM_MAGIC; /* force macro expansion */ } switch( s ) { case STRM_END: atstart = TRUE; return( TOK_END ); case EOL: atstart = TRUE; return( TOK_EOL ); case STRM_TMP_LEX_START: case STRM_MAGIC: p = DeMacroDoubleQuote( FALSE ); /* expand to next white space */ if( *p == NULLCHAR ) { /* already at ws */ FreeSafe( p ); s = PreGetCH(); /* eat the ws */ while( isws( s ) ) { s = PreGetCH(); } if( s == EOL ) { atstart = TRUE; return( TOK_EOL ); } if( s == STRM_END ) { atstart = TRUE; return( TOK_END ); } UnGetCH( s ); p = DeMacroDoubleQuote( FALSE ); } UnGetCH( STRM_MAGIC ); /* mark spot we have to expand from nxt */ InsString( p, TRUE ); /* put expansion in stream */ break; case SPACE: /* fall through */ case TAB: break; case L_CURL_PAREN: /* could only be a sufsuf */ case DOT: UnGetCH( s ); return( lexDotName() ); /* could be a file... */ case SEMI: /* treat semi-colon as {nl}{ws} */ InsString( "\n ", FALSE ); break; /* try again */ case COLON: s = PreGetCH(); if( s == COLON ) { return( TOK_DCOLON ); } UnGetCH( s ); return( TOK_SCOLON ); default: if( isfilec( s ) || s == DOUBLEQUOTE || ( (Glob.compat_nmake || Glob.compat_posix) && s == SPECIAL_TMP_DOL_C ) ) { return( lexFileName( s ) ); } PrtMsg( WRN | LOC | UNKNOWN_TOKEN, s ); break; } s = PreGetCH(); /* fetch a character */ } }
STATIC char *DeMacroDoubleQuote( BOOLEAN IsDoubleQuote ) /******************************************************* * This procedure takes care of double quotes in the stream * Note: each double quote must be paired with a double quote in the * input stream or this will expand until the EOL a backlash double * quote will be considered as a non-double quote. */ { char buffer[_MAX_PATH]; char *current; char *p; VECSTR OutString; int pos; STRM_T s; BOOLEAN StartDoubleQuote; s = PreGetCH(); UnGetCH( s ); if( s == EOL || s == STRM_END || s == STRM_MAGIC ) { return( StrDupSafe( "" ) ); } if( s == STRM_TMP_LEX_START ) { PreGetCH(); /* Eat STRM_TMP_LEX_START */ pos = 0; for( s = PreGetCH(); s != STRM_MAGIC && pos < _MAX_PATH; s = PreGetCH() ) { assert( s != EOL || s != STRM_END ); buffer[pos++] = s; } if( pos >= _MAX_PATH ) { PrtMsgExit(( FTL | LOC | MAXIMUM_TOKEN_IS, _MAX_PATH - 1 )); // NOTREACHED } buffer[pos] = NULLCHAR; p = StrDupSafe( buffer ); } else { p = DeMacro( MAC_WS ); } StartDoubleQuote = IsDoubleQuote; for( current = p; *current != NULLCHAR; ++current ) { if( *current == DOUBLEQUOTE ) { if( !IsDoubleQuote ) { /* Found the start of a Double Quoted String */ if( current != p ) { UnGetCH( STRM_MAGIC ); InsString( StrDupSafe( current ), TRUE ); UnGetCH( STRM_TMP_LEX_START ); *current = NULLCHAR; return( p ); } IsDoubleQuote = TRUE; } else { /* Found the end of the Double Quoted String */ if( *(current + 1) != NULLCHAR) { UnGetCH( STRM_MAGIC ); InsString( StrDupSafe( current + 1 ), TRUE ); UnGetCH( STRM_TMP_LEX_START ); *(current + 1) = NULLCHAR; } return( p ); } } } if( !StartDoubleQuote && !IsDoubleQuote ) { /* there are no double quotes in the text */ /* so return text as is */ return( p ); } pos = 0; s = PreGetCH(); while( isws( s ) ) { buffer[pos++] = s; s = PreGetCH(); } buffer[pos] = NULLCHAR; UnGetCH( s ); OutString = StartVec(); CatStrToVec( OutString, p ); FreeSafe( p ); CatStrToVec( OutString, buffer ); p = DeMacroDoubleQuote( TRUE ); CatStrToVec( OutString, p ); FreeSafe( p ); return( FinishVec( OutString ) ); }
TOKEN_T LexPath( STRM_T s ) /********************************* * returns: ({filec}*";")+ TOK_PATH * EOL EOL * STRM_END STRM_END */ { char path[_MAX_PATH]; char string_open; unsigned pos; VECSTR vec; /* we'll store file/path here */ for( ;; ) { /* get first valid character */ if( s == EOL || s == STRM_END ) { /* now we pass this to LexParser() so that it can reset */ return( LexParser( s ) ); } if( s == STRM_MAGIC ) { InsString( DeMacro( TOK_EOL ), TRUE ); } else if( !isfilec( s ) && s != PATH_SPLIT && s != ';' && s != '\"' && !isws( s ) ) { PrtMsg( ERR | LOC | EXPECTING_M, M_PATH ); } else if( !isws( s ) ) { break; } s = PreGetCH(); /* keep fetching characters */ } /* just so you know what we've got now */ assert( isfilec( s ) || s == PATH_SPLIT || s == ';' || s == '\"' ); vec = StartVec(); pos = 0; for( ;; ) { /* * Extract path from stream. If double quote is found, start string mode * and ignore all filename character specifiers and just copy all * characters. String mode ends with another double quote. Backslash can * be used to escape only double quotes, otherwise they are recognized * as path seperators. If we are not in string mode character validity * is checked against isfilec(). */ string_open = 0; while( pos < _MAX_PATH && s != EOL && s != STRM_END ) { if( s == BACKSLASH ) { s = PreGetCH(); if( s == DOUBLEQUOTE ) { path[pos++] = DOUBLEQUOTE; } else if( s == EOL || s == STRM_END ) { // Handle special case when backslash is placed at end of // line or file path[pos++] = BACKSLASH; } else { path[pos++] = BACKSLASH; // make sure we don't cross boundaries if( pos < _MAX_PATH ) { path[pos++] = s; } } } else { if( s == DOUBLEQUOTE ) { string_open = !string_open; } else { if( string_open ) { path[pos++] = s; } else if( isfilec( s ) ) { path[pos++] = s; } else { break; // not valid path character, break out. } } } s = PreGetCH(); } if( string_open ) { FreeSafe( FinishVec( vec ) ); PrtMsgExit(( FTL | LOC | ERROR_STRING_OPEN )); } if( pos == _MAX_PATH ) { FreeSafe( FinishVec( vec ) ); PrtMsgExit(( FTL | LOC | MAXIMUM_TOKEN_IS, _MAX_PATH - 1 )); // NOTREACHED } path[pos] = NULLCHAR; WriteVec( vec, path ); if( s != PATH_SPLIT && s != ';' ) { break; } pos = 0; path[pos++] = PATH_SPLIT; s = PreGetCH(); /* use Pre here to allow path;&(nl)path */ } UnGetCH( s ); CurAttr.u.ptr = FinishVec( vec ); return( TOK_PATH ); }
TOKEN_T LexParser( STRM_T s ) /************************************ * returns: next token for parser * remarks: possibly defines a macro */ { static bool atstart = true; char *p; for( ;; ) { if( atstart ) { /* atstart == true if either of these succeed */ if( sisws( s ) ) { /* cmd line */ return( lexCmd() ); } if( sismacc( s ) && checkMacro( s ) ) { /* check if macro = body */ s = PreGetCHR(); continue; } atstart = false; UnGetCHR( s ); /* put back our probe */ s = STRM_MAGIC; /* force macro expansion */ } switch( s ) { case STRM_END: atstart = true; return( TOK_END ); case '\n': atstart = true; return( TOK_EOL ); case STRM_TMP_LEX_START: case STRM_MAGIC: p = DeMacroDoubleQuote( false ); /* expand to next white space */ if( *p == NULLCHAR ) { /* already at ws */ FreeSafe( p ); s = PreGetCHR(); /* eat the ws */ while( sisws( s ) ) { s = PreGetCHR(); } if( s == '\n' ) { atstart = true; return( TOK_EOL ); } if( s == STRM_END ) { atstart = true; return( TOK_END ); } UnGetCHR( s ); p = DeMacroDoubleQuote( false ); } UnGetCHR( STRM_MAGIC ); /* mark spot we have to expand from nxt */ InsString( p, true ); /* put expansion in stream */ break; case ' ': case '\t': break; case '{': /* could only be a sufsuf */ case '.': UnGetCHR( s ); return( lexDotName() ); /* could be a file... */ case ';': /* treat semi-colon as {nl}{ws} */ InsString( "\n ", false ); break; /* try again */ case ':': s = PreGetCHR(); if( s == ':' ) { return( TOK_DCOLON ); } UnGetCHR( s ); return( TOK_SCOLON ); default: if( sisfilec( s ) || s == '\"' || ( (Glob.compat_nmake || Glob.compat_posix) && s == SPECIAL_TMP_DOLLAR ) ) { return( lexFileName( s ) ); } PrtMsg( WRN | LOC | UNKNOWN_TOKEN, s ); break; } s = PreGetCHR(); /* fetch a character */ } }