Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / lib / libedit / tokenizer.c
1 /*-
2  * Copyright (c) 1992, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Christos Zoulas of Cornell University.
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. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *      This product includes software developed by the University of
19  *      California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  *
36  * @(#)tokenizer.c      8.1 (Berkeley) 6/4/93
37  */
38
39 /*
40  * tokenize.c: Bourne shell like tokenizer
41  */
42 #include "sys.h"
43 #include <string.h>
44 #include <stdlib.h>
45 #include "tokenizer.h"
46
47 typedef enum { Q_none, Q_single, Q_double, Q_one, Q_doubleone } quote_t;
48
49 #define IFS "\t \n"
50
51 #define TOK_KEEP        1
52 #define TOK_EAT         2
53
54 #define WINCR 20
55 #define AINCR 10
56
57 #define tok_malloc(a)           malloc(a)
58 #define tok_free(a)             free(a)
59 #define tok_realloc(a, b)       realloc(a, b)
60 #define tok_reallocf(a, b)      reallocf(a, b)
61
62
63 struct tokenizer {
64     char   *ifs;                /* In field separator                   */
65     int     argc, amax;         /* Current and maximum number of args   */
66     char  **argv;               /* Argument list                        */
67     char   *wptr, *wmax;        /* Space and limit on the word buffer   */
68     char   *wstart;             /* Beginning of next word               */
69     char   *wspace;             /* Space of word buffer                 */
70     quote_t quote;              /* Quoting state                        */
71     int     flags;              /* flags;                               */
72 };
73
74
75 private void tok_finish __P((Tokenizer *));
76
77
78 /* tok_finish():
79  *      Finish a word in the tokenizer.
80  */
81 private void
82 tok_finish(tok)
83     Tokenizer *tok;
84 {
85     *tok->wptr = '\0';
86     if ((tok->flags & TOK_KEEP) || tok->wptr != tok->wstart) {
87         tok->argv[tok->argc++] = tok->wstart;
88         tok->argv[tok->argc] = NULL;
89         tok->wstart = ++tok->wptr;
90     }
91     tok->flags &= ~TOK_KEEP;
92 }
93
94
95 /* tok_init():
96  *      Initialize the tokenizer
97  */
98 public Tokenizer *
99 tok_init(ifs)
100     const char *ifs;
101 {
102     Tokenizer* tok = (Tokenizer*) tok_malloc(sizeof(Tokenizer));
103
104     tok->ifs     = strdup(ifs ? ifs : IFS);
105     tok->argc    = 0;
106     tok->amax    = AINCR;
107     tok->argv    = (char **) tok_malloc(sizeof(char *) * tok->amax);
108     tok->argv[0] = NULL;
109     tok->wspace  = (char *) tok_malloc(WINCR);
110     tok->wmax    = tok->wspace + WINCR;
111     tok->wstart  = tok->wspace;
112     tok->wptr    = tok->wspace;
113     tok->flags   = 0;
114     tok->quote   = Q_none;
115
116     return tok;
117 }
118
119
120 /* tok_reset():
121  *      Reset the tokenizer
122  */
123 public void
124 tok_reset(tok)
125     Tokenizer *tok;
126 {
127     tok->argc  = 0;
128     tok->wstart = tok->wspace;
129     tok->wptr = tok->wspace;
130     tok->flags = 0;
131     tok->quote = Q_none;
132 }
133
134
135 /* tok_end():
136  *      Clean up
137  */
138 public void
139 tok_end(tok)
140     Tokenizer *tok;
141 {
142     tok_free((ptr_t) tok->ifs);
143     tok_free((ptr_t) tok->wspace);
144     tok_free((ptr_t) tok->argv);
145     tok_free((ptr_t) tok);
146 }
147
148
149
150 /* tok_line():
151  *      Bourne shell like tokenizing
152  *      Return:
153  *              -1: Internal error
154  *               3: Quoted return
155  *               2: Unmatched double quote
156  *               1: Unmatched single quote
157  *               0: Ok
158  */
159 public int
160 tok_line(tok, line, argc, argv)
161     Tokenizer *tok;
162     const char* line;
163     int *argc;
164     char ***argv;
165 {
166     const char *ptr;
167
168     while (1) {
169         switch (*(ptr = line++)) {
170         case '\'':
171             tok->flags |= TOK_KEEP;
172             tok->flags &= ~TOK_EAT;
173             switch (tok->quote) {
174             case Q_none:
175                 tok->quote = Q_single;  /* Enter single quote mode */
176                 break;
177
178             case Q_single:              /* Exit single quote mode */
179                 tok->quote = Q_none;
180                 break;
181
182             case Q_one:                 /* Quote this ' */
183                 tok->quote = Q_none;
184                 *tok->wptr++ = *ptr;
185                 break;
186
187             case Q_double:              /* Stay in double quote mode */
188                 *tok->wptr++ = *ptr;
189                 break;
190
191             case Q_doubleone:           /* Quote this ' */
192                 tok->quote = Q_double;
193                 *tok->wptr++ = *ptr;
194                 break;
195
196             default:
197                 return(-1);
198             }
199             break;
200
201         case '"':
202             tok->flags &= ~TOK_EAT;
203             tok->flags |= TOK_KEEP;
204             switch (tok->quote) {
205             case Q_none:                /* Enter double quote mode */
206                 tok->quote = Q_double;
207                 break;
208
209             case Q_double:
210                 tok->quote = Q_none;    /* Exit double quote mode */
211                 break;
212
213             case Q_one:                 /* Quote this " */
214                 tok->quote = Q_none;
215                 *tok->wptr++ = *ptr;
216                 break;
217
218             case Q_single:              /* Stay in single quote mode */
219                 *tok->wptr++ = *ptr;
220                 break;
221
222             case Q_doubleone:           /* Quote this " */
223                 tok->quote = Q_double;
224                 *tok->wptr++ = *ptr;
225                 break;
226
227             default:
228                 return(-1);
229             }
230             break;
231
232         case '\\':
233             tok->flags |= TOK_KEEP;
234             tok->flags &= ~TOK_EAT;
235             switch (tok->quote) {
236             case Q_none:                /* Quote next character */
237                 tok->quote = Q_one;
238                 break;
239
240             case Q_double:
241                 tok->quote = Q_doubleone;/* Quote next character */
242                 break;
243
244             case Q_one:
245                 *tok->wptr++ = *ptr;
246                 tok->quote = Q_none;    /* Quote this, restore state */
247                 break;
248
249             case Q_single:              /* Stay in single quote mode */
250                 *tok->wptr++ = *ptr;
251                 break;
252
253             case Q_doubleone:           /* Quote this \ */
254                 tok->quote = Q_double;
255                 *tok->wptr++ = *ptr;
256                 break;
257
258             default:
259                 return(-1);
260             }
261             break;
262
263         case '\n':
264             tok->flags &= ~TOK_EAT;
265             switch (tok->quote) {
266             case Q_none:
267                 tok_finish(tok);
268                 *argv = tok->argv;
269                 *argc = tok->argc;
270                 return(0);
271
272             case Q_single:
273             case Q_double:
274                 *tok->wptr++ = *ptr;    /* Add the return               */
275                 break;
276
277             case Q_doubleone:
278                 tok->flags |= TOK_EAT;
279                 tok->quote = Q_double;  /* Back to double, eat the '\n' */
280                 break;
281
282             case Q_one:
283                 tok->flags |= TOK_EAT;
284                 tok->quote = Q_none;    /* No quote, more eat the '\n' */
285                 break;
286
287             default:
288                 return(0);
289             }
290             break;
291
292         case '\0':
293             switch (tok->quote) {
294             case Q_none:
295                 /* Finish word and return */
296                 if (tok->flags & TOK_EAT) {
297                     tok->flags &= ~TOK_EAT;
298                     return 3;
299                 }
300                 tok_finish(tok);
301                 *argv = tok->argv;
302                 *argc = tok->argc;
303                 return(0);
304
305             case Q_single:
306                 return(1);
307
308             case Q_double:
309                 return(2);
310
311             case Q_doubleone:
312                 tok->quote = Q_double;
313                 *tok->wptr++ = *ptr;
314                 break;
315
316             case Q_one:
317                 tok->quote = Q_none;
318                 *tok->wptr++ = *ptr;
319                 break;
320
321             default:
322                 return(-1);
323             }
324             break;
325
326         default:
327             tok->flags &= ~TOK_EAT;
328             switch (tok->quote) {
329             case Q_none:
330                 if (strchr(tok->ifs, *ptr) != NULL)
331                     tok_finish(tok);
332                 else
333                     *tok->wptr++ = *ptr;
334                 break;
335
336             case Q_single:
337             case Q_double:
338                 *tok->wptr++ = *ptr;
339                 break;
340
341
342             case Q_doubleone:
343                 *tok->wptr++ = '\\';
344                 tok->quote = Q_double;
345                 *tok->wptr++ = *ptr;
346                 break;
347
348             case Q_one:
349                 tok->quote = Q_none;
350                 *tok->wptr++ = *ptr;
351                 break;
352
353             default:
354                 return(-1);
355
356             }
357             break;
358         }
359
360         if (tok->wptr >= tok->wmax - 4) {
361             size_t size = tok->wmax - tok->wspace + WINCR;
362             char *s = (char *) tok_realloc(tok->wspace, size);
363             /*SUPPRESS 22*/
364             int offs = s - tok->wspace;
365
366             if (offs != 0) {
367                 int i;
368                 for (i = 0; i < tok->argc; i++)
369                     tok->argv[i] = tok->argv[i] + offs;
370                 tok->wptr   = tok->wptr + offs;
371                 tok->wstart = tok->wstart + offs;
372                 tok->wmax   = s + size;
373                 tok->wspace = s;
374             }
375         }
376
377         if (tok->argc >= tok->amax - 4) {
378             tok->amax += AINCR;
379             tok->argv = (char **) tok_reallocf(tok->argv,
380                                                tok->amax * sizeof(char*));
381         }
382
383     }
384 }