summaryrefslogtreecommitdiff
path: root/win32
diff options
context:
space:
mode:
authorusa <usa@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2003-07-18 06:00:24 +0000
committerusa <usa@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2003-07-18 06:00:24 +0000
commit5b1008a005da0a6d4a65873e0f26e458002c9bd9 (patch)
tree13dbb5d37a78644b244361764ab649892c325b89 /win32
parent8654ce809b09e2422ef4d37acc76241582c98786 (diff)
* win32/win32.c (make_cmdvector): recognize quote within string.
based on Nobu's patch ([ruby-win32:450]). [ruby-talk:75853] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@4087 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'win32')
-rw-r--r--win32/win32.c384
1 files changed, 173 insertions, 211 deletions
diff --git a/win32/win32.c b/win32/win32.c
index d819dba2ee..e36c0d1cb7 100644
--- a/win32/win32.c
+++ b/win32/win32.c
@@ -89,7 +89,8 @@
bool NtSyncProcess = TRUE;
static struct ChildRecord *CreateChild(char *, char *, SECURITY_ATTRIBUTES *, HANDLE, HANDLE, HANDLE);
-static bool NtHasRedirection (char *);
+static int make_cmdvector(const char *, char ***);
+static bool has_redirection(const char *);
static int valid_filename(char *s);
static void StartSockets ();
static char *str_grow(struct RString *str, size_t new_size);
@@ -370,7 +371,7 @@ NtInitialize(int *argc, char ***argv)
//
// subvert cmd.exe's feeble attempt at command line parsing
//
- *argc = NtMakeCmdVector((char *)GetCommandLine(), argv, TRUE);
+ *argc = make_cmdvector(GetCommandLine(), argv);
//
// Now set up the correct time stuff
@@ -510,28 +511,44 @@ static char *szInternalCmds[] = {
"type",
"ver",
"vol",
- NULL
};
-int
-isInternalCmd(char *cmd)
+static int
+internal_match(const void *key, const void *elem)
{
- int i, fRet=0;
- char **vec;
- int vecc = NtMakeCmdVector(cmd, &vec, FALSE);
+ return strcmp(key, *(const char *const *)elem);
+}
- if (vecc == 0)
+static int
+isInternalCmd(const char *cmd)
+{
+ int i;
+ char cmdname[8], *b = cmdname, c;
+
+ do {
+ if (!(c = *cmd++)) return 0;
+ } while (isspace(c));
+ while (isalpha(c)) {
+ *b++ = tolower(c);
+ if (b == cmdname + sizeof(cmdname)) return 0;
+ if (!(c = *cmd++)) return 0;
+ }
+ if (c == '.') c = *cmd;
+ switch (c) {
+ case '<': case '>': case '|':
+ return 1;
+ case '\0': case ' ': case '\t': case '\n':
+ break;
+ default:
return 0;
- for( i = 0; szInternalCmds[i] ; i++){
- if(!strcasecmp(szInternalCmds[i], vec[0])){
- fRet = 1;
- break;
- }
}
-
- SafeFree(vec, vecc);
-
- return fRet;
+ *b = 0;
+ if (!bsearch(cmdname, szInternalCmds,
+ sizeof(szInternalCmds) / sizeof(*szInternalCmds),
+ sizeof(*szInternalCmds),
+ internal_match))
+ return 0;
+ return 1;
}
@@ -860,14 +877,15 @@ CreateChild(char *cmd, char *prog, SECURITY_ATTRIBUTES *psa, HANDLE hInput, HAND
shell = prog;
}
else {
- if ((shell = getenv("RUBYSHELL")) && NtHasRedirection(cmd)) {
+ int redir = -1;
+ if ((shell = getenv("RUBYSHELL")) && (redir = has_redirection(cmd))) {
char *tmp = ALLOCA_N(char, strlen(shell) + strlen(cmd) +
sizeof (" -c "));
sprintf(tmp, "%s -c %s", shell, cmd);
cmd = tmp;
}
else if ((shell = getenv("COMSPEC")) &&
- (NtHasRedirection(cmd) || isInternalCmd(cmd))) {
+ ((redir < 0 ? has_redirection(cmd) : redir) || isInternalCmd(cmd))) {
char *tmp = ALLOCA_N(char, strlen(shell) + strlen(cmd) +
sizeof (" /c "));
sprintf(tmp, "%s /c %s", shell, cmd);
@@ -904,7 +922,7 @@ CreateChild(char *cmd, char *prog, SECURITY_ATTRIBUTES *psa, HANDLE hInput, HAND
}
typedef struct _NtCmdLineElement {
- struct _NtCmdLineElement *next, *prev;
+ struct _NtCmdLineElement *next;
char *str;
int len;
int flags;
@@ -918,38 +936,11 @@ typedef struct _NtCmdLineElement {
#define NTMALLOC 0x2 // string in element was malloc'ed
#define NTSTRING 0x4 // element contains a quoted string
-NtCmdLineElement *NtCmdHead = NULL, *NtCmdTail = NULL;
-
-void
-NtFreeCmdLine(void)
-{
- NtCmdLineElement *ptr;
-
- while(NtCmdHead) {
- ptr = NtCmdHead;
- NtCmdHead = NtCmdHead->next;
- free(ptr);
- }
- NtCmdHead = NtCmdTail = NULL;
-}
-
-//
-// This function expands wild card characters that were spotted
-// during the parse phase. The idea here is to call FindFirstFile and
-// FindNextFile with the wildcard pattern specified, and splice in the
-// resulting list of new names. If the wildcard pattern doesn't match
-// any existing files, just leave it in the list.
-//
-typedef struct {
- NtCmdLineElement *head;
- NtCmdLineElement *tail;
-} ListInfo;
-
static void
insert(const char *path, VALUE vinfo)
{
NtCmdLineElement *tmpcurr;
- ListInfo *listinfo = (ListInfo *)vinfo;
+ NtCmdLineElement ***tail = (NtCmdLineElement ***)vinfo;
tmpcurr = ALLOC(NtCmdLineElement);
MEMZERO(tmpcurr, NtCmdLineElement, 1);
@@ -957,14 +948,8 @@ insert(const char *path, VALUE vinfo)
tmpcurr->str = ALLOC_N(char, tmpcurr->len + 1);
tmpcurr->flags |= NTMALLOC;
strcpy(tmpcurr->str, path);
- if (listinfo->tail) {
- listinfo->tail->next = tmpcurr;
- tmpcurr->prev = listinfo->tail;
- listinfo->tail = tmpcurr;
- }
- else {
- listinfo->tail = listinfo->head = tmpcurr;
- }
+ **tail = tmpcurr;
+ *tail = &tmpcurr->next;
}
#ifdef HAVE_SYS_PARAM_H
@@ -973,14 +958,13 @@ insert(const char *path, VALUE vinfo)
# define MAXPATHLEN 512
#endif
-void
-NtCmdGlob (NtCmdLineElement *patt)
+
+static NtCmdLineElement **
+cmdglob(NtCmdLineElement *patt, NtCmdLineElement **tail)
{
- ListInfo listinfo;
char buffer[MAXPATHLEN], *buf = buffer;
char *p;
-
- listinfo.head = listinfo.tail = 0;
+ NtCmdLineElement **last = tail;
if (patt->len >= MAXPATHLEN)
buf = ruby_xmalloc(patt->len + 1);
@@ -990,21 +974,15 @@ NtCmdGlob (NtCmdLineElement *patt)
for (p = buf; *p; p = CharNext(p))
if (*p == '\\')
*p = '/';
- rb_globi(buf, insert, (VALUE)&listinfo);
+ rb_globi(buf, insert, (VALUE)&tail);
if (buf != buffer)
free(buf);
- if (listinfo.head && listinfo.tail) {
- listinfo.head->prev = patt->prev;
- listinfo.tail->next = patt->next;
- if (listinfo.head->prev)
- listinfo.head->prev->next = listinfo.head;
- if (listinfo.tail->next)
- listinfo.tail->next->prev = listinfo.tail;
- }
+ if (last == tail) return 0;
if (patt->flags & NTMALLOC)
free(patt->str);
- // free(patt); //TODO: memory leak occures here. we have to fix it.
+ free(patt);
+ return tail;
}
//
@@ -1013,80 +991,77 @@ NtCmdGlob (NtCmdLineElement *patt)
//
static bool
-NtHasRedirection (char *cmd)
+has_redirection(const char *cmd)
{
- int inquote = 0;
char quote = '\0';
- char *ptr ;
+ const char *ptr;
//
// Scan the string, looking for redirection (< or >) or pipe
// characters (|) that are not in a quoted string
//
- for (ptr = cmd; *ptr; ptr++) {
-
+ for (ptr = cmd; *ptr;) {
switch (*ptr) {
-
case '\'':
case '\"':
- if (inquote) {
- if (quote == *ptr) {
- inquote = 0;
- quote = '\0';
- }
- }
- else {
+ if (!quote)
quote = *ptr;
- inquote++;
- }
+ else if (quote == *ptr)
+ quote = '\0';
+ ptr++;
break;
case '>':
case '<':
case '|':
-
- if (!inquote)
+ if (!quote)
return TRUE;
+ ptr++;
+ break;
+
+ case '\\':
+ ptr++;
+ default:
+ ptr = CharNext(ptr);
+ break;
}
}
return FALSE;
}
+static inline char *
+skipspace(char *ptr)
+{
+ while (ISSPACE(*ptr))
+ ptr++;
+ return ptr;
+}
-int
-NtMakeCmdVector (char *cmdline, char ***vec, int InputCmd)
-{
- int cmdlen = strlen(cmdline);
- int done, instring, globbing, quoted, len;
- int newline, need_free = 0, i;
- int elements, strsz;
- int slashes = 0;
- char *ptr, *base, *buffer;
+static int
+make_cmdvector(const char *cmd, char ***vec)
+{
+ int cmdlen, globbing, len, i;
+ int elements, strsz, done;
+ int slashes, escape;
+ char *ptr, *base, *buffer, *cmdline;
char **vptr;
char quote;
- NtCmdLineElement *curr;
+ NtCmdLineElement *curr, **tail;
+ NtCmdLineElement *cmdhead = NULL, **cmdtail = &cmdhead;
//
// just return if we don't have a command line
//
- if (cmdlen == 0) {
+ while (ISSPACE(*cmd))
+ cmd++;
+ if (!*cmd) {
*vec = NULL;
return 0;
}
- cmdline = strdup(cmdline);
-
- //
- // strip trailing white space
- //
-
- ptr = cmdline+(cmdlen - 1);
- while(ptr >= cmdline && ISSPACE(*ptr))
- --ptr;
- *++ptr = '\0';
-
+ ptr = cmdline = strdup(cmd);
//
// Ok, parse the command line, building a list of CmdLineElements.
@@ -1097,19 +1072,10 @@ NtMakeCmdVector (char *cmdline, char ***vec, int InputCmd)
// The inner loop does one interation for each character in the element.
//
- for (done = 0, ptr = cmdline; *ptr;) {
-
- //
- // zap any leading whitespace
- //
-
- while(ISSPACE(*ptr))
- ptr++;
+ while (*(ptr = skipspace(ptr))) {
base = ptr;
-
- for (done = newline = globbing = instring = quoted = 0;
- *ptr && !done; ptr++) {
-
+ quote = slashes = globbing = escape = 0;
+ for (done = 0; !done && *ptr; ) {
//
// Switch on the current character. We only care about the
// white-space characters, the wild-card characters, and the
@@ -1118,55 +1084,40 @@ NtMakeCmdVector (char *cmdline, char ***vec, int InputCmd)
switch (*ptr) {
case '\\':
- if (ptr[1] == '"') ptr++;
+ slashes++;
break;
+
case ' ':
case '\t':
-#if 0
- case '/': // have to do this for NT/DOS option strings
-
- //
- // check to see if we're parsing an option switch
- //
-
- if (*ptr == '/' && base == ptr)
- continue;
-#endif
+ case '\n':
//
// if we're not in a string, then we're finished with this
// element
//
- if (!instring)
- done++;
+ if (!quote) {
+ *ptr = 0;
+ done = 1;
+ }
break;
case '*':
case '?':
-
+ case '[':
+ case '{':
//
// record the fact that this element has a wildcard character
// N.B. Don't glob if inside a single quoted string
//
- if (!(instring && quote == '\''))
+ if (quote != '\'')
globbing++;
- break;
-
- case '\n':
-
- //
- // If this string contains a newline, mark it as such so
- // we can replace it with the two character sequence "\n"
- // (cmd.exe doesn't like raw newlines in strings...sigh).
- //
-
- newline++;
+ ptr++;
+ slashes = 0;
break;
case '\'':
case '\"':
-
//
// if we're already in a string, see if this is the
// terminating close-quote. If it is, we're finished with
@@ -1174,90 +1125,99 @@ NtMakeCmdVector (char *cmdline, char ***vec, int InputCmd)
// If we're not already in a string, start one.
//
- if (instring) {
- if (quote == *ptr) {
- instring = 0;
+ if (!(slashes & 1)) {
+ if (!quote)
+ quote = *ptr;
+ else if (quote == *ptr)
quote = '\0';
- }
- }
- else {
- instring++;
- quote = *ptr;
- quoted++;
+ escape++;
}
+ slashes = 0;
break;
+
+ default:
+ ptr = CharNext(ptr);
+ slashes = 0;
+ continue;
}
+ ptr++;
}
//
- // need to back up ptr by one due to last increment of for loop
- // (if we got out by seeing white space)
- //
-
- if (*ptr)
- ptr--;
-
- //
// when we get here, we've got a pair of pointers to the element,
// base and ptr. Base points to the start of the element while ptr
// points to the character following the element.
//
- curr = ALLOC(NtCmdLineElement);
- memset (curr, 0, sizeof(*curr));
-
len = ptr - base;
+ if (quote) escape = 0;
+ else if (done) --len;
//
// if it's an input vector element and it's enclosed by quotes,
// we can remove them.
//
- if (InputCmd && !instring && (base[0] == '\"' && base[len-1] == '\"')) {
- char *p;
- base++;
- len -= 2;
- base[len] = 0;
- for (p = base; p < base + len; p++) {
- if ((p[0] == '\\' || p[0] == '\"') && p[1] == '"') {
- strcpy(p, p + 1);
- len--;
+ if (escape) {
+ char *p = base;
+ slashes = quote = 0;
+ while (p < base + len) {
+ switch (*p) {
+ case '\\':
+ p++;
+ slashes++;
+ break;
+
+ case '\'':
+ case '"':
+ if (!(slashes & 1)) {
+ if (!quote)
+ quote = *p;
+ else if (quote == *p)
+ quote = '\0';
+ else {
+ p++;
+ slashes = 0;
+ break;
+ }
+ }
+ if (base + slashes == p) {
+ base += slashes >> 1;
+ len -= slashes >> 1;
+ slashes &= 1;
+ }
+ if (base == p) {
+ base = ++p;
+ --len;
+ }
+ else {
+ memcpy(p - ((slashes + 1) >> 1), p + (~slashes & 1), base + len - p);
+ slashes >>= 1;
+ p -= slashes;
+ len -= slashes + 1;
+ slashes = 0;
+ }
+ break;
+
+ default:
+ p = CharNext(p);
+ slashes = 0;
+ break;
}
}
}
- else if (InputCmd && !instring && (base[0] == '\'' && base[len-1] == '\'')) {
- base++;
- len -= 2;
- }
+ curr = ALLOC(NtCmdLineElement);
+ MEMZERO(curr, NtCmdLineElement, 1);
curr->str = base;
curr->len = len;
- curr->flags |= (globbing ? NTGLOB : 0);
- //
- // Now put it in the list of elements
- //
- if (NtCmdTail) {
- NtCmdTail->next = curr;
- curr->prev = NtCmdTail;
- NtCmdTail = curr;
+ if (globbing && (tail = cmdglob(curr, cmdtail))) {
+ cmdtail = tail;
}
else {
- NtCmdHead = NtCmdTail = curr;
- }
- }
-
- if (InputCmd) {
-
- //
- // When we get here we've finished parsing the command line. Now
- // we need to run the list, expanding any globbing patterns.
- //
-
- for(curr = NtCmdHead; curr; curr = curr->next) {
- if (curr->flags & NTGLOB) {
- NtCmdGlob(curr);
- }
+ *cmdtail = curr;
+ cmdtail = &curr->next;
}
}
@@ -1267,7 +1227,7 @@ NtMakeCmdVector (char *cmdline, char ***vec, int InputCmd)
// (argv) and a string table for the elements.
//
- for (elements = 0, strsz = 0, curr = NtCmdHead; curr; curr = curr->next) {
+ for (elements = 0, strsz = 0, curr = cmdhead; curr; curr = curr->next) {
elements++;
strsz += (curr->len + 1);
}
@@ -1275,8 +1235,6 @@ NtMakeCmdVector (char *cmdline, char ***vec, int InputCmd)
len = (elements+1)*sizeof(char *) + strsz;
buffer = ALLOC_N(char, len);
- memset (buffer, 0, len);
-
//
// make vptr point to the start of the buffer
// and ptr point to the area we'll consider the string table.
@@ -1293,13 +1251,17 @@ NtMakeCmdVector (char *cmdline, char ***vec, int InputCmd)
ptr = buffer + (elements+1) * sizeof(char *);
- for (curr = NtCmdHead; curr; curr = curr->next) {
+ while (curr = cmdhead) {
strncpy (ptr, curr->str, curr->len);
ptr[curr->len] = '\0';
*vptr++ = ptr;
ptr += curr->len + 1;
+ cmdhead = curr->next;
+ if (curr->flags & NTMALLOC) free(curr->str);
+ free(curr);
}
- NtFreeCmdLine();
+ *vptr = 0;
+
*vec = (char **) buffer;
free(cmdline);
return elements;