Whamcloud - gitweb
Merge branch 'maint' into next
[tools/e2fsprogs.git] / lib / ss / parse.c
1 /*
2  * Copyright 1987, 1988 by MIT Student Information Processing Board
3  *
4  * Permission to use, copy, modify, and distribute this software and
5  * its documentation for any purpose is hereby granted, provided that
6  * the names of M.I.T. and the M.I.T. S.I.P.B. not be used in
7  * advertising or publicity pertaining to distribution of the software
8  * without specific, written prior permission.  M.I.T. and the
9  * M.I.T. S.I.P.B. make no representations about the suitability of
10  * this software for any purpose.  It is provided "as is" without
11  * express or implied warranty.
12  */
13
14 #include "config.h"
15 #ifdef HAS_STDLIB_H
16 #include <stdlib.h>
17 #endif
18 #include <string.h>
19 #ifdef HAVE_ERRNO_H
20 #include <errno.h>
21 #endif
22
23 #include "ss_internal.h"
24
25 enum parse_mode { WHITESPACE, TOKEN, QUOTED_STRING };
26
27 /*
28  * parse(line_ptr, argc_ptr)
29  *
30  * Function:
31  *      Parses line, dividing at whitespace, into tokens, returns
32  *      the "argc" and "argv" values.
33  * Arguments:
34  *      line_ptr (char *)
35  *              Pointer to text string to be parsed.
36  *      argc_ptr (int *)
37  *              Where to put the "argc" (number of tokens) value.
38  * Returns:
39  *      argv (char **)
40  *              Series of pointers to parsed tokens.
41  */
42
43 #define NEW_ARGV(old,n) (char **)realloc((char *)old,\
44                                          (unsigned)(n+2)*sizeof(char*))
45
46 char **ss_parse(int sci_idx, register char *line_ptr, int *argc_ptr)
47 {
48     register char **argv, *cp;
49     register int argc;
50     register enum parse_mode parse_mode;
51
52     argv = (char **) malloc (sizeof(char *));
53     if (argv == (char **)NULL) {
54         ss_error(sci_idx, errno, "Can't allocate storage");
55         *argc_ptr = 0;
56         return(argv);
57     }
58     *argv = (char *)NULL;
59
60     argc = 0;
61
62     parse_mode = WHITESPACE;    /* flushing whitespace */
63     cp = line_ptr;              /* cp is for output */
64     while (1) {
65 #ifdef DEBUG
66         {
67             printf ("character `%c', mode %d\n", *line_ptr, parse_mode);
68         }
69 #endif
70         while (parse_mode == WHITESPACE) {
71             if (*line_ptr == '\0')
72                 goto end_of_line;
73             if (*line_ptr == ' ' || *line_ptr == '\t') {
74                 line_ptr++;
75                 continue;
76             }
77             if (*line_ptr == '"') {
78                 /* go to quoted-string mode */
79                 parse_mode = QUOTED_STRING;
80                 cp = line_ptr++;
81                 argv = NEW_ARGV (argv, argc);
82                 argv[argc++] = cp;
83                 argv[argc] = NULL;
84             }
85             else {
86                 /* random-token mode */
87                 parse_mode = TOKEN;
88                 cp = line_ptr;
89                 argv = NEW_ARGV (argv, argc);
90                 if (argv == NULL) {
91                         *argc_ptr = errno;
92                         return argv;
93                 }
94                 argv[argc++] = line_ptr;
95                 argv[argc] = NULL;
96             }
97         }
98         while (parse_mode == TOKEN) {
99             if (*line_ptr == '\0') {
100                 *cp++ = '\0';
101                 goto end_of_line;
102             }
103             else if (*line_ptr == ' ' || *line_ptr == '\t') {
104                 *cp++ = '\0';
105                 line_ptr++;
106                 parse_mode = WHITESPACE;
107             }
108             else if (*line_ptr == '"') {
109                 line_ptr++;
110                 parse_mode = QUOTED_STRING;
111             }
112             else {
113                 *cp++ = *line_ptr++;
114             }
115         }
116         while (parse_mode == QUOTED_STRING) {
117             if (*line_ptr == '\0') {
118                 ss_error (sci_idx, 0,
119                           "Unbalanced quotes in command line");
120                 free (argv);
121                 *argc_ptr = 0;
122                 return NULL;
123             }
124             else if (*line_ptr == '"') {
125                 if (*++line_ptr == '"') {
126                     *cp++ = '"';
127                     line_ptr++;
128                 }
129                 else {
130                     parse_mode = TOKEN;
131                 }
132             }
133             else {
134                 *cp++ = *line_ptr++;
135             }
136         }
137     }
138 end_of_line:
139     *argc_ptr = argc;
140 #ifdef DEBUG
141     {
142         int i;
143         printf ("argc = %d\n", argc);
144         for (i = 0; i <= argc; i++)
145             printf ("\targv[%2d] = `%s'\n", i,
146                     argv[i] ? argv[i] : "<NULL>");
147     }
148 #endif
149     return(argv);
150 }