STATIC void popSENT( void ) /************************** * pop top SENT off stack. If necessary, close or free the apropriate things. */ { SENT *tmp; assert( headSent != NULL ); tmp = headSent; switch( tmp->type ) { case SENT_FILE: if( tmp->free ) { close( tmp->data.file.fh ); PrtMsg( DBG | INF | LOC | FINISHED_FILE, tmp->data.file.name ); } FreeSafe( tmp->data.file.buf ); FreeSafe( (void *)headSent->data.file.name ); break; case SENT_STR: if( tmp->free ) { FreeSafe( (void *)headSent->data.str.str ); } break; case SENT_CHAR: break; } headSent = tmp->next; /* advance to next SENT */ tmp->next = freeSent; /* push onto free stack */ freeSent = tmp; }
void LexFini( void ) /*************************/ { if( *targ_path != NULLCHAR ) { FreeSafe( targ_path ); targ_path = ""; } if( *dep_path != NULLCHAR ) { FreeSafe( dep_path ); dep_path = ""; } PreProcFini(); }
void DoWildCardClose( void ) /*********************************/ { if( path != NULL ) { FreeSafe( path ); path = NULL; } if( pattern != NULL ) { FreeSafe( pattern ); pattern = NULL; } if( parent != NULL ) { closedir( parent ); parent = NULL; } }
STATIC void freePathRing( PATHRING pathring ) /*******************************************/ { PATHNODE *walk; PATHNODE *cur; if( pathring == NULL ) { return; } walk = pathring; do { cur = walk; walk = walk->next; FreeSafe( cur->name ); FreeSafe( cur ); } while( walk != pathring ); }
void RenameTarget( TARGET *targ, const char *newname ) /****************************************************/ { (void)RemHashNode( targTab, targ->node.name, CASESENSITIVE ); if( targ->node.name != NULL ) { FreeSafe( targ->node.name ); } targ->node.name = FixName( StrDupSafe( newname ) ); AddHashNode( targTab, (HASHNODE *)targ ); }
int PutEnvSafe( ENV_TRACKER *env ) /**************************************** * This function takes over responsibility for freeing env */ { char *p; ENV_TRACKER **walk; ENV_TRACKER *old; int rc; size_t len; p = env->value; // upper case the name while( *p != '=' && *p != NULLCHAR ) { *p = toupper( *p ); ++p; } rc = putenv( env->value ); // put into environment if( p[0] == '=' && p[1] == '\0' ) { rc = 0; // we are deleting the envvar, ignore errors } len = p - env->value + 1; // len including '=' walk = &envList; while( *walk != NULL ) { if( strncmp( (*walk)->value, env->value, len ) == 0 ) { break; } walk = &(*walk)->next; } old = *walk; if( old != NULL ) { *walk = old->next; // unlink from chain FreeSafe( old ); } if( p[1] != 0 ) { // we're giving it a new value env->next = envList; // save the memory since putenv keeps a envList = env; // pointer to it... } else { // we're deleting an old value FreeSafe( env ); } return( rc ); }
void PutEnvFini( void ) /****************************/ { ENV_TRACKER *cur; while( envList != NULL ) { cur = envList; envList = cur->next; FreeSafe( cur ); } }
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 ); } } } }
STATIC void cleanDLLCmd( void ) { #ifdef DLLS_IMPLEMENTED DLL_CMD *n; DLL_CMD *temp; n = dllCommandList; while( n != NULL ) { FreeSafe( (char *)n->cmd_name ); if( n->inf.dll_name != NULL ) { FreeSafe( (char*) n->inf.dll_name ); } if( n->inf.ent_name != NULL ) { FreeSafe( (char *)n->inf.ent_name ); } temp = n; n = n->next; FreeSafe( temp ); } #endif }
STATIC BOOLEAN freeSuffix( void *node, void *ptr ) /************************************************/ { SUFFIX *suffix = node; CREATOR *creator; CREATOR *creator_next; (void)ptr; // Unused FreeSafe( suffix->node.name ); freePathRing( suffix->pathring ); for( creator = suffix->creator; creator != NULL; creator = creator_next ) { creator_next = creator->next; FreeSList( creator->slist ); FreeSafe( creator ); } FreeSafe( suffix ); return( FALSE ); }
STATIC BOOLEAN freeSuffix( void *node, void *ptr ) /************************************************/ { SUFFIX *suf = node; CREATOR *ccur; CREATOR *cwalk; (void)ptr; // Unused FreeSafe( suf->node.name ); freePathRing( suf->first ); cwalk = suf->creator; while( cwalk != NULL ) { ccur = cwalk; cwalk = cwalk->next; KillTarget( ccur->cretarg->node.name ); FreeSafe( ccur ); } FreeSafe( suf ); return( FALSE ); }
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 ); } }
STATIC void ExpandWildCards( TARGET *targ, DEPEND *depend ) /********************************************************** * Expand the wild cards now * also deMacroSpecial macros */ { TLIST *tlist; TLIST *currentEnd; TLIST *outTList; TLIST *temp; char *NodeName; assert( depend != NULL ); tlist = depend->targs; currentEnd = outTList = NULL; while( tlist != NULL ) { temp = NULL; // In Microsoft it is possible to have macros in the dependency. if( Glob.microsoft ) { exPush( targ, NULL, NULL ); NodeName = DeMacroSpecial( tlist->target->node.name ); exPop(); WildTList( &temp, NodeName, TRUE, TRUE ); FreeSafe( NodeName ); } else { WildTList( &temp, tlist->target->node.name, TRUE, TRUE ); } tlist = tlist->next; if( outTList != NULL ) { currentEnd->next = temp; } else { outTList = temp; } if( temp != NULL ) { currentEnd = temp; /* find the current end */ while( currentEnd->next != NULL ) { currentEnd = currentEnd -> next; } } } FreeTList( depend->targs ); depend->targs = outTList; }
STATIC RET_T streamScarce( void ) /*******************************/ { SENT *cur; if( freeSent == NULL ) { return( RET_ERROR ); } while( freeSent != NULL ) { cur = freeSent; freeSent = freeSent->next; FreeSafe( cur ); } return( RET_SUCCESS ); }
void LexMaybeFree( TOKEN_T tok ) /************************************** * remarks: Some tokens set CurAttr.u.ptr to a memory region. This routine * FreeSafes the region if tok is one of these token types. */ { switch( tok ) { case TOK_FILENAME: case TOK_CMD: case TOK_SUF: case TOK_SUFSUF: case TOK_PATH: case MAC_WS: case MAC_NAME: case MAC_PUNC: case MAC_TEXT: FreeSafe( CurAttr.u.ptr ); break; } }
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 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 */ } }
STATIC RET_T imply( TARGET *targ, const char *drive, const char *dir, const char *fname, const char *ext, bool must ) /******************************************************************** * targ is the target to be implied * drive is the drive of the target * dir is the path of the target * fname is the portion of targ's name without the extension * ext is the extension of targ's name * must must we make this target? * * RET_SUCCESS - performed cmds, * RET_WARN unable to imply, * RET_ERROR - perform failed */ { SUFFIX *srcsuf; CREATOR *cur; SUFFIX *cursuf; TARGET *imptarg = NULL; RET_T ret; bool newtarg; UINT32 startcount; char *buf; SLIST *curslist; SLIST *slist; // Slist chosen for sufsuf SLIST *slistDef; // Slist that has dependent path = "" SLIST *slistEmptyTargDepPath; bool UseDefaultSList; int slistCount; srcsuf = FindSuffix( ext ); if( srcsuf == NULL || srcsuf->creator == NULL ) { PrtMsg( DBG | INF | IMP_ENV_M, targ->node.name, M_HAS_NO_IMPLICIT ); return( RET_WARN ); } PrtMsg( DBG | INF | IMP_ENV_M, targ->node.name, M_CHECKING_IMPLICIT ); startcount = cListCount; for( cur = srcsuf->creator; cur != NULL; cur = cur->next ) { cursuf = cur->suffix; /* allocate a buffer */ buf = MallocSafe( _MAX_PATH ); slist = NULL; slistDef = NULL; slistEmptyTargDepPath = NULL; ret = RET_ERROR; UseDefaultSList = true; /* find path in SLIST */ slistCount = 0; for( curslist = cur->slist; curslist != NULL && ret != RET_SUCCESS; curslist = curslist->next ) { _makepath( buf, drive, dir, NULL, NULL ); FixName( buf ); /* * note the path of the current target must match the * path as specified in the slist */ if( stricmp( buf, curslist->targ_path ) == 0 ) { /* build filename for implied target */ _makepath( buf, NULL, curslist->dep_path, fname, cursuf->node.name ); /* try to find this file on path or in targets */ ret = TrySufPath( buf, buf, &imptarg, false ); if( ret == RET_SUCCESS ) { slist = curslist; /* later on we need to check if implied target does not */ /* exist we need to create it on the first directory we */ /* see on the SLIST since */ /* the first on the list is the one that was defined */ /* last in the makefile */ } else if( slistDef == NULL ) { slistDef = curslist; } } if( *curslist->targ_path == NULLCHAR && *curslist->dep_path == NULLCHAR ) { slistEmptyTargDepPath = curslist; } if( slistCount > 0 && slistEmptyTargDepPath != NULL ) { UseDefaultSList = false; } ++slistCount; } if( UseDefaultSList && slist == NULL && !Glob.compat_nmake ) { _makepath( buf, NULL, NULL, fname, cursuf->node.name ); /* try to find this file on path or in targets */ ret = TrySufPath( buf, buf, &imptarg, false ); switch( ret ) { case RET_WARN: break; case RET_ERROR: if( !Glob.compat_nmake ) { slistDef = slistEmptyTargDepPath; } break; case RET_SUCCESS: slist = slistEmptyTargDepPath; break; } } if( ret == RET_ERROR && slistDef == NULL ) { /* * No Default Slist found so must continue and find * another slist */ FreeSafe( buf ); continue; } if( (ret == RET_SUCCESS && imptarg == NULL) || ret == RET_ERROR ) { /* Either file doesn't exist, or it exists and we don't already * have a target for it. Either way, we create a new target. */ if( ret == RET_ERROR ) { slist = slistDef; /* file doesn't exist, assume in directory */ /* pointed to by the slistDef */ _makepath( buf, NULL, slist->dep_path, fname, cursuf->node.name ); } newtarg = true; imptarg = NewTarget( buf ); FreeSafe( buf ); /* don't need any more */ getStats( imptarg ); imptarg->busy = true; /* protect against recursion */ if( imply( imptarg, NULL, slist->dep_path, fname, cursuf->node.name, false ) == RET_ERROR ) { imptarg->error = true; } if( startcount != cListCount && (Glob.noexec || Glob.query) ) { imptarg->touched = true; imptarg->executed = true; } imptarg->updated = true; imptarg->busy = false; } else { /* We already know about imptarg, so just update it */ assert( imptarg != NULL ); FreeSafe( buf ); /* don't need any more */ newtarg = false; /* this isn't a new target */ Update( imptarg ); } /* We've tried our best to make the imptarg, check if it exists * after our efforts. */ if( targExists( imptarg ) ) { /* it exists - now we perform the implicit cmd list, and return */ ret = implyMaybePerform( targ, imptarg, slist->cretarg, must ); if( newtarg && !Glob.noexec ) { /* destroy the implied target, because the info in the target * structure is nicely stored on disk (unless Glob.noexec) */ KillTarget( imptarg->node.name ); } implyDebugInfo( targ, startcount ); return( ret ); } else if( newtarg ) { /* we created an unsuccessful target - so destroy it */ KillTarget( imptarg->node.name ); } /* We couldn't imply with this suffix... try next one */ } implyDebugInfo( targ, startcount ); return( RET_WARN ); }
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 ); }