chiark / gitweb /
lib/: Pure C machinery for handling `keyword arguments' to functions.
[sod] / lib / keyword.c
1 /* -*-c-*-
2  *
3  * Keyword argument handling
4  *
5  * (c) 2015 Straylight/Edgeware
6  */
7
8 /*----- Licensing notice --------------------------------------------------*
9  *
10  * This file is part of the Sensible Object Design, an object system for C.
11  *
12  * SOD is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU Library General Public License as
14  * published by the Free Software Foundation; either version 2 of the
15  * License, or (at your option) any later version.
16  *
17  * SOD is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU Library General Public License for more details.
21  *
22  * You should have received a copy of the GNU Library General Public
23  * License along with SOD; if not, write to the Free
24  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25  * MA 02111-1307, USA.
26  */
27
28 /*----- Header files ------------------------------------------------------*/
29
30 #include "keyword.h"
31
32 /*----- Global variables --------------------------------------------------*/
33
34 kw_unkhookfn *kw_unkhook = kw_defunknown;
35
36 /*----- Main code ---------------------------------------------------------*/
37
38 /* --- @kw_unknown@ --- *
39  *
40  * Arguments:   @const char *set@ = the keyword set name, as a string
41  *              @const char *kw@ = the unknown keyword argument, as a string
42  *
43  * Returns:     Doesn't.
44  *
45  * Use:         Called when an unrecognized keyword argument is encountered
46  *              during parsing.  This calls the @kw_unkhook@ with the same
47  *              arguments. Recovery via @longjmp@ or a similar machanism is
48  *              acceptable.
49  */
50
51 void kw_unknown(const char *set, const char *kw)
52   { kw_unkhook(set, kw); kw__hookfailed(); }
53
54 /* --- @kw_parseempty@ --- *
55  *
56  * Arguments:   @const char *set@ = the keyword set name, as a string
57  *              @const char *kwfirst@ = the first keyword argument name
58  *              @va_list *ap@ = pointer to argument-tail extraction state
59  *              @const struct kwval *v@ = base address of argument vector
60  *              @size_t n@ = size of argument vector
61  *
62  * Returns:     ---
63  *
64  * Use:         Goes through the motions of parsing keyword arguments, but
65  *              doesn't in fact handle any other than the standard ones
66  *              described above (see @KWSET_PARSEFN@).  This is useful when a
67  *              function doesn't currently define any keyword arguments but
68  *              wants to reserve the right to define some in the future.
69  *              (The usual machinery can't be used in this case, since the
70  *              argument structure would be empty.  Besides, it would be
71  *              pointless to include multiple copies of the same boilerplate
72  *              code in a program.)
73  */
74
75 void kw_parseempty(const char *set, const char *kwfirst, va_list *ap,
76                    const struct kwval *v, size_t n)
77 {
78   const char *k, *kk;
79   va_list *aap;
80   const struct kwtab *t;
81   const struct kwval *vv;
82   size_t nn;
83
84   for (k = kwfirst; k; k = va_arg(*ap, const char *)) {
85     if (!strcmp(k, "kw.va_list")) {
86       aap = va_arg(*ap, va_list *);
87       kk = va_arg(*aap, const char *);
88       kw_parseempty(set, kk, aap, 0, 0);
89     } else if (!strcmp(k, "kw.tab")) {
90       vv = va_arg(*ap, const struct kwval *);
91       nn = va_arg(*ap, size_t);
92       kw_parseempty(set, 0, 0, vv, nn);
93     } else
94       kw_unknown(set, k);
95   }
96   while (n) {
97     if (!strcmp(v->kw, "kw.va_list")) {
98       aap = *(va_list *const *)v->val;
99       kk = va_arg(*aap, const char *);
100       kw_parseempty(set, kk, aap, 0, 0);
101     } else if (!strcmp(k, "kw.tab")) {
102       t = (const struct kwtab *)v->val;
103       kw_parseempty(set, 0, 0, t->v, t->n);
104     } else
105       kw_unknown(set, k);
106     v++; n--;
107   }
108 }
109
110 /*----- That's all, folks -------------------------------------------------*/