X-Git-Url: https://git.distorted.org.uk/~mdw/sod/blobdiff_plain/e520bc2484f96c38991fb8d3b49cd9a3b2410842..9e91c8e7b5fcdeb6389ac7ccbcd9c77348c4493a:/lib/keyword.c diff --git a/lib/keyword.c b/lib/keyword.c new file mode 100644 index 0000000..8ebf655 --- /dev/null +++ b/lib/keyword.c @@ -0,0 +1,110 @@ +/* -*-c-*- + * + * Keyword argument handling + * + * (c) 2015 Straylight/Edgeware + */ + +/*----- Licensing notice --------------------------------------------------* + * + * This file is part of the Sensible Object Design, an object system for C. + * + * SOD is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * SOD is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with SOD; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +/*----- Header files ------------------------------------------------------*/ + +#include "keyword.h" + +/*----- Global variables --------------------------------------------------*/ + +kw_unkhookfn *kw_unkhook = kw_defunknown; + +/*----- Main code ---------------------------------------------------------*/ + +/* --- @kw_unknown@ --- * + * + * Arguments: @const char *set@ = the keyword set name, as a string + * @const char *kw@ = the unknown keyword argument, as a string + * + * Returns: Doesn't. + * + * Use: Called when an unrecognized keyword argument is encountered + * during parsing. This calls the @kw_unkhook@ with the same + * arguments. Recovery via @longjmp@ or a similar machanism is + * acceptable. + */ + +void kw_unknown(const char *set, const char *kw) + { kw_unkhook(set, kw); kw__hookfailed(); } + +/* --- @kw_parseempty@ --- * + * + * Arguments: @const char *set@ = the keyword set name, as a string + * @const char *kwfirst@ = the first keyword argument name + * @va_list *ap@ = pointer to argument-tail extraction state + * @const struct kwval *v@ = base address of argument vector + * @size_t n@ = size of argument vector + * + * Returns: --- + * + * Use: Goes through the motions of parsing keyword arguments, but + * doesn't in fact handle any other than the standard ones + * described above (see @KWSET_PARSEFN@). This is useful when a + * function doesn't currently define any keyword arguments but + * wants to reserve the right to define some in the future. + * (The usual machinery can't be used in this case, since the + * argument structure would be empty. Besides, it would be + * pointless to include multiple copies of the same boilerplate + * code in a program.) + */ + +void kw_parseempty(const char *set, const char *kwfirst, va_list *ap, + const struct kwval *v, size_t n) +{ + const char *k, *kk; + va_list *aap; + const struct kwtab *t; + const struct kwval *vv; + size_t nn; + + for (k = kwfirst; k; k = va_arg(*ap, const char *)) { + if (!strcmp(k, "kw.va_list")) { + aap = va_arg(*ap, va_list *); + kk = va_arg(*aap, const char *); + kw_parseempty(set, kk, aap, 0, 0); + } else if (!strcmp(k, "kw.tab")) { + vv = va_arg(*ap, const struct kwval *); + nn = va_arg(*ap, size_t); + kw_parseempty(set, 0, 0, vv, nn); + } else + kw_unknown(set, k); + } + while (n) { + if (!strcmp(v->kw, "kw.va_list")) { + aap = *(va_list *const *)v->val; + kk = va_arg(*aap, const char *); + kw_parseempty(set, kk, aap, 0, 0); + } else if (!strcmp(k, "kw.tab")) { + t = (const struct kwtab *)v->val; + kw_parseempty(set, 0, 0, t->v, t->n); + } else + kw_unknown(set, k); + v++; n--; + } +} + +/*----- That's all, folks -------------------------------------------------*/