options-generator.c (33972B)
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 = (char *)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 (const 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 /* Emit " DST = SRC;", wrapped after the '=' when the whole line would 633 * exceed the 80-column target. */ 634 static void 635 dump_setter_assignment (const char *dst, 636 const char *src) 637 { 638 if (80 >= 6 + strlen (dst) + 3 + strlen (src) + 1) 639 fprintf (f, 640 " %s = %s;\n", 641 dst, 642 src); 643 else 644 fprintf (f, 645 " %s =\n" 646 " %s;\n", 647 dst, 648 src); 649 } 650 651 652 static void 653 dump_option_set_switch (const char *name, 654 unsigned int value, 655 const char *comment, 656 const char *type, 657 const char *conditional, 658 const char *custom_setter, 659 unsigned int argc, 660 char **arguments, 661 unsigned int desc, 662 char **descriptions) 663 { 664 if (NULL != conditional) 665 fprintf (f, 666 "#ifdef HAVE_%s", 667 uppercase (conditional)); 668 fprintf (f, 669 " case MHD_%c_O_%s:\n", 670 (char)toupper (*category), 671 uppercase (name)); 672 if (NULL != custom_setter) 673 { 674 /* Emit line by line: preprocessor directives must stay at the first 675 * column, ordinary code lines get the 'case' body indentation. */ 676 const char *line = custom_setter; 677 678 while (NULL != line) 679 { 680 const char *nl = strchr (line, '\n'); 681 size_t len = (NULL == nl) ? strlen (line) : (size_t)(nl - line); 682 683 if (0 == len) 684 fprintf (f, "\n"); 685 else if ('#' == line[0]) 686 fprintf (f, "%.*s\n", (int)len, line); 687 else 688 fprintf (f, " %.*s\n", (int)len, line); 689 line = (NULL == nl) ? NULL : nl + 1; 690 } 691 } 692 else 693 { 694 if (0 == argc) 695 { 696 char *dst; 697 char *src; 698 699 my_asprintf (&dst, "settings->%s", lowercase (name)); 700 my_asprintf (&src, "option->val.%s", lowercase (name)); 701 dump_setter_assignment (dst, src); 702 free (dst); 703 free (src); 704 } 705 else 706 { 707 for (unsigned int i = 0; i < argc; i++) 708 { 709 const char *vn = var_name (arguments[i]); 710 char *dst; 711 char *src; 712 713 if (1 < argc) 714 { 715 my_asprintf (&dst, "settings->%s.v_%s", lowercase (name), vn); 716 my_asprintf (&src, "option->val.%s.v_%s", lowercase (name), vn); 717 } 718 else 719 { 720 my_asprintf (&dst, "settings->%s", lowercase (name)); 721 my_asprintf (&src, "option->val.%s", lowercase (name)); 722 } 723 dump_setter_assignment (dst, src); 724 free (dst); 725 free (src); 726 } 727 } 728 } 729 fprintf (f, 730 " continue;\n"); 731 if (NULL != conditional) 732 fprintf (f, 733 "#endif\n"); 734 } 735 736 737 static char ** 738 parse (char **target, 739 const char *prefix, 740 const char *input) 741 { 742 if (0 != strncasecmp (prefix, 743 input, 744 strlen (prefix))) 745 return NULL; 746 *target = strdup (input + strlen (prefix)); 747 return target; 748 } 749 750 751 int 752 main (int argc, 753 char **argv) 754 { 755 static char *dummy; 756 struct Option *head = NULL; 757 758 if (argc < 2) 759 { 760 fprintf (stderr, 761 "Category argument required\n"); 762 return 3; 763 } 764 category = argv[1]; 765 766 { 767 char *fn; 768 char line[4092]; 769 char **larg = NULL; 770 unsigned int off; 771 struct Option *last = NULL; 772 773 my_asprintf (&fn, 774 "%c_options.rec", 775 *category); 776 f = fopen (fn, "r"); 777 if (NULL == f) 778 { 779 fprintf (stderr, 780 "Failed to open %s: %s\n", 781 fn, 782 strerror (errno)); 783 free (fn); 784 return 2; 785 } 786 off = 0; 787 TOP: 788 while (1) 789 { 790 ssize_t r; 791 792 if (NULL == 793 fgets (line, 794 sizeof (line), 795 f)) 796 break; 797 r = strlen (line); 798 off++; 799 while ((r > 0) 800 && ((isspace (line[r - 1])) 801 || (line[r - 1] == '\n'))) 802 line[--r] = '\0'; /* remove new line */ 803 if (0 == r) 804 { 805 larg = NULL; 806 continue; 807 } 808 if ((NULL != larg) 809 && ((0 == strncmp ("+ ", 810 line, 811 2)) 812 || (0 == strcmp ("+", 813 line)))) 814 { 815 if (larg == &dummy) 816 { 817 fprintf (stderr, 818 "Continuation after 'Value:' not supported on line %u\n", 819 off); 820 exit (2); 821 } 822 823 *larg = (char *)realloc (*larg, 824 strlen (*larg) + r + 2); 825 strcat (*larg, 826 "\n"); 827 if (0 != strcmp ("+", 828 line)) 829 strcat (*larg, 830 line + 2); 831 continue; 832 } 833 if (('%' == line[0]) 834 || ('#' == line[0])) 835 continue; 836 if (NULL == larg) 837 { 838 struct Option *o = (struct Option *)malloc (sizeof (struct Option)); 839 840 memset (o, 0, sizeof (*o)); 841 if (NULL == head) 842 head = o; 843 else 844 last->next = o; 845 last = o; 846 } 847 if (NULL != (larg = parse (&last->name, 848 "Name: ", 849 line))) 850 continue; 851 if (NULL != (larg = parse (&last->comment, 852 "Comment: ", 853 line))) 854 continue; 855 if (NULL != (larg = parse (&last->type, 856 "Type: ", 857 line))) 858 continue; 859 if (NULL != (larg = parse (&last->conditional, 860 "Conditional: ", 861 line))) 862 continue; 863 if (NULL != (larg = parse (&last->custom_setter, 864 "CustomSetter: ", 865 line))) 866 continue; 867 if (0 == strncasecmp (line, 868 "Value: ", 869 strlen ("Value: "))) 870 { 871 char xdummy; 872 873 if (1 == sscanf (line + strlen ("Value: "), 874 "%u%c", 875 &last->value, 876 &xdummy)) 877 { 878 larg = &dummy; 879 continue; 880 } 881 fprintf (stderr, 882 "Value on line %d not a number\n", 883 off); 884 return 2; 885 } 886 for (unsigned int i = 0; i < MAX_ARGS; i++) 887 { 888 char name[32]; 889 890 snprintf (name, 891 sizeof (name), 892 "Argument%u: ", 893 i + 1); 894 if (NULL != (larg = parse (&last->arguments[i], 895 name, 896 line))) 897 { 898 last->argc = i + 1; 899 goto TOP; 900 } 901 snprintf (name, 902 sizeof (name), 903 "Description%u: ", 904 i + 1); 905 if (NULL != (larg = parse (&last->descriptions[i], 906 name, 907 line))) 908 { 909 last->desc = i + 1; 910 goto TOP; 911 } 912 } 913 fprintf (stderr, 914 "Could not parse line %u: `%s'\n", 915 off, 916 line); 917 exit (2); 918 } 919 free (fn); 920 } 921 922 iterate (head, 923 &check); 924 925 /* Generate enum MHD_${CATEGORY}Option */ 926 printf ("/**\n" 927 " * The options (parameters) for MHD %s\n" 928 " */\n" 929 "enum MHD_FIXED_ENUM_APP_SET_ MHD_%sOption\n" 930 "{", 931 category, 932 capitalize (category)); 933 printf (" /**\n" 934 " * Not a real option.\n" 935 " * Should not be used directly.\n" 936 " * This value indicates the end of the list of the options.\n" 937 " */\n" 938 " MHD_%c_O_END = 0\n" 939 " ,\n\n", 940 (char)toupper (*category)); 941 iterate (head, 942 &dump_enum); 943 printf (" /**\n" 944 " * The sentinel value.\n" 945 " * This value enforces specific underlying integer type for the enum.\n" 946 " * Do not use.\n" 947 " */\n" 948 " MHD_%c_O_SENTINEL = 65535\n\n", 949 (char)toupper (*category)); 950 printf ("};\n\n"); 951 iterate (head, 952 &dump_union_members); 953 954 /* Generate union MHD_${CATEGORY}OptionValue */ 955 printf ("/**\n" 956 " * Parameters for MHD %s options\n" 957 " */\n" 958 "union MHD_%sOptionValue\n" 959 "{\n", 960 category, 961 capitalize (category)); 962 f = stdout; 963 iterate (head, 964 &dump_union); 965 f = NULL; 966 printf ("};\n\n"); 967 968 printf ("\n" 969 "struct MHD_%sOptionAndValue\n" 970 "{\n" 971 " /**\n" 972 " * The %s configuration option\n" 973 " */\n" 974 " enum MHD_%sOption opt;\n\n" 975 " /**\n" 976 " * The value for the @a opt option\n" 977 " */\n" 978 " union MHD_%sOptionValue val;\n" 979 "};\n\n", 980 capitalize (category), 981 category, 982 capitalize (category), 983 capitalize (category)); 984 printf ( 985 "#if defined(MHD_USE_COMPOUND_LITERALS) && defined(MHD_USE_DESIG_NEST_INIT)\n"); 986 iterate (head, 987 &dump_option_macros); 988 printf ( 989 "\n" 990 "/**\n" 991 " * Terminate the list of the options\n" 992 " * @return the terminating object of struct MHD_%sOptionAndValue\n" 993 " */\n" 994 "# define MHD_%c_OPTION_TERMINATE() \\\n" 995 " MHD_NOWARN_COMPOUND_LITERALS_ \\\n" 996 " (const struct MHD_%sOptionAndValue) \\\n" 997 " { \\\n" 998 " .opt = (MHD_%c_O_END) \\\n" 999 " } \\\n" 1000 " MHD_RESTORE_WARN_COMPOUND_LITERALS_\n\n", 1001 capitalize (category), 1002 (char)toupper (*category), 1003 capitalize (category), 1004 (char)toupper (*category)); 1005 1006 printf ( 1007 "#else /* !MHD_USE_COMPOUND_LITERALS || !MHD_USE_DESIG_NEST_INIT */\n"); 1008 printf ("MHD_NOWARN_UNUSED_FUNC_"); 1009 iterate (head, 1010 &dump_option_static_functions); 1011 printf ("\n/**\n" 1012 " * Terminate the list of the options\n" 1013 " * @return the terminating object of struct MHD_%sOptionAndValue\n" 1014 " */\n" 1015 "static MHD_INLINE struct MHD_%sOptionAndValue\n" 1016 "MHD_%c_OPTION_TERMINATE (void)\n" 1017 "{\n" 1018 " struct MHD_%sOptionAndValue opt_val;\n\n" 1019 " opt_val.opt = MHD_%c_O_END;\n\n" 1020 " return opt_val;\n" 1021 "}\n\n\n", 1022 capitalize (category), 1023 capitalize (category), 1024 (char)toupper (*category), 1025 capitalize (category), 1026 (char)toupper (*category)); 1027 1028 printf ("MHD_RESTORE_WARN_UNUSED_FUNC_\n"); 1029 printf ( 1030 "#endif /* !MHD_USE_COMPOUND_LITERALS || !MHD_USE_DESIG_NEST_INIT */\n"); 1031 1032 { 1033 char *doc_in; 1034 1035 my_asprintf (&doc_in, 1036 "microhttpd2_inline_%s_documentation.h.in", 1037 category); 1038 (void)unlink (doc_in); 1039 f = fopen (doc_in, "w"); 1040 if (NULL == f) 1041 { 1042 fprintf (stderr, 1043 "Failed to open `%s': %s\n", 1044 doc_in, 1045 strerror (errno)); 1046 return 2; 1047 } 1048 fprintf (f, 1049 "/* Beginning of generated code documenting how to use options.\n" 1050 " You should treat the following functions *as if* they were\n" 1051 " part of the header/API. The actual declarations are more\n" 1052 " complex, so these here are just for documentation!\n" 1053 " We do not actually *build* this code... */\n" 1054 "#if 0\n\n"); 1055 iterate (head, 1056 &dump_option_documentation_functions); 1057 fprintf (f, 1058 "/* End of generated code documenting how to use options */\n#endif\n\n"); 1059 fclose (f); 1060 chmod (doc_in, S_IRUSR | S_IRGRP | S_IROTH); 1061 } 1062 1063 { 1064 char *so_c; 1065 1066 my_asprintf (&so_c, 1067 "../mhd2/%s_set_options.c", 1068 category); 1069 (void)unlink (so_c); 1070 f = fopen (so_c, "w"); 1071 if (NULL == f) 1072 { 1073 fprintf (stderr, 1074 "Failed to open `%s': %s\n", 1075 so_c, 1076 strerror (errno)); 1077 return 2; 1078 } 1079 fprintf (f, 1080 "/* This is generated code, it is still under LGPLv2.1+.\n" 1081 " Do not edit directly! */\n" 1082 "/**\n" 1083 " * @file %s_set_options.c\n" 1084 " * @author options-generator.c\n" 1085 " */\n" 1086 "\n", 1087 category); 1088 if (0 == strcmp (category, "daemon")) 1089 { 1090 fprintf (f, 1091 "#include \"mhd_sys_options.h\"\n" 1092 "#include \"sys_base_types.h\"\n" 1093 "#include \"sys_malloc.h\"\n" 1094 "#include <string.h>\n" 1095 "#include \"mhd_daemon.h\"\n" 1096 "#include \"daemon_options.h\"\n" 1097 "#include \"mhd_public_api.h\"\n" 1098 "\n"); 1099 } 1100 else if (0 == strcmp (category, "response")) 1101 { 1102 fprintf (f, 1103 "#include \"mhd_sys_options.h\"\n" 1104 "#include \"response_set_options.h\"\n" 1105 "#include \"sys_base_types.h\"\n" 1106 "#include \"sys_bool_type.h\"\n" 1107 "#include \"response_options.h\"\n" 1108 "#include \"mhd_response.h\"\n" 1109 "#include \"mhd_public_api.h\"\n" 1110 "#include \"mhd_locks.h\"\n" 1111 "#include \"mhd_assert.h\"\n" 1112 "#include \"response_funcs.h\"\n" 1113 "\n"); 1114 } 1115 1116 fprintf (f, 1117 "\n" 1118 "MHD_FN_PAR_NONNULL_ALL_ MHD_EXTERN_\n" 1119 "enum MHD_StatusCode\n" 1120 "MHD_%s_set_options (\n" 1121 " struct MHD_%s *MHD_RESTRICT %s,\n" 1122 " const struct MHD_%sOptionAndValue *MHD_RESTRICT options,\n" 1123 " size_t options_max_num)\n" 1124 "{\n", 1125 category, 1126 capitalize (category), 1127 category, 1128 capitalize (category)); 1129 fprintf (f, 1130 " struct %sOptions *restrict settings = %s->settings;\n" 1131 " enum MHD_StatusCode res = MHD_SC_OK;\n" 1132 " size_t i;\n", 1133 capitalize (category), 1134 category); 1135 if (0 == strcmp (category, "daemon")) 1136 { 1137 fprintf (f, 1138 "\n" 1139 " if (mhd_DAEMON_STATE_NOT_STARTED != daemon->state)\n" 1140 " return MHD_SC_TOO_LATE;\n" 1141 "\n"); 1142 } 1143 else if (0 == strcmp (category, "response")) 1144 { 1145 fprintf (f, 1146 " bool need_unlock = false;\n" 1147 "\n" 1148 " if (response->frozen)\n" 1149 " return MHD_SC_TOO_LATE;\n" 1150 " if (response->reuse.reusable)\n" 1151 " {\n" 1152 " need_unlock = true;\n" 1153 " if (!mhd_mutex_lock (&response->reuse.settings_lock))\n" 1154 " return MHD_SC_RESP_MUTEX_LOCK_FAILED;\n" 1155 " mhd_assert (1 == mhd_atomic_counter_get (&response->reuse.counter));\n" 1156 " if (response->frozen) /* Firm re-check under the lock */\n" 1157 " {\n" 1158 " mhd_mutex_unlock_chk (&response->reuse.settings_lock);\n" 1159 " return MHD_SC_TOO_LATE;\n" 1160 " }\n" 1161 " }\n" 1162 "\n"); 1163 } 1164 else 1165 { 1166 fprintf (f, 1167 "\n" 1168 " if (NULL == settings)\n" 1169 " return MHD_SC_TOO_LATE;\n" 1170 "\n"); 1171 } 1172 fprintf (f, 1173 " for (i = 0; i < options_max_num; i++)\n" 1174 " {\n" 1175 " const struct MHD_%sOptionAndValue *const option\n" 1176 " = options + i;\n" 1177 " switch (option->opt)\n" 1178 " {\n", 1179 capitalize (category)); 1180 fprintf (f, 1181 " case MHD_%c_O_END:\n" 1182 " i = options_max_num - 1;\n" 1183 " break;\n", 1184 (char)toupper (*category)); 1185 iterate (head, 1186 &dump_option_set_switch); 1187 fprintf (f, 1188 " case MHD_%c_O_SENTINEL:\n" 1189 " default: /* for -Wswitch-default -Wswitch-enum */\n" 1190 " res = MHD_SC_OPTION_UNKNOWN;\n" 1191 " i = options_max_num - 1;\n" 1192 " break;\n", 1193 (char)toupper (*category)); 1194 fprintf (f, 1195 " }\n" 1196 " }\n"); 1197 if (0 == strcmp (category, "response")) 1198 { 1199 fprintf (f, 1200 "\n" 1201 " if (need_unlock)\n" 1202 " mhd_mutex_unlock_chk (&response->reuse.settings_lock);\n" 1203 "\n"); 1204 } 1205 fprintf (f, 1206 " return res;\n" 1207 "}\n"); 1208 fclose (f); 1209 chmod (so_c, S_IRUSR | S_IRGRP | S_IROTH); 1210 free (so_c); 1211 } 1212 1213 { 1214 char *do_h; 1215 1216 my_asprintf (&do_h, 1217 "../mhd2/%s_options.h", 1218 category); 1219 (void)unlink (do_h); 1220 f = fopen (do_h, "w"); 1221 if (NULL == f) 1222 { 1223 fprintf (stderr, 1224 "Failed to open `%s': %s\n", 1225 do_h, 1226 strerror (errno)); 1227 return 2; 1228 } 1229 fprintf (f, 1230 "/* This is generated code, it is still under LGPLv2.1+.\n" 1231 " Do not edit directly! */\n" 1232 "/**\n" 1233 " * @file %s_options.h\n" 1234 " * @author %s-options-generator.c\n" 1235 " */\n\n" 1236 "#ifndef MHD_%s_OPTIONS_H\n" 1237 "#define MHD_%s_OPTIONS_H 1\n" 1238 "\n" 1239 "#include \"mhd_sys_options.h\"\n" 1240 "#include \"mhd_public_api.h\"\n" 1241 "\n" 1242 "struct %sOptions\n" 1243 "{\n", 1244 category, 1245 category, 1246 uppercase (category), 1247 uppercase (category), 1248 capitalize (category)); 1249 iterate (head, 1250 &dump_struct); 1251 fprintf (f, 1252 "};\n" 1253 "\n" 1254 "#endif /* ! MHD_%s_OPTIONS_H 1 */\n", 1255 uppercase (category)); 1256 fclose (f); 1257 chmod (do_h, S_IRUSR | S_IRGRP | S_IROTH); 1258 free (do_h); 1259 } 1260 1261 return 0; 1262 }