]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netgraph/ng_parse.c
Experiemntal ascii based device configuration mechanism.
[FreeBSD/FreeBSD.git] / sys / netgraph / ng_parse.c
1
2 /*
3  * ng_parse.c
4  *
5  * Copyright (c) 1999 Whistle Communications, Inc.
6  * All rights reserved.
7  * 
8  * Subject to the following obligations and disclaimer of warranty, use and
9  * redistribution of this software, in source or object code forms, with or
10  * without modifications are expressly permitted by Whistle Communications;
11  * provided, however, that:
12  * 1. Any and all reproductions of the source or object code must include the
13  *    copyright notice above and the following disclaimer of warranties; and
14  * 2. No rights are granted, in any manner or form, to use Whistle
15  *    Communications, Inc. trademarks, including the mark "WHISTLE
16  *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
17  *    such appears in the above copyright notice or in the software.
18  * 
19  * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
20  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
21  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
22  * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
23  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
24  * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
25  * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
26  * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
27  * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
28  * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
29  * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
30  * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
31  * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
32  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34  * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
35  * OF SUCH DAMAGE.
36  *
37  * Author: Archie Cobbs <archie@whistle.com>
38  *
39  * $Whistle: ng_parse.c,v 1.3 1999/11/29 01:43:48 archie Exp $
40  * $FreeBSD$
41  */
42
43 #include <sys/types.h>
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/errno.h>
47 #include <sys/malloc.h>
48 #include <sys/ctype.h>
49
50 #include <netinet/in.h>
51
52 #include <netgraph/ng_message.h>
53 #include <netgraph/netgraph.h>
54 #include <netgraph/ng_parse.h>
55
56 /* Compute alignment for primitive integral types */
57 struct int16_temp {
58         char    x;
59         int16_t y;
60 };
61
62 struct int32_temp {
63         char    x;
64         int32_t y;
65 };
66
67 struct int64_temp {
68         char    x;
69         int64_t y;
70 };
71
72 #define INT8_ALIGNMENT          1
73 #define INT16_ALIGNMENT         ((int)&((struct int16_temp *)0)->y)
74 #define INT32_ALIGNMENT         ((int)&((struct int32_temp *)0)->y)
75 #define INT64_ALIGNMENT         ((int)&((struct int64_temp *)0)->y)
76
77 /* Type of composite object: struct, array, or fixedarray */
78 enum comptype {
79         CT_STRUCT,
80         CT_ARRAY,
81         CT_FIXEDARRAY,
82 };
83
84 /* Composite types helper functions */
85 static int      ng_parse_composite(const struct ng_parse_type *type,
86                         const char *s, int *off, const u_char *start,
87                         u_char *const buf, int *buflen, enum comptype ctype);
88 static int      ng_unparse_composite(const struct ng_parse_type *type,
89                         const u_char *data, int *off, char *cbuf, int cbuflen,
90                         enum comptype ctype);
91 static int      ng_get_composite_elem_default(const struct ng_parse_type *type,
92                         int index, const u_char *start, u_char *buf,
93                         int *buflen, enum comptype ctype);
94 static int      ng_get_composite_len(const struct ng_parse_type *type,
95                         const u_char *start, const u_char *buf,
96                         enum comptype ctype);
97 static const    struct ng_parse_type *ng_get_composite_etype(const struct
98                         ng_parse_type *type, int index, enum comptype ctype);
99 static int      ng_parse_get_elem_pad(const struct ng_parse_type *type,
100                         int index, enum comptype ctype, int posn);
101
102 /* Parsing helper functions */
103 static int      ng_parse_skip_value(const char *s, int off, int *lenp);
104
105 /* Poor man's virtual method calls */
106 #define METHOD(t,m)     (ng_get_ ## m ## _method(t))
107 #define INVOKE(t,m)     (*METHOD(t,m))
108
109 static ng_parse_t       *ng_get_parse_method(const struct ng_parse_type *t);
110 static ng_unparse_t     *ng_get_unparse_method(const struct ng_parse_type *t);
111 static ng_getDefault_t  *ng_get_getDefault_method(const
112                                 struct ng_parse_type *t);
113 static ng_getAlign_t    *ng_get_getAlign_method(const struct ng_parse_type *t);
114
115 #define ALIGNMENT(t)    (METHOD(t, getAlign) == NULL ? \
116                                 0 : INVOKE(t, getAlign)(t))
117
118 /* For converting binary to string */
119 #define NG_PARSE_APPEND(fmt, args...)                           \
120                 do {                                            \
121                         int len;                                \
122                                                                 \
123                         len = snprintf((cbuf), (cbuflen),       \
124                                 fmt , ## args);                 \
125                         if (len >= (cbuflen))                   \
126                                 return (ERANGE);                \
127                         (cbuf) += len;                          \
128                         (cbuflen) -= len;                       \
129                 } while (0)
130
131 /************************************************************************
132                         PUBLIC FUNCTIONS
133  ************************************************************************/
134
135 /*
136  * Convert an ASCII string to binary according to the supplied type descriptor
137  */
138 int
139 ng_parse(const struct ng_parse_type *type,
140         const char *string, int *off, u_char *buf, int *buflen)
141 {
142         return INVOKE(type, parse)(type, string, off, buf, buf, buflen);
143 }
144
145 /*
146  * Convert binary to an ASCII string according to the supplied type descriptor
147  */
148 int
149 ng_unparse(const struct ng_parse_type *type,
150         const u_char *data, char *cbuf, int cbuflen)
151 {
152         int off = 0;
153
154         return INVOKE(type, unparse)(type, data, &off, cbuf, cbuflen);
155 }
156
157 /*
158  * Fill in the default value according to the supplied type descriptor
159  */
160 int
161 ng_parse_getDefault(const struct ng_parse_type *type, u_char *buf, int *buflen)
162 {
163         ng_getDefault_t *const func = METHOD(type, getDefault);
164
165         if (func == NULL)
166                 return (EOPNOTSUPP);
167         return (*func)(type, buf, buf, buflen);
168 }
169
170
171 /************************************************************************
172                         STRUCTURE TYPE
173  ************************************************************************/
174
175 static int
176 ng_struct_parse(const struct ng_parse_type *type,
177         const char *s, int *off, const u_char *const start,
178         u_char *const buf, int *buflen)
179 {
180         return ng_parse_composite(type, s, off, start, buf, buflen, CT_STRUCT);
181 }
182
183 static int
184 ng_struct_unparse(const struct ng_parse_type *type,
185         const u_char *data, int *off, char *cbuf, int cbuflen)
186 {
187         return ng_unparse_composite(type, data, off, cbuf, cbuflen, CT_STRUCT);
188 }
189
190 static int
191 ng_struct_getDefault(const struct ng_parse_type *type,
192         const u_char *const start, u_char *buf, int *buflen)
193 {
194         int off = 0;
195
196         return ng_parse_composite(type,
197             "{}", &off, start, buf, buflen, CT_STRUCT);
198 }
199
200 static int
201 ng_struct_getAlign(const struct ng_parse_type *type)
202 {
203         const struct ng_parse_struct_info *si = type->info;
204         const struct ng_parse_struct_field *field;
205         int align = 0;
206
207         for (field = si->fields; field->name != NULL; field++) {
208                 int falign = ALIGNMENT(field->type);
209
210                 if (falign > align)
211                         align = falign;
212         }
213         return align;
214 }
215
216 const struct ng_parse_type ng_parse_struct_type = {
217         NULL,
218         NULL,
219         NULL,
220         ng_struct_parse,
221         ng_struct_unparse,
222         ng_struct_getDefault,
223         ng_struct_getAlign
224 };
225
226 /************************************************************************
227                         FIXED LENGTH ARRAY TYPE
228  ************************************************************************/
229
230 static int
231 ng_fixedarray_parse(const struct ng_parse_type *type,
232         const char *s, int *off, const u_char *const start,
233         u_char *const buf, int *buflen)
234 {
235         return ng_parse_composite(type,
236             s, off, start, buf, buflen, CT_FIXEDARRAY);
237 }
238
239 static int
240 ng_fixedarray_unparse(const struct ng_parse_type *type,
241         const u_char *data, int *off, char *cbuf, int cbuflen)
242 {
243         return ng_unparse_composite(type,
244                 data, off, cbuf, cbuflen, CT_FIXEDARRAY);
245 }
246
247 static int
248 ng_fixedarray_getDefault(const struct ng_parse_type *type,
249         const u_char *const start, u_char *buf, int *buflen)
250 {
251         int off = 0;
252
253         return ng_parse_composite(type,
254             "[]", &off, start, buf, buflen, CT_FIXEDARRAY);
255 }
256
257 static int
258 ng_fixedarray_getAlign(const struct ng_parse_type *type)
259 {
260         const struct ng_parse_fixedarray_info *fi = type->info;
261
262         return ALIGNMENT(fi->elementType);
263 }
264
265 const struct ng_parse_type ng_parse_fixedarray_type = {
266         NULL,
267         NULL,
268         NULL,
269         ng_fixedarray_parse,
270         ng_fixedarray_unparse,
271         ng_fixedarray_getDefault,
272         ng_fixedarray_getAlign
273 };
274
275 /************************************************************************
276                         VARIABLE LENGTH ARRAY TYPE
277  ************************************************************************/
278
279 static int
280 ng_array_parse(const struct ng_parse_type *type,
281         const char *s, int *off, const u_char *const start,
282         u_char *const buf, int *buflen)
283 {
284         return ng_parse_composite(type, s, off, start, buf, buflen, CT_ARRAY);
285 }
286
287 static int
288 ng_array_unparse(const struct ng_parse_type *type,
289         const u_char *data, int *off, char *cbuf, int cbuflen)
290 {
291         return ng_unparse_composite(type, data, off, cbuf, cbuflen, CT_ARRAY);
292 }
293
294 static int
295 ng_array_getDefault(const struct ng_parse_type *type,
296         const u_char *const start, u_char *buf, int *buflen)
297 {
298         int off = 0;
299
300         return ng_parse_composite(type,
301             "[]", &off, start, buf, buflen, CT_ARRAY);
302 }
303
304 static int
305 ng_array_getAlign(const struct ng_parse_type *type)
306 {
307         const struct ng_parse_array_info *ai = type->info;
308
309         return ALIGNMENT(ai->elementType);
310 }
311
312 const struct ng_parse_type ng_parse_array_type = {
313         NULL,
314         NULL,
315         NULL,
316         ng_array_parse,
317         ng_array_unparse,
318         ng_array_getDefault,
319         ng_array_getAlign
320 };
321
322 /************************************************************************
323                                 INT8 TYPE
324  ************************************************************************/
325
326 static int
327 ng_int8_parse(const struct ng_parse_type *type,
328         const char *s, int *off, const u_char *const start,
329         u_char *const buf, int *buflen)
330 {
331         long val;
332         int8_t val8;
333         char *eptr;
334
335         val = strtol(s + *off, &eptr, 0);
336         if (val < -0x80 || val > 0xff || eptr == s + *off)
337                 return (EINVAL);
338         *off = eptr - s;
339         val8 = (int8_t)val;
340         bcopy(&val8, buf, sizeof(int8_t));
341         *buflen = sizeof(int8_t);
342         return (0);
343 }
344
345 static int
346 ng_int8_unparse(const struct ng_parse_type *type,
347         const u_char *data, int *off, char *cbuf, int cbuflen)
348 {
349         int8_t val;
350
351         bcopy(data + *off, &val, sizeof(int8_t));
352         NG_PARSE_APPEND("%d", (int)val);
353         *off += sizeof(int8_t);
354         return (0);
355 }
356
357 static int
358 ng_int8_getDefault(const struct ng_parse_type *type,
359         const u_char *const start, u_char *buf, int *buflen)
360 {
361         int8_t val;
362
363         if (*buflen < sizeof(int8_t))
364                 return (ERANGE);
365         val = 0;
366         bcopy(&val, buf, sizeof(int8_t));
367         *buflen = sizeof(int8_t);
368         return (0);
369 }
370
371 static int
372 ng_int8_getAlign(const struct ng_parse_type *type)
373 {
374         return INT8_ALIGNMENT;
375 }
376
377 const struct ng_parse_type ng_parse_int8_type = {
378         NULL,
379         NULL,
380         NULL,
381         ng_int8_parse,
382         ng_int8_unparse,
383         ng_int8_getDefault,
384         ng_int8_getAlign
385 };
386
387 /************************************************************************
388                                 INT16 TYPE
389  ************************************************************************/
390
391 static int
392 ng_int16_parse(const struct ng_parse_type *type,
393         const char *s, int *off, const u_char *const start,
394         u_char *const buf, int *buflen)
395 {
396         long val;
397         int16_t val16;
398         char *eptr;
399
400         val = strtol(s + *off, &eptr, 0);
401         if (val < -0x8000 || val > 0xffff || eptr == s + *off)
402                 return (EINVAL);
403         *off = eptr - s;
404         val16 = (int16_t)val;
405         bcopy(&val16, buf, sizeof(int16_t));
406         *buflen = sizeof(int16_t);
407         return (0);
408 }
409
410 static int
411 ng_int16_unparse(const struct ng_parse_type *type,
412         const u_char *data, int *off, char *cbuf, int cbuflen)
413 {
414         int16_t val;
415
416         bcopy(data + *off, &val, sizeof(int16_t));
417         NG_PARSE_APPEND("%d", (int)val);
418         *off += sizeof(int16_t);
419         return (0);
420 }
421
422 static int
423 ng_int16_getDefault(const struct ng_parse_type *type,
424         const u_char *const start, u_char *buf, int *buflen)
425 {
426         int16_t val;
427
428         if (*buflen < sizeof(int16_t))
429                 return (ERANGE);
430         val = 0;
431         bcopy(&val, buf, sizeof(int16_t));
432         *buflen = sizeof(int16_t);
433         return (0);
434 }
435
436 static int
437 ng_int16_getAlign(const struct ng_parse_type *type)
438 {
439         return INT16_ALIGNMENT;
440 }
441
442 const struct ng_parse_type ng_parse_int16_type = {
443         NULL,
444         NULL,
445         NULL,
446         ng_int16_parse,
447         ng_int16_unparse,
448         ng_int16_getDefault,
449         ng_int16_getAlign
450 };
451
452 /************************************************************************
453                                 INT32 TYPE
454  ************************************************************************/
455
456 static int
457 ng_int32_parse(const struct ng_parse_type *type,
458         const char *s, int *off, const u_char *const start,
459         u_char *const buf, int *buflen)
460 {
461         long val;                       /* assumes long is at least 32 bits */
462         int32_t val32;
463         char *eptr;
464
465         val = strtol(s + *off, &eptr, 0);
466         if (val < (long)-0x80000000
467             || val > (u_long)0xffffffff || eptr == s + *off)
468                 return (EINVAL);
469         *off = eptr - s;
470         val32 = (int32_t)val;
471         bcopy(&val32, buf, sizeof(int32_t));
472         *buflen = sizeof(int32_t);
473         return (0);
474 }
475
476 static int
477 ng_int32_unparse(const struct ng_parse_type *type,
478         const u_char *data, int *off, char *cbuf, int cbuflen)
479 {
480         int32_t val;
481
482         bcopy(data + *off, &val, sizeof(int32_t));
483         NG_PARSE_APPEND("%ld", (long)val);
484         *off += sizeof(int32_t);
485         return (0);
486 }
487
488 static int
489 ng_int32_getDefault(const struct ng_parse_type *type,
490         const u_char *const start, u_char *buf, int *buflen)
491 {
492         int32_t val;
493
494         if (*buflen < sizeof(int32_t))
495                 return (ERANGE);
496         val = 0;
497         bcopy(&val, buf, sizeof(int32_t));
498         *buflen = sizeof(int32_t);
499         return (0);
500 }
501
502 static int
503 ng_int32_getAlign(const struct ng_parse_type *type)
504 {
505         return INT32_ALIGNMENT;
506 }
507
508 const struct ng_parse_type ng_parse_int32_type = {
509         NULL,
510         NULL,
511         NULL,
512         ng_int32_parse,
513         ng_int32_unparse,
514         ng_int32_getDefault,
515         ng_int32_getAlign
516 };
517
518 /************************************************************************
519                                 INT64 TYPE
520  ************************************************************************/
521
522 static int
523 ng_int64_parse(const struct ng_parse_type *type,
524         const char *s, int *off, const u_char *const start,
525         u_char *const buf, int *buflen)
526 {
527         quad_t val;
528         int64_t val64;
529         char *eptr;
530
531         val = strtoq(s + *off, &eptr, 0);
532         if (eptr == s + *off)
533                 return (EINVAL);
534         *off = eptr - s;
535         val64 = (int64_t)val;
536         bcopy(&val64, buf, sizeof(int64_t));
537         *buflen = sizeof(int64_t);
538         return (0);
539 }
540
541 static int
542 ng_int64_unparse(const struct ng_parse_type *type,
543         const u_char *data, int *off, char *cbuf, int cbuflen)
544 {
545         int64_t val;
546
547         bcopy(data + *off, &val, sizeof(int64_t));
548         NG_PARSE_APPEND("%lld", (long long)val);
549         *off += sizeof(int64_t);
550         return (0);
551 }
552
553 static int
554 ng_int64_getDefault(const struct ng_parse_type *type,
555         const u_char *const start, u_char *buf, int *buflen)
556 {
557         int64_t val;
558
559         if (*buflen < sizeof(int64_t))
560                 return (ERANGE);
561         val = 0;
562         bcopy(&val, buf, sizeof(int64_t));
563         *buflen = sizeof(int64_t);
564         return (0);
565 }
566
567 static int
568 ng_int64_getAlign(const struct ng_parse_type *type)
569 {
570         return INT64_ALIGNMENT;
571 }
572
573 const struct ng_parse_type ng_parse_int64_type = {
574         NULL,
575         NULL,
576         NULL,
577         ng_int64_parse,
578         ng_int64_unparse,
579         ng_int64_getDefault,
580         ng_int64_getAlign
581 };
582
583 /************************************************************************
584                                 STRING TYPE
585  ************************************************************************/
586
587 static int
588 ng_string_parse(const struct ng_parse_type *type,
589         const char *s, int *off, const u_char *const start,
590         u_char *const buf, int *buflen)
591 {
592         char *sval;
593         int len;
594
595         if ((sval = ng_get_string_token(s, off, &len)) == NULL)
596                 return (EINVAL);
597         *off += len;
598         len = strlen(sval) + 1;
599         bcopy(sval, buf, len);
600         FREE(sval, M_NETGRAPH);
601         *buflen = len;
602         return (0);
603 }
604
605 static int
606 ng_string_unparse(const struct ng_parse_type *type,
607         const u_char *data, int *off, char *cbuf, int cbuflen)
608 {
609         const char *const raw = (const char *)data + *off;
610         char *const s = ng_encode_string(raw);
611
612         if (s == NULL)
613                 return (ENOMEM);
614         NG_PARSE_APPEND("%s", s);
615         *off += strlen(raw) + 1;
616         FREE(s, M_NETGRAPH);
617         return (0);
618 }
619
620 static int
621 ng_string_getDefault(const struct ng_parse_type *type,
622         const u_char *const start, u_char *buf, int *buflen)
623 {
624
625         if (*buflen < 1)
626                 return (ERANGE);
627         buf[0] = (u_char)'\0';
628         *buflen = 1;
629         return (0);
630 }
631
632 const struct ng_parse_type ng_parse_string_type = {
633         NULL,
634         NULL,
635         NULL,
636         ng_string_parse,
637         ng_string_unparse,
638         ng_string_getDefault,
639         NULL
640 };
641
642 /************************************************************************
643                         FIXED BUFFER STRING TYPE
644  ************************************************************************/
645
646 static int
647 ng_fixedstring_parse(const struct ng_parse_type *type,
648         const char *s, int *off, const u_char *const start,
649         u_char *const buf, int *buflen)
650 {
651         const struct ng_parse_fixedstring_info *const fi = type->info;
652         char *sval;
653         int len;
654
655         if ((sval = ng_get_string_token(s, off, &len)) == NULL)
656                 return (EINVAL);
657         if (strlen(sval) + 1 > fi->bufSize)
658                 return (E2BIG);
659         *off += len;
660         len = strlen(sval) + 1;
661         bcopy(sval, buf, len);
662         FREE(sval, M_NETGRAPH);
663         bzero(buf + len, fi->bufSize - len);
664         *buflen = fi->bufSize;
665         return (0);
666 }
667
668 static int
669 ng_fixedstring_unparse(const struct ng_parse_type *type,
670         const u_char *data, int *off, char *cbuf, int cbuflen)
671 {
672         const struct ng_parse_fixedstring_info *const fi = type->info;
673         int error, temp = *off;
674
675         if ((error = ng_string_unparse(type, data, &temp, cbuf, cbuflen)) != 0)
676                 return (error);
677         *off += fi->bufSize;
678         return (0);
679 }
680
681 static int
682 ng_fixedstring_getDefault(const struct ng_parse_type *type,
683         const u_char *const start, u_char *buf, int *buflen)
684 {
685         const struct ng_parse_fixedstring_info *const fi = type->info;
686
687         if (*buflen < fi->bufSize)
688                 return (ERANGE);
689         bzero(buf, fi->bufSize);
690         *buflen = fi->bufSize;
691         return (0);
692 }
693
694 const struct ng_parse_type ng_parse_fixedstring_type = {
695         NULL,
696         NULL,
697         NULL,
698         ng_fixedstring_parse,
699         ng_fixedstring_unparse,
700         ng_fixedstring_getDefault,
701         NULL
702 };
703
704 const struct ng_parse_fixedstring_info ng_parse_nodebuf_info = {
705         NG_NODELEN + 1
706 };
707 const struct ng_parse_type ng_parse_nodebuf_type = {
708         &ng_parse_fixedstring_type,
709         &ng_parse_nodebuf_info
710 };
711
712 const struct ng_parse_fixedstring_info ng_parse_hookbuf_info = {
713         NG_HOOKLEN + 1
714 };
715 const struct ng_parse_type ng_parse_hookbuf_type = {
716         &ng_parse_fixedstring_type,
717         &ng_parse_hookbuf_info
718 };
719
720 const struct ng_parse_fixedstring_info ng_parse_pathbuf_info = {
721         NG_PATHLEN + 1
722 };
723 const struct ng_parse_type ng_parse_pathbuf_type = {
724         &ng_parse_fixedstring_type,
725         &ng_parse_pathbuf_info
726 };
727
728 const struct ng_parse_fixedstring_info ng_parse_typebuf_info = {
729         NG_TYPELEN + 1
730 };
731 const struct ng_parse_type ng_parse_typebuf_type = {
732         &ng_parse_fixedstring_type,
733         &ng_parse_typebuf_info
734 };
735
736 const struct ng_parse_fixedstring_info ng_parse_cmdbuf_info = {
737         NG_CMDSTRLEN + 1
738 };
739 const struct ng_parse_type ng_parse_cmdbuf_type = {
740         &ng_parse_fixedstring_type,
741         &ng_parse_cmdbuf_info
742 };
743
744 /************************************************************************
745                         IP ADDRESS TYPE
746  ************************************************************************/
747
748 static int
749 ng_ipaddr_parse(const struct ng_parse_type *type,
750         const char *s, int *off, const u_char *const start,
751         u_char *const buf, int *buflen)
752 {
753         int i, error;
754
755         for (i = 0; i < 4; i++) {
756                 if ((error = ng_int8_parse(&ng_parse_int8_type,
757                     s, off, start, buf + i, buflen)) != 0)
758                         return (error);
759                 if (i < 3 && s[*off] != '.')
760                         return (EINVAL);
761                 (*off)++;
762         }
763         *buflen = 4;
764         return (0);
765 }
766
767 static int
768 ng_ipaddr_unparse(const struct ng_parse_type *type,
769         const u_char *data, int *off, char *cbuf, int cbuflen)
770 {
771         struct in_addr ip;
772
773         bcopy(data + *off, &ip, sizeof(ip));
774         NG_PARSE_APPEND("%d.%d.%d.%d", ((u_char *)&ip)[0],
775             ((u_char *)&ip)[1], ((u_char *)&ip)[2], ((u_char *)&ip)[3]);
776         *off += sizeof(ip);
777         return (0);
778 }
779
780 static int
781 ng_ipaddr_getDefault(const struct ng_parse_type *type,
782         const u_char *const start, u_char *buf, int *buflen)
783 {
784         struct in_addr ip = { 0 };
785
786         if (*buflen < sizeof(ip))
787                 return (ERANGE);
788         bcopy(&ip, buf, sizeof(ip));
789         *buflen = sizeof(ip);
790         return (0);
791 }
792
793 const struct ng_parse_type ng_parse_ipaddr_type = {
794         NULL,
795         NULL,
796         NULL,
797         ng_ipaddr_parse,
798         ng_ipaddr_unparse,
799         ng_ipaddr_getDefault,
800         ng_int32_getAlign
801 };
802
803 /************************************************************************
804                         BYTE ARRAY TYPE
805  ************************************************************************/
806
807 /* Get the length of a byte array */
808 static int
809 ng_parse_bytearray_subtype_getLength(const struct ng_parse_type *type,
810         const u_char *start, const u_char *buf)
811 {
812         ng_parse_array_getLength_t *const getLength = type->private;
813
814         return (*getLength)(type, start, buf);
815 }
816
817 static int
818 ng_bytearray_elem_unparse(const struct ng_parse_type *type,
819         const u_char *data, int *off, char *cbuf, int cbuflen)
820 {
821         int8_t val;
822
823         bcopy(data + *off, &val, sizeof(int8_t));
824         NG_PARSE_APPEND("0x%02x", (int)val & 0xff);     /* always hex format */
825         *off += sizeof(int8_t);
826         return (0);
827 }
828
829 /* Byte array element type is int8, but always output in hex format */
830 const struct ng_parse_type ng_parse_bytearray_elem_type = {
831         &ng_parse_int8_type,
832         NULL,
833         NULL,
834         NULL,
835         ng_bytearray_elem_unparse,
836         NULL,
837         NULL
838 };
839
840 static const struct ng_parse_array_info ng_parse_bytearray_subtype_info = {
841         &ng_parse_bytearray_elem_type,
842         &ng_parse_bytearray_subtype_getLength,
843         NULL
844 };
845 static const struct ng_parse_type ng_parse_bytearray_subtype = {
846         &ng_parse_array_type,
847         &ng_parse_bytearray_subtype_info
848 };
849
850 static int
851 ng_bytearray_parse(const struct ng_parse_type *type,
852         const char *s, int *off, const u_char *const start,
853         u_char *const buf, int *buflen)
854 {
855         char *str;
856         int toklen;
857
858         /* We accept either an array of bytes or a string constant */
859         if ((str = ng_get_string_token(s, off, &toklen)) != NULL) {
860                 ng_parse_array_getLength_t *const getLength = type->info;
861                 int arraylen, slen;
862
863                 arraylen = (*getLength)(type, start, buf);
864                 if (arraylen > *buflen) {
865                         FREE(str, M_NETGRAPH);
866                         return (ERANGE);
867                 }
868                 slen = strlen(str) + 1;
869                 if (slen > arraylen) {
870                         FREE(str, M_NETGRAPH);
871                         return (E2BIG);
872                 }
873                 bcopy(str, buf, slen);
874                 bzero(buf + slen, arraylen - slen);
875                 FREE(str, M_NETGRAPH);
876                 *off += toklen;
877                 *buflen = arraylen;
878                 return (0);
879         } else {
880                 struct ng_parse_type subtype;
881
882                 subtype = ng_parse_bytearray_subtype;
883                 (const void *)subtype.private = type->info;
884                 return ng_array_parse(&subtype, s, off, start, buf, buflen);
885         }
886 }
887
888 static int
889 ng_bytearray_unparse(const struct ng_parse_type *type,
890         const u_char *data, int *off, char *cbuf, int cbuflen)
891 {
892         struct ng_parse_type subtype;
893
894         subtype = ng_parse_bytearray_subtype;
895         (const void *)subtype.private = type->info;
896         return ng_array_unparse(&subtype, data, off, cbuf, cbuflen);
897 }
898
899 static int
900 ng_bytearray_getDefault(const struct ng_parse_type *type,
901         const u_char *const start, u_char *buf, int *buflen)
902 {
903         struct ng_parse_type subtype;
904
905         subtype = ng_parse_bytearray_subtype;
906         (const void *)subtype.private = type->info;
907         return ng_array_getDefault(&subtype, start, buf, buflen);
908 }
909
910 const struct ng_parse_type ng_parse_bytearray_type = {
911         NULL,
912         NULL,
913         NULL,
914         ng_bytearray_parse,
915         ng_bytearray_unparse,
916         ng_bytearray_getDefault,
917         NULL
918 };
919
920 /************************************************************************
921                         STRUCT NG_MESG TYPE
922  ************************************************************************/
923
924 /* Get msg->header.arglen when "buf" is pointing to msg->data */
925 static int
926 ng_parse_ng_mesg_getLength(const struct ng_parse_type *type,
927         const u_char *start, const u_char *buf)
928 {
929         const struct ng_mesg *msg;
930
931         msg = (const struct ng_mesg *)(buf - sizeof(*msg));
932         return msg->header.arglen;
933 }
934
935 /* Type for the variable length data portion of a struct ng_mesg */
936 static const struct ng_parse_type ng_msg_data_type = {
937         &ng_parse_bytearray_type,
938         &ng_parse_ng_mesg_getLength
939 };
940
941 /* Type for the entire struct ng_mesg header with data section */
942 static const struct ng_parse_struct_info
943         ng_parse_ng_mesg_type_info = NG_GENERIC_NG_MESG_INFO(&ng_msg_data_type);
944 const struct ng_parse_type ng_parse_ng_mesg_type = {
945         &ng_parse_struct_type,
946         &ng_parse_ng_mesg_type_info,
947 };
948
949 /************************************************************************
950                         COMPOSITE HELPER ROUTINES
951  ************************************************************************/
952
953 /*
954  * Convert a structure or array from ASCII to binary
955  */
956 static int
957 ng_parse_composite(const struct ng_parse_type *type, const char *s,
958         int *off, const u_char *const start, u_char *const buf, int *buflen,
959         const enum comptype ctype)
960 {
961         const int num = ng_get_composite_len(type, start, buf, ctype);
962         int nextIndex = 0;              /* next implicit array index */
963         u_int index;                    /* field or element index */
964         int *foff;                      /* field value offsets in string */
965         int align, len, blen, error = 0;
966
967         /* Initialize */
968         MALLOC(foff, int *, num * sizeof(*foff), M_NETGRAPH, M_NOWAIT);
969         if (foff == NULL) {
970                 error = ENOMEM;
971                 goto done;
972         }
973         bzero(foff, num * sizeof(*foff));
974
975         /* Get opening brace/bracket */
976         if (ng_parse_get_token(s, off, &len)
977             != (ctype == CT_STRUCT ? T_LBRACE : T_LBRACKET)) {
978                 error = EINVAL;
979                 goto done;
980         }
981         *off += len;
982
983         /* Get individual element value positions in the string */
984         for (;;) {
985                 enum ng_parse_token tok;
986
987                 /* Check for closing brace/bracket */
988                 tok = ng_parse_get_token(s, off, &len);
989                 if (tok == (ctype == CT_STRUCT ? T_RBRACE : T_RBRACKET)) {
990                         *off += len;
991                         break;
992                 }
993
994                 /* For arrays, the 'name' (ie, index) is optional, so
995                    distinguish name from values by seeing if the next
996                    token is an equals sign */
997                 if (ctype != CT_STRUCT) {
998                         int len2, off2;
999                         char *eptr;
1000
1001                         /* If an opening brace/bracket, index is implied */
1002                         if (tok == T_LBRACE || tok == T_LBRACKET) {
1003                                 index = nextIndex++;
1004                                 goto gotIndex;
1005                         }
1006
1007                         /* Might be an index, might be a value, either way... */
1008                         if (tok != T_WORD) {
1009                                 error = EINVAL;
1010                                 goto done;
1011                         }
1012
1013                         /* If no equals sign follows, index is implied */
1014                         off2 = *off + len;
1015                         if (ng_parse_get_token(s, &off2, &len2) != T_EQUALS) {
1016                                 index = nextIndex++;
1017                                 goto gotIndex;
1018                         }
1019
1020                         /* Index was specified explicitly; parse it */
1021                         index = (u_int)strtoul(s + *off, &eptr, 0);
1022                         if (index < 0 || eptr - (s + *off) != len) {
1023                                 error = EINVAL;
1024                                 goto done;
1025                         }
1026                         nextIndex = index + 1;
1027                         *off += len + len2;
1028 gotIndex:
1029                 } else {                        /* a structure field */
1030                         const struct ng_parse_struct_field *field = NULL;
1031                         const struct ng_parse_struct_info *si = type->info;
1032
1033                         /* Find the field by name (required) in field list */
1034                         if (tok != T_WORD) {
1035                                 error = EINVAL;
1036                                 goto done;
1037                         }
1038                         for (index = 0; index < num; index++) {
1039                                 field = &si->fields[index];
1040                                 if (strncmp(&s[*off], field->name, len) == 0
1041                                     && field->name[len] == '\0')
1042                                         break;
1043                         }
1044                         if (index == num) {
1045                                 error = ENOENT;
1046                                 goto done;
1047                         }
1048                         *off += len;
1049
1050                         /* Get equals sign */
1051                         if (ng_parse_get_token(s, off, &len) != T_EQUALS) {
1052                                 error = EINVAL;
1053                                 goto done;
1054                         }
1055                         *off += len;
1056                 }
1057
1058                 /* Check array index */
1059                 if (index >= num) {
1060                         error = E2BIG;
1061                         goto done;
1062                 }
1063
1064                 /* Save value's position and skip over it for now */
1065                 if (foff[index] != 0) {
1066                         error = EALREADY;               /* duplicate */
1067                         goto done;
1068                 }
1069                 while (isspace(s[*off]))
1070                         (*off)++;
1071                 foff[index] = *off;
1072                 if ((error = ng_parse_skip_value(s, *off, &len)) != 0)
1073                         goto done;
1074                 *off += len;
1075         }
1076
1077         /* Now build binary structure from supplied values and defaults */
1078         for (blen = index = 0; index < num; index++) {
1079                 const struct ng_parse_type *const
1080                     etype = ng_get_composite_etype(type, index, ctype);
1081                 int k, pad, vlen;
1082
1083                 /* Zero-pad any alignment bytes */
1084                 pad = ng_parse_get_elem_pad(type, index, ctype, blen);
1085                 for (k = 0; k < pad; k++) {
1086                         if (blen >= *buflen) {
1087                                 error = ERANGE;
1088                                 goto done;
1089                         }
1090                         buf[blen++] = 0;
1091                 }
1092
1093                 /* Get value */
1094                 vlen = *buflen - blen;
1095                 if (foff[index] == 0) {         /* use default value */
1096                         error = ng_get_composite_elem_default(type, index,
1097                             start, buf + blen, &vlen, ctype);
1098                 } else {                        /* parse given value */
1099                         *off = foff[index];
1100                         error = INVOKE(etype, parse)(etype,
1101                             s, off, start, buf + blen, &vlen);
1102                 }
1103                 if (error != 0)
1104                         goto done;
1105                 blen += vlen;
1106         }
1107
1108         /* Make total composite structure size a multiple of its alignment */
1109         if ((align = ALIGNMENT(type)) != 0) {
1110                 while (blen % align != 0) {
1111                         if (blen >= *buflen) {
1112                                 error = ERANGE;
1113                                 goto done;
1114                         }
1115                         buf[blen++] = 0;
1116                 }
1117         }
1118
1119         /* Done */
1120         *buflen = blen;
1121 done:
1122         FREE(foff, M_NETGRAPH);
1123         return (error);
1124 }
1125
1126 /*
1127  * Convert an array or structure from binary to ASCII
1128  */
1129 static int
1130 ng_unparse_composite(const struct ng_parse_type *type, const u_char *data,
1131         int *off, char *cbuf, int cbuflen, const enum comptype ctype)
1132 {
1133         const int num = ng_get_composite_len(type, data, data + *off, ctype);
1134         int nextIndex = 0, didOne = 0;
1135         int error, index;
1136
1137         /* Opening brace/bracket */
1138         NG_PARSE_APPEND("%c", (ctype == CT_STRUCT) ? '{' : '[');
1139
1140         /* Do each item */
1141         for (index = 0; index < num; index++) {
1142                 const struct ng_parse_type *const
1143                     etype = ng_get_composite_etype(type, index, ctype);
1144                 u_char temp[1024];
1145
1146                 /* Skip any alignment pad bytes */
1147                 *off += ng_parse_get_elem_pad(type, index, ctype, *off);
1148
1149                 /* See if element is equal to its default value; skip if so */
1150                 if (*off < sizeof(temp)) {
1151                         int tempsize = sizeof(temp) - *off;
1152
1153                         bcopy(data, temp, *off);
1154                         if (ng_get_composite_elem_default(type, index, temp,
1155                               temp + *off, &tempsize, ctype) == 0
1156                             && bcmp(temp + *off, data + *off, tempsize) == 0) {
1157                                 *off += tempsize;
1158                                 continue;
1159                         }
1160                 }
1161
1162                 /* Print name= */
1163                 NG_PARSE_APPEND(" ");
1164                 if (ctype != CT_STRUCT) {
1165                         if (index != nextIndex) {
1166                                 nextIndex = index;
1167                                 NG_PARSE_APPEND("%d=", index);
1168                         }
1169                         nextIndex++;
1170                 } else {
1171                         const struct ng_parse_struct_info *si = type->info;
1172
1173                         NG_PARSE_APPEND("%s=", si->fields[index].name);
1174                 }
1175
1176                 /* Print value */
1177                 if ((error = INVOKE(etype, unparse)
1178                     (etype, data, off, cbuf, cbuflen)) != 0)
1179                         return (error);
1180                 cbuflen -= strlen(cbuf);
1181                 cbuf += strlen(cbuf);
1182                 didOne = 1;
1183         }
1184
1185         /* Closing brace/bracket */
1186         NG_PARSE_APPEND("%s%c",
1187             didOne ? " " : "", (ctype == CT_STRUCT) ? '}' : ']');
1188         return (0);
1189 }
1190
1191 /*
1192  * Generate the default value for an element of an array or structure
1193  * Returns EOPNOTSUPP if default value is unspecified.
1194  */
1195 static int
1196 ng_get_composite_elem_default(const struct ng_parse_type *type,
1197         int index, const u_char *const start, u_char *buf, int *buflen,
1198         const enum comptype ctype)
1199 {
1200         const struct ng_parse_type *etype;
1201         ng_getDefault_t *func;
1202
1203         switch (ctype) {
1204         case CT_STRUCT:
1205                 break;
1206         case CT_ARRAY:
1207             {
1208                 const struct ng_parse_array_info *const ai = type->info;
1209
1210                 if (ai->getDefault != NULL) {
1211                         return (*ai->getDefault)(type,
1212                             index, start, buf, buflen);
1213                 }
1214                 break;
1215             }
1216         case CT_FIXEDARRAY:
1217             {
1218                 const struct ng_parse_fixedarray_info *const fi = type->info;
1219
1220                 if (*fi->getDefault != NULL) {
1221                         return (*fi->getDefault)(type,
1222                             index, start, buf, buflen);
1223                 }
1224                 break;
1225             }
1226         default:
1227             panic("%s", __FUNCTION__);
1228         }
1229
1230         /* Default to element type default */
1231         etype = ng_get_composite_etype(type, index, ctype);
1232         func = METHOD(etype, getDefault);
1233         if (func == NULL)
1234                 return (EOPNOTSUPP);
1235         return (*func)(etype, start, buf, buflen);
1236 }
1237
1238 /*
1239  * Get the number of elements in a struct, variable or fixed array.
1240  */
1241 static int
1242 ng_get_composite_len(const struct ng_parse_type *type,
1243         const u_char *const start, const u_char *buf,
1244         const enum comptype ctype)
1245 {
1246         switch (ctype) {
1247         case CT_STRUCT:
1248             {
1249                 const struct ng_parse_struct_info *const si = type->info;
1250                 int numFields = 0;
1251
1252                 for (numFields = 0; ; numFields++) {
1253                         const struct ng_parse_struct_field *const
1254                                 fi = &si->fields[numFields];
1255
1256                         if (fi->name == NULL)
1257                                 break;
1258                 }
1259                 return (numFields);
1260             }
1261         case CT_ARRAY:
1262             {
1263                 const struct ng_parse_array_info *const ai = type->info;
1264
1265                 return (*ai->getLength)(type, start, buf);
1266             }
1267         case CT_FIXEDARRAY:
1268             {
1269                 const struct ng_parse_fixedarray_info *const fi = type->info;
1270
1271                 return fi->length;
1272             }
1273         default:
1274             panic("%s", __FUNCTION__);
1275         }
1276         return (0);
1277 }
1278
1279 /*
1280  * Return the type of the index'th element of a composite structure
1281  */
1282 static const struct ng_parse_type *
1283 ng_get_composite_etype(const struct ng_parse_type *type,
1284         int index, const enum comptype ctype)
1285 {
1286         const struct ng_parse_type *etype = NULL;
1287
1288         switch (ctype) {
1289         case CT_STRUCT:
1290             {
1291                 const struct ng_parse_struct_info *const si = type->info;
1292
1293                 etype = si->fields[index].type;
1294                 break;
1295             }
1296         case CT_ARRAY:
1297             {
1298                 const struct ng_parse_array_info *const ai = type->info;
1299
1300                 etype = ai->elementType;
1301                 break;
1302             }
1303         case CT_FIXEDARRAY:
1304             {
1305                 const struct ng_parse_fixedarray_info *const fi = type->info;
1306
1307                 etype = fi->elementType;
1308                 break;
1309             }
1310         default:
1311             panic("%s", __FUNCTION__);
1312         }
1313         return (etype);
1314 }
1315
1316 /*
1317  * Get the number of bytes to skip to align for the next
1318  * element in a composite structure.
1319  */
1320 static int
1321 ng_parse_get_elem_pad(const struct ng_parse_type *type,
1322         int index, enum comptype ctype, int posn)
1323 {
1324         const struct ng_parse_type *const
1325             etype = ng_get_composite_etype(type, index, ctype);
1326         int align;
1327
1328         /* Get element's alignment, and possibly override */
1329         align = ALIGNMENT(etype);
1330         if (ctype == CT_STRUCT) {
1331                 const struct ng_parse_struct_info *si = type->info;
1332
1333                 if (si->fields[index].alignment != 0)
1334                         align = si->fields[index].alignment;
1335         }
1336
1337         /* Return number of bytes to skip to align */
1338         return (align ? (align - (posn % align)) % align : 0);
1339 }
1340
1341 /************************************************************************
1342                         PARSING HELPER ROUTINES
1343  ************************************************************************/
1344
1345 /*
1346  * Skip over a value
1347  */
1348 static int
1349 ng_parse_skip_value(const char *s, int off0, int *lenp)
1350 {
1351         int len, nbracket, nbrace;
1352         int off = off0;
1353
1354         len = nbracket = nbrace = 0;
1355         do {
1356                 switch (ng_parse_get_token(s, &off, &len)) {
1357                 case T_LBRACKET:
1358                         nbracket++;
1359                         break;
1360                 case T_LBRACE:
1361                         nbrace++;
1362                         break;
1363                 case T_RBRACKET:
1364                         if (nbracket-- == 0)
1365                                 return (EINVAL);
1366                         break;
1367                 case T_RBRACE:
1368                         if (nbrace-- == 0)
1369                                 return (EINVAL);
1370                         break;
1371                 case T_EOF:
1372                         return (EINVAL);
1373                 default:
1374                         break;
1375                 }
1376                 off += len;
1377         } while (nbracket > 0 || nbrace > 0);
1378         *lenp = off - off0;
1379         return (0);
1380 }
1381
1382 /*
1383  * Find the next token in the string, starting at offset *startp.
1384  * Returns the token type, with *startp pointing to the first char
1385  * and *lenp the length.
1386  */
1387 enum ng_parse_token
1388 ng_parse_get_token(const char *s, int *startp, int *lenp)
1389 {
1390         char *t;
1391         int i;
1392
1393         while (isspace(s[*startp]))
1394                 (*startp)++;
1395         switch (s[*startp]) {
1396         case '\0':
1397                 *lenp = 0;
1398                 return T_EOF;
1399         case '{':
1400                 *lenp = 1;
1401                 return T_LBRACE;
1402         case '}':
1403                 *lenp = 1;
1404                 return T_RBRACE;
1405         case '[':
1406                 *lenp = 1;
1407                 return T_LBRACKET;
1408         case ']':
1409                 *lenp = 1;
1410                 return T_RBRACKET;
1411         case '=':
1412                 *lenp = 1;
1413                 return T_EQUALS;
1414         case '"':
1415                 if ((t = ng_get_string_token(s, startp, lenp)) == NULL)
1416                         return T_ERROR;
1417                 FREE(t, M_NETGRAPH);
1418                 return T_STRING;
1419         default:
1420                 for (i = *startp + 1; s[i] != '\0' && !isspace(s[i])
1421                     && s[i] != '{' && s[i] != '}' && s[i] != '['
1422                     && s[i] != ']' && s[i] != '=' && s[i] != '"'; i++)
1423                         ;
1424                 *lenp = i - *startp;
1425                 return T_WORD;
1426         }
1427 }
1428
1429 /*
1430  * Get a string token, which must be enclosed in double quotes.
1431  * The normal C backslash escapes are recognized.
1432  */
1433 char *
1434 ng_get_string_token(const char *s, int *startp, int *lenp)
1435 {
1436         char *cbuf, *p;
1437         int start, off;
1438
1439         while (isspace(s[*startp]))
1440                 (*startp)++;
1441         start = *startp;
1442         if (s[*startp] != '"')
1443                 return (NULL);
1444         MALLOC(cbuf, char *, strlen(s + start), M_NETGRAPH, M_NOWAIT);
1445         if (cbuf == NULL)
1446                 return (NULL);
1447         strcpy(cbuf, s + start + 1);
1448         for (off = 1, p = cbuf; *p != '\0'; off++, p++) {
1449                 if (*p == '"') {
1450                         *p = '\0';
1451                         *lenp = off + 1;
1452                         return (cbuf);
1453                 } else if (p[0] == '\\' && p[1] != '\0') {
1454                         int x, k;
1455                         char *v;
1456
1457                         strcpy(p, p + 1);
1458                         v = p;
1459                         switch (*p) {
1460                         case 't':
1461                                 *v = '\t';
1462                                 off++;
1463                                 continue;
1464                         case 'n':
1465                                 *v = '\n';
1466                                 off++;
1467                                 continue;
1468                         case 'r':
1469                                 *v = '\r';
1470                                 off++;
1471                                 continue;
1472                         case 'v':
1473                                 *v =  '\v';
1474                                 off++;
1475                                 continue;
1476                         case 'f':
1477                                 *v =  '\f';
1478                                 off++;
1479                                 continue;
1480                         case '"':
1481                                 *v =  '"';
1482                                 off++;
1483                                 continue;
1484                         case '0': case '1': case '2': case '3':
1485                         case '4': case '5': case '6': case '7':
1486                                 for (x = k = 0;
1487                                     k < 3 && *v >= '0' && *v <= '7'; v++) {
1488                                         x = (x << 3) + (*v - '0');
1489                                         off++;
1490                                 }
1491                                 *--v = (char)x;
1492                                 break;
1493                         case 'x':
1494                                 for (v++, x = k = 0;
1495                                     k < 2 && isxdigit(*v); v++) {
1496                                         x = (x << 4) + (isdigit(*v) ?
1497                                               (*v - '0') :
1498                                               (tolower(*v) - 'a' + 10));
1499                                         off++;
1500                                 }
1501                                 *--v = (char)x;
1502                                 break;
1503                         default:
1504                                 continue;
1505                         }
1506                         strcpy(p, v);
1507                 }
1508         }
1509         return (NULL);          /* no closing quote */
1510 }
1511
1512 /*
1513  * Encode a string so it can be safely put in double quotes.
1514  * Caller must free the result.
1515  */
1516 char *
1517 ng_encode_string(const char *raw)
1518 {
1519         char *cbuf;
1520         int off = 0;
1521
1522         MALLOC(cbuf, char *, strlen(raw) * 4 + 3, M_NETGRAPH, M_NOWAIT);
1523         if (cbuf == NULL)
1524                 return (NULL);
1525         cbuf[off++] = '"';
1526         for ( ; *raw != '\0'; raw++) {
1527                 switch (*raw) {
1528                 case '\t':
1529                         cbuf[off++] = '\\';
1530                         cbuf[off++] = 't';
1531                         break;
1532                 case '\f':
1533                         cbuf[off++] = '\\';
1534                         cbuf[off++] = 'f';
1535                         break;
1536                 case '\n':
1537                         cbuf[off++] = '\\';
1538                         cbuf[off++] = 'n';
1539                         break;
1540                 case '\r':
1541                         cbuf[off++] = '\\';
1542                         cbuf[off++] = 'r';
1543                         break;
1544                 case '\v':
1545                         cbuf[off++] = '\\';
1546                         cbuf[off++] = 'v';
1547                         break;
1548                 case '"':
1549                 case '\\':
1550                         cbuf[off++] = '\\';
1551                         cbuf[off++] = *raw;
1552                         break;
1553                 default:
1554                         if (*raw < 0x20 || *raw > 0x7e) {
1555                                 off += sprintf(cbuf + off,
1556                                     "\\x%02x", (u_char)*raw);
1557                                 break;
1558                         }
1559                         cbuf[off++] = *raw;
1560                         break;
1561                 }
1562         }
1563         cbuf[off++] = '"';
1564         cbuf[off] = '\0';
1565         return (cbuf);
1566 }
1567
1568 /************************************************************************
1569                         VIRTUAL METHOD LOOKUP
1570  ************************************************************************/
1571
1572 static ng_parse_t *
1573 ng_get_parse_method(const struct ng_parse_type *t)
1574 {
1575         while (t != NULL && t->parse == NULL)
1576                 t = t->supertype;
1577         return (t ? t->parse : NULL);
1578 }
1579
1580 static ng_unparse_t *
1581 ng_get_unparse_method(const struct ng_parse_type *t)
1582 {
1583         while (t != NULL && t->unparse == NULL)
1584                 t = t->supertype;
1585         return (t ? t->unparse : NULL);
1586 }
1587
1588 static ng_getDefault_t *
1589 ng_get_getDefault_method(const struct ng_parse_type *t)
1590 {
1591         while (t != NULL && t->getDefault == NULL)
1592                 t = t->supertype;
1593         return (t ? t->getDefault : NULL);
1594 }
1595
1596 static ng_getAlign_t *
1597 ng_get_getAlign_method(const struct ng_parse_type *t)
1598 {
1599         while (t != NULL && t->getAlign == NULL)
1600                 t = t->supertype;
1601         return (t ? t->getAlign : NULL);
1602 }
1603