* 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
This commit is contained in:
usa 2003-07-18 06:00:24 +00:00
parent 8654ce809b
commit 5b1008a005
2 changed files with 179 additions and 212 deletions

View File

@ -1,3 +1,8 @@
Fri Jul 18 14:57:19 2003 NAKAMURA Usaku <usa@ruby-lang.org>
* win32/win32.c (make_cmdvector): recognize quote within string.
based on Nobu's patch ([ruby-win32:450]). [ruby-talk:75853]
Fri Jul 18 13:04:36 2003 Yukihiro Matsumoto <matz@ruby-lang.org> Fri Jul 18 13:04:36 2003 Yukihiro Matsumoto <matz@ruby-lang.org>
* eval.c (rb_f_missing): VCALL is called only for LOCAL_ID. no * eval.c (rb_f_missing): VCALL is called only for LOCAL_ID. no

View File

@ -89,7 +89,8 @@
bool NtSyncProcess = TRUE; bool NtSyncProcess = TRUE;
static struct ChildRecord *CreateChild(char *, char *, SECURITY_ATTRIBUTES *, HANDLE, HANDLE, HANDLE); 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 int valid_filename(char *s);
static void StartSockets (); static void StartSockets ();
static char *str_grow(struct RString *str, size_t new_size); 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 // 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 // Now set up the correct time stuff
@ -510,28 +511,44 @@ static char *szInternalCmds[] = {
"type", "type",
"ver", "ver",
"vol", "vol",
NULL
}; };
int static int
isInternalCmd(char *cmd) internal_match(const void *key, const void *elem)
{ {
int i, fRet=0; return strcmp(key, *(const char *const *)elem);
char **vec; }
int vecc = NtMakeCmdVector(cmd, &vec, FALSE);
if (vecc == 0) static int
return 0; isInternalCmd(const char *cmd)
for( i = 0; szInternalCmds[i] ; i++){ {
if(!strcasecmp(szInternalCmds[i], vec[0])){ int i;
fRet = 1; char cmdname[8], *b = cmdname, c;
break;
} 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;
SafeFree(vec, vecc); switch (c) {
case '<': case '>': case '|':
return fRet; return 1;
case '\0': case ' ': case '\t': case '\n':
break;
default:
return 0;
}
*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; shell = prog;
} }
else { 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) + char *tmp = ALLOCA_N(char, strlen(shell) + strlen(cmd) +
sizeof (" -c ")); sizeof (" -c "));
sprintf(tmp, "%s -c %s", shell, cmd); sprintf(tmp, "%s -c %s", shell, cmd);
cmd = tmp; cmd = tmp;
} }
else if ((shell = getenv("COMSPEC")) && 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) + char *tmp = ALLOCA_N(char, strlen(shell) + strlen(cmd) +
sizeof (" /c ")); sizeof (" /c "));
sprintf(tmp, "%s /c %s", shell, cmd); 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 { typedef struct _NtCmdLineElement {
struct _NtCmdLineElement *next, *prev; struct _NtCmdLineElement *next;
char *str; char *str;
int len; int len;
int flags; int flags;
@ -918,38 +936,11 @@ typedef struct _NtCmdLineElement {
#define NTMALLOC 0x2 // string in element was malloc'ed #define NTMALLOC 0x2 // string in element was malloc'ed
#define NTSTRING 0x4 // element contains a quoted string #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 static void
insert(const char *path, VALUE vinfo) insert(const char *path, VALUE vinfo)
{ {
NtCmdLineElement *tmpcurr; NtCmdLineElement *tmpcurr;
ListInfo *listinfo = (ListInfo *)vinfo; NtCmdLineElement ***tail = (NtCmdLineElement ***)vinfo;
tmpcurr = ALLOC(NtCmdLineElement); tmpcurr = ALLOC(NtCmdLineElement);
MEMZERO(tmpcurr, NtCmdLineElement, 1); MEMZERO(tmpcurr, NtCmdLineElement, 1);
@ -957,14 +948,8 @@ insert(const char *path, VALUE vinfo)
tmpcurr->str = ALLOC_N(char, tmpcurr->len + 1); tmpcurr->str = ALLOC_N(char, tmpcurr->len + 1);
tmpcurr->flags |= NTMALLOC; tmpcurr->flags |= NTMALLOC;
strcpy(tmpcurr->str, path); strcpy(tmpcurr->str, path);
if (listinfo->tail) { **tail = tmpcurr;
listinfo->tail->next = tmpcurr; *tail = &tmpcurr->next;
tmpcurr->prev = listinfo->tail;
listinfo->tail = tmpcurr;
}
else {
listinfo->tail = listinfo->head = tmpcurr;
}
} }
#ifdef HAVE_SYS_PARAM_H #ifdef HAVE_SYS_PARAM_H
@ -973,14 +958,13 @@ insert(const char *path, VALUE vinfo)
# define MAXPATHLEN 512 # define MAXPATHLEN 512
#endif #endif
void
NtCmdGlob (NtCmdLineElement *patt) static NtCmdLineElement **
cmdglob(NtCmdLineElement *patt, NtCmdLineElement **tail)
{ {
ListInfo listinfo;
char buffer[MAXPATHLEN], *buf = buffer; char buffer[MAXPATHLEN], *buf = buffer;
char *p; char *p;
NtCmdLineElement **last = tail;
listinfo.head = listinfo.tail = 0;
if (patt->len >= MAXPATHLEN) if (patt->len >= MAXPATHLEN)
buf = ruby_xmalloc(patt->len + 1); buf = ruby_xmalloc(patt->len + 1);
@ -990,21 +974,15 @@ NtCmdGlob (NtCmdLineElement *patt)
for (p = buf; *p; p = CharNext(p)) for (p = buf; *p; p = CharNext(p))
if (*p == '\\') if (*p == '\\')
*p = '/'; *p = '/';
rb_globi(buf, insert, (VALUE)&listinfo); rb_globi(buf, insert, (VALUE)&tail);
if (buf != buffer) if (buf != buffer)
free(buf); free(buf);
if (listinfo.head && listinfo.tail) { if (last == tail) return 0;
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 (patt->flags & NTMALLOC) if (patt->flags & NTMALLOC)
free(patt->str); 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 static bool
NtHasRedirection (char *cmd) has_redirection(const char *cmd)
{ {
int inquote = 0;
char quote = '\0'; char quote = '\0';
char *ptr ; const char *ptr;
// //
// Scan the string, looking for redirection (< or >) or pipe // Scan the string, looking for redirection (< or >) or pipe
// characters (|) that are not in a quoted string // characters (|) that are not in a quoted string
// //
for (ptr = cmd; *ptr; ptr++) { for (ptr = cmd; *ptr;) {
switch (*ptr) { switch (*ptr) {
case '\'': case '\'':
case '\"': case '\"':
if (inquote) { if (!quote)
if (quote == *ptr) {
inquote = 0;
quote = '\0';
}
}
else {
quote = *ptr; quote = *ptr;
inquote++; else if (quote == *ptr)
} quote = '\0';
ptr++;
break; break;
case '>': case '>':
case '<': case '<':
case '|': case '|':
if (!quote)
if (!inquote)
return TRUE; return TRUE;
ptr++;
break;
case '\\':
ptr++;
default:
ptr = CharNext(ptr);
break;
} }
} }
return FALSE; return FALSE;
} }
static inline char *
int skipspace(char *ptr)
NtMakeCmdVector (char *cmdline, char ***vec, int InputCmd)
{ {
int cmdlen = strlen(cmdline); while (ISSPACE(*ptr))
int done, instring, globbing, quoted, len; ptr++;
int newline, need_free = 0, i; return ptr;
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 **vptr;
char quote; char quote;
NtCmdLineElement *curr; NtCmdLineElement *curr, **tail;
NtCmdLineElement *cmdhead = NULL, **cmdtail = &cmdhead;
// //
// just return if we don't have a command line // just return if we don't have a command line
// //
if (cmdlen == 0) { while (ISSPACE(*cmd))
cmd++;
if (!*cmd) {
*vec = NULL; *vec = NULL;
return 0; return 0;
} }
cmdline = strdup(cmdline); ptr = cmdline = strdup(cmd);
//
// strip trailing white space
//
ptr = cmdline+(cmdlen - 1);
while(ptr >= cmdline && ISSPACE(*ptr))
--ptr;
*++ptr = '\0';
// //
// Ok, parse the command line, building a list of CmdLineElements. // 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. // The inner loop does one interation for each character in the element.
// //
for (done = 0, ptr = cmdline; *ptr;) { while (*(ptr = skipspace(ptr))) {
//
// zap any leading whitespace
//
while(ISSPACE(*ptr))
ptr++;
base = ptr; base = ptr;
quote = slashes = globbing = escape = 0;
for (done = newline = globbing = instring = quoted = 0; for (done = 0; !done && *ptr; ) {
*ptr && !done; ptr++) {
// //
// Switch on the current character. We only care about the // Switch on the current character. We only care about the
// white-space characters, the wild-card characters, and the // white-space characters, the wild-card characters, and the
@ -1118,55 +1084,40 @@ NtMakeCmdVector (char *cmdline, char ***vec, int InputCmd)
switch (*ptr) { switch (*ptr) {
case '\\': case '\\':
if (ptr[1] == '"') ptr++; slashes++;
break; break;
case ' ': case ' ':
case '\t': case '\t':
#if 0 case '\n':
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
// //
// if we're not in a string, then we're finished with this // if we're not in a string, then we're finished with this
// element // element
// //
if (!instring) if (!quote) {
done++; *ptr = 0;
done = 1;
}
break; break;
case '*': case '*':
case '?': case '?':
case '[':
case '{':
// //
// record the fact that this element has a wildcard character // record the fact that this element has a wildcard character
// N.B. Don't glob if inside a single quoted string // N.B. Don't glob if inside a single quoted string
// //
if (!(instring && quote == '\'')) if (quote != '\'')
globbing++; globbing++;
break; ptr++;
slashes = 0;
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++;
break; break;
case '\'': case '\'':
case '\"': case '\"':
// //
// if we're already in a string, see if this is the // if we're already in a string, see if this is the
// terminating close-quote. If it is, we're finished with // 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 we're not already in a string, start one.
// //
if (instring) { if (!(slashes & 1)) {
if (quote == *ptr) { if (!quote)
instring = 0; quote = *ptr;
else if (quote == *ptr)
quote = '\0'; quote = '\0';
} escape++;
}
else {
instring++;
quote = *ptr;
quoted++;
} }
slashes = 0;
break; 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, // 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 // base and ptr. Base points to the start of the element while ptr
// points to the character following the element. // points to the character following the element.
// //
curr = ALLOC(NtCmdLineElement);
memset (curr, 0, sizeof(*curr));
len = ptr - base; len = ptr - base;
if (quote) escape = 0;
else if (done) --len;
// //
// if it's an input vector element and it's enclosed by quotes, // if it's an input vector element and it's enclosed by quotes,
// we can remove them. // we can remove them.
// //
if (InputCmd && !instring && (base[0] == '\"' && base[len-1] == '\"')) { if (escape) {
char *p; char *p = base;
base++; slashes = quote = 0;
len -= 2; while (p < base + len) {
base[len] = 0; switch (*p) {
for (p = base; p < base + len; p++) { case '\\':
if ((p[0] == '\\' || p[0] == '\"') && p[1] == '"') { p++;
strcpy(p, p + 1); slashes++;
len--; 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->str = base;
curr->len = len; curr->len = len;
curr->flags |= (globbing ? NTGLOB : 0);
// if (globbing && (tail = cmdglob(curr, cmdtail))) {
// Now put it in the list of elements cmdtail = tail;
//
if (NtCmdTail) {
NtCmdTail->next = curr;
curr->prev = NtCmdTail;
NtCmdTail = curr;
} }
else { else {
NtCmdHead = NtCmdTail = curr; *cmdtail = curr;
} cmdtail = &curr->next;
}
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);
}
} }
} }
@ -1267,7 +1227,7 @@ NtMakeCmdVector (char *cmdline, char ***vec, int InputCmd)
// (argv) and a string table for the elements. // (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++; elements++;
strsz += (curr->len + 1); strsz += (curr->len + 1);
} }
@ -1275,8 +1235,6 @@ NtMakeCmdVector (char *cmdline, char ***vec, int InputCmd)
len = (elements+1)*sizeof(char *) + strsz; len = (elements+1)*sizeof(char *) + strsz;
buffer = ALLOC_N(char, len); buffer = ALLOC_N(char, len);
memset (buffer, 0, len);
// //
// make vptr point to the start of the buffer // make vptr point to the start of the buffer
// and ptr point to the area we'll consider the string table. // 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 *); ptr = buffer + (elements+1) * sizeof(char *);
for (curr = NtCmdHead; curr; curr = curr->next) { while (curr = cmdhead) {
strncpy (ptr, curr->str, curr->len); strncpy (ptr, curr->str, curr->len);
ptr[curr->len] = '\0'; ptr[curr->len] = '\0';
*vptr++ = ptr; *vptr++ = ptr;
ptr += curr->len + 1; ptr += curr->len + 1;
cmdhead = curr->next;
if (curr->flags & NTMALLOC) free(curr->str);
free(curr);
} }
NtFreeCmdLine(); *vptr = 0;
*vec = (char **) buffer; *vec = (char **) buffer;
free(cmdline); free(cmdline);
return elements; return elements;