Subversion Repositories DevTools

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
227 dpurdie 1
/*
2
     Emulation of DOS startup code, using the following rules when 
3
     interpreting arguments given on the operating system command line:
4
 
5
          Arguments are delimited by white space, which is either a space 
6
          or a tab. 
7
 
8
          A string surrounded by double quotation marks is interpreted as 
9
          a single argument, regardless of white space contained within. A 
10
          quoted string can be embedded in an argument. Note that the 
11
          caret (^) is not recognized as an escape character or delimiter. 
12
 
13
          A double quotation mark preceded by a backslash, \", is 
14
          interpreted as a literal double quotation mark ("). 
15
 
16
          Backslashes are interpreted literally, unless they immediately 
17
          precede a double quotation mark. 
18
 
19
          If an even number of backslashes is followed by a double 
20
          quotation mark, then one backslash (\) is placed in the argv 
21
          array for every pair of backslashes (\\), and the double 
22
          quotation mark (") is interpreted as a string delimiter. 
23
 
24
          If an odd number of backslashes is followed by a double 
25
          quotation mark, then one backslash (\) is placed in the argv 
26
          array for every pair of backslashes (\\) and the double quotation 
27
          mark is interpreted as an escape sequence by the remaining 
28
          backslash, causing a literal double quotation mark (") to 
29
          be placed in argv. 
30
 
31
     This list illustrates the rules above by showing the interpreted 
32
     result passed to argv for several examples of command-line 
33
     arguments. The output listed in the second, third, and fourth 
34
     columns is from the ARGS.C program that follows the list.
35
 
36
     Command-Line Input       argv[1]        argv[2]        argv[3] 
37
     "a b c" d e              a b c          d              e 
38
     "ab\"c" "\\" d           ab"c           \              d 
39
     a\\\b d"e f"g h          a\\\b          de fg          h 
40
     a\\\"b c d               a\"b           c              d 
41
     a\\\\"b c" d e           a\\b c         d              e 
42
 */
43
#include <stdio.h>
44
#include <stdlib.h>
45
#include <tchar.h>
46
 
47
#define NULCHAR     '\0'
48
#define NLCHAR      '\n'
49
#define CRCHAR      '\r'
50
#define SPACECHAR   ' '
51
#define TABCHAR     '\t'
52
#define DQUOTECHAR  '\"'
53
#define SLASHCHAR   '\\'
54
 
55
static void         parse(const char *, const char *, char **, char *, int *, int *, int);
56
 
57
/***
58
*_setargv, __setargv - set up "argc" and "argv" for C programs
59
*
60
*Purpose:
61
*       Read the command line and create the argv array for C
62
*       programs.
63
*
64
*Entry:
65
*       Arguments are retrieved from the program command line,
66
*       pointed to by _acmdln.
67
*
68
*Exit:
69
*       "argv" points to a null-terminated list of pointers to ASCIZ
70
*       strings, each of which is an argument from the command line.
71
*       "argc" is the number of arguments.  The strings are copied from
72
*       the environment segment into space allocated on the heap/stack.
73
*       The list of pointers is also located on the heap or stack.
74
*       _pgmptr points to the program name.
75
*
76
*Exceptions:
77
*       Terminates with out of memory error if no memory to allocate.
78
*
79
*******************************************************************************/
80
 
81
int
82
parse_cmdbuffer(
83
    const char *arg0, const char *cmd, char ***__argv, int *__argc )
84
{
85
    char    *p;
86
    int     numargs, numchars;
87
    int     nls;                            /* 1 = contained line feeds */
88
 
89
    /* Are there line feeds, of so dont use SPACES or TABS as 
90
    argument delimitors */
91
    nls = strchr(cmd, NLCHAR) ? 1 : 0;
92
 
93
    /* first find out how much space is needed to store args */
94
    parse(arg0, cmd, NULL, NULL, &numargs, &numchars, nls);
95
 
96
    /* allocate space for argv[] vector and strings */
97
    p = malloc(numargs * sizeof(char *) + numchars * sizeof(char));
98
    if (p == NULL)
99
            return -1;                      /* error */
100
 
101
    /* store args and argv ptrs in just allocated block */
102
    parse(arg0, cmd, (char **)p, p + numargs * sizeof(char *), &numargs, &numchars, nls);
103
 
104
    /* set argv and argc */
105
    *__argc = numargs - 1;
106
    *__argv = (char **)p;
107
    return *__argc;
108
}
109
 
110
 
