libmicrohttpd2

HTTP server C library (MHD 2.x, alpha)
Log | Files | Refs | README | LICENSE

options-generator.c (32942B)


      1 /* SPDX-License-Identifier: LGPL-2.1-or-later OR (GPL-2.0-or-later WITH eCos-exception-2.0) */
      2 /*
      3   This file is part of GNU libmicrohttpd.
      4   Copyright (C) 2024 Christian Grothoff (and other contributing authors)
      5 
      6   GNU libmicrohttpd is free software; you can redistribute it and/or
      7   modify it under the terms of the GNU Lesser General Public
      8   License as published by the Free Software Foundation; either
      9   version 2.1 of the License, or (at your option) any later version.
     10 
     11   GNU libmicrohttpd is distributed in the hope that it will be useful,
     12   but WITHOUT ANY WARRANTY; without even the implied warranty of
     13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14   Lesser General Public License for more details.
     15 
     16   Alternatively, you can redistribute GNU libmicrohttpd and/or
     17   modify it under the terms of the GNU General Public License as
     18   published by the Free Software Foundation; either version 2 of
     19   the License, or (at your option) any later version, together
     20   with the eCos exception, as follows:
     21 
     22     As a special exception, if other files instantiate templates or
     23     use macros or inline functions from this file, or you compile this
     24     file and link it with other works to produce a work based on this
     25     file, this file does not by itself cause the resulting work to be
     26     covered by the GNU General Public License. However the source code
     27     for this file must still be made available in accordance with
     28     section (3) of the GNU General Public License v2.
     29 
     30     This exception does not invalidate any other reasons why a work
     31     based on this file might be covered by the GNU General Public
     32     License.
     33 
     34   You should have received copies of the GNU Lesser General Public
     35   License and the GNU General Public License along with this library;
     36   if not, see <https://www.gnu.org/licenses/>.
     37 */
     38 /**
     39  * @file options-generator.c
     40  * @brief Generates code based on Recutils database
     41  * @author Christian Grothoff
     42  */
     43 #include <stdio.h>
     44 #include <stdlib.h>
     45 #include <stdarg.h>
     46 #include <string.h>
     47 #include <ctype.h>
     48 #if ! defined(_WIN32) || defined(__CYGWIN__)
     49 #  include <unistd.h>
     50 #endif
     51 #include <sys/stat.h>
     52 #include <errno.h>
     53 
     54 #define MAX_ARGS 3
     55 
     56 struct Option
     57 {
     58   struct Option *next;
     59   char *name;
     60   unsigned int value;
     61   char *type;
     62   char *comment;
     63   char *custom_setter;
     64   unsigned int argc;
     65   char *arguments[MAX_ARGS];
     66   unsigned int desc;
     67   char *descriptions[MAX_ARGS];
     68   char *conditional;
     69 };
     70 
     71 static FILE *f;
     72 
     73 static char *category;
     74 
     75 typedef void
     76 (*Callback) (const char *name,
     77              unsigned int value,
     78              const char *comment,
     79              const char *type,
     80              const char *conditional,
     81              const char *custom_setter,
     82              unsigned int argc,
     83              char **arguments,
     84              unsigned int desc,
     85              char **descriptions);
     86 
     87 
     88 static int
     89 my_asprintf (char **buf,
     90              const char *format,
     91              ...)
     92 {
     93   int ret;
     94   va_list args;
     95 
     96   va_start (args,
     97             format);
     98   ret = vsnprintf (NULL,
     99                    0,
    100                    format,
    101                    args);
    102   va_end (args);
    103   *buf = malloc (ret + 1);
    104   va_start (args,
    105             format);
    106   ret = vsprintf (*buf,
    107                   format,
    108                   args);
    109   va_end (args);
    110   return ret;
    111 }
    112 
    113 
    114 static void
    115 iterate (struct Option *head,
    116          Callback cb)
    117 {
    118   for (struct Option *o = head; NULL != o; o = o->next)
    119   {
    120     if (0 == strcmp ("end",
    121                      o->name))
    122       continue;
    123     cb (o->name,
    124         o->value,
    125         o->comment,
    126         o->type,
    127         o->conditional,
    128         o->custom_setter,
    129         o->argc,
    130         o->arguments,
    131         o->desc,
    132         o->descriptions);
    133   }
    134 }
    135 
    136 
    137 static void
    138 check (const char *name,
    139        unsigned int value,
    140        const char *comment,
    141        const char *type,
    142        const char *conditional,
    143        const char *custom_setter,
    144        unsigned int argc,
    145        char **arguments,
    146        unsigned int desc,
    147        char **descriptions)
    148 {
    149   if (argc != desc)
    150   {
    151     fprintf (stderr,
    152              "Mismatch between descriptions and arguments for `%s'\n",
    153              name);
    154     exit (2);
    155   }
    156   if ( (NULL == type) &&
    157        ( (0 == argc) ||
    158          (1 != argc) ) )
    159   {
    160     fprintf (stderr,
    161              "Type and argument missing for `%s' and not exactly 1 argument\n",
    162              name);
    163     exit (2);
    164   }
    165   for (unsigned int i = 0; i<argc; i++)
    166   {
    167     const char *arg = arguments[i];
    168 
    169     if (NULL == (strrchr (arg, ' ')))
    170     {
    171       fprintf (stderr,
    172                "Mandatory space missing in argument%u of `%s'\n",
    173                i,
    174                name);
    175       exit (2);
    176     }
    177   }
    178   if (NULL != strchr (name, ' '))
    179   {
    180     fprintf (stderr,
    181              "Spaces are not allowed in names, found one in `%s'\n",
    182              name);
    183     exit (2);
    184   }
    185 }
    186 
    187 
    188 static char *
    189 indent (char *pfx,
    190         const char *input)
    191 {
    192   char *ret = strdup (input);
    193   char *xfx = strdup (pfx);
    194   char *off;
    195   size_t pos = 0;
    196 
    197   while ( (strlen (xfx) > 0) &&
    198           (isspace (xfx[strlen (xfx) - 1])) )
    199     xfx[strlen (xfx) - 1] = '\0';
    200   while (NULL != (off = strchr (ret + pos, '\n')))
    201   {
    202     char *tmp;
    203 
    204     my_asprintf (&tmp,
    205                  "%.*s\n%s%s",
    206                  (int) (off - ret),
    207                  ret,
    208                  (off[1] == '\n')
    209               ? xfx
    210               : pfx,
    211                  off + 1);
    212     pos = (off - ret) + strlen (pfx) + 1;
    213     free (ret);
    214     ret = tmp;
    215   }
    216   return ret;
    217 }
    218 
    219 
    220 static char *
    221 uppercase (const char *input)
    222 {
    223   char *ret = strdup (input);
    224 
    225   for (size_t i = 0; '\0' != ret[i]; i++)
    226     ret[i] = toupper (ret[i]);
    227   return ret;
    228 }
    229 
    230 
    231 static char *
    232 capitalize (const char *input)
    233 {
    234   char *ret = strdup (input);
    235 
    236   ret[0] = toupper (ret[0]);
    237   return ret;
    238 }
    239 
    240 
    241 static char *
    242 lowercase (const char *input)
    243 {
    244   char *ret = strdup (input);
    245 
    246   for (size_t i = 0; '\0' != ret[i]; i++)
    247     ret[i] = tolower (ret[i]);
    248   return ret;
    249 }
    250 
    251 
    252 static void
    253 dump_enum (const char *name,
    254            unsigned int value,
    255            const char *comment,
    256            const char *type,
    257            const char *conditional,
    258            const char *custom_setter,
    259            unsigned int argc,
    260            char **arguments,
    261            unsigned int desc,
    262            char **descriptions)
    263 {
    264   printf ("  /**\n   * %s\n   */\n  MHD_%c_O_%s = %u\n  ,\n\n",
    265           indent ("   * ", comment),
    266           (char) toupper (*category),
    267           uppercase (name),
    268           value);
    269 }
    270 
    271 
    272 static const char *
    273 var_name (const char *arg)
    274 {
    275   const char *space;
    276 
    277   space = strrchr (arg, ' ');
    278   while ('*' == space[1])
    279     space++;
    280   return space + 1;
    281 }
    282 
    283 
    284 static void
    285 dump_union_members (const char *name,
    286                     unsigned int value,
    287                     const char *comment,
    288                     const char *type,
    289                     const char *conditional,
    290                     const char *custom_setter,
    291                     unsigned int argc,
    292                     char **arguments,
    293                     unsigned int desct,
    294                     char **descriptions)
    295 {
    296   if (NULL == type)
    297     return;
    298   if (1 >= argc)
    299     return;
    300 
    301   printf ("/**\n * Data for #MHD_%c_O_%s\n */\n%s\n{\n",
    302           (char) toupper (*category),
    303           uppercase (name),
    304           type);
    305   for (unsigned int i = 0; i<argc; i++)
    306   {
    307     const char *arg = arguments[i];
    308     const char *desc = descriptions[i];
    309     const char *vn = var_name (arg);
    310 
    311     printf ("  /**\n   * %s\n   */\n  %.*sv_%s;\n\n",
    312             indent ("   * ",
    313                     desc),
    314             (int) (vn - arg),
    315             arg,
    316             vn);
    317   }
    318   printf ("};\n\n");
    319 }
    320 
    321 
    322 static void
    323 dump_union (const char *name,
    324             unsigned int value,
    325             const char *comment,
    326             const char *type,
    327             const char *conditional,
    328             const char *custom_setter,
    329             unsigned int argc,
    330             char **arguments,
    331             unsigned int desc,
    332             char **descriptions)
    333 {
    334   const char *xcomment = xcomment = descriptions[0];
    335 
    336   fprintf (f,
    337            "  /**\n"
    338            "   * Value for #MHD_%c_O_%s.%s%s\n"
    339            "   */\n",
    340            (char) toupper (*category),
    341            uppercase (name),
    342            NULL != xcomment
    343           ? "\n   * "
    344           : "",
    345            NULL != xcomment
    346           ? indent ("   * ", xcomment)
    347           : "");
    348   if (NULL != type)
    349   {
    350     fprintf (f,
    351              "  %s %s;\n",
    352              type,
    353              lowercase (name));
    354   }
    355   else
    356   {
    357     const char *arg = arguments[0];
    358     const char *vn = var_name (arg);
    359 
    360     fprintf (f,
    361              "  %.*s%s;\n",
    362              (int) (vn - arg),
    363              arg,
    364              lowercase (name));
    365   }
    366   fprintf (f,
    367            "\n");
    368 }
    369 
    370 
    371 static void
    372 dump_struct (const char *name,
    373              unsigned int value,
    374              const char *comment,
    375              const char *type,
    376              const char *conditional,
    377              const char *custom_setter,
    378              unsigned int argc,
    379              char **arguments,
    380              unsigned int desc,
    381              char **descriptions)
    382 {
    383   if (NULL != conditional)
    384     fprintf (f,
    385              "#ifdef HAVE_%s",
    386              uppercase (conditional));
    387   dump_union (name,
    388               value,
    389               comment,
    390               type,
    391               conditional,
    392               custom_setter,
    393               argc,
    394               arguments,
    395               desc,
    396               descriptions);
    397   if (NULL != conditional)
    398     fprintf (f,
    399              "#endif\n");
    400   fprintf (f,
    401            "\n");
    402 }
    403 
    404 
    405 static void
    406 dump_option_macros (const char *name,
    407                     unsigned int value,
    408                     const char *comment,
    409                     const char *type,
    410                     const char *conditional,
    411                     const char *custom_setter,
    412                     unsigned int argc,
    413                     char **arguments,
    414                     unsigned int desct,
    415                     char **descriptions)
    416 {
    417   printf (
    418     "/**\n * %s\n",
    419     indent (" * ", comment));
    420   for (unsigned int off = 0; off<desct; off++)
    421   {
    422     const char *arg = arguments[off];
    423     const char *desc = descriptions[off];
    424     const char *vn = var_name (arg);
    425 
    426     printf (" * @param %s %s\n",
    427             vn,
    428             indent (" *   ",
    429                     desc));
    430   }
    431   if (0 == desct)
    432     printf (" * @param value the value of the parameter");
    433   printf (" * @return structure with the requested setting\n */\n");
    434   printf ("#  define MHD_%c_OPTION_%s(",
    435           (char) toupper (*category),
    436           uppercase (name));
    437   if (0 == argc)
    438     printf ("value");
    439   else
    440     for (unsigned int i = 0; i<argc; i++)
    441     {
    442       if (0 != i)
    443         printf (",");
    444       printf ("%s",
    445               var_name (arguments[i]));
    446     }
    447   printf (") \\\n"
    448           "        MHD_NOWARN_COMPOUND_LITERALS_ " \
    449           "MHD_NOWARN_AGGR_DYN_INIT_ \\\n"
    450           "          (const struct MHD_%sOptionAndValue) \\\n"
    451           "        { \\\n"
    452           "          .opt = MHD_%c_O_%s,  \\\n",
    453           capitalize (category),
    454           (char) toupper (*category),
    455           uppercase (name));
    456   if (0 == argc)
    457     printf ("          .val.%s = (value) \\\n",
    458             lowercase (name));
    459   else
    460     for (unsigned int i = 0; i<argc; i++)
    461     {
    462       const char *vn = var_name (arguments[i]);
    463 
    464       if (1 < argc)
    465         printf ("          .val.%s.v_%s = (%s)%s \\\n",
    466                 lowercase (name),
    467                 vn,
    468                 vn,
    469                 (i < argc - 1)
    470               ? ","
    471               : "");
    472       else
    473         printf ("          .val.%s = (%s)%s \\\n",
    474                 lowercase (name),
    475                 vn,
    476                 (i < argc - 1)
    477                 ? ","
    478                 : "");
    479     }
    480 
    481   printf ("        } \\\n"
    482           "        MHD_RESTORE_WARN_COMPOUND_LITERALS_ "
    483           "MHD_RESTORE_WARN_AGGR_DYN_INIT_\n");
    484 }
    485 
    486 
    487 static void
    488 dump_option_static_functions (const char *name,
    489                               unsigned int value,
    490                               const char *comment,
    491                               const char *type,
    492                               const char *conditional,
    493                               const char *custom_setter,
    494                               unsigned int argc,
    495                               char **arguments,
    496                               unsigned int desct,
    497                               char **descriptions)
    498 {
    499   printf (
    500     "\n"
    501     "/**\n * %s\n",
    502     indent (" * ", comment));
    503   for (unsigned int off = 0; off < desct; off++)
    504   {
    505     const char *arg = arguments[off];
    506     const char *desc = descriptions[off];
    507     const char *vn = var_name (arg);
    508 
    509     printf (" * @param %s %s\n",
    510             vn,
    511             indent (" *   ",
    512                     desc));
    513   }
    514   if (0 == desct)
    515     printf (" * @param value the value of the parameter");
    516   printf (" * @return structure with the requested setting\n */\n");
    517   printf ("static MHD_INLINE struct MHD_%sOptionAndValue\n"
    518           "MHD_%c_OPTION_%s (\n",
    519           capitalize (category),
    520           (char) toupper (*category),
    521           uppercase (name));
    522   if (0 == argc)
    523     printf ("  %s value",
    524             NULL != type
    525             ? type
    526             : arguments[0]);
    527   else
    528     for (unsigned int i = 0; i<argc; i++)
    529     {
    530       const char *arg = arguments[i];
    531       const char *vn
    532         = var_name (arg);
    533 
    534       if (0 != i)
    535         printf (",\n");
    536       printf ("  %.*s%s",
    537               (int) (vn - arg),
    538               arg,
    539               vn);
    540     }
    541   printf (
    542     "\n"
    543     "  )\n"
    544     "{\n"
    545     "  struct MHD_%sOptionAndValue opt_val;\n\n"
    546     "  opt_val.opt = MHD_%c_O_%s;\n",
    547     capitalize (category),
    548     (char) toupper (*category),
    549     uppercase (name));
    550   if (0 == argc)
    551     printf ("  opt_val.val.%s = (value); \\\n",
    552             lowercase (name));
    553   else
    554     for (unsigned int i = 0; i<argc; i++)
    555     {
    556       const char *vn = var_name (arguments[i]);
    557 
    558       if (1 < argc)
    559         printf ("  opt_val.val.%s.v_%s = %s;\n",
    560                 lowercase (name),
    561                 vn,
    562                 vn);
    563       else
    564         printf ("  opt_val.val.%s = %s;\n",
    565                 lowercase (name),
    566                 vn);
    567     }
    568   printf ("\n  return opt_val;\n}\n\n");
    569 }
    570 
    571 
    572 static void
    573 dump_option_documentation_functions (const char *name,
    574                                      unsigned int value,
    575                                      const char *comment,
    576                                      const char *type,
    577                                      const char *conditional,
    578                                      const char *custom_setter,
    579                                      unsigned int argc,
    580                                      char **arguments,
    581                                      unsigned int desct,
    582                                      char **descriptions)
    583 {
    584 
    585   fprintf (f,
    586            "/**\n * %s\n",
    587            indent (" * ", comment));
    588   for (unsigned int off = 0; off<desct; off++)
    589   {
    590     const char *arg = arguments[off];
    591     const char *desc = descriptions[off];
    592     const char *vn = var_name (arg);
    593 
    594     fprintf (f, " * @param %s %s\n",
    595              vn,
    596              indent (" *   ",
    597                      desc));
    598   }
    599   if (0 == desct)
    600     fprintf (f, " * @param value the value of the parameter");
    601   fprintf (f, " * @return structure with the requested setting\n */\n");
    602   fprintf (f,"struct MHD_%sOptionAndValue\n"
    603            "MHD_%c_OPTION_%s (\n",
    604            capitalize (category),
    605            (char) toupper (*category),
    606            uppercase (name));
    607   if (0 == argc)
    608     fprintf (f,
    609              "  %s value",
    610              NULL != type
    611              ? type
    612              : arguments[0]);
    613   else
    614     for (unsigned int i = 0; i<argc; i++)
    615     {
    616       const char *arg = arguments[i];
    617       const char *vn = var_name (arg);
    618 
    619       if (0 != i)
    620         fprintf (f, ",\n");
    621       fprintf (f,
    622                "  %.*s%s",
    623                (int) (vn - arg),
    624                arg,
    625                vn);
    626     }
    627   fprintf (f,
    628            "\n  );\n\n");
    629 }
    630 
    631 
    632 static void
    633 dump_option_set_switch (const char *name,
    634                         unsigned int value,
    635                         const char *comment,
    636                         const char *type,
    637                         const char *conditional,
    638                         const char *custom_setter,
    639                         unsigned int argc,
    640                         char **arguments,
    641                         unsigned int desc,
    642                         char **descriptions)
    643 {
    644   if (NULL != conditional)
    645     fprintf (f,
    646              "#ifdef HAVE_%s",
    647              uppercase (conditional));
    648   fprintf (f,
    649            "    case MHD_%c_O_%s:\n",
    650            (char) toupper (*category),
    651            uppercase (name));
    652   if (NULL != custom_setter)
    653   {
    654     fprintf (f,
    655              "      %s\n",
    656              indent ("      ",
    657                      custom_setter));
    658   }
    659   else
    660   {
    661     if (0 == argc)
    662     {
    663       fprintf (f,
    664                "      settings->%s = option->val.%s;\n",
    665                lowercase (name),
    666                lowercase (name));
    667     }
    668     else
    669     {
    670       for (unsigned int i = 0; i<argc; i++)
    671       {
    672         const char *vn = var_name (arguments[i]);
    673 
    674         if (1 < argc)
    675           fprintf (f,
    676                    "      settings->%s.v_%s = option->val.%s.v_%s;\n",
    677                    lowercase (name),
    678                    vn,
    679                    lowercase (name),
    680                    vn);
    681         else
    682           fprintf (f,
    683                    "      settings->%s = option->val.%s;\n",
    684                    lowercase (name),
    685                    lowercase (name));
    686       }
    687     }
    688   }
    689   fprintf (f,
    690            "      continue;\n");
    691   if (NULL != conditional)
    692     fprintf (f,
    693              "#endif\n");
    694 }
    695 
    696 
    697 static char **
    698 parse (char **target,
    699        const char *prefix,
    700        const char *input)
    701 {
    702   if (0 != strncasecmp (prefix,
    703                         input,
    704                         strlen (prefix)))
    705     return NULL;
    706   *target = strdup (input + strlen (prefix));
    707   return target;
    708 }
    709 
    710 
    711 int
    712 main (int argc,
    713       char **argv)
    714 {
    715   static char *dummy;
    716   struct Option *head = NULL;
    717 
    718   if (argc < 2)
    719   {
    720     fprintf (stderr,
    721              "Category argument required\n");
    722     return 3;
    723   }
    724   category = argv[1];
    725 
    726   {
    727     char *fn;
    728     char line[4092];
    729     char **larg = NULL;
    730     unsigned int off;
    731     struct Option *last = NULL;
    732 
    733     my_asprintf (&fn,
    734                  "%c_options.rec",
    735                  *category);
    736     f = fopen (fn, "r");
    737     if (NULL == f)
    738     {
    739       fprintf (stderr,
    740                "Failed to open %s: %s\n",
    741                fn,
    742                strerror (errno));
    743       free (fn);
    744       return 2;
    745     }
    746     off = 0;
    747 TOP:
    748     while (1)
    749     {
    750       ssize_t r;
    751 
    752       if (NULL ==
    753           fgets (line,
    754                  sizeof (line),
    755                  f))
    756         break;
    757       r = strlen (line);
    758       off++;
    759       while ( (r > 0) &&
    760               ( (isspace (line[r - 1])) ||
    761                 (line[r - 1] == '\n') ) )
    762         line[--r] = '\0'; /* remove new line */
    763       if (0 == r)
    764       {
    765         larg = NULL;
    766         continue;
    767       }
    768       if ( (NULL != larg) &&
    769            ( (0 == strncmp ("+ ",
    770                             line,
    771                             2) ) ||
    772              (0 == strcmp ("+",
    773                            line) ) ) )
    774       {
    775         if (larg == &dummy)
    776         {
    777           fprintf (stderr,
    778                    "Continuation after 'Value:' not supported on line %u\n",
    779                    off);
    780           exit (2);
    781         }
    782 
    783         *larg = realloc (*larg,
    784                          strlen (*larg) + r + 2);
    785         strcat (*larg,
    786                 "\n");
    787         if (0 != strcmp ("+",
    788                          line) )
    789           strcat (*larg,
    790                   line + 2);
    791         continue;
    792       }
    793       if ( ('%' == line[0]) ||
    794            ('#' == line[0]) )
    795         continue;
    796       if (NULL == larg)
    797       {
    798         struct Option *o = malloc (sizeof (struct Option));
    799 
    800         memset (o, 0, sizeof (*o));
    801         if (NULL == head)
    802           head = o;
    803         else
    804           last->next = o;
    805         last = o;
    806       }
    807       if (NULL != (larg = parse (&last->name,
    808                                  "Name: ",
    809                                  line)))
    810         continue;
    811       if (NULL != (larg = parse (&last->comment,
    812                                  "Comment: ",
    813                                  line)))
    814         continue;
    815       if (NULL != (larg = parse (&last->type,
    816                                  "Type: ",
    817                                  line)))
    818         continue;
    819       if (NULL != (larg = parse (&last->conditional,
    820                                  "Conditional: ",
    821                                  line)))
    822         continue;
    823       if (NULL != (larg = parse (&last->custom_setter,
    824                                  "CustomSetter: ",
    825                                  line)))
    826         continue;
    827       if (0 == strncasecmp (line,
    828                             "Value: ",
    829                             strlen ("Value: ")))
    830       {
    831         char xdummy;
    832 
    833         if (1 == sscanf (line + strlen ("Value: "),
    834                          "%u%c",
    835                          &last->value,
    836                          &xdummy))
    837         {
    838           larg = &dummy;
    839           continue;
    840         }
    841         fprintf (stderr,
    842                  "Value on line %d not a number\n",
    843                  off);
    844         return 2;
    845       }
    846       for (unsigned int i = 0; i<MAX_ARGS; i++)
    847       {
    848         char name[32];
    849 
    850         snprintf (name,
    851                   sizeof (name),
    852                   "Argument%u: ",
    853                   i + 1);
    854         if (NULL != (larg = parse (&last->arguments[i],
    855                                    name,
    856                                    line)))
    857         {
    858           last->argc = i + 1;
    859           goto TOP;
    860         }
    861         snprintf (name,
    862                   sizeof (name),
    863                   "Description%u: ",
    864                   i + 1);
    865         if (NULL != (larg = parse (&last->descriptions[i],
    866                                    name,
    867                                    line)))
    868         {
    869           last->desc = i + 1;
    870           goto TOP;
    871         }
    872       }
    873       fprintf (stderr,
    874                "Could not parse line %u: `%s'\n",
    875                off,
    876                line);
    877       exit (2);
    878     }
    879     free (fn);
    880   }
    881 
    882   iterate (head,
    883            &check);
    884 
    885   /* Generate enum MHD_${CATEGORY}Option */
    886   printf ("/**\n"
    887           " * The options (parameters) for MHD %s\n"
    888           " */\n"
    889           "enum MHD_FIXED_ENUM_APP_SET_ MHD_%sOption\n"
    890           "{",
    891           category,
    892           capitalize (category));
    893   printf ("  /**\n"
    894           "   * Not a real option.\n"
    895           "   * Should not be used directly.\n"
    896           "   * This value indicates the end of the list of the options.\n"
    897           "   */\n"
    898           "  MHD_%c_O_END = 0\n"
    899           "  ,\n\n",
    900           (char) toupper (*category));
    901   iterate (head,
    902            &dump_enum);
    903   printf ("  /**\n"
    904           "   * The sentinel value.\n"
    905           "   * This value enforces specific underlying integer type for the enum.\n"
    906           "   * Do not use.\n"
    907           "   */\n"
    908           "  MHD_%c_O_SENTINEL = 65535\n\n",
    909           (char) toupper (*category));
    910   printf ("};\n\n");
    911   iterate (head,
    912            &dump_union_members);
    913 
    914   /* Generate union MHD_${CATEGORY}OptionValue */
    915   printf ("/**\n"
    916           " * Parameters for MHD %s options\n"
    917           " */\n"
    918           "union MHD_%sOptionValue\n"
    919           "{\n",
    920           category,
    921           capitalize (category));
    922   f = stdout;
    923   iterate (head,
    924            &dump_union);
    925   f = NULL;
    926   printf ("};\n\n");
    927 
    928   printf ("\n"
    929           "struct MHD_%sOptionAndValue\n"
    930           "{\n"
    931           "  /**\n"
    932           "   * The %s configuration option\n"
    933           "   */\n"
    934           "  enum MHD_%sOption opt;\n\n"
    935           "  /**\n"
    936           "   * The value for the @a opt option\n"
    937           "   */\n"
    938           "  union MHD_%sOptionValue val;\n"
    939           "};\n\n",
    940           capitalize (category),
    941           category,
    942           capitalize (category),
    943           capitalize (category));
    944   printf (
    945     "#if defined(MHD_USE_COMPOUND_LITERALS) && defined(MHD_USE_DESIG_NEST_INIT)\n");
    946   iterate (head,
    947            &dump_option_macros);
    948   printf (
    949     "\n"
    950     "/**\n"
    951     " * Terminate the list of the options\n"
    952     " * @return the terminating object of struct MHD_%sOptionAndValue\n"
    953     " */\n"
    954     "#  define MHD_%c_OPTION_TERMINATE() \\\n"
    955     "        MHD_NOWARN_COMPOUND_LITERALS_ \\\n"
    956     "          (const struct MHD_%sOptionAndValue) \\\n"
    957     "        { \\\n"
    958     "          .opt = (MHD_%c_O_END) \\\n"
    959     "        } \\\n"
    960     "        MHD_RESTORE_WARN_COMPOUND_LITERALS_\n\n",
    961     capitalize (category),
    962     (char) toupper (*category),
    963     capitalize (category),
    964     (char) toupper (*category));
    965 
    966   printf (
    967     "#else /* !MHD_USE_COMPOUND_LITERALS || !MHD_USE_DESIG_NEST_INIT */\n");
    968   printf ("MHD_NOWARN_UNUSED_FUNC_");
    969   iterate (head,
    970            &dump_option_static_functions);
    971   printf ("\n/**\n"
    972           " * Terminate the list of the options\n"
    973           " * @return the terminating object of struct MHD_%sOptionAndValue\n"
    974           " */\n"
    975           "static MHD_INLINE struct MHD_%sOptionAndValue\n"
    976           "MHD_%c_OPTION_TERMINATE (void)\n"
    977           "{\n"
    978           "  struct MHD_%sOptionAndValue opt_val;\n\n"
    979           "  opt_val.opt = MHD_%c_O_END;\n\n"
    980           "  return opt_val;\n"
    981           "}\n\n\n",
    982           capitalize (category),
    983           capitalize (category),
    984           (char) toupper (*category),
    985           capitalize (category),
    986           (char) toupper (*category));
    987 
    988   printf ("MHD_RESTORE_WARN_UNUSED_FUNC_\n");
    989   printf (
    990     "#endif /* !MHD_USE_COMPOUND_LITERALS || !MHD_USE_DESIG_NEST_INIT */\n");
    991 
    992   {
    993     char *doc_in;
    994 
    995     my_asprintf (&doc_in,
    996                  "microhttpd2_inline_%s_documentation.h.in",
    997                  category);
    998     (void) unlink (doc_in);
    999     f = fopen (doc_in, "w");
   1000     if (NULL == f)
   1001     {
   1002       fprintf (stderr,
   1003                "Failed to open `%s': %s\n",
   1004                doc_in,
   1005                strerror (errno));
   1006       return 2;
   1007     }
   1008     fprintf (f,
   1009              "/* Beginning of generated code documenting how to use options.\n"
   1010              "   You should treat the following functions *as if* they were\n"
   1011              "   part of the header/API. The actual declarations are more\n"
   1012              "   complex, so these here are just for documentation!\n"
   1013              "   We do not actually *build* this code... */\n"
   1014              "#if 0\n\n");
   1015     iterate (head,
   1016              &dump_option_documentation_functions);
   1017     fprintf (f,
   1018              "/* End of generated code documenting how to use options */\n#endif\n\n");
   1019     fclose (f);
   1020     chmod (doc_in, S_IRUSR | S_IRGRP | S_IROTH);
   1021   }
   1022 
   1023   {
   1024     char *so_c;
   1025 
   1026     my_asprintf (&so_c,
   1027                  "../mhd2/%s_set_options.c",
   1028                  category);
   1029     (void) unlink (so_c);
   1030     f = fopen (so_c, "w");
   1031     if (NULL == f)
   1032     {
   1033       fprintf (stderr,
   1034                "Failed to open `%s': %s\n",
   1035                so_c,
   1036                strerror (errno));
   1037       return 2;
   1038     }
   1039     fprintf (f,
   1040              "/* This is generated code, it is still under LGPLv2.1+.\n"
   1041              "   Do not edit directly! */\n"
   1042              "/* *INDENT-OFF* */\n"
   1043              "/**\n"
   1044              " * @file %s_set_options.c\n"
   1045              " * @author options-generator.c\n"
   1046              " */\n"
   1047              "\n",
   1048              category);
   1049     if (0 == strcmp (category, "daemon"))
   1050     {
   1051       fprintf (f,
   1052                "#include \"mhd_sys_options.h\"\n"
   1053                "#include \"sys_base_types.h\"\n"
   1054                "#include \"sys_malloc.h\"\n"
   1055                "#include <string.h>\n"
   1056                "#include \"mhd_daemon.h\"\n"
   1057                "#include \"daemon_options.h\"\n"
   1058                "#include \"mhd_public_api.h\"\n"
   1059                "\n");
   1060     }
   1061     else if (0 == strcmp (category, "response"))
   1062     {
   1063       fprintf (f,
   1064                "#include \"mhd_sys_options.h\"\n"
   1065                "#include \"response_set_options.h\"\n"
   1066                "#include \"sys_base_types.h\"\n"
   1067                "#include \"sys_bool_type.h\"\n"
   1068                "#include \"response_options.h\"\n"
   1069                "#include \"mhd_response.h\"\n"
   1070                "#include \"mhd_public_api.h\"\n"
   1071                "#include \"mhd_locks.h\"\n"
   1072                "#include \"mhd_assert.h\"\n"
   1073                "#include \"response_funcs.h\"\n"
   1074                "\n");
   1075     }
   1076 
   1077     fprintf (f,
   1078              "\n"
   1079              "MHD_FN_PAR_NONNULL_ALL_ MHD_EXTERN_\n"
   1080              "enum MHD_StatusCode\n"
   1081              "MHD_%s_set_options (\n"
   1082              "  struct MHD_%s *MHD_RESTRICT %s,\n"
   1083              "  const struct MHD_%sOptionAndValue *MHD_RESTRICT options,\n"
   1084              "  size_t options_max_num)\n"
   1085              "{\n",
   1086              category,
   1087              capitalize (category),
   1088              category,
   1089              capitalize (category));
   1090     fprintf (f,
   1091              "  struct %sOptions *restrict settings = %s->settings;\n"
   1092              "  enum MHD_StatusCode res = MHD_SC_OK;\n"
   1093              "  size_t i;\n",
   1094              capitalize (category),
   1095              category);
   1096     if (0 == strcmp (category, "daemon"))
   1097     {
   1098       fprintf (f,
   1099                "\n"
   1100                "  if (mhd_DAEMON_STATE_NOT_STARTED != daemon->state)\n"
   1101                "    return MHD_SC_TOO_LATE;\n"
   1102                "\n");
   1103     }
   1104     else if (0 == strcmp (category, "response"))
   1105     {
   1106       fprintf (f,
   1107                "  bool need_unlock = false;\n"
   1108                "\n"
   1109                "  if (response->frozen)\n"
   1110                "    return MHD_SC_TOO_LATE;\n"
   1111                "  if (response->reuse.reusable)\n"
   1112                "  {\n"
   1113                "    need_unlock = true;\n"
   1114                "    if (! mhd_mutex_lock(&response->reuse.settings_lock))\n"
   1115                "      return MHD_SC_RESPONSE_MUTEX_LOCK_FAILED;\n"
   1116                "    mhd_assert (1 == mhd_atomic_counter_get(&response->reuse.counter));\n"
   1117                "    if (response->frozen) /* Firm re-check under the lock */\n"
   1118                "    {\n"
   1119                "      mhd_mutex_unlock_chk(&response->reuse.settings_lock);\n"
   1120                "      return MHD_SC_TOO_LATE;\n"
   1121                "    }\n"
   1122                "  }\n"
   1123                "\n");
   1124     }
   1125     else
   1126     {
   1127       fprintf (f,
   1128                "\n"
   1129                "  if (NULL == settings)\n"
   1130                "    return MHD_SC_TOO_LATE;\n"
   1131                "\n");
   1132     }
   1133     fprintf (f,
   1134              "  for (i = 0; i < options_max_num; i++)\n"
   1135              "  {\n"
   1136              "    const struct MHD_%sOptionAndValue *const option\n"
   1137              "      = options + i;\n"
   1138              "    switch (option->opt)\n"
   1139              "    {\n",
   1140              capitalize (category));
   1141     fprintf (f,
   1142              "    case MHD_%c_O_END:\n"
   1143              "      i = options_max_num - 1;\n"
   1144              "      break;\n",
   1145              (char) toupper (*category));
   1146     iterate (head,
   1147              &dump_option_set_switch);
   1148     fprintf (f,
   1149              "    case MHD_%c_O_SENTINEL:\n"
   1150              "    default: /* for -Wswitch-default -Wswitch-enum */\n"
   1151              "      res = MHD_SC_OPTION_UNKNOWN;\n"
   1152              "      i = options_max_num - 1;\n"
   1153              "      break;\n",
   1154              (char) toupper (*category));
   1155     fprintf (f,
   1156              "    }\n"
   1157              "  }\n");
   1158     if (0 == strcmp (category, "response"))
   1159     {
   1160       fprintf (f,
   1161                "\n"
   1162                "  if (need_unlock)\n"
   1163                "    mhd_mutex_unlock_chk(&response->reuse.settings_lock);\n"
   1164                "\n");
   1165     }
   1166     fprintf (f,
   1167              "  return res;\n"
   1168              "}\n");
   1169     fclose (f);
   1170     chmod (so_c, S_IRUSR | S_IRGRP | S_IROTH);
   1171     free (so_c);
   1172   }
   1173 
   1174   {
   1175     char *do_h;
   1176 
   1177     my_asprintf (&do_h,
   1178                  "../mhd2/%s_options.h",
   1179                  category);
   1180     (void) unlink (do_h);
   1181     f = fopen (do_h, "w");
   1182     if (NULL == f)
   1183     {
   1184       fprintf (stderr,
   1185                "Failed to open `%s': %s\n",
   1186                do_h,
   1187                strerror (errno));
   1188       return 2;
   1189     }
   1190     fprintf (f,
   1191              "/* This is generated code, it is still under LGPLv2.1+.\n"
   1192              "   Do not edit directly! */\n"
   1193              "/* *INDENT-OFF* */\n"
   1194              "/**\n"
   1195              " * @file %s_options.h\n"
   1196              " * @author %s-options-generator.c\n"
   1197              " */\n\n"
   1198              "#ifndef MHD_%s_OPTIONS_H\n"
   1199              "#define MHD_%s_OPTIONS_H 1\n"
   1200              "\n"
   1201              "#include \"mhd_sys_options.h\"\n"
   1202              "#include \"mhd_public_api.h\"\n"
   1203              "\n"
   1204              "struct %sOptions\n"
   1205              "{\n",
   1206              category,
   1207              category,
   1208              uppercase (category),
   1209              uppercase (category),
   1210              capitalize (category));
   1211     iterate (head,
   1212              &dump_struct);
   1213     fprintf (f,
   1214              "};\n"
   1215              "\n"
   1216              "#endif /* ! MHD_%s_OPTIONS_H 1 */\n",
   1217              uppercase (category));
   1218     fclose (f);
   1219     chmod (do_h, S_IRUSR | S_IRGRP | S_IROTH);
   1220     free (do_h);
   1221   }
   1222 
   1223   return 0;
   1224 }