]> git.draconx.ca Git - gob-dx.git/blobdiff - src/main.c
Use help formatting routines from dxcommon.
[gob-dx.git] / src / main.c
index 295199cb6c0263d3d89b929f9c26b97729b37621..0e6c55c84c1709aeed581a94f1a7ac679a0bd689 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (C) 1999,2000 the Free Software Foundation.
  * Copyright (C) 2000 Eazel, Inc.
  * Copyright (C) 2001-2011 George (Jiri) Lebl
- * Copyright © 2019-2020 Nick Bowler
+ * Copyright © 2019-2022 Nick Bowler
  *
  * Author: George (Jiri) Lebl
  *
 #include <unistd.h>
 #include <stdlib.h>
 #include <sys/stat.h>
+#include <limits.h>
+#include <getopt.h>
 
 #include "treefuncs.h"
 #include "parse.h"
 #include "out.h"
 #include "util.h"
 #include "checks.h"
+#include "help.h"
 
 #include "main.h"
 
+#include "options.h"
+
+static const char sopts[] = SOPT_STRING;
+static const struct option lopts[] = {
+       LOPTS_INITIALIZER,
+       { 0 }
+};
+
 char *filename = NULL;
 
 int yyparse(void);
@@ -128,7 +139,6 @@ gint prealloc = 0;
 
 
 gboolean use_m4 = FALSE; /* preprocess sources with m4 */
-gboolean use_m4_clean = FALSE; /* preprocess sources with m4, no m4 flags */
 char *m4_commandline = NULL;
 #define M4_INCLUDE_DIR  PKGDATADIR "/m4"
 #define M4_BASE_FILENAME "gobm4.m4"
@@ -1498,7 +1508,7 @@ make_run_signal_flags(Method *m, gboolean last)
                                     "perhaps it was misspelled",
                                     flag);
                }
-               g_string_sprintfa(gs, " | G_SIGNAL_%s", flag);
+               g_string_append_printf(gs, " | G_SIGNAL_%s", flag);
        }
 
        {
@@ -1722,7 +1732,7 @@ make_argument (Argument *a)
                        if(strcmp(argflags[i], flag)==0)
                                break;
                }
-               g_string_sprintfa(flags, " | %s%s", argflags[i] ? "G_PARAM_" : "", flag);
+               g_string_append_printf(flags, " | %s%s", argflags[i] ? "G_PARAM_" : "", flag);
        }
 
        g_string_append (flags, ")");
@@ -1912,7 +1922,7 @@ make_property (Property *p)
                                if(strcmp(argflags[i], flag)==0)
                                        break;
                        }
-                       g_string_sprintfa(flags, " | %s%s", argflags[i] ? "G_PARAM_" : "", flag);
+                       g_string_append_printf(flags, " | %s%s", argflags[i] ? "G_PARAM_" : "", flag);
                }
 
                g_string_append (flags, ")");
@@ -3160,7 +3170,7 @@ get_arg_names_for_macro (Method *m)
        sep = "";
        for(li=m->args;li;li=g_list_next(li)) {
                FuncArg *arg = li->data;
-               g_string_sprintfa (gs, "%s___%s", sep, arg->name);
+               g_string_append_printf(gs, "%s___%s", sep, arg->name);
                sep = ",";
        }
        return g_string_free (gs, FALSE);
@@ -4526,13 +4536,11 @@ generate_outfiles(void)
 static void print_version(void)
 {
        printf("%s (%s) %s\n", PACKAGE_NAME, PACKAGE_TARNAME, PACKAGE_VERSION);
-       putchar('\n');
        puts("Copyright (C) 2013 George (Jiri) Lebl et al.");
-       puts("Copyright (C) 2020 Nick Bowler");
-       puts("License GPLv2+: GNU GPL version 2 or later <https://gnu.org/licenses/gpl.html>.");
+       puts("Copyright (C) 2022 Nick Bowler");
+       puts("License GPLv2+: GNU GPL version 2 or any later version");
        puts("This is free software: you are free to change and redistribute it.");
        puts("There is NO WARRANTY, to the extent permitted by law.");
-
 }
 
 static void print_usage(FILE *f)
