]> git.ipfire.org Git - thirdparty/gettext.git/commitdiff
xgettext: Support per-file options wip/ueno/xgettext-suboptions
authorDaiki Ueno <ueno@gnu.org>
Wed, 2 Mar 2016 10:18:40 +0000 (19:18 +0900)
committerDaiki Ueno <ueno@gnu.org>
Wed, 2 Mar 2016 10:18:40 +0000 (19:18 +0900)
* autogen.sh (GNULIB_MODULES_TOOLS_FOR_SRC): Add getsubopt.
* gettext-tools/src/xgettext.c: Include <fnmatch.h>.
(long_options): Add --options.
(main): Handle --options.  Factor out language guessing to...
(filename_to_language): ...here.
(usage): Mention --options.
(enum suboption_type): New enum.
(suboption_tokens): New variable.
(struct suboption_ty, struct suboption_list_ty,
struct suboption_list_list_ty): New struct.
(suboption_list_destroy, suboption_list_insert,
suboption_list_list_destroy, suboption_list_list_insert): New function.
(suboptions): New variable.

autogen.sh
gettext-tools/src/xgettext.c

index 61a1ee588705b78231ca38e281fab0ddf855a404..7d22e7c621d32b849b2e15979e58678510777e1e 100755 (executable)
@@ -200,6 +200,7 @@ if ! $skip_gnulib; then
       gcd
       getline
       getopt-gnu
+      getsubopt
       gettext-h
       hash
       html-styled-ostream
index f269ce711eba2a0bd675d263d338d3936602c3df..b4eb586e250cdbd4eda94cb560b80e48e0bbc7ed 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <ctype.h>
 #include <errno.h>
+#include <fnmatch.h>
 #include <getopt.h>
 #include <stdio.h>
 #include <time.h>
@@ -258,6 +259,7 @@ static const struct option long_options[] =
   { "no-location", no_argument, NULL, CHAR_MAX + 16 },
   { "no-wrap", no_argument, NULL, CHAR_MAX + 4 },
   { "omit-header", no_argument, &xgettext_omit_header, 1 },
+  { "options", required_argument, NULL, 'O' },
   { "output", required_argument, NULL, 'o' },
   { "output-dir", required_argument, NULL, 'p' },
   { "package-name", required_argument, NULL, CHAR_MAX + 12 },
@@ -278,6 +280,87 @@ static const struct option long_options[] =
 };
 
 
+enum suboption_type
+{
+  OPT_FLAG,
+  OPT_KEYWORD,
+  OPT_LANGUAGE,
+  NSUBOPTS
+};
+
+static char * const suboption_tokens[] =
+{
+  "flag",
+  "keyword",
+  "language",
+  NULL
+};
+
+struct suboption_ty
+{
+  enum suboption_type type;
+  char *value;
+};
+
+struct suboption_list_ty
+{
+  char *pattern;
+  struct suboption_ty *items;
+  size_t nitems;
+  size_t nitems_max;
+};
+
+struct suboption_list_list_ty
+{
+  struct suboption_list_ty *items;
+  size_t nitems;
+  size_t nitems_max;
+};
+
+static void
+suboption_list_destroy (struct suboption_list_ty *opts)
+{
+  free (opts->items);
+}
+
+static void
+suboption_list_insert (struct suboption_list_ty *opts, struct suboption_ty *opt)
+{
+  if (opts->nitems == opts->nitems_max)
+    {
+      opts->nitems_max = opts->nitems_max * 2 + 1;
+      opts->items = xrealloc (opts->items,
+                              opts->nitems_max * sizeof (struct suboption_ty));
+    }
+  memcpy (&opts->items[opts->nitems++], opt, sizeof (struct suboption_ty));
+}
+
+static void
+suboption_list_list_destroy (struct suboption_list_list_ty *list)
+{
+  size_t i;
+
+  for (i = 0; i < list->nitems; i++)
+    suboption_list_destroy (&list->items[i]);
+  free (list->items);
+}
+
+static void
+suboption_list_list_insert (struct suboption_list_list_ty *list,
+                            struct suboption_list_ty *opts)
+{
+  if (list->nitems == list->nitems_max)
+    {
+      list->nitems_max = list->nitems_max * 2 + 1;
+      list->items = xrealloc (list->items,
+                              list->nitems_max * sizeof (struct suboption_list_ty));
+    }
+  memcpy (&list->items[list->nitems++], opts,
+          sizeof (struct suboption_list_ty));
+}
+
+static struct suboption_list_list_ty suboptions;
+
 /* The extractors must all be functions returning void and taking three
    arguments designating the input stream and one message domain list argument
    in which to add the messages.  */
@@ -314,6 +397,7 @@ static message_ty *construct_header (void);
 static void finalize_header (msgdomain_list_ty *mdlp);
 static extractor_ty language_to_extractor (const char *name);
 static const char *extension_to_language (const char *extension);
+static const char *filename_to_language (const char *filename);
 
 
 int