111
/***
112
*static void parse_cmdline(cmdstart, argv, args, numargs, numchars)
113
*
114
*Purpose:
115
*       Parses the command line and sets up the argv[] array.
116
*       On entry, cmdstart should point to the command line,
117
*       argv should point to memory for the argv array, args
118
*       points to memory to place the text of the arguments.
119
*       If these are NULL, then no storing (only coujting)
120
*       is done.  On exit, *numargs has the number of
121
*       arguments (plus one for a final NULL argument),
122
*       and *numchars has the number of bytes used in the buffer
123
*       pointed to by args.
124
*
125
*Entry:
126
*       char *cmdstart - pointer to command line of the form
127
*           <progname><nul><args><nul>
128
*       char **argv - where to build argv array; NULL means don't
129
*                       build array
130
*       char *args - where to place argument text; NULL means don't
131
*                       store text
132
*
133
*Exit:
134
*       no return value
135
*       int *numargs - returns number of argv entries created
136
*       int *numchars - number of characters used in args buffer
137
*
138
*Exceptions:
139
*
140
*******************************************************************************/
141
 
142
static void
143
parse( const char *arg0, const char *cmdstart, 
144
    char **argv, char *args, int *numargs, int *numchars, int linefeeds )
145
{
146
    const char *p;
147
    int inquote = 0;                        /* 1 = inside quotes */
148
    char quote_char;
149
    int copychar = 0;                       /* 1 = copy char to *args */
150
    unsigned numslash;                      /* num of backslashes seen */
151
 
152
    /* Handle arg0 */
153
    if (argv)
154
        *argv++ = (char *)arg0;
155
    *numargs = 1;                           /* the program name at least */
156
    *numchars = strlen(arg0)+1;
157
 
158
    /* Loop on each argument */
159
    for(p = cmdstart;;) {
160
 
161
        /* Eat (leading) white space */
162
        if ( *p ) {
163
            while (*p == SPACECHAR || *p == TABCHAR || *p == NLCHAR || *p == CRCHAR)
164
                ++p;
165
        }
166
 
167
        if (*p == NULCHAR)
168
            break;                          /* end of args */
169
 
170
        /* scan an argument */
171
        if (argv)
172
            *argv++ = args;                 /* store ptr to arg */
173
        ++*numargs;
174
 
175
        /* loop through scanning one argument */
176
        for (;;) {
177
            copychar = 1;
178
 
179
            /* Rules: 2N backslashes + " ==> N backslashes and begin/end quote
180
            2N+1 backslashes + " ==> N backslashes + literal "
181
            N backslashes ==> N backslashes */
182
            numslash = 0;
183
            while (*p == SLASHCHAR) {
184
                /* count number of backslashes for use below */
185
                ++p;
186
                ++numslash;
187
            }
188
 
189
            if (*p == DQUOTECHAR) {
190
                /* if 2N backslashes before, start/end quote, otherwise
191
                    copy literally */
192
                if (numslash % 2 == 0) {
193
                    if (inquote) {
194
                        if (p[1] == DQUOTECHAR)
195
                            p++;            /* Double quote inside quoted string */
196
                        else                /* skip first quote char and copy second */
197
                            copychar = 0;
198
                    } else
199
                        copychar = 0;       /* don't copy quote */
200
 
201
                    inquote = !inquote;
202
                }
203
                numslash /= 2;              /* divide numslash by two */
204
            }
205
 
206
            /* copy slashes */
207
            while (numslash--) {
208
                if (args)
209
                    *args++ = SLASHCHAR;
210
                ++*numchars;
211
                quote_char = SLASHCHAR;
212
            }
213
 
214
            /* if at end of arg, break loop */
215
            if (*p == NULCHAR || *p == NLCHAR || *p == CRCHAR ||
216
                    (!inquote && !linefeeds && 
217
                            (*p == SPACECHAR || *p == TABCHAR)))
218
                break;
219
 
220
            /* copy character into argument */
221
            if (copychar) {
222
                if (args)
223
                    *args++ = *p;
224
                ++*numchars;
225
            }
226
            ++p;
227
        }
228
 
229
        /* Warnings */
230
        if (inquote) {
231
            fprintf(stderr, "%s: Unmatched quote argument (@%u).\n", 
232
               arg0, (unsigned)(p - cmdstart)+1);
233
        }
234
        inquote = 0;
235
 
236
        /* null-terminate the argument */
237
        if (args)
238
            *args++ = NULCHAR;              /* terminate string */
239
        ++*numchars;
240
    }
241
 
242
    /* We put one last argument in -- a null ptr */
243
    if (argv)
244
        *argv++ = NULL;
245
    ++*numargs;
246
}
247
 
248