@@ -4544,243 +4552,173 @@ static void print_usage(FILE *f)
        }
 }
 
-static void
-print_help(void)
+static void print_help(void)
 {
+       const struct option *opt;
+
        print_usage(stdout);
 
-       puts(
-"This is \"GObject Builder\": a simple preprocessor to help with\n"
-"implementing GObject types in C.\n"
-       );
-
-       puts("Options:");
-       puts("  --help,-h,-?            Display this help\n"
-            "  --version               Display version\n"
-            "  --exit-on-warn,-w       Exit with an error on warnings\n"
-            "  --no-exit-on-warn       Don't exit on warnings [default]\n"
-            "  --for-cpp               Create C++ files\n"
-            "  --no-extern-c           Never print extern \"C\" into the "
-                                      "header\n"
-            "  --no-gnu                Never use GNU extentions\n"
-            "  --no-touch              Don't touch output files unless they "
-                                      "really\n"
-            "                          changed (implies --no-touch-headers)\n"
-            "  --no-touch-headers      Don't touch headers unless they "
-                                      "really changed\n"
-            "  --always-private-header Always create a private header "
-                                      "file,\n"
-            "                          even if it would be empty\n"
-            "  --ondemand-private-header Create private header only when "
-                                      "needed\n"
-            "                          [default]\n"
-            "  --no-private-header     Don't create a private header, "
-                                      "put private\n"
-            "                          structure and protected "
-                                      "prototypes inside c file\n"
-            "  --always-private-struct Always create a private pointer "
-                                      "in\n"
-            "                          the object structure\n"
-            "  --m4                    Preprocess source with m4. "
-                                      "Following args will\n"
-            "                          be passed to m4\n"
-            "  --m4-dir                Print directory that will be "
-                                      "searched for m4\n"
-            "                          files\n"
-            "  --no-write,-n           Don't write output files, just "
-                                      "check syntax\n"
-            "  --no-lines              Don't print '#line' to output\n"
-            "  --no-self-alias         Don't create self type and macro "
-                                      "aliases\n"
-            "  --no-kill-underscores   Ignored for compatibility\n"
-            "  -o,--output-dir         The directory where output "
-                                 "should be placed\n"
-            "  --file-sep[=c]          replace default \'-\' file "
-                                      "name separator\n\n"
-            "  --gtk3                  Use gtk+3\n"
-            );
+       puts("This is \"GObject Builder\": a simple preprocessor to help with\n"
+             "implementing GObject types in C.");
+
+       puts("\nOptions:");
+       for (opt = lopts; opt->name; opt++) {
+               struct lopt_help help;
+
+               /* Don't display obsolete options that don't do anything */
+               if (!opt->flag && !opt->val)
+                       continue;
+
+               if (!lopt_get_help(opt, &help))
+                       continue;
+
+               help_print_option(opt, help.arg, help.desc, 20);
+       }
+       putchar('\n');
 
        puts("End world hunger, donate to the World Food Programme: https://www.wfp.org/");
 }
 