@@ -381,7 +465,7 @@ main (int argc, char *argv[])
   init_flag_table_vala ();
 
   while ((optchar = getopt_long (argc, argv,
-                                 "ac::Cd:D:eEf:Fhijk::l:L:m::M::no:p:sTVw:W:x:",
+                                 "ac::Cd:D:eEf:Fhijk::l:L:m::M::no:O:p:sTVw:W:x:",
                                  long_options, NULL)) != EOF)
     switch (optchar)
       {
@@ -518,6 +602,53 @@ main (int argc, char *argv[])
         output_file = optarg;
         break;
 
+      case 'O':
+        {
+          char *subopts = strchr (optarg, ':');
+
+          if (subopts != NULL)
+            {
+              char *pattern;
+              struct suboption_list_ty *opts;
+
+              pattern = xmalloc (subopts - optarg + 1);
+              memcpy (pattern, optarg, subopts - optarg);
+              pattern[subopts - optarg] = '\0';
+
+              opts = XZALLOC (struct suboption_list_ty);
+              opts->pattern = pattern;
+
+              subopts++;
+              while (*subopts != '\0')
+                {
+                  int suboptchar;
+                  char *value;
+
+                  suboptchar = getsubopt (&subopts, suboption_tokens, &value);
+                  switch (suboptchar)
+                    {
+                    case OPT_FLAG:
+                    case OPT_KEYWORD:
+                    case OPT_LANGUAGE:
+                      {
+                        struct suboption_ty opt;
+
+                        opt.type = suboptchar;
+                        opt.value = xstrdup (value);
+                        suboption_list_insert (opts, &opt);
+                      }
+                      break;
+
+                    default:
+                      error (EXIT_FAILURE, 0, _("unknown sub-option for -O"));
+                      break;
+                    }
+                }
+              suboption_list_list_insert (&suboptions, opts);
+            }
+        }
+        break;
+
       case 'p':
         {
           size_t len = strlen (optarg);
@@ -872,12 +1003,14 @@ warning: ITS rule file '%s' does not exist"), explicit_its_filename);
         }
       else
         {
-          const char *language_from_extension = NULL;
+          const char *language_from_filename = NULL;
           const char *base;
           char *reduced;
 
           base = strrchr (filename, '/');
-          if (!base)
+          if (base)
+            base++;
+          else
             base = filename;
 
           reduced = xstrdup (base);
@@ -886,31 +1019,14 @@ warning: ITS rule file '%s' does not exist"), explicit_its_filename);
                  && memcmp (reduced + strlen (reduced) - 3, ".in", 3) == 0)
             reduced[strlen (reduced) - 3] = '\0';
 
-          /* If no language is specified with -L, deduce it the extension.  */
+          /* If no language is specified with -L, guess it from the
+             --options and the file name extension.  */
           if (language == NULL)
-            {
-              const char *p;
-
-              /* Work out what the file extension is.  */
-              p = reduced + strlen (reduced);
-              for (; p > reduced && language_from_extension == NULL; p--)
-                {
-                  if (*p == '.')
-                    {
-                      const char *extension = p + 1;
-
-                      /* Derive the language from the extension, and
-                         the extractor function from the language.  */
-                      language_from_extension =
-                        extension_to_language (extension);
-                    }
-                }
-            }
+            language_from_filename = filename_to_language (reduced);
 
           /* If language is not determined from the file name
              extension, check ITS locating rules.  */
-          if (language_from_extension == NULL
-              && strcmp (filename, "-") != 0)
+          if (language_from_filename == NULL && strcmp (filename, "-") != 0)
             {
               const char *its_basename;
 
@@ -958,7 +1074,7 @@ warning: ITS rule file '%s' does not exist; check your gettext installation"),
 
           if (its_rules == NULL)
             {
-              if (language_from_extension == NULL)
+              if (language_from_filename == NULL)
                 {
                   const char *extension = strrchr (reduced, '.');
                   if (extension == NULL)
@@ -967,11 +1083,11 @@ warning: ITS rule file '%s' does not exist; check your gettext installation"),
                     extension++;
                   error (0, 0, _("\
 warning: file '%s' extension '%s' is unknown; will try C"), filename, extension);
-                  language_from_extension = "C";
+                  language_from_filename = "C";
                 }
 
               this_file_extractor =
-                language_to_extractor (language_from_extension);
+                language_to_extractor (language_from_filename);
             }
 
           free (reduced);
@@ -1033,6 +1149,8 @@ warning: file '%s' extension '%s' is unknown; will try C"), filename, extension)
   for (i = 0; i < SIZEOF (its_dirs); i++)
     free (its_dirs[i]);
 
+  suboption_list_list_destroy (&suboptions);
+
   exit (EXIT_SUCCESS);
 }
 
@@ -1102,6 +1220,9 @@ Input file interpretation:\n"));
       --from-code=NAME        encoding of input files\n\
                                 (except for Python, Tcl, Glade)\n"));
       printf (_("\
+  -O, --options=PAT:OPTIONS   specify options effective to files matching PAT\n\
+                                (flag, keyword, language)\n"));
+      printf (_("\
 By default the input files are assumed to be in ASCII.\n"));
       printf ("\n");
       printf (_("\
@@ -4013,3 +4134,45 @@ extension_to_language (const char *extension)
       return tp->language;
   return NULL;
 }
+
+static const char *
+filename_to_language (const char *filename)
+{
+  const char *p;
+  size_t i;
+
+  for (i = 0; i < suboptions.nitems; i++)
+    {
+      struct suboption_list_ty *opts =
+        &suboptions.items[suboptions.nitems - 1 - i];
+
+      if (fnmatch (opts->pattern, filename, FNM_PATHNAME) == 0)
+        {
+          size_t j;
+
+          for (j = 0; j < opts->nitems; j++)
+            {
+              struct suboption_ty *opt = &opts->items[j];
+
+              if (opt->type == OPT_LANGUAGE)
+                return opt->value;
+            }
+        }
+    }
+
+  /* Work out what the file extension is.  */
+  p = filename + strlen (filename);
+  for (; p > filename; p--)
+    {
+      if (*p == '.')
+        {
+          const char *extension = p + 1;
+
+          /* Derive the language from the extension, and
+             the extractor function from the language.  */
+          return extension_to_language (extension);
+        }
+    }
+
+  return NULL;
+}