Module: wine Branch: master Commit: 3ab449c96a281ec47ea9173b1a38687390311eb4 URL: http://source.winehq.org/git/wine.git/?a=commit;h=3ab449c96a281ec47ea9173b1a...
Author: Jason Edmeades us@edmeades.me.uk Date: Fri Feb 23 22:22:57 2007 +0000
cmd.exe: Add special SET modifiers.
---
programs/cmd/wcmdmain.c | 225 +++++++++++++++++++++++++++++++++++++++++++---- 1 files changed, 207 insertions(+), 18 deletions(-)
diff --git a/programs/cmd/wcmdmain.c b/programs/cmd/wcmdmain.c index 2d5f805..b7845c7 100644 --- a/programs/cmd/wcmdmain.c +++ b/programs/cmd/wcmdmain.c @@ -46,6 +46,8 @@ char quals[MAX_PATH], param1[MAX_PATH], param2[MAX_PATH]; BATCH_CONTEXT *context = NULL; static HANDLE old_stdin = INVALID_HANDLE_VALUE, old_stdout = INVALID_HANDLE_VALUE;
+static char *WCMD_expand_envvar(char *start); + /***************************************************************************** * Main entry point. This is a console application so we have a main() not a * winmain(). @@ -303,7 +305,7 @@ void WCMD_process_command (char *command) { char *cmd, *p, *s, *t; char temp[MAXSTRING]; - int status, i, len; + int status, i; DWORD count, creationDisposition; HANDLE h; char *whichcmd; @@ -410,25 +412,10 @@ void WCMD_process_command (char *command) strcat (p, s);
} else { - p++; + p = WCMD_expand_envvar(p); } } - -/* - * Expand up environment variables. - * FIXME: Move this to above, without reallocating - */ - len = ExpandEnvironmentStrings (new_cmd, NULL, 0); - cmd = HeapAlloc( GetProcessHeap(), 0, len ); - status = ExpandEnvironmentStrings (new_cmd, cmd, len); - if (!status) { - WCMD_print_error (); - HeapFree( GetProcessHeap(), 0, cmd ); - HeapFree( GetProcessHeap(), 0, new_cmd ); - return; - } else { - HeapFree( GetProcessHeap(), 0, new_cmd ); - } + cmd = new_cmd;
/* In a batch program, unknown variables are replace by nothing */ /* so remove any remaining %var% */ @@ -1135,3 +1122,205 @@ char temp_path[MAX_PATH], temp_file[MAX_PATH], temp_file2[MAX_PATH], temp_cmd[10 WCMD_process_command (temp_cmd); DeleteFile (temp_file); } + +/************************************************************************* + * WCMD_expand_envvar + * + * Expands environment variables, allowing for character substitution + */ +static char *WCMD_expand_envvar(char *start) { + char *endOfVar = NULL, *s; + char *colonpos = NULL; + char thisVar[MAXSTRING]; + char thisVarContents[MAXSTRING]; + char savedchar = 0x00; + int len; + + /* Find the end of the environment variable, and extract name */ + endOfVar = strchr(start+1, '%'); + if (endOfVar == NULL) { + /* FIXME: Some special conditions here depending opn whether + in batch, complex or not, and whether env var exists or not! */ + return start+1; + } + strncpy(thisVar, start, (endOfVar - start)+1); + thisVar[(endOfVar - start)+1] = 0x00; + colonpos = strchr(thisVar+1, ':'); + + /* If there's complex substitution, just need %var% for now + to get the expanded data to play with */ + if (colonpos) { + *colonpos = '%'; + savedchar = *(colonpos+1); + *(colonpos+1) = 0x00; + } + + /* Expand to contents, if unchanged, return */ + len = ExpandEnvironmentStrings(thisVar, thisVarContents, + sizeof(thisVarContents)); + if (len == 0) + return endOfVar+1; + + /* In a batch program, unknown env vars are replaced with nothing, + note syntax %garbage:1,3% results in anything after the ':' + except the % + From the command line, you just get back what you entered */ + if (lstrcmpi(thisVar, thisVarContents) == 0) { + + /* Restore the complex part after the compare */ + if (colonpos) { + *colonpos = ':'; + *(colonpos+1) = savedchar; + } + + s = strdup (endOfVar + 1); + + /* Command line - just ignore this */ + if (context == NULL) return endOfVar+1; + + /* Batch - replace unknown env var with nothing */ + if (colonpos == NULL) { + strcpy (start, s); + + } else { + len = strlen(thisVar); + thisVar[len-1] = 0x00; + /* If %:...% supplied, : is retained */ + if (colonpos == thisVar+1) { + strcpy (start, colonpos); + } else { + strcpy (start, colonpos+1); + } + strcat (start, s); + } + free (s); + return start; + + } + + /* See if we need to do complex substitution (any ':'s), if not + then our work here is done */ + if (colonpos == NULL) { + s = strdup (endOfVar + 1); + strcpy (start, thisVarContents); + strcat (start, s); + free(s); + return start; + } + + /* Restore complex bit */ + *colonpos = ':'; + *(colonpos+1) = savedchar; + + /* + Handle complex substitutions: + xxx=yyy (replace xxx with yyy) + *xxx=yyy (replace up to and including xxx with yyy) + ~x (from x chars in) + ~-x (from x chars from the end) + ~x,y (from x chars in for y characters) + ~x,-y (from x chars in until y characters from the end) + */ + + /* ~ is substring manipulation */ + if (savedchar == '~') { + + int substrposition, substrlength; + char *commapos = strchr(colonpos+2, ','); + char *startCopy; + + substrposition = atol(colonpos+2); + if (commapos) substrlength = atol(commapos+1); + + s = strdup (endOfVar + 1); + + /* Check bounds */ + if (substrposition >= 0) { + startCopy = &thisVarContents[min(substrposition, len)]; + } else { + startCopy = &thisVarContents[max(0, len+substrposition-1)]; + } + + if (commapos == NULL) { + strcpy (start, startCopy); /* Copy the lot */ + } else if (substrlength < 0) { + + int copybytes = (len+substrlength-1)-(startCopy-thisVarContents); + if (copybytes > len) copybytes = len; + else if (copybytes < 0) copybytes = 0; + strncpy (start, startCopy, copybytes); /* Copy the lot */ + start[copybytes] = 0x00; + } else { + strncpy (start, startCopy, substrlength); /* Copy the lot */ + start[substrlength] = 0x00; + } + + strcat (start, s); + free(s); + return start; + + /* search and replace manipulation */ + } else { + char *equalspos = strstr(colonpos, "="); + char *replacewith = equalspos+1; + char *found = NULL; + char *searchIn; + char *searchFor; + + s = strdup (endOfVar + 1); + if (equalspos == NULL) return start+1; + + /* Null terminate both strings */ + thisVar[strlen(thisVar)-1] = 0x00; + *equalspos = 0x00; + + /* Since we need to be case insensitive, copy the 2 buffers */ + searchIn = strdup(thisVarContents); + CharUpperBuff(searchIn, strlen(thisVarContents)); + searchFor = strdup(colonpos+1); + CharUpperBuff(searchFor, strlen(colonpos+1)); + + + /* Handle wildcard case */ + if (*(colonpos+1) == '*') { + /* Search for string to replace */ + found = strstr(searchIn, searchFor+1); + + if (found) { + /* Do replacement */ + strcpy(start, replacewith); + strcat(start, thisVarContents + (found-searchIn) + strlen(searchFor+1)); + strcat(start, s); + free(s); + } else { + /* Copy as it */ + strcpy(start, thisVarContents); + strcat(start, s); + } + + } else { + /* Loop replacing all instances */ + char *lastFound = searchIn; + char *outputposn = start; + + *start = 0x00; + while ((found = strstr(lastFound, searchFor))) { + strncpy(outputposn, + thisVarContents + (lastFound-searchIn), + (found - lastFound)); + outputposn = outputposn + (found - lastFound); + *outputposn = 0x00; + strcat(outputposn, replacewith); + outputposn = outputposn + strlen(replacewith); + lastFound = found + strlen(searchFor); + } + strcat(outputposn, + thisVarContents + (lastFound-searchIn)); + strcat(outputposn, s); + } + free(searchIn); + free(searchFor); + return start; + } + return start+1; +}