1d0e51869Samw /*
2d0e51869Samw * CDDL HEADER START
3d0e51869Samw *
4d0e51869Samw * The contents of this file are subject to the terms of the
5d0e51869Samw * Common Development and Distribution License (the "License").
6d0e51869Samw * You may not use this file except in compliance with the License.
7d0e51869Samw *
8d0e51869Samw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9d0e51869Samw * or http://www.opensolaris.org/os/licensing.
10d0e51869Samw * See the License for the specific language governing permissions
11d0e51869Samw * and limitations under the License.
12d0e51869Samw *
13d0e51869Samw * When distributing Covered Code, include this CDDL HEADER in each
14d0e51869Samw * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15d0e51869Samw * If applicable, add the following below this CDDL HEADER, with the
16d0e51869Samw * fields enclosed by brackets "[]" replaced with your own identifying
17d0e51869Samw * information: Portions Copyright [yyyy] [name of copyright owner]
18d0e51869Samw *
19d0e51869Samw * CDDL HEADER END
20d0e51869Samw */
21d0e51869Samw
22d0e51869Samw /*
23*a0b6e447SAlan Wright * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24d0e51869Samw * Use is subject to license terms.
25d0e51869Samw */
26d0e51869Samw
27d0e51869Samw #include <errno.h>
28d0e51869Samw #include <stdarg.h>
29d0e51869Samw #include "ndrgen.h"
30d0e51869Samw #include "y.tab.h"
31d0e51869Samw
32d0e51869Samw /*
33d0e51869Samw * C-like lexical analysis.
34d0e51869Samw *
35d0e51869Samw * 1. Define a "struct node"
36d0e51869Samw * 2. Define a "struct symbol" that encapsulates a struct node.
37d0e51869Samw * 3. Define a "struct integer" that encapsulates a struct node.
38d0e51869Samw * 4. Set the YACC stack type in the grammar:
39d0e51869Samw * %{
40d0e51869Samw * #define YYSTYPE struct node *
41d0e51869Samw * %}
42d0e51869Samw * 5. Define %token's in the grammer for IDENTIFIER, STRING and INTEGER.
43d0e51869Samw * Using "_KW" as a suffix for keyword tokens, i.e. "struct" is
44d0e51869Samw * "%token STRUCT_KW":
45d0e51869Samw * // atomic values
46d0e51869Samw * %token INTEGER STRING IDENTIFIER
47d0e51869Samw * // keywords
48d0e51869Samw * %token STRUCT_KW CASE_KW
49d0e51869Samw * // operators
50d0e51869Samw * %token PLUS MINUS ASSIGN ARROW
51d0e51869Samw * // overloaded tokens (++ --, < > <= >=, == !=, += -= *= ...)
52d0e51869Samw * %token INCOP RELOP EQUOP ASSOP
53d0e51869Samw * 6. It's easiest to use the yacc(1) generated token numbers for node
54d0e51869Samw * labels. For node labels that are not actually part of the grammer,
55d0e51869Samw * use a %token with an L_ prefix:
56d0e51869Samw * // node labels (can't be generated by lex)
57d0e51869Samw * %token L_LT L_LTE L_GT L_GTE L_EQU L_NEQ
58d0e51869Samw * 7. Call set_lex_input() before parsing.
59d0e51869Samw */
60d0e51869Samw
61d0e51869Samw #define SQ '\''
62d0e51869Samw #define DQ '"'
63d0e51869Samw
64d0e51869Samw #define isquote(c) ((c) == SQ || (c) == DQ)
65d0e51869Samw #define iswhite(c) ((c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\f')
66d0e51869Samw
67d0e51869Samw #define is_between(c, l, u) ((l) <= (c) && (c) <= (u))
68d0e51869Samw #define is_white(c) ((c) == ' ' || c == '\r' || c == '\t' || c == '\f')
69d0e51869Samw #define is_lower(c) is_between((c), 'a', 'z')
70d0e51869Samw #define is_upper(c) is_between((c), 'A', 'Z')
71d0e51869Samw #define is_alpha(c) (is_lower(c) || is_upper(c))
72d0e51869Samw #define is_digit(c) is_between((c), '0', '9')
73d0e51869Samw #define is_sstart(c) (is_alpha(c) || (c) == '_')
74d0e51869Samw #define is_sfollow(c) (is_sstart(c) || is_digit(c))
75d0e51869Samw #define is_xdigit(c) \
76d0e51869Samw (is_digit(c) || is_between((c), 'A', 'F') || is_between((c), 'a', 'f'))
77d0e51869Samw
78d0e51869Samw ndr_symbol_t *symbol_list;
79d0e51869Samw static ndr_integer_t *integer_list;
80d0e51869Samw static FILE *lex_infp;
81d0e51869Samw static ndr_symbol_t *file_name;
82d0e51869Samw int line_number;
83d0e51869Samw int n_compile_error;
84d0e51869Samw
85d0e51869Samw static int lex_at_bol;
86d0e51869Samw
87d0e51869Samw /* In yacc(1) generated parser */
88d0e51869Samw extern struct node *yylval;
89d0e51869Samw
90d0e51869Samw /*
91d0e51869Samw * The keywtab[] and optable[] could be external to this lex
92d0e51869Samw * and it would all still work.
93d0e51869Samw */
94d0e51869Samw static ndr_keyword_t keywtable[] = {
95d0e51869Samw { "struct", STRUCT_KW, 0 },
96d0e51869Samw { "union", UNION_KW, 0 },
97d0e51869Samw { "typedef", TYPEDEF_KW, 0 },
98d0e51869Samw
99d0e51869Samw { "interface", INTERFACE_KW, 0 },
100d0e51869Samw { "uuid", UUID_KW, 0 },
101d0e51869Samw { "_no_reorder", _NO_REORDER_KW, 0 },
102d0e51869Samw { "extern", EXTERN_KW, 0 },
103d0e51869Samw { "reference", REFERENCE_KW, 0 },
104d0e51869Samw
105d0e51869Samw { "align", ALIGN_KW, 0 },
106d0e51869Samw { "operation", OPERATION_KW, 0 },
107d0e51869Samw { "in", IN_KW, 0 },
108d0e51869Samw { "out", OUT_KW, 0 },
109d0e51869Samw
110d0e51869Samw { "string", STRING_KW, 0 },
111d0e51869Samw { "size_is", SIZE_IS_KW, 0 },
112d0e51869Samw { "length_is", LENGTH_IS_KW, 0 },
113d0e51869Samw
114d0e51869Samw { "switch_is", SWITCH_IS_KW, 0 },
115d0e51869Samw { "case", CASE_KW, 0 },
116d0e51869Samw { "default", DEFAULT_KW, 0 },
117d0e51869Samw
118d0e51869Samw { "transmit_as", TRANSMIT_AS_KW, 0 },
119d0e51869Samw { "arg_is", ARG_IS_KW, 0 },
120d0e51869Samw
121d0e51869Samw { "char", BASIC_TYPE, 1 },
122d0e51869Samw { "uchar", BASIC_TYPE, 1 },
123d0e51869Samw { "wchar", BASIC_TYPE, 2 },
124d0e51869Samw { "short", BASIC_TYPE, 2 },
125d0e51869Samw { "ushort", BASIC_TYPE, 2 },
126d0e51869Samw { "long", BASIC_TYPE, 4 },
127d0e51869Samw { "ulong", BASIC_TYPE, 4 },
128d0e51869Samw {0}
129d0e51869Samw };
130d0e51869Samw
131d0e51869Samw static ndr_keyword_t optable[] = {
132d0e51869Samw { "{", LC, 0 },
133d0e51869Samw { "}", RC, 0 },
134d0e51869Samw { "(", LP, 0 },
135d0e51869Samw { ")", RP, 0 },
136d0e51869Samw { "[", LB, 0 },
137d0e51869Samw { "]", RB, 0 },
138d0e51869Samw { "*", STAR, 0 },
139*a0b6e447SAlan Wright { "/", DIV, 0 },
140*a0b6e447SAlan Wright { "%", MOD, 0 },
141*a0b6e447SAlan Wright { "-", MINUS, 0 },
142*a0b6e447SAlan Wright { "+", PLUS, 0 },
143*a0b6e447SAlan Wright { "&", AND, 0 },
144*a0b6e447SAlan Wright { "|", OR, 0 },
145*a0b6e447SAlan Wright { "^", XOR, 0 },
146d0e51869Samw { ";", SEMI, 0 },
147d0e51869Samw {0}
148d0e51869Samw };
149d0e51869Samw
150d0e51869Samw static int getch(FILE *fp);
151d0e51869Samw static ndr_integer_t *int_enter(long);
152*a0b6e447SAlan Wright static ndr_symbol_t *sym_enter(char *);
153d0e51869Samw static ndr_symbol_t *sym_find(char *);
154d0e51869Samw static int str_to_sv(char *, char *sv[]);
155d0e51869Samw
156d0e51869Samw /*
157d0e51869Samw * Enter the symbols for keyword.
158d0e51869Samw */
159d0e51869Samw static void
keyw_tab_init(ndr_keyword_t kwtable[])160d0e51869Samw keyw_tab_init(ndr_keyword_t kwtable[])
161d0e51869Samw {
162d0e51869Samw int i;
163d0e51869Samw ndr_keyword_t *kw;
164d0e51869Samw ndr_symbol_t *sym;
165d0e51869Samw
166d0e51869Samw for (i = 0; kwtable[i].name; i++) {
167d0e51869Samw kw = &kwtable[i];
168d0e51869Samw
169d0e51869Samw sym = sym_enter(kw->name);
170d0e51869Samw sym->kw = kw;
171d0e51869Samw }
172d0e51869Samw }
173d0e51869Samw
174d0e51869Samw void
set_lex_input(FILE * fp,char * name)175d0e51869Samw set_lex_input(FILE *fp, char *name)
176d0e51869Samw {
177d0e51869Samw keyw_tab_init(keywtable);
178d0e51869Samw keyw_tab_init(optable);
179d0e51869Samw
180d0e51869Samw lex_infp = fp;
181d0e51869Samw file_name = sym_enter(name);
182d0e51869Samw line_number = 1;
183d0e51869Samw lex_at_bol = 1;
184d0e51869Samw }
185d0e51869Samw
186d0e51869Samw static int
getch(FILE * fp)187d0e51869Samw getch(FILE *fp)
188d0e51869Samw {
189d0e51869Samw return (getc(fp));
190d0e51869Samw }
191d0e51869Samw
192d0e51869Samw int
yylex(void)193d0e51869Samw yylex(void)
194d0e51869Samw {
195d0e51869Samw char lexeme[512];
196d0e51869Samw char *p = lexeme;
197d0e51869Samw FILE *fp = lex_infp;
198d0e51869Samw int c, xc;
199d0e51869Samw ndr_symbol_t *sym;
200d0e51869Samw ndr_integer_t *intg;
201d0e51869Samw
202d0e51869Samw top:
203d0e51869Samw p = lexeme;
204d0e51869Samw
205d0e51869Samw c = getch(fp);
206d0e51869Samw if (c == EOF)
207d0e51869Samw return (EOF);
208d0e51869Samw
209d0e51869Samw if (c == '\n') {
210d0e51869Samw line_number++;
211d0e51869Samw lex_at_bol = 1;
212d0e51869Samw goto top;
213d0e51869Samw }
214d0e51869Samw
215d0e51869Samw /*
216d0e51869Samw * Handle preprocessor lines. This just notes
217d0e51869Samw * which file we're processing.
218d0e51869Samw */
219d0e51869Samw if (c == '#' && lex_at_bol) {
220d0e51869Samw char *sv[10];
221d0e51869Samw int sc;
222d0e51869Samw
223d0e51869Samw while ((c = getch(fp)) != EOF && c != '\n')
224d0e51869Samw *p++ = c;
225d0e51869Samw
226d0e51869Samw *p = 0;
227d0e51869Samw /* note: no ungetc() of newline, we don't want to count it */
228d0e51869Samw
229d0e51869Samw if (*lexeme != ' ') {
230d0e51869Samw /* not a line we know */
231d0e51869Samw goto top;
232d0e51869Samw }
233d0e51869Samw
234d0e51869Samw sc = str_to_sv(lexeme, sv);
235d0e51869Samw if (sc < 2)
236d0e51869Samw goto top;
237d0e51869Samw
238d0e51869Samw file_name = sym_enter(sv[1]);
239d0e51869Samw line_number = atoi(sv[0]); /* for next input line */
240d0e51869Samw lex_at_bol = 1;
241d0e51869Samw goto top;
242d0e51869Samw }
243d0e51869Samw
244d0e51869Samw lex_at_bol = 0;
245d0e51869Samw
246d0e51869Samw /*
247d0e51869Samw * Skip white space
248d0e51869Samw */
249d0e51869Samw if (is_white(c))
250d0e51869Samw goto top;
251d0e51869Samw
252d0e51869Samw /*
253d0e51869Samw * Symbol? Might be a keyword or just an identifier
254d0e51869Samw */
255d0e51869Samw if (is_sstart(c)) {
256d0e51869Samw /* we got a symbol */
257d0e51869Samw do {
258d0e51869Samw *p++ = c;
259d0e51869Samw c = getch(fp);
260d0e51869Samw } while (is_sfollow(c));
261d0e51869Samw (void) ungetc(c, fp);
262d0e51869Samw *p = 0;
263d0e51869Samw
264d0e51869Samw sym = sym_enter(lexeme);
265d0e51869Samw
266d0e51869Samw yylval = &sym->s_node;
267d0e51869Samw
268d0e51869Samw if (sym->kw) {
269d0e51869Samw return (sym->kw->token);
270d0e51869Samw } else {
271d0e51869Samw return (IDENTIFIER);
272d0e51869Samw }
273d0e51869Samw }
274d0e51869Samw
275d0e51869Samw /*
276d0e51869Samw * Integer constant?
277d0e51869Samw */
278d0e51869Samw if (is_digit(c)) {
279d0e51869Samw /* we got a number */
280d0e51869Samw *p++ = c;
281d0e51869Samw if (c == '0') {
282d0e51869Samw c = getch(fp);
283d0e51869Samw if (c == 'x' || c == 'X') {
284d0e51869Samw /* handle hex specially */
285d0e51869Samw do {
286d0e51869Samw *p++ = c;
287d0e51869Samw c = getch(fp);
288d0e51869Samw } while (is_xdigit(c));
289d0e51869Samw goto convert_icon;
290d0e51869Samw } else if (c == 'b' || c == 'B' ||
291d0e51869Samw c == 'd' || c == 'D' ||
292d0e51869Samw c == 'o' || c == 'O') {
293d0e51869Samw do {
294d0e51869Samw *p++ = c;
295d0e51869Samw c = getch(fp);
296d0e51869Samw } while (is_digit(c));
297d0e51869Samw goto convert_icon;
298d0e51869Samw }
299d0e51869Samw (void) ungetc(c, fp);
300d0e51869Samw }
301d0e51869Samw /* could be anything */
302d0e51869Samw c = getch(fp);
303d0e51869Samw while (is_digit(c)) {
304d0e51869Samw *p++ = c;
305d0e51869Samw c = getch(fp);
306d0e51869Samw }
307d0e51869Samw
308d0e51869Samw convert_icon:
309d0e51869Samw *p = 0;
310d0e51869Samw (void) ungetc(c, fp);
311d0e51869Samw
312d0e51869Samw intg = int_enter(strtol(lexeme, 0, 0));
313d0e51869Samw yylval = &intg->s_node;
314d0e51869Samw
315d0e51869Samw return (INTEGER);
316d0e51869Samw }
317d0e51869Samw
318d0e51869Samw /* Could handle strings. We don't seem to need them yet */
319d0e51869Samw
320d0e51869Samw yylval = 0; /* operator tokens have no value */
321d0e51869Samw xc = getch(fp); /* get look-ahead for two-char lexemes */
322d0e51869Samw
323d0e51869Samw lexeme[0] = c;
324d0e51869Samw lexeme[1] = xc;
325d0e51869Samw lexeme[2] = 0;
326d0e51869Samw
327d0e51869Samw /*
328d0e51869Samw * Look for to-end-of-line comment
329d0e51869Samw */
330d0e51869Samw if (c == '/' && xc == '/') {
331d0e51869Samw /* eat the comment */
332d0e51869Samw while ((c = getch(fp)) != EOF && c != '\n')
333d0e51869Samw ;
334d0e51869Samw (void) ungetc(c, fp); /* put back newline */
335d0e51869Samw goto top;
336d0e51869Samw }
337d0e51869Samw
338d0e51869Samw /*
339d0e51869Samw * Look for multi-line comment
340d0e51869Samw */
341d0e51869Samw if (c == '/' && xc == '*') {
342d0e51869Samw /* eat the comment */
343d0e51869Samw xc = -1;
344d0e51869Samw while ((c = getch(fp)) != EOF) {
345d0e51869Samw if (xc == '*' && c == '/') {
346d0e51869Samw /* that's it */
347d0e51869Samw break;
348d0e51869Samw }
349d0e51869Samw xc = c;
350d0e51869Samw if (c == '\n')
351d0e51869Samw line_number++;
352d0e51869Samw }
353d0e51869Samw goto top;
354d0e51869Samw }
355d0e51869Samw
356d0e51869Samw /*
357d0e51869Samw * Use symbol table lookup for two-character and
358d0e51869Samw * one character operator tokens.
359d0e51869Samw */
360d0e51869Samw sym = sym_find(lexeme);
361d0e51869Samw if (sym) {
362d0e51869Samw /* there better be a keyword attached */
363d0e51869Samw yylval = &sym->s_node;
364d0e51869Samw return (sym->kw->token);
365d0e51869Samw }
366d0e51869Samw
367d0e51869Samw /* Try a one-character form */
368d0e51869Samw (void) ungetc(xc, fp);
369d0e51869Samw lexeme[1] = 0;
370d0e51869Samw sym = sym_find(lexeme);
371d0e51869Samw if (sym) {
372d0e51869Samw /* there better be a keyword attached */
373d0e51869Samw yylval = &sym->s_node;
374d0e51869Samw return (sym->kw->token);
375d0e51869Samw }
376d0e51869Samw
377*a0b6e447SAlan Wright if (is_between(c, ' ', '~'))
378*a0b6e447SAlan Wright compile_error("unrecognized character: 0x%02x (%c)", c, c);
379*a0b6e447SAlan Wright else
380*a0b6e447SAlan Wright compile_error("unrecognized character: 0x%02x", c);
381d0e51869Samw goto top;
382d0e51869Samw }
383d0e51869Samw
384d0e51869Samw static ndr_symbol_t *
sym_find(char * name)385d0e51869Samw sym_find(char *name)
386d0e51869Samw {
387d0e51869Samw ndr_symbol_t **pp;
388d0e51869Samw ndr_symbol_t *p;
389d0e51869Samw
390d0e51869Samw for (pp = &symbol_list; (p = *pp) != 0; pp = &p->next) {
391d0e51869Samw if (strcmp(p->name, name) == 0)
392d0e51869Samw return (p);
393d0e51869Samw }
394d0e51869Samw
395d0e51869Samw return (0);
396d0e51869Samw }
397d0e51869Samw
398*a0b6e447SAlan Wright static ndr_symbol_t *
sym_enter(char * name)399d0e51869Samw sym_enter(char *name)
400d0e51869Samw {
401d0e51869Samw ndr_symbol_t **pp;
402d0e51869Samw ndr_symbol_t *p;
403d0e51869Samw
404d0e51869Samw for (pp = &symbol_list; (p = *pp) != 0; pp = &p->next) {
405d0e51869Samw if (strcmp(p->name, name) == 0)
406d0e51869Samw return (p);
407d0e51869Samw }
408d0e51869Samw
409d0e51869Samw p = ndr_alloc(1, sizeof (ndr_symbol_t));
410d0e51869Samw
411d0e51869Samw if ((p->name = strdup(name)) == NULL)
412d0e51869Samw fatal_error("%s", strerror(ENOMEM));
413d0e51869Samw
414d0e51869Samw p->s_node.label = IDENTIFIER;
415d0e51869Samw p->s_node.n_sym = p;
416d0e51869Samw
417d0e51869Samw *pp = p;
418d0e51869Samw
419d0e51869Samw return (p);
420d0e51869Samw }
421d0e51869Samw
422d0e51869Samw static ndr_integer_t *
int_enter(long value)423d0e51869Samw int_enter(long value)
424d0e51869Samw {
425d0e51869Samw ndr_integer_t **pp;
426d0e51869Samw ndr_integer_t *p;
427d0e51869Samw
428d0e51869Samw for (pp = &integer_list; (p = *pp) != 0; pp = &p->next) {
429d0e51869Samw if (p->value == value)
430d0e51869Samw return (p);
431d0e51869Samw }
432d0e51869Samw
433d0e51869Samw p = ndr_alloc(1, sizeof (ndr_integer_t));
434d0e51869Samw
435d0e51869Samw p->value = value;
436d0e51869Samw p->s_node.label = INTEGER;
437d0e51869Samw p->s_node.n_int = value;
438d0e51869Samw
439d0e51869Samw *pp = p;
440d0e51869Samw
441d0e51869Samw return (p);
442d0e51869Samw }
443d0e51869Samw
444d0e51869Samw void *
ndr_alloc(size_t nelem,size_t elsize)445d0e51869Samw ndr_alloc(size_t nelem, size_t elsize)
446d0e51869Samw {
447d0e51869Samw void *p;
448d0e51869Samw
449d0e51869Samw if ((p = calloc(nelem, elsize)) == NULL) {
450d0e51869Samw fatal_error("%s", strerror(ENOMEM));
451d0e51869Samw /* NOTREACHED */
452d0e51869Samw }
453d0e51869Samw
454d0e51869Samw return (p);
455d0e51869Samw }
456d0e51869Samw
457d0e51869Samw /*
458d0e51869Samw * The input context (filename, line number) is maintained by the
459d0e51869Samw * lexical analysis, and we generally want such info reported for
460d0e51869Samw * errors in a consistent manner.
461d0e51869Samw */
462d0e51869Samw void
compile_error(const char * fmt,...)463d0e51869Samw compile_error(const char *fmt, ...)
464d0e51869Samw {
465d0e51869Samw char buf[NDLBUFSZ];
466d0e51869Samw va_list ap;
467d0e51869Samw
468d0e51869Samw va_start(ap, fmt);
469d0e51869Samw (void) vsnprintf(buf, NDLBUFSZ, fmt, ap);
470d0e51869Samw va_end(ap);
471d0e51869Samw
472d0e51869Samw (void) fprintf(stderr, "ndrgen: compile error: %s:%d: %s\n",
473d0e51869Samw file_name->name, line_number, buf);
474d0e51869Samw
475d0e51869Samw n_compile_error++;
476d0e51869Samw }
477d0e51869Samw
478d0e51869Samw void
fatal_error(const char * fmt,...)479d0e51869Samw fatal_error(const char *fmt, ...)
480d0e51869Samw {
481d0e51869Samw char buf[NDLBUFSZ];
482d0e51869Samw va_list ap;
483d0e51869Samw
484d0e51869Samw va_start(ap, fmt);
485d0e51869Samw (void) vsnprintf(buf, NDLBUFSZ, fmt, ap);
486d0e51869Samw va_end(ap);
487d0e51869Samw
488d0e51869Samw (void) fprintf(stderr, "ndrgen: fatal error: %s\n", buf);
489d0e51869Samw exit(1);
490d0e51869Samw }
491d0e51869Samw
492d0e51869Samw /*
493d0e51869Samw * Setup nodes for the lexical analyzer.
494d0e51869Samw */
495d0e51869Samw struct node *
n_cons(int label,...)496d0e51869Samw n_cons(int label, ...)
497d0e51869Samw {
498d0e51869Samw ndr_node_t *np;
499d0e51869Samw va_list ap;
500d0e51869Samw
501d0e51869Samw np = ndr_alloc(1, sizeof (ndr_node_t));
502d0e51869Samw
503d0e51869Samw va_start(ap, label);
504d0e51869Samw np->label = label;
505d0e51869Samw np->n_arg[0] = va_arg(ap, void *);
506d0e51869Samw np->n_arg[1] = va_arg(ap, void *);
507d0e51869Samw np->n_arg[2] = va_arg(ap, void *);
508d0e51869Samw va_end(ap);
509d0e51869Samw
510d0e51869Samw np->line_number = line_number;
511d0e51869Samw np->file_name = file_name;
512d0e51869Samw
513d0e51869Samw return (np);
514d0e51869Samw }
515d0e51869Samw
516d0e51869Samw /*
517d0e51869Samw * list: item
518d0e51869Samw * | list item ={ n_splice($1, $2); }
519d0e51869Samw * ;
520d0e51869Samw */
521d0e51869Samw void
n_splice(struct node * np1,struct node * np2)522d0e51869Samw n_splice(struct node *np1, struct node *np2)
523d0e51869Samw {
524d0e51869Samw while (np1->n_next)
525d0e51869Samw np1 = np1->n_next;
526d0e51869Samw
527d0e51869Samw np1->n_next = np2;
528d0e51869Samw }
529d0e51869Samw
530d0e51869Samw /*
531d0e51869Samw * Convert a string of words to a vector of strings.
532d0e51869Samw * Returns the number of words.
533d0e51869Samw */
534d0e51869Samw static int
str_to_sv(char * buf,char * sv[])535d0e51869Samw str_to_sv(char *buf, char *sv[])
536d0e51869Samw {
537d0e51869Samw char **pp = sv;
538d0e51869Samw char *p = buf;
539d0e51869Samw char *q = buf;
540d0e51869Samw int in_word = 0;
541d0e51869Samw int c;
542d0e51869Samw
543d0e51869Samw for (;;) {
544d0e51869Samw c = *p++;
545d0e51869Samw if (c == 0)
546d0e51869Samw break;
547d0e51869Samw
548d0e51869Samw if (!in_word) {
549d0e51869Samw if (iswhite(c))
550d0e51869Samw continue;
551d0e51869Samw
552d0e51869Samw *pp++ = q;
553d0e51869Samw in_word = 1;
554d0e51869Samw }
555d0e51869Samw
556d0e51869Samw if (isquote(c)) {
557d0e51869Samw int qc = c;
558d0e51869Samw
559d0e51869Samw while (((c = *p++) != 0) && (c != qc))
560d0e51869Samw *q++ = c;
561d0e51869Samw if (c == 0)
562d0e51869Samw break;
563d0e51869Samw } else if (iswhite(c)) {
564d0e51869Samw /* end of word */
565d0e51869Samw *q++ = 0;
566d0e51869Samw in_word = 0;
567d0e51869Samw } else {
568d0e51869Samw /* still inside word */
569d0e51869Samw *q++ = c;
570d0e51869Samw }
571d0e51869Samw }
572d0e51869Samw
573d0e51869Samw if (in_word)
574d0e51869Samw *q++ = 0;
575d0e51869Samw
576d0e51869Samw *pp = (char *)0;
577d0e51869Samw return (pp - sv);
578d0e51869Samw }
579