-static void
-parse_options(int argc, char *argv[])
+/*
+ * Called after getopt_long receives an --m4 argument.  Immediately stop
+ * processing options.  Then all non-option arguments seen so far together
+ * with all remaining arguments are appended to M4_COMMANDLINE.  If m4_clean
+ * is false, then M4_FLAGS is inserted before the first non-option argument,
+ * if any.
+ *
+ * The resulting string is returned, which should be freed by the caller.
+ */
+static char *parse_m4_options(int argc, char **argv, gboolean m4_clean)
 {
-       int i;
-       int got_file = FALSE;
-       int no_opts = FALSE;
-       int m4_opts = FALSE; /* if we are just passing on args to m4 */
-
-       filename = NULL;
-
-       for(i = 1 ; i < argc; i++) {
-               if(m4_opts) {
-                       char *new_commandline;
-                       g_assert(m4_commandline!=NULL);
-
-                       /* check whether this one looks like the filename */
-                       if((!strcmp(argv[i],"-") || argv[i][0] != '-') 
-                          && !got_file) {
-                               const gchar *m4_flags=use_m4_clean?"":M4_FLAGS;
-                               filename = argv[i];
-                               got_file = TRUE;
-                               
-                               /* insert flags before the filename */
-                               new_commandline=g_strconcat(m4_commandline,
-                                                           " ",
-                                                           m4_flags, 
-                                                           " ",
-                                                           argv[i],
-                                                           NULL);
-                       }
+       char **nonopt = NULL, *save_argv0, *ret;
+       int opt;
 
-                       /* just an ordinary option */
-                       else                      
-                         new_commandline=g_strconcat(m4_commandline,
-                                                     " ",
-                                                     argv[i],
-                                                     NULL);
-
-                       /* free old commandline */
-                       g_free(m4_commandline);
-                       m4_commandline=new_commandline;
-
-               } else if(no_opts ||
-                  argv[i][0] != '-') {
-                       /*must be a file*/
-                       if(got_file) {
-                               fprintf(stderr, "Specify only one file!\n");
-                               print_usage(stderr);
-                               exit(1);
-                       }
-                       filename = argv[i];
-                       got_file = TRUE;
-               } else if(strcmp(argv[i], "--help")==0) {
-                       print_help();
-                       exit(0);
-               } else if(strcmp(argv[i], "--version")==0) {
-                       print_version();
-                       exit(0);
-               } else if(strcmp(argv[i], "--exit-on-warn")==0) {
-                       exit_on_warn = TRUE;
-               } else if(strcmp(argv[i], "--no-exit-on-warn")==0) {
-                       exit_on_warn = FALSE;
-               } else if(strcmp(argv[i], "--for-cpp")==0) {
-                       for_cpp = TRUE;
-               } else if(strcmp(argv[i], "--no-touch")==0) {
-                       no_touch = TRUE;
-                       no_touch_headers = TRUE;
-               } else if(strcmp(argv[i], "--no-touch-headers")==0) {
-                       no_touch_headers = TRUE;
-               } else if(strcmp(argv[i], "--ondemand-private-header")==0) {
-                       private_header = PRIVATE_HEADER_ONDEMAND;
-               } else if(strcmp(argv[i], "--always-private-header")==0) {
-                       private_header = PRIVATE_HEADER_ALWAYS;
-               } else if(strcmp(argv[i], "--no-private-header")==0) {
-                       private_header = PRIVATE_HEADER_NEVER;
-               } else if(strcmp(argv[i], "--no-gnu")==0) {
-                       no_gnu = TRUE;
-               } else if(strcmp(argv[i], "--no-extern-c")==0) {
-                       no_extern_c = TRUE;
-               } else if(strcmp(argv[i], "--no-write")==0) {
+       /* First, conclude getopt run and reset with remaining args */
+       getopt_long(optind, argv, sopts, lopts, NULL);
+       argv += optind-1;
+       argc -= optind-1;
+       optind = 0;
+
+       save_argv0 = argv[0];
+       argv[0] = M4_COMMANDLINE;
+
+       if (m4_clean) {
+               ret = g_strjoinv(" ", argv);
+               argv[0] = save_argv0;
+               return ret;
+       }
+
+       /* Locate first non-option argument, if any. */
+       while ((opt = getopt_long(argc, argv, "-", NULL, NULL)) != -1) {
+               if (opt == 1) {
+                       nonopt = &argv[optind-2];
+                       break;
+               }
+       }
+
+       /* If there is a non-option but the above didn't see it, must be "--" */
+       if (!nonopt && argv[optind])
+               nonopt = &argv[optind-2];
+
+       if (nonopt) {
+               /* Found non-option, insert M4_FLAGS just before it. */
+               char *save_argv[3] = { nonopt[0], nonopt[1], nonopt[2] };
+
+               nonopt[1] = M4_FLAGS;
+               nonopt[2] = NULL;
+               nonopt[0] = g_strjoinv(" ", argv);
+
+               nonopt[1] = save_argv[1];
+               nonopt[2] = save_argv[2];
+               ret = g_strjoinv(" ", nonopt);
+
+               g_free(nonopt[0]);
+               nonopt[0] = save_argv[0];
+       } else {
+               /* Only options, not inserting M4_FLAGS. */
+               ret = g_strjoinv(" ", argv);
+       }
+
+       argv[0] = save_argv0;
+       return ret;
+}
+
+static int parse_options(int argc, char **argv)
+{
+       gboolean show_m4_dir = FALSE, m4_clean = FALSE;
+       char *raw_file_sep = "-";
+       int opt;
+
+       opterr = 0;
+       while ((opt = getopt_long(argc, argv, sopts, lopts, NULL)) != -1) {
+               switch (opt) {
+               case 'n':
                        no_write = TRUE;
-               } else if(strcmp(argv[i], "--no-lines")==0) {
-                       no_lines = TRUE;
-               } else if(strcmp(argv[i], "--no-self-alias")==0) {
-                       no_self_alias = TRUE;
-               } else if(strcmp(argv[i], "--no-kill-underscores")==0) {
-                       /* no op */;
-               } else if(strcmp(argv[i], "--always-private-struct")==0) {
-                       always_private_struct = TRUE;
-               } else if(strcmp(argv[i], "--m4-dir")==0) {
-                       printf("%s\n",M4_INCLUDE_DIR);
-                       exit(0);
-               } else if(strcmp(argv[i], "--m4")==0) {
-                       use_m4 = TRUE;
-                       use_m4_clean=FALSE;
-                       m4_opts = TRUE;
-                       m4_commandline=g_strdup(M4_COMMANDLINE);
-               } else if(strcmp(argv[i], "--m4-clean")==0) {
+                       break;
+               case 'o':
+                       output_dir = optarg;
+                       break;
+               case 'w':
+                       exit_on_warn = TRUE;
+                       break;
+               case LOPT_FILE_SEP:
+                       raw_file_sep = optarg ? optarg : "";
+                       break;
+               case LOPT_M4_DIR:
+                       show_m4_dir = TRUE;
+                       break;
+               case LOPT_NO_TOUCH:
+                       no_touch = no_touch_headers = TRUE;
+                       break;
+               case LOPT_M4_CLEAN:
+                       m4_clean = TRUE;
+               case LOPT_M4:
                        use_m4 = TRUE;
-                       use_m4_clean=TRUE;
-                       m4_opts = TRUE;
-                       m4_commandline=g_strdup(M4_COMMANDLINE);
-               } else if (strcmp (argv[i], "-o") == 0 || 
-                          strcmp (argv[i], "--output-dir") == 0) {
-                       if (i+1 < argc) {
-                               output_dir = g_strdup (argv[i+1]);
-                               i++;
-                       } else {
-                               output_dir = NULL;
-                       }
-               } else if (strncmp (argv[i], "-o=", strlen ("-o=")) == 0 || 
-                          strncmp (argv[i],
-                                   "--output-dir=",
-                                   strlen ("--output-dir=")) == 0) {
-                       char *p = strchr (argv[i], '=');
-                       g_assert (p != NULL);
-                       output_dir = g_strdup (p+1);
-               } else if (strncmp (argv[i], "--file-sep=",
-                                    strlen ("--file-sep=")) == 0) {
-                       char *p = strchr (argv[i], '=');
-                       g_assert (p != NULL);
-                       file_sep = *(p+1);
-               } else if (strncmp (argv[i], "--file-sep",
-                                    strlen ("--file-sep")) == 0) {
-                       if (i+1 < argc) {
-                               file_sep = (argv[i+1])[0];
-                               i++;
-                       } else {
-                               file_sep = 0;
-                       }
-               } else if(strcmp(argv[i], "--gtk3")==0) {
-                       gtk3_ok = TRUE;
-               } else if(strcmp(argv[i], "--")==0) {
-                       /*further arguments are files*/
-                       no_opts = TRUE;
-               } else if(strncmp(argv[i], "--", 2)==0) {
-                       /*unknown long option*/
-                       fprintf(stderr, "Unknown option '%s'!\n", argv[i]);
-                       print_usage(stderr);
-                       exit(1);
-               } else {
-                       /*by now we know we have a string starting with
-                         - which is a short option string*/
-                       char *p;
-                       for(p = argv[i] + 1; *p; p++) {
-                               switch(*p) {
-                               case 'w':
-                                       exit_on_warn=TRUE;
-                                       break;
-                               case 'n':
-                                       no_write = TRUE;
-                                       break;
-                               case 'h':
-                               case '?':
-                                       print_help();
-                                       exit(0);
-                               default:
-                                       fprintf(stderr,
-                                               "Unknown option '%c'!\n", *p);
-                                       print_usage(stderr);
-                                       exit(1);
-                               }
+                       m4_commandline = parse_m4_options(argc, argv, m4_clean);
+                       goto out;
+               case LOPT_VERSION:
+                       print_version();
+                       return 1;
+               default:
+                       if (optopt == '?') {
+               case 'h':
+                               print_help();
+                               return 1;
                        }
+
+                       /* Rewind getopt to get internal error messages. */
+                       optind = 0, opterr = 1;
+                       while (getopt_long(argc, argv, sopts, lopts, NULL)
+                              != opt);
+                       return -1;
+               case 0: /* no-op or option set by flag */;
                }
        }
 
-#if 0
-       /* if we are using m4, and got no filename, append m4 flags now */
-       if(!got_file && use_m4 && !use_m4_clean) {
-               char *new_commandline;
-               new_commandline=g_strconcat(m4_commandline,
-                                           " ",
-                                           M4_FLAGS,
-                                           NULL);
-               g_free(m4_commandline);
-               m4_commandline=new_commandline;
+       filename = argv[optind];
+       if (argc > optind+1) {
+               char *s = g_strjoinv(" ", argv+optind+1);
+               fprintf(stderr, "%s: Warning: excess arguments ignored: %s\n",
+                               g_get_prgname(), s);
+               g_free(s);
+               if (exit_on_warn)
+                       return -1;
+       }
+out:
+       file_sep = raw_file_sep[0];
+       if (raw_file_sep[0] && raw_file_sep[1]) {
+               fprintf(stderr, "%s: Warning: --file-sep characters beyond the first are ignored\n",
+                               g_get_prgname());
+               if (exit_on_warn)
+                       return -1;
+       }
+
+       if (show_m4_dir) {
+               printf("%s\n", M4_INCLUDE_DIR);
+               return 1;
        }
-#endif
+
+       return 0;
 }
 
 static void
@@ -4861,9 +4799,17 @@ compare_and_move (const char *old_filename)
 int
 main(int argc, char *argv[])
 {
+       int rc;
+
        g_set_prgname(argc > 0 ? argv[0] : "gob2");
 
-       parse_options(argc, argv);
+       rc = parse_options(argc, argv);
+       if (rc < 0) {
+               print_usage(stderr);
+               return EXIT_FAILURE;
+       } else if (rc > 0) {
+               return EXIT_SUCCESS;
+       }
 
        if(use_m4) {
                yyin = popen(m4_commandline, "r");