2 * Copyright (C) 2016 Andre Noll <maan@tuebingen.mpg.de>
4 * Licensed under the GPL v3, see http://www.gnu.org/licenses/gpl-3.0.html
16 #include "lopsub-internal.h"
20 * To stringify the result of the *expansion* of a macro argument, we have to
21 * use two levels of macros.
23 #define LLS_STRINGIFY_EXPAND(_arg) LLS_STRINGIFY(_arg)
24 #define LLS_STRINGIFY(_arg) #_arg
25 #define LLS_ABI_VERSION_VAR_STRING LLS_STRINGIFY_EXPAND(LLS_ABI_VERSION_VAR)
29 static void gen_license_header(FILE *out
, const char *cmdline
, const char *pfx
,
32 fprintf(out
, "%sautogenerated by lopsubgen version %s%s\n",
33 pfx
, lls_version(), sfx
);
35 fprintf(out
, "%scommand line:", pfx
);
36 fprintf(out
, " %s", cmdline
);
37 fprintf(out
, "%s\n", sfx
);
39 fprintf(out
, "%sPublic domain, no copyright claims.%s\n",
43 static void inplace_sanitize(char *src
)
50 static void inplace_toupper(char *src
)
53 *src
= toupper((int)*src
);
56 static void lsg_init_name(struct lsg_name
*name
)
59 name
->sanitized
= strdup(name
->orig
);
60 inplace_sanitize(name
->sanitized
);
61 name
->capitalized
= strdup(name
->sanitized
);
62 inplace_toupper(name
->capitalized
);
65 static void print_tabs(int num
, FILE *out
)
71 static void format_c_text(const char *text
, const char *member
, int indent
,
78 print_tabs(indent
, out
);
79 fprintf(out
, ".%s = (char []) {", member
);
80 for (i
= 0; text
[i
]; i
++) {
83 print_tabs(indent
+ 1, out
);
85 fprintf(out
, "0x%02x,", (unsigned char)text
[i
]);
87 fprintf(out
, "0x00\n");
88 print_tabs(indent
, out
);
92 static void format_flags(struct lsg_option
*opt
, FILE *out
)
94 fprintf(out
, "\t\t\t\t\t.flags = 0");
96 fprintf(out
, " | LLS_MULTIPLE");
98 fprintf(out
, " | LLS_REQUIRED");
100 fprintf(out
, " | LLS_IGNORED");
101 if (opt
->default_val
)
102 fprintf(out
, " | LLS_HAS_DEFAULT");
106 static int string_literal(const char *src
, FILE *out
)
110 len
+= fprintf(out
, "\"");
111 while (src
&& *src
) {
112 if (*src
== '"' || *src
== '\\')
113 len
+= fprintf(out
, "\\");
114 len
+= fprintf(out
, "%c", *src
);
117 len
+= fprintf(out
, "\"");
121 static void format_man_text(FILE *out
, bool bol
, const char *text
)
127 for (i
= 0; text
[i
]; i
++) {
147 fprintf(out
, "%c", text
[i
]);
151 static int format_option_arg(const struct lsg_option
*opt
, FILE *out
,
154 char *typestr
= opt
->typestr
? opt
->typestr
: "val";
155 int arg_info
, len
= 0;
161 else if (strcmp(opt
->arg_info
, "LLS_NO_ARGUMENT") == 0)
163 else if (strcmp(opt
->arg_info
, "LLS_OPTIONAL_ARGUMENT") == 0)
165 else if (strcmp(opt
->arg_info
, "LLS_REQUIRED_ARGUMENT") == 0)
171 len
+= fprintf(out
, "[");
173 len
+= fprintf(out
, "=<");
175 len
+= fprintf(out
, "%s", typestr
);
177 len
+= fprintf(out
, "\"");
178 len
+= string_literal(typestr
, out
);
179 len
+= fprintf(out
, "\"");
184 len
+= fprintf(out
, "]");
188 static void format_synopsis(const struct lsg_command
*cmd
, FILE *out
,
197 format_man_text(out
, true, cmd
->synopsis
);
199 string_literal(cmd
->synopsis
, out
);
206 len
= strlen(cmd
->name
.orig
) + 8;
207 for (j
= 0; j
< cmd
->num_options
; j
++) {
208 struct lsg_option
*opt
= cmd
->options
+ j
;
212 if (!man_format
&& len
> 70) {
213 fprintf(out
, "\\n\"\n\t\t\t\t\" ");
216 len
+= fprintf(out
, " ");
219 len
+= fprintf(out
, "[");
220 len
+= fprintf(out
, "--%s", opt
->name
.orig
);
221 len
+= format_option_arg(opt
, out
, man_format
);
223 len
+= fprintf(out
, "]");
225 if (cmd
->non_opts_name
) {
226 len
+= strlen(cmd
->non_opts_name
);
227 if (!man_format
&& len
> 70)
228 fprintf(out
, "\\n\"\n\t\t\t\t\" ");
229 if (cmd
->num_options
> 0)
230 fprintf(out
, " [--]");
231 fprintf(out
, " %s", cmd
->non_opts_name
);
237 static void gen_c_options(const struct lsg_command
*cmd
, FILE *out
)
241 if (cmd
->num_options
== 0)
243 fprintf(out
, "\t\t.options = (struct lls_option[]) {\n");
244 for (j
= 0; j
< cmd
->num_options
; j
++) {
245 struct lsg_option
*opt
= cmd
->options
+ j
;
246 fprintf(out
, "\t\t\t{\n");
247 fprintf(out
, "\t\t\t\t.name = \"%s\",\n",
250 fprintf(out
, "\t\t\t\t.short_opt = '%c',\n",
253 fprintf(out
, "\t\t\t\t.summary = ");
254 string_literal(opt
->summary
, out
);
258 fprintf(out
, "\t\t\t\t.arg_info = %s,\n",
261 fprintf(out
, "\t\t\t\t.arg_type = %s,\n",
264 fprintf(out
, "\t\t\t\t.typestr = ");
265 string_literal(opt
->typestr
, out
);
268 fprintf(out
, "\t\t\t\t.values = ");
270 fprintf(out
, "(union lls_val *)(union lls_val[]) {\n");
271 for (i
= 0; i
< opt
->num_values
; i
++)
272 fprintf(out
, "\t\t\t\t\t{.string_val = %s},\n",
273 opt
->value_literals
[i
]);
274 fprintf(out
, "\t\t\t\t\t{.string_val = NULL}\n");
275 fprintf(out
, "\t\t\t\t},\n");
277 fprintf(out
, "NULL,\n");
278 format_flags(opt
, out
);
279 if (opt
->default_val
) {
280 bool string
= strcmp(opt
->arg_type
, "LLS_STRING") == 0;
281 fprintf(out
, "\t\t\t\t.default_val = {");
284 fprintf(out
, ".uint32_val = ");
286 fprintf(out
, ".string_val = ");
287 string_literal(opt
->default_val
, out
);
289 } else if (strcmp(opt
->arg_type
, "LLS_INT32") == 0)
290 fprintf(out
, ".int32_val = ");
291 else if (strcmp(opt
->arg_type
, "LLS_UINT32") == 0)
292 fprintf(out
, ".uint32_val = ");
293 else if (strcmp(opt
->arg_type
, "LLS_INT64") == 0)
294 fprintf(out
, ".int64_val = ");
295 else if (strcmp(opt
->arg_type
, "LLS_UINT64") == 0)
296 fprintf(out
, ".uint64_val = ");
297 if (!string
|| opt
->values
)
298 fprintf(out
, "%s", opt
->default_val
);
299 fprintf(out
, "},\n");
301 format_c_text(opt
->help
, "help", 5, out
);
302 fprintf(out
, "\t\t\t},\n");
304 fprintf(out
, "\t\t\t{\n\t\t\t\t\t.name = NULL\n\t\t\t}\n");
305 fprintf(out
, "\t\t}\n");
308 static void format_command(const struct lsg_command
*cmd
, FILE *out
)
310 if (!cmd
->name
.orig
) {
311 fprintf(out
, "{.name = NULL}\n");
314 fprintf(out
, "{\n\t\t.name = \"%s\",\n", cmd
->name
.orig
);
315 fprintf(out
, "\t\t.purpose = ");
316 string_literal(cmd
->purpose
, out
);
318 format_c_text(cmd
->description
, "description", 3, out
);
319 if (cmd
->non_opts_name
|| cmd
->synopsis
)
320 fprintf(out
, "\t\t.non_opts_name = \"%s\",\n",
321 cmd
->non_opts_name
? cmd
->non_opts_name
: "");
322 fprintf(out
, "\t\t.synopsis = ");
323 format_synopsis(cmd
, out
, false);
324 format_c_text(cmd
->closing
, "closing", 3, out
);
325 fprintf(out
, "\n\t\t.user_data = &lsg_%s_com_%s_user_data,\n",
326 suite
.name
.sanitized
, cmd
->name
.sanitized
);
327 fprintf(out
, "\t\t.num_options = %d,\n", cmd
->num_options
);
328 gen_c_options(cmd
, out
);
332 static void format_user_data(const struct lsg_command
*cmd
, FILE *out
)
336 fprintf(out
, "extern const void *lsg_%s_com_%s_user_data "
337 "__attribute__ ((weak));\n",
338 suite
.name
.sanitized
,
343 static void gen_c(const char *outpath
, const char *cmdline
)
347 FILE *out
= fopen(outpath
, "w");
352 gen_license_header(out
, cmdline
, "/* ", " */");
353 fprintf(out
, "#include <stdlib.h>\n");
354 fprintf(out
, "#include <inttypes.h>\n");
355 fprintf(out
, "#include <lopsub-internal.h>\n");
356 fprintf(out
, "#include <lopsub.h>\n");
357 fprintf(out
, "__attribute__ ((unused)) "
358 "static const unsigned *abi_version = &%s;\n",
359 LLS_ABI_VERSION_VAR_STRING
);
360 fprintf(out
, "#if LLS_ABI_VERSION - %d\n", LLS_ABI_VERSION
);
361 fprintf(out
, "#error: \"ABI version mismatch: header version "
362 "differs from lopsubgen version\"\n");
363 fprintf(out
, "#endif\n");
364 for (i
= 0; i
<= suite
.num_subcommands
; i
++)
365 format_user_data(suite
.commands
+ i
, out
);
366 fprintf(out
, "static const struct lls_suite the_%s_suite = {\n",
367 suite
.name
.sanitized
);
368 fprintf(out
, "\t.name = \"%s\",\n", suite
.name
.orig
);
370 fprintf(out
, "\t.caption = \"%s\",\n", suite
.caption
);
371 fprintf(out
, "\t.num_subcommands = %d,\n", suite
.num_subcommands
);
372 fprintf(out
, "\t.commands = (struct lls_command[]) {\n");
373 for (i
= 0; i
<= suite
.num_subcommands
; i
++) {
374 struct lsg_command
*cmd
= suite
.commands
+ i
;
375 fprintf(out
, "%s", i
? ", " : "\t\t");
376 format_command(cmd
, out
);
378 fprintf(out
, ", {\n\t\t\t.name = NULL\n\t\t}\n");
379 fprintf(out
, "\t}\n");
380 fprintf(out
, "};\n");
381 fprintf(out
, "const struct lls_suite *%s_suite = &the_%s_suite;\n",
382 suite
.name
.sanitized
, suite
.name
.sanitized
);
386 static inline bool has_arg(struct lsg_option
*opt
)
390 return strcmp(opt
->arg_info
, "LLS_NO_ARGUMENT");
393 static void gen_header(const char *outpath
, const char *cmdline
)
396 FILE *out
= fopen(outpath
, "w");
403 gen_license_header(out
, cmdline
, "/* ", " */");
404 /* generate command enum */
405 fprintf(out
, "extern const struct lls_suite *%s_suite;\n",
406 suite
.name
.sanitized
);
407 fprintf(out
, "#define LSG_%s_SUBCOMMANDS \\\n", suite
.name
.capitalized
);
408 for (i
= 1; i
<= suite
.num_subcommands
; i
++)
409 fprintf(out
, "\tLSG_%s_CMD(%s), \\\n", suite
.name
.capitalized
,
410 suite
.commands
[i
].name
.sanitized
);
412 fprintf(out
, "#define LSG_%s_COMMANDS \\\n", suite
.name
.capitalized
);
413 name
= suite
.commands
[0].name
.sanitized
;
414 fprintf(out
, "\tLSG_%s_CMD(%s), \\\n", suite
.name
.capitalized
,
415 name
? name
: "SUPERCOMMAND_UNAVAILABLE");
416 fprintf(out
, "\tLSG_%s_SUBCOMMANDS\n", suite
.name
.capitalized
);
417 fprintf(out
, "enum lsg_%s_command {\n", suite
.name
.sanitized
);
418 for (i
= 0; i
<= suite
.num_subcommands
; i
++) {
419 struct lsg_command
*cmd
= suite
.commands
+ i
;
420 char *name
= cmd
->name
.capitalized
;
423 name
= "SUPERCOMMAND_UNAVAILABLE";
424 fprintf(out
, "\tLSG_%s_CMD_%s,\n", suite
.name
.capitalized
, name
);
426 fprintf(out
, "};\n#define LSG_NUM_%s_SUBCOMMANDS %u\n", suite
.name
.capitalized
,
427 suite
.num_subcommands
);
428 fprintf(out
, "#define LSG_%s_AUX_INFOS \\\n", suite
.name
.capitalized
);
429 for (i
= 0; i
<= suite
.num_subcommands
; i
++) {
430 struct lsg_command
*cmd
= suite
.commands
+ i
;
431 char *ai
= cmd
->aux_info
;
433 ai
= suite
.aux_info_default
;
437 fprintf(out
, "\t%s_AUX_INFO(%s) /* %s */ \\\n",
438 suite
.name
.capitalized
, ai
, cmd
->name
.orig
?
439 cmd
->name
.orig
: "NO_SUPERCOMMAND");
442 /* generate one option enum per command */
443 for (i
= 0; i
<= suite
.num_subcommands
; i
++) {
444 struct lsg_command
*cmd
= suite
.commands
+ i
;
447 fprintf(out
, "enum lsg_%s_%s_option {\n", suite
.name
.sanitized
,
448 cmd
->name
.sanitized
);
449 for (j
= 0; j
< cmd
->num_options
; j
++) {
450 struct lsg_option
*opt
= cmd
->options
+ j
;
451 char suffix
[20] = "";
453 sprintf(suffix
, "%d", j
);
454 fprintf(out
, "\tLSG_%s_%s_OPT_%s%s,\n",
455 suite
.name
.capitalized
,
456 cmd
->name
.capitalized
,
457 opt
->name
.capitalized
,
461 fprintf(out
, "\tLSG_NUM_%s_%s_OPTIONS\n};\n",
462 suite
.name
.capitalized
, cmd
->name
.capitalized
);
465 /* generate enumeration for options of type enum */
466 for (i
= 0; i
<= suite
.num_subcommands
; i
++) {
467 struct lsg_command
*cmd
= suite
.commands
+ i
;
470 for (j
= 0; j
< cmd
->num_options
; j
++) {
471 struct lsg_option
*opt
= cmd
->options
+ j
;
474 fprintf(out
, "/* cmd %s, opt %s */\n", cmd
->name
.orig
,
476 fprintf(out
, "enum {");
477 for (k
= 0; k
< opt
->num_values
; k
++)
478 fprintf(out
, "%s, ", opt
->value_ids
[k
]);
479 fprintf(out
, "LSG_NUM_%s_%s_%s_VALUES};\n",
480 suite
.name
.capitalized
, cmd
->name
.capitalized
,
481 opt
->name
.capitalized
);
484 for (i
= 0; i
<= suite
.num_subcommands
; i
++) {
485 struct lsg_command
*cmd
= suite
.commands
+ i
;
488 fprintf(out
, "#define LSG_%s_%s_SHORT_OPTS ",
489 suite
.name
.capitalized
, cmd
->name
.capitalized
);
490 for (j
= 0; j
< cmd
->num_options
; j
++) {
491 struct lsg_option
*opt
= cmd
->options
+ j
;
494 fprintf(out
, "\"-%c%s\"%s", opt
->short_opt
,
495 has_arg(opt
)? "=" : "",
496 j
== cmd
->num_options
- 1? "" : ", ");
500 fprintf(out
, "#define LSG_%s_%s_LONG_OPTS ",
501 suite
.name
.capitalized
, cmd
->name
.capitalized
);
502 for (j
= 0; j
< cmd
->num_options
; j
++) {
503 struct lsg_option
*opt
= cmd
->options
+ j
;
504 fprintf(out
, "\"--%s%s\"%s", opt
->name
.orig
,
505 has_arg(opt
)? "=" : "",
506 j
== cmd
->num_options
- 1? "" : ", ");
509 fprintf(out
, "#define LSG_%s_%s_OPTS "
510 "LSG_%s_%s_SHORT_OPTS, LSG_%s_%s_LONG_OPTS\n",
511 suite
.name
.capitalized
, cmd
->name
.capitalized
,
512 suite
.name
.capitalized
, cmd
->name
.capitalized
,
513 suite
.name
.capitalized
, cmd
->name
.capitalized
519 static void check_option(struct lsg_option
*opt
)
521 if (!opt
->arg_info
|| !strcmp(opt
->arg_info
, "no_arg"))
523 if (opt
->arg_type
&& strcmp(opt
->arg_type
, "none"))
525 fprintf(stderr
, "option '%s': inconsistent arg_type/arg_info\n",
530 static void sanity_check(void)
534 if (suite
.num_subcommands
== 0 && !suite
.commands
) {
535 fprintf(stderr
, "no (sub)commands defined\n");
538 for (i
= 0; i
<= suite
.num_subcommands
; i
++) {
539 struct lsg_command
*cmd
= suite
.commands
+ i
;
542 for (j
= 0; j
< cmd
->num_options
; j
++)
543 check_option(cmd
->options
+ j
);
547 static void run_yylex(void)
552 if (!suite
.name
.orig
)
553 suite
.name
.orig
= strdup("lopsubgen");
555 lsg_init_name(&suite
.name
);
556 for (i
= 0; i
<= suite
.num_subcommands
; i
++) {
557 struct lsg_command
*cmd
= suite
.commands
+ i
;
560 lsg_init_name(&cmd
->name
);
561 for (j
= 0; j
< cmd
->num_options
; j
++)
562 lsg_init_name(&cmd
->options
[j
].name
);
564 for (i
= 0; i
< suite
.num_sections
; i
++)
565 lsg_init_name(&suite
.sections
[i
].name
);
569 int main(int argc
, char **argv
)
572 gen_c("lopsubgen.lsg.c", NULL
);
573 gen_header("lopsubgen.lsg.h", NULL
);
579 #include "lopsubgen.lsg.h"
581 static char *get_output_path(const char *suffix
, const char *arg
,
582 const struct lls_parse_result
*lpr
)
585 char *result
, *output_dir
;
587 output_dir
= OPT_STRING_VAL(OUTPUT_DIR
, lpr
);
589 if (arg
&& arg
[0] == '/') {
590 result
= strdup(arg
);
594 if (arg
) { /* relative path */
595 len
= strlen(output_dir
) + strlen(arg
) + 1;
596 result
= malloc(len
+ 1);
598 sprintf(result
, "%s/%s", output_dir
, arg
);
601 /* default: suite name plus suffix */
602 len
= strlen(output_dir
) + 1 /* slash */ + strlen(suite
.name
.orig
)
603 + 1 /* dot */ + 3 /* "lsg" */ + 1 /* dot */ + strlen(suffix
);
604 result
= malloc(len
+ 1);
606 sprintf(result
, "%s/%s.lsg.%s", output_dir
, suite
.name
.orig
, suffix
);
610 static void gen_man(struct lls_parse_result
*lpr
, const char *cmdline
)
616 char *outpath
= get_output_path("man",
617 OPT_STRING_VAL(GEN_MAN
, lpr
), lpr
);
619 out
= fopen(outpath
, "w");
625 gen_license_header(out
, cmdline
, ".\\\" ", "");
626 if (suite
.commands
[0].name
.orig
) {
628 const char *version_string
;
631 * If the SOURCE_DATE_EPOCH environment variable
632 * contains a positive integer in the time_t range, use
633 * that instead of the current time. See:
634 * <https://reproducible-builds.org/specs/source-date-epoch/>
635 * for more information.
637 char *source_date_epoch
= getenv("SOURCE_DATE_EPOCH");
638 if (source_date_epoch
!= NULL
)
639 t
= strtoll(source_date_epoch
, NULL
, 10);
647 if (strftime(date
, sizeof(date
), "%B %Y", tmp
) == 0) {
648 fprintf(stderr
, "strftime returned 0\n");
652 if (OPT_GIVEN(VERSION_STRING
, lpr
))
653 version_string
= OPT_STRING_VAL(VERSION_STRING
, lpr
);
655 version_string
= suite
.version_string
?
656 suite
.version_string
: "";
657 fprintf(out
, ".TH %s \"%s\" \"%s\" \"%s\" \"%s\"\n",
658 suite
.title
? suite
.title
: suite
.commands
[0].name
.orig
,
659 suite
.mansect
? suite
.mansect
: "1",
660 suite
.date
? suite
.date
: date
,
662 suite
.manual_title
? suite
.manual_title
: "User commands"
665 for (i
= 0; i
<= suite
.num_subcommands
; i
++) {
666 struct lsg_command
*cmd
= suite
.commands
+ i
;
671 fprintf(out
, ".SH NAME\n");
672 fprintf(out
, ".B\n%s \\- ", cmd
->name
.orig
);
673 format_man_text(out
, false, cmd
->purpose
);
675 if (i
== 1 && suite
.caption
) {
676 char *caption
= strdup(suite
.caption
);
677 inplace_toupper(caption
);
678 fprintf(out
, ".SH %s\n.P\n", caption
);
681 if (i
== 1 && suite
.introduction
)
682 format_man_text(out
, true, suite
.introduction
);
683 fprintf(out
, ".SS \n%s \\- ", cmd
->name
.orig
);
684 format_man_text(out
, false, cmd
->purpose
);
686 fprintf(out
, "\n.P\n");
688 fprintf(out
, ".SH SYNOPSIS\n");
690 fprintf(out
, "Usage: \n");
691 fprintf(out
, ".B %s\n", cmd
->name
.orig
);
692 format_synopsis(cmd
, out
, true);
693 fprintf(out
, "\n.P\n");
694 if (cmd
->description
) {
696 fprintf(out
, ".SH DESCRIPTION\n");
697 format_man_text(out
, true, cmd
->description
);
699 if (cmd
->num_options
> 0)
701 fprintf(out
, ".SH OPTIONS\n");
702 for (opt_num
= 0; opt_num
< cmd
->num_options
; opt_num
++) {
703 struct lsg_option
*opt
= cmd
->options
+ opt_num
;
706 fprintf(out
, ".SS ");
707 format_man_text(out
, false, opt
->summary
);
710 format_man_text(out
, true, opt
->help
);
714 fprintf(out
, ".TP\n");
715 if (opt
->short_opt
!= '\0')
716 fprintf(out
, "\\fB\\-%c\\fR, ", opt
->short_opt
);
717 fprintf(out
, "\\fB\\-\\-%s\\fR", opt
->name
.orig
);
718 format_option_arg(opt
, out
, true /* man_format */);
720 format_man_text(out
, true, opt
->summary
);
724 fprintf(out
, ".IP\n");
725 fprintf(out
, "values:\n");
726 dflt
= opt
->default_val
?
727 atoi(opt
->default_val
) : 0;
728 for (n
= 0; n
< opt
->num_values
; n
++) {
731 fprintf(out
, "%s%s\n", opt
->values
[n
],
732 n
== opt
->num_values
- 1?
735 } else if (opt
->default_val
) {
736 fprintf(out
, ".IP\n");
737 fprintf(out
, "default: ");
738 format_man_text(out
, false, opt
->default_val
);
739 fprintf(out
, "\n.P\n");
742 fprintf(out
, ".IP\n");
743 format_man_text(out
, true, opt
->help
);
746 fprintf(out
, ".PP\n");
748 char *pfx
= suite
.aux_info_prefix
;
749 fprintf(out
, ".RS\n");
751 fprintf(out
, "%s ", pfx
);
752 fprintf(out
, "%s\n.PP\n", cmd
->aux_info
);
753 fprintf(out
, ".RE\n");
756 format_man_text(out
, true, cmd
->closing
);
758 if (suite
.conclusion
)
759 format_man_text(out
, true, suite
.conclusion
);
760 for (i
= 0; i
< suite
.num_sections
; i
++) {
761 struct lsg_section
*sec
= suite
.sections
+ i
;
762 fprintf(out
, "\n.P\n.SH \"%s\"\n", sec
->name
.capitalized
);
763 fprintf(out
, "%s\n.P\n", sec
->text
);
768 int main(int argc
, char **argv
)
770 const struct lls_command
*cmd
= lls_cmd(0, lopsubgen_suite
);
771 char *errctx
, *outpath
, *cmdline
;
772 struct lls_parse_result
*lpr
;
775 /* Make a copy of the command line because lls_parse() permutes argv[] */
776 for (i
= 0, ret
= 0; argv
[i
]; i
++)
777 ret
+= strlen(argv
[i
]) + 1;
778 cmdline
= malloc(ret
+ 1);
780 for (i
= 0, ret
= 0; argv
[i
]; i
++)
781 ret
+= sprintf(cmdline
+ ret
, "%s ", argv
[i
]);
782 cmdline
[ret
- 1] = '\0';
784 ret
= lls_parse(argc
, argv
, cmd
, &lpr
, &errctx
);
787 fprintf(stderr
, "%s\n", errctx
);
788 fprintf(stderr
, "%s\n", lls_strerror(-ret
));
791 if (OPT_GIVEN(VERSION
, lpr
)) {
792 printf("lopsubgen-%s\n", lls_version());
795 if (OPT_GIVEN(HELP
, lpr
)) {
797 if (OPT_GIVEN(HELP
, lpr
) > 1)
798 help
= lls_long_help(cmd
);
800 help
= lls_short_help(cmd
);
806 if (OPT_GIVEN(GEN_C
, lpr
)) {
807 outpath
= get_output_path("c",
808 OPT_STRING_VAL(GEN_C
, lpr
), lpr
);
809 gen_c(outpath
, cmdline
);
812 if (OPT_GIVEN(GEN_HEADER
, lpr
)) {
813 outpath
= get_output_path("h",
814 OPT_STRING_VAL(GEN_HEADER
, lpr
), lpr
);
815 gen_header(outpath
, cmdline
);
818 if (OPT_GIVEN(GEN_MAN
, lpr
))
819 gen_man(lpr
, cmdline
);