Skip to content

Commit 35028b6

Browse files
committed
fix issue# 52 call incorrectly parsing arguments
when CALLing a batch file, the command line should not attempt to determine what are option characters when splitting into separate options this may break some batch files that depend on FreeCOM bug of splitting argument1/opt1 into %1=argument1 %2=/opt1 instead of %1=argument1/op1 as done by other command shells.
1 parent 6528c46 commit 35028b6

File tree

7 files changed

+69
-9
lines changed

7 files changed

+69
-9
lines changed

docs/cmt5.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ i) /A and /B of the COPY command are local options, e.g.:
2626
ii) the /C option of FreeCom itself don't follow any common rule for
2727
option, because anything right of it (except one optional argument
2828
sign) is interpreted as an argument for this option.
29+
Note: CALL command is similar, except it supports several optional
30+
arguments then batch filename followed by its arguments
2931

3032

3133
=== How an option is parsed
@@ -349,7 +351,7 @@ xmpl(char *line)
349351
== General reflections
350352

351353
1) The callback mechanism allows a very flexible association between
352-
a syntacical correct option to a semantic.
354+
a syntactical correct option to a semantic.
353355
However, if other semantics are needed, the optScan***() function
354356
set should be improved rather than locally implemented into
355357
the callback function.

lib/find.c

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,37 @@ char *skip_word(char *p)
9898
char *skipdm(char *p)
9999
{ return find(p, 0);
100100
}
101+
102+
/*
103+
* Find the next delimiter/non-delimiter within p
104+
* Honor quotes and leading option characters
105+
*/
106+
static char *find_batch(char *p, int delim)
107+
{ int ch, quote;
108+
109+
assert(p);
110+
111+
dprintf(("find_batch(%s, %i) -- ", p, delim));
112+
quote = 0;
113+
while((ch = *p++) != '\0' && (quote
114+
|| (delim && !(isargdelim(ch)))
115+
|| (!delim && isargdelim(ch))))
116+
{
117+
if(quote == ch)
118+
quote = 0;
119+
else if(strchr(QUOTE_STR, ch))
120+
quote = ch;
121+
}
122+
123+
dprintf(("returning %s\n", (p-1)));
124+
return p - 1;
125+
}
126+
127+
128+
char *skipnonoptdm(char *p)
129+
{ return find_batch(p, 0);
130+
}
131+
132+
char *skipnonopt_word(char *p)
133+
{ return find_batch(p, 1);
134+
}

lib/split.c

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,19 @@
4747

4848
#include "../include/cmdline.h"
4949

50-
static int addArg(char ***Xarg, int *argc, char *sBeg, char **sEnd)
50+
char *skipnonoptdm(char *p); /* lib/find.c */
51+
char *skipnonopt_word(char *p);
52+
53+
54+
static int addArg(char ***Xarg, int *argc, char *sBeg, char **sEnd, int ignore_options)
5155
{ char **arg;
5256

5357
assert(Xarg);
5458
assert(argc);
5559
assert(sEnd);
5660
assert(sBeg);
5761

58-
*sEnd = skip_word(sBeg); /* find end of argument */
62+
*sEnd = (ignore_options ? skipnonopt_word(sBeg) : skip_word(sBeg)); /* find end of argument */
5963

6064
/* Because *start != '\0' && !isargdelim(*start) ==> s != start */
6165
assert(*sEnd > sBeg);
@@ -77,7 +81,7 @@ static int addArg(char ***Xarg, int *argc, char *sBeg, char **sEnd)
7781
return 0;
7882
}
7983

80-
char **split(char *s, int *args)
84+
static char **split_cmdline(char *s, int *args, int ignore_options)
8185
{
8286
char **arg,
8387
*start;
@@ -91,12 +95,23 @@ char **split(char *s, int *args)
9195
ac = 0;
9296

9397
/* skip to next argument */
94-
if(s) while (*(start = skipdm(s)) != '\0')
98+
if(s) while (*(start = (ignore_options?skipnonoptdm(s):skipdm(s))) != '\0')
9599
{
96-
if(addArg(&arg, &ac, start, &s))
100+
if(addArg(&arg, &ac, start, &s, ignore_options))
97101
return 0;
98102
}
99103

100104
arg[*args = ac] = 0;
101105
return arg;
102106
}
107+
108+
char **split(char *s, int *args)
109+
{
110+
return split_cmdline(s, args, 0);
111+
}
112+
113+
/* we must not split on option delimiters, only argument delimiters, see issue#52 */
114+
char **split_batchargs(char *s, int *args)
115+
{
116+
return split_cmdline(s, args, 1);
117+
}

shell/batch.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,14 +134,20 @@ struct bcontext *activeBatchContext(void)
134134
return b;
135135
}
136136

137+
138+
/* see split(...) in lib\split.c
139+
-- we must not split on option delimiters, only argument delimiters, see issue#52
140+
*/
141+
char **split_batchargs(char *s, int *args);
142+
137143
/*
138144
* setBatchParams builds a parameter list in newly allocated memory.
139145
* The parameters consist of null terminated strings with a final
140146
* NULL character signalling the end of the parameters.
141147
*/
142148
int setBatchParams(char *s)
143149
{
144-
if((bc->params = split(s, &bc->numParams)) == 0)
150+
if((bc->params = split_batchargs(s, &bc->numParams)) == 0)
145151
{
146152
error_out_of_memory();
147153
return 0;

shell/command.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ void execute(char *first, char *rest, int lh_lf)
204204
assert(extension);
205205

206206
/* loadhigh/loadfix don't do batch files */
207-
if(!lh_lf && stricmp(extension, ".bat") == 0) {
207+
if(!lh_lf && ((stricmp(extension, ".bat") == 0) || (stricmp(extension, ".cmd") == 0))) {
208208
dprintf(("[BATCH: %s %s]\n", fullname, rest));
209209
batch(fullname, first, rest);
210210
} else if(stricmp(extension, ".exe") == 0

tests/bat2.bat

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
echo in bat 2
2-
call bat3.bat
2+
call bat3.bat ../nonexistantdir/argument1 ..\nonexistantdir\argument2 3\4\5/6
33
echo back in bat 2

tests/bat3.bat

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
11
echo in bat 3
2+
echo %1
3+
echo all the args [%1 %2 %3 %4 %5 %6 %7 %8 %9]
4+
echo leaving bat 3

0 commit comments

Comments
 (0)