libmicrohttpd2

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

options-generator.c (34296B)


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