Use .Pq for parentheses.
[dragonfly.git] / sbin / vinum / vinumparser.c
1 /*-
2  * Copyright (c) 1997, 1998
3  *      Nan Yang Computer Services Limited.  All rights reserved.
4  *
5  *  This software is distributed under the so-called ``Berkeley
6  *  License'':
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the Company nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * This software is provided ``as is'', and any express or implied
21  * warranties, including, but not limited to, the implied warranties of
22  * merchantability and fitness for a particular purpose are disclaimed.
23  * In no event shall the company or contributors be liable for any
24  * direct, indirect, incidental, special, exemplary, or consequential
25  * damages (including, but not limited to, procurement of substitute
26  * goods or services; loss of use, data, or profits; or business
27  * interruption) however caused and on any theory of liability, whether
28  * in contract, strict liability, or tort (including negligence or
29  * otherwise) arising in any way out of the use of this software, even if
30  * advised of the possibility of such damage.
31  *
32  * $Id: vinumparser.c,v 1.21 2000/12/20 03:44:13 grog Exp grog $
33  * $FreeBSD: src/sys/dev/vinum/vinumparser.c,v 1.20.2.5 2001/05/28 05:56:27 grog Exp $
34  * $DragonFly: src/sbin/vinum/vinumparser.c,v 1.8 2007/01/20 19:20:39 dillon Exp $
35  */
36
37 /*
38  * This file contains the parser for the configuration routines.  It's used
39  * both in the kernel and in the user interface program, thus the separate file.
40  */
41
42 /*
43  * Go through a text and split up into text tokens.  These are either non-blank
44  * sequences, or any sequence (except \0) enclosed in ' or ".  Embedded ' or
45  * " characters may be escaped by \, which otherwise has no special meaning.
46  *
47  * Delimit by following with a \0, and return pointers to the starts at token [].
48  * Return the number of tokens found as the return value.
49  *
50  * This method has the restriction that a closing " or ' must be followed by
51  * grey space.
52  *
53  * Error conditions are end of line before end of quote, or no space after
54  * a closing quote.  In this case, tokenize() returns -1.
55  */
56
57 #include <sys/param.h>
58 #include <dev/raid/vinum/vinumkw.h>
59 #include <ctype.h>
60 #include <errno.h>
61 #include <fcntl.h>
62 #include <string.h>
63 #define iswhite isspace                                     /* use the ctype macro */
64
65 /* enum keyword is defined in vinumvar.h */
66
67 #define keypair(x) { #x, kw_##x }                           /* create pair "foo", kw_foo */
68 #define flagkeypair(x) { "-"#x, kw_##x }                    /* create pair "-foo", kw_foo */
69 #define KEYWORDSET(x) {sizeof (x) / sizeof (struct _keywords), x}
70
71 /* Normal keywords.  These are all the words that vinum knows. */
72 struct _keywords keywords[] =
73 {keypair(drive),
74     keypair(partition),
75     keypair(sd),
76     keypair(subdisk),
77     keypair(plex),
78     keypair(volume),
79     keypair(vol),
80     keypair(setupstate),
81     keypair(readpol),
82     keypair(org),
83     keypair(name),
84     keypair(writethrough),
85     keypair(writeback),
86     keypair(raw),
87     keypair(device),
88     keypair(concat),
89     keypair(raid4),
90     keypair(raid5),
91     keypair(striped),
92     keypair(plexoffset),
93     keypair(driveoffset),
94     keypair(length),
95     keypair(len),
96     keypair(size),
97     keypair(state),
98     keypair(round),
99     keypair(prefer),
100     keypair(rename),
101     keypair(detached),
102 #ifdef VINUMDEBUG
103     keypair(debug),
104 #endif
105     keypair(stripe),
106     keypair(mirror),
107     keypair(attach),
108     keypair(detach),
109     keypair(printconfig),
110     keypair(saveconfig),
111     keypair(replace),
112     keypair(create),
113     keypair(read),
114     keypair(modify),
115     keypair(list),
116     keypair(l),
117     keypair(ld),
118     keypair(ls),
119     keypair(lp),
120     keypair(lv),
121     keypair(info),
122     keypair(set),
123     keypair(rm),
124     keypair(mv),
125     keypair(move),
126     keypair(init),
127     keypair(label),
128     keypair(resetconfig),
129     keypair(start),
130     keypair(stop),
131     keypair(makedev),
132     keypair(help),
133     keypair(quit),
134     keypair(setdaemon),
135     keypair(getdaemon),
136     keypair(max),
137     keypair(replace),
138     keypair(readpol),
139     keypair(resetstats),
140     keypair(setstate),
141     keypair(checkparity),
142     keypair(rebuildparity),
143     keypair(dumpconfig),
144     keypair(retryerrors)
145 };
146 struct keywordset keyword_set = KEYWORDSET(keywords);
147
148 struct _keywords flag_keywords[] =
149 {flagkeypair(f),
150     flagkeypair(d),
151     flagkeypair(v),
152     flagkeypair(s),
153     flagkeypair(r),
154     flagkeypair(w)
155 };
156 struct keywordset flag_set = KEYWORDSET(flag_keywords);
157
158 /*
159  * Take a blank separated list of tokens and turn it into a list of
160  * individual nul-delimited strings.  Build a list of pointers at
161  * token, which must have enough space for the tokens.  Return the
162  * number of tokens, or -1 on error (typically a missing string
163  * delimiter).
164  */
165 int
166 tokenize(char *cptr, char *token[])
167 {
168     char delim;                                             /* delimiter for searching for the partner */
169     int tokennr;                                            /* index of this token */
170     tokennr = 0;                                            /* none found yet */
171
172     for (;;) {
173         while (iswhite(*cptr))
174             cptr++;                                         /* skip initial white space */
175         if ((*cptr == '\0') || (*cptr == '\n') || (*cptr == '#')) /* end of line */
176             return tokennr;                                 /* return number of tokens found */
177         delim = *cptr;
178         token[tokennr] = cptr;                              /* point to it */
179         tokennr++;                                          /* one more */
180         /* XXX this is broken.  It leaves superfluous \\ characters in the text */
181         if ((delim == '\'') || (delim == '"')) {            /* delimitered */
182             for (;;) {
183                 cptr++;
184                 if ((*cptr == delim) && (cptr[-1] != '\\')) { /* found the partner */
185                     cptr++;                                 /* move on past */
186                     if (!iswhite(*cptr))                    /* error, no space after closing quote */
187                         return -1;
188                     *cptr++ = '\0';                         /* delimit */
189                 } else if ((*cptr == '\0') || (*cptr == '\n')) /* end of line */
190                     return -1;
191             }
192         } else {                                            /* not quoted */
193             while ((*cptr != '\0') && (!iswhite(*cptr)) && (*cptr != '\n'))
194                 cptr++;
195             if (*cptr != '\0')                              /* not end of the line, */
196                 *cptr++ = '\0';                             /* delimit and move to the next */
197         }
198     }
199 }
200
201 /* Find a keyword and return an index */
202 enum keyword
203 get_keyword(char *name, struct keywordset *keywordset)
204 {
205     int i;
206     struct _keywords *keywords = keywordset->k;             /* point to the keywords */
207     if (name != NULL) {                                     /* parameter exists */
208         for (i = 0; i < keywordset->size; i++)
209             if (!strcmp(name, keywords[i].name))
210                 return (enum keyword) keywords[i].keyword;
211     }
212     return kw_invalid_keyword;
213 }