STATIC char *getCurlPath( void ) /******************************* * get the path between { and } */ { STRM_T s; char path[_MAX_PATH + 1]; int pos; pos = 0; s = PreGetCH(); if( s == L_CURL_PAREN ) { for( s = PreGetCH(); s != R_CURL_PAREN && s != EOL && pos < _MAX_PATH; s = PreGetCH() ) { path[pos++] = s; } path[pos] = NULLCHAR; if( s == EOL ) { UnGetCH( EOL ); PrtMsg( ERR | LOC | NON_MATCHING_CURL_PAREN); } else if( pos == _MAX_PATH ) { PrtMsg( WRN | LOC | PATH_TOO_LONG ); } return( StrDupSafe( path ) ); } else { UnGetCH( s ); return( "" ); } }
TOKEN_T LexMacDef( STRM_T s ) /************************************ * returns: MAC_TEXT, or MAC_WS up to EOL or $+ */ { char *cur; BOOLEAN onlyws; /* are we collecting ws? */ char text[MAX_TOK_SIZE]; /* store stuff here temp. */ if( s == STRM_END ) { return( TOK_END ); } if( s == STRM_MAGIC ) { return( TOK_MAGIC ); } if( s == EOL ) { return( TOK_EOL ); } assert( isascii( s ) ); cur = text; if( s == DOLLAR ) { *cur++ = DOLLAR; s = PreGetCH(); if( s == '+' ) { return( MAC_EXPAND_ON ); } } onlyws = isws( s ); while( cur - text < MAX_TOK_SIZE - 1 ) { *cur++ = s; s = PreGetCH(); if( s == STRM_END || s == STRM_MAGIC || s == EOL || s == DOLLAR || (onlyws && !isws( s )) || (!onlyws && isws( s )) ) { break; } } UnGetCH( s ); *cur = NULLCHAR; CurAttr.u.ptr = StrDupSafe( text ); if( onlyws ) { return( MAC_WS ); } return( MAC_TEXT ); }
STATIC BOOLEAN checkMacro( STRM_T s ) /************************************* * returns: TRUE if the line WAS a macro defn * FALSE if it wasn't * recognizes: {macc}+{ws}*"="{ws}*{defn}*"\n" * {macc}+{ws}*"+="{ws}*{defn}*"\n" * second gets translated from "macro += defn" to "macro=$+$(macro)$- defn" */ { char mac[MAX_MAC_NAME]; unsigned pos; BOOLEAN ws; pos = 0; while( pos < MAX_MAC_NAME && ismacc( s ) ) { mac[pos++] = s; s = PreGetCH(); } if( pos == MAX_MAC_NAME ) { PrtMsgExit(( FTL | LOC | MAXIMUM_TOKEN_IS, MAX_MAC_NAME - 1 )); } mac[pos] = NULLCHAR; ws = isws( s ); while( isws( s ) ) { s = PreGetCH(); } if( s == '=' ) { DefMacro( mac ); return( TRUE ); /* go around again */ } else if( s == '+' ) { s = PreGetCH(); if( s == '=' ) { InsString( ")$-", FALSE ); InsString( mac, FALSE ); InsString( "$+$(", FALSE ); DefMacro( mac ); return( TRUE ); /* go around again */ } UnGetCH( s ); s = '+'; } UnGetCH( s ); /* not a macro line, put everything back*/ if( ws ) { UnGetCH( SPACE ); } InsString( StrDupSafe( mac + 1 ), TRUE ); return( FALSE ); }
void GetModifier( void ) /*****************************/ { STRM_T s; // Modifier already eaten by CatModifier if( !IsPartDeMacro ) { s = PreGetCH(); switch( s ) { case 'D': case 'd': CurAttr.u.form = FORM_PATH; break; case 'B': case 'b': CurAttr.u.form = FORM_NOEXT_NOPATH; break; case 'F': case 'f': CurAttr.u.form = FORM_NOPATH; break; case 'R': case 'r': CurAttr.u.form = FORM_NOEXT; break; default: UnGetCH( s ); } } }
STATIC TOKEN_T lexFormQualifier( TOKEN_T tok ) /********************************************* * pre: $<file_specifier> read already; passed in tok * post: 1 character of input may be read * returns: tok; CurAttr.u.form contains enum FormQualifiers * errors: If next character of input is not a form-qual. it is pushed back * and CurAttr.u.form == FORM_FULL */ { STRM_T s; s = PreGetCH(); switch( s ) { case '@': CurAttr.u.form = FORM_FULL; break; case '*': CurAttr.u.form = FORM_NOEXT; break; case '&': CurAttr.u.form = FORM_NOEXT_NOPATH; break; case '.': CurAttr.u.form = FORM_NOPATH; break; case ':': CurAttr.u.form = FORM_PATH; break; case '!': CurAttr.u.form = FORM_EXT; break; default: PrtMsg( ERR | LOC | EXPECTING_M, M_FORM_QUALIFIER ); UnGetCH( s ); /* put character back */ CurAttr.u.form = FORM_FULL; /* assume full name */ } return( tok ); }
STATIC TOKEN_T lexDollar( void ) /******************************* * pre: $ read off input * post: 0 or more characters of token read * returns: MAC token type */ { STRM_T s; TOKEN_T t; s = PreGetCH(); if( (Glob.compat_nmake || Glob.compat_posix) && ismsspecial( s ) ) { t = LexMSDollar( s ); GetModifier(); return( t ); } switch( s ) { case DOLLAR: return( MAC_DOLLAR ); case COMMENT: return( MAC_COMMENT ); case '(': return( MAC_OPEN ); case '+': return( MAC_EXPAND_ON ); case '-': return( MAC_EXPAND_OFF ); case '^': return( lexFormQualifier( MAC_CUR ) ); case '[': return( lexFormQualifier( MAC_FIRST ) ); case ']': return( lexFormQualifier( MAC_LAST ) ); case '@': CurAttr.u.form = FORM_FULL; return( MAC_CUR ); /* UNIX */ case '*': CurAttr.u.form = FORM_NOEXT; return( MAC_CUR ); /* UNIX */ case '<': CurAttr.u.form = FORM_FULL; return( MAC_ALL_DEP ); /* UNIX */ case '?': CurAttr.u.form = FORM_FULL; return( MAC_YOUNG_DEP ); /* UNIX */ default: UnGetCH( s ); return( MAC_START ); } }
STATIC TOKEN_T lexLongFilePathName( STRM_T s, TOKEN_T tok ) /********************************************************** * This will enable taking in of special filenames * it takes long file names or long path names */ { char file[_MAX_PATH]; int pos; assert( s == DOUBLEQUOTE ); pos = 0; s = PreGetCH(); /* \" is considered a double quote character */ /* and if a double quote is found again then we break out as the end */ /* of the filename */ while( pos < _MAX_PATH && s != DOUBLEQUOTE && s != EOL && s != STRM_END ) { file[pos++] = s; s = PreGetCH(); if( s == BACKSLASH ) { if( pos >= _MAX_PATH ) { break; } s = PreGetCH(); if( s == DOUBLEQUOTE ) { file[pos++] = s; s = PreGetCH(); } else { file[pos++] = BACKSLASH; } } } if( pos >= _MAX_PATH ) { PrtMsgExit(( FTL | LOC | MAXIMUM_TOKEN_IS, _MAX_PATH - 1 )); // NOTREACHED } file[pos] = NULLCHAR; if( s != DOUBLEQUOTE ) { UnGetCH( s ); } CurAttr.u.ptr = StrDupSafe( file ); return( tok ); }
STATIC TOKEN_T lexSubString( STRM_T s ) /**************************************/ { char text[MAX_TOK_SIZE]; /* temporary storage */ unsigned pos; /* position in text */ TOKEN_T state; /* what are we collecting */ BOOLEAN done; /* are we done collecting ? */ VECSTR vec; /* build string here */ assert( isascii( s ) ); vec = StartVec(); if( ismacc( s ) ) { state = MAC_NAME; } else if( isws( s ) ) { state = MAC_WS; } else { state = MAC_PUNC; } pos = 0; done = FALSE; while( !done ) { text[pos++] = s; if( pos == MAX_TOK_SIZE - 1 ) { text[pos] = NULLCHAR; WriteVec( vec, text ); pos = 0; } s = PreGetCH(); switch( s ) { case EOL: /* always stop on these characters */ case STRM_END: case STRM_MAGIC: case ')': case DOLLAR: done = TRUE; break; default: switch( state ) { case MAC_NAME: done = !ismacc( s ); break; case MAC_WS: done = !isws( s ); break; case MAC_PUNC: done = ismacc( s ) || isws( s ); break; } } } UnGetCH( s ); text[pos] = NULLCHAR; WriteVec( vec, text ); CurAttr.u.ptr = FinishVec( vec ); return( state ); }
STATIC TOKEN_T lexFileName( STRM_T s ) /************************************* * Now we need two ways of taking file names if the filename needs special * characters then use "filename" this will ignore all the different * characters except for the quote which can be specified as \t */ { char file[_MAX_PATH]; unsigned pos; assert( isfilec( s ) || s == DOUBLEQUOTE || ( (Glob.compat_nmake || Glob.compat_posix) && s == SPECIAL_TMP_DOL_C ) ); if( s == DOUBLEQUOTE ) { return( lexLongFilePathName( s, TOK_FILENAME ) ); } pos = 0; while( pos < _MAX_PATH && (isfilec( s ) || ( s == SPECIAL_TMP_DOL_C && (Glob.compat_nmake || Glob.compat_posix) ) ) ) { file[pos++] = s; s = PreGetCH(); } if( pos == _MAX_PATH ) { PrtMsgExit(( FTL | LOC | MAXIMUM_TOKEN_IS, _MAX_PATH - 1 )); // NOTREACHED } file[pos] = NULLCHAR; UnGetCH( s ); /* if it is a file, we have to check last position for a ':', and * trim it off if it's there */ if( pos > 1 && file[pos - 1] == COLON ) { file[pos - 1] = NULLCHAR; /* trim a trailing colon */ UnGetCH( COLON ); /* push back the colon */ --pos; } /* * try to do the trim twice because if file ends with a double colon * it means its a double colon explicit rule */ if( pos > 1 && file[pos - 1] == COLON ) { file[pos - 1] = NULLCHAR; /* trim a trailing colon */ UnGetCH( COLON ); /* push back the colon */ } CurAttr.u.ptr = StrDupSafe( file ); return( TOK_FILENAME ); }
STATIC char *CatModifier( char *inString, BOOLEAN destroy ) /********************************************************** * Get the modifier * if it is modify the value inInString to the specs of the modifier * it then returns the modified string with the right format */ { STRM_T s; VECSTR output; char buffer[2]; char *ret; assert( inString != NULL ); s = PreGetCH(); if( ismsmodifier( s ) ) { buffer[0] = s; buffer[1] = NULLCHAR; output = StartVec(); WriteVec( output, "" ); CatStrToVec( output, inString ); CatStrToVec( output, buffer ); if( destroy ) { FreeSafe( inString ); } return( FinishVec( output ) ); } else { UnGetCH( s ); ret = StrDupSafe( inString ); if( destroy ) { FreeSafe( inString ); } return( ret ); } }
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 ) ); }
STATIC TOKEN_T lexDotName( void ) /******************************** * Given that the last character was a DOT, input the maximum string * possible, and check if it is a TOK_DOTNAME, TOK_SUF, or TOK_SUFSUF * Special cases to look for: "."{dirc}; ".."{dirc}; ".."{extc}+; * and "."{extc}+"." * recognizes: * "."{extc}* TOK_SUF * "."{extc}*"."{extc}* TOK_SUFSUF * "{"path"}""."{extc}*"{"path"}""."{extc} TOK_SUFSUF * "."{dot-name} TOK_DOTNAME * "."{dirc} passes to lexFileName() * ".."{dirc} passes to lexFileName() */ { char ext[MAX_SUFFIX]; unsigned pos; STRM_T s; STRM_T s2; TOKEN_T ret; pos = 0; if( *targ_path != NULLCHAR ) { FreeSafe( targ_path ); targ_path = ""; } if( *dep_path != NULLCHAR ) { FreeSafe( dep_path ); dep_path = ""; } dep_path = getCurlPath(); s = PreGetCH(); if( s != DOT ) { PrtMsg( ERR | LOC | INVALID_SUFSUF ); return( TOK_NULL ); } else { ext[pos++] = DOT; s = PreGetCH(); } if( isdirc( s ) || s == PATH_SPLIT || s == ';' ) { // check for "."{dirc} UnGetCH( s ); if( *dep_path != NULLCHAR ) { PrtMsg( ERR | LOC | INVALID_SUFSUF ); } return( lexFileName( DOT ) ); } if( s == DOT ) { /* check if ".."{extc} or ".."{dirc} */ s2 = PreGetCH(); /* probe one character */ UnGetCH( s2 ); if( isdirc( s2 ) || s2 == PATH_SPLIT || s2 == ';' ) { // is ".."{dirc} UnGetCH( s ); if( *dep_path != NULLCHAR ) { PrtMsg( ERR | LOC | INVALID_SUFSUF ); } return( lexFileName( DOT ) ); } } else { /* get string {extc}+ */ while( pos < MAX_SUFFIX && isextc( s ) && s != L_CURL_PAREN ) { ext[pos++] = s; s = PreGetCH(); } if( pos == MAX_SUFFIX ) { PrtMsgExit(( FTL | LOC | MAXIMUM_TOKEN_IS, MAX_SUFFIX - 1 )); } ext[pos] = NULLCHAR; } UnGetCH( s ); targ_path = getCurlPath(); s = PreGetCH(); /* next char */ if( s == DOT ) { /* maybe of form "."{extc}*"."{extc}* */ ext[pos++] = s; for( s = PreGetCH(); pos < MAX_SUFFIX && isextc( s ); s = PreGetCH() ) { ext[pos++] = s; } if( pos == MAX_SUFFIX ) { PrtMsgExit(( FTL | LOC | MAXIMUM_TOKEN_IS, MAX_SUFFIX - 1 )); //NOTREACHED } ext[pos] = NULLCHAR; ret = TOK_SUFSUF; } else { if( *targ_path != NULLCHAR && *dep_path != NULLCHAR ) { PrtMsg( ERR | LOC | INVALID_SUFSUF ); } ret = TOK_SUF; } UnGetCH( s ); /* put back what we don't need */ if( *targ_path != NULLCHAR && *dep_path != NULLCHAR && ret == TOK_SUF ) { PrtMsg( ERR | LOC | INVALID_SUFSUF ); } else if( ret == TOK_SUF && checkDotName( ext ) ) { return( TOK_DOTNAME ); } CurAttr.u.ptr = StrDupSafe( ext ); return( ret ); }
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 LexMSDollar( STRM_T s ) /************************************* * If it is PartDeMacro then we have to put back the tokens as if it were a * MAC_NAME so that it can be DeMacroed fully later * This part only works since microsoft does not handle recursions */ { char temp[8]; assert( ismsspecial( s ) ); if( IsPartDeMacro || !DoingUpdate ) { /* we need to use SPECIAL_TMP_DOL_C to prevent recursion from kicking in because recursion occurs when there are still dollars remaining */ temp[0] = SPECIAL_TMP_DOL_C; temp[1] = s; if( s == '*' ) { s = PreGetCH(); if( s == '*' ) { temp[2] = s; temp[3] = NULLCHAR; } else { UnGetCH( s ); temp[2] = NULLCHAR; } } else { temp[2] = NULLCHAR; } CurAttr.u.ptr = CatModifier( temp, FALSE ); return( MAC_NAME ); } else { switch( s ) { case '<': CurAttr.u.form = FORM_FULL; return( MAC_INF_DEP ); case '*': s = PreGetCH(); if( s == '*' ) { CurAttr.u.form = FORM_FULL; return( MAC_ALL_DEP ); } else { CurAttr.u.form = FORM_NOEXT; UnGetCH( s ); return( MAC_CUR ); } case '?': CurAttr.u.form = FORM_FULL; return( MAC_YOUNG_DEP ); case '@': CurAttr.u.form = FORM_FULL; return( MAC_CUR ); default: UnGetCH( s ); return( MAC_START ); } } }