summaryrefslogtreecommitdiffstats
path: root/patches/argp-domain.patch
blob: 3297a328fac485470d095bef680aeeb4355d0b14 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
commit a304ab22b12f41712dbcd41b6ff001feb062b03f
Author: Colin Watson <cjwatson@debian.org>
Date:   Mon May 28 17:41:05 2018 +0100

    Fix domain handling in argp
    
    man-db sets its default text domain to "man-db", and keeps all Gnulib's
    strings in a separate "man-db-gnulib" domain, using 'gnulib-tool
    --po-domain=man-db' which results in
    -DDEFAULT_TEXT_DOMAIN=\"man-db-gnulib\". (I checked this general
    approach with Bruno a while back and he said it was fine.)
    
    However, Gnulib's argp implementation has three bugs which cause this
    not to work properly:
    
      * It hardcodes "libc" as a domain in two places. This is obviously
        wrong in Gnulib.
    
      * It uses argp_domain as both the domain used to translate its own
        strings (i.e. string literals in lib/argp-*.c) and the domain used
        to translate strings provided by the user, which normally have to
        use gettext_noop so that they can be used as 'struct argp_option'
        initialisers. This is dreadfully inconvenient because you have to
        copy strings about all over the place and keep your POT file up to
        date as the argp implementation changes. If argp is in libc then
        this is obviously impossible.
    
        Instead, argp should use DEFAULT_TEXT_DOMAIN to translate its own
        string literals (falling back to the default program domain if that
        is not set), and should reserve argp_domain for translating strings
        that appear in that argp structure.
    
      * In a number of places, argp uses the domain of the root argp
        structure when translating text from a child argp structure. This is
        the direct cause of Robert's bug, because the standard --help and
        --version options are implemented as a child argp structure with its
        own domain.
    
        My patch changes this to use argp_domain from the child instead.
        However, on reflection, I'm not certain that this is correct;
        arguably it needs to walk up the tree until it finds a domain to
        use. This depends on whether you think that argp_domain == NULL
        means "use default program domain" or "use same domain as parent
        argp structure".
    
    https://lists.gnu.org/r/bug-gnulib/2008-03/msg00144.html

diff --git a/gl/lib/argp-help.c b/gl/lib/argp-help.c
index 80cdb44937..4e600f269d 100644
--- a/gl/lib/argp-help.c
+++ b/gl/lib/argp-help.c
@@ -49,6 +49,16 @@
 # include "gettext.h"
 #endif
 
+#ifdef _LIBC
+# define ARGP_TEXT_DOMAIN "libc"
+#else
+# ifdef DEFAULT_TEXT_DOMAIN
+#  define ARGP_TEXT_DOMAIN DEFAULT_TEXT_DOMAIN
+# else
+#  define ARGP_TEXT_DOMAIN NULL
+# endif
+#endif
+
 #include "argp.h"
 #include "argp-fmtstream.h"
 #include "argp-namefrob.h"
@@ -148,7 +158,7 @@ validate_uparams (const struct argp_state *state, struct uparams *upptr)
         {
           __argp_failure (state, 0, 0,
                           dgettext (state == NULL ? NULL
-                                    : state->root_argp->argp_domain,
+                                    : ARGP_TEXT_DOMAIN,
                                     "\
 ARGP_HELP_FMT: %s value is less than or equal to %s"),
                           "rmargin", up->name);
@@ -224,7 +234,7 @@ fill_in_uparams (const struct argp_state *state)
                     if (unspec && !un->is_bool)
                       __argp_failure (state, 0, 0,
                                       dgettext (state == NULL ? NULL
-                                                : state->root_argp->argp_domain,
+                                                : ARGP_TEXT_DOMAIN,
                                                 "\
 %.*s: ARGP_HELP_FMT parameter requires a value"),
                                       (int) var_len, var);
@@ -235,7 +245,7 @@ fill_in_uparams (const struct argp_state *state)
               if (un == uparam_names + nuparam_names)
                 __argp_failure (state, 0, 0,
                                 dgettext (state == NULL ? NULL
-                                          : state->root_argp->argp_domain, "\
+                                          : ARGP_TEXT_DOMAIN, "\
 %.*s: Unknown ARGP_HELP_FMT parameter"),
                                 (int) var_len, var);
 
@@ -247,7 +257,7 @@ fill_in_uparams (const struct argp_state *state)
             {
               __argp_failure (state, 0, 0,
                               dgettext (state == NULL ? NULL
-                                        : state->root_argp->argp_domain,
+                                        : ARGP_TEXT_DOMAIN,
                                         "Garbage in ARGP_HELP_FMT: %s"), var);
               break;
             }
@@ -1256,7 +1266,7 @@ hol_entry_help (struct hol_entry *entry, const struct argp_state *state,
             __argp_fmtstream_putc (stream, *so);
             if (!have_long_opt || uparams.dup_args)
               arg (real, " %s", "[%s]",
-                   state == NULL ? NULL : state->root_argp->argp_domain,
+                   state == NULL ? NULL : entry->argp->argp_domain,
                    stream);
             else if (real->arg)
               hhstate->suppressed_dup_arg = 1;
@@ -1278,7 +1288,7 @@ hol_entry_help (struct hol_entry *entry, const struct argp_state *state,
                should be pretty rare anyway...  */
             __argp_fmtstream_puts (stream,
                                    dgettext (state == NULL ? NULL
-                                             : state->root_argp->argp_domain,
+                                             : entry->argp->argp_domain,
                                              opt->name));
           }
     }
@@ -1292,7 +1302,7 @@ hol_entry_help (struct hol_entry *entry, const struct argp_state *state,
             comma (uparams.long_opt_col, &pest);
             __argp_fmtstream_printf (stream, "--%s", opt->name);
             arg (real, "=%s", "[=%s]",
-                 state == NULL ? NULL : state->root_argp->argp_domain, stream);
+                 state == NULL ? NULL : entry->argp->argp_domain, stream);
           }
     }
 
@@ -1312,7 +1322,7 @@ hol_entry_help (struct hol_entry *entry, const struct argp_state *state,
   else
     {
       const char *tstr = real->doc ? dgettext (state == NULL ? NULL
-                                               : state->root_argp->argp_domain,
+                                               : entry->argp->argp_domain,
                                                real->doc) : 0;
       const char *fstr = filter_doc (tstr, real->key, entry->argp, state);
       if (fstr && *fstr)
@@ -1361,7 +1371,7 @@ hol_help (struct hol *hol, const struct argp_state *state,
   if (hhstate.suppressed_dup_arg && uparams.dup_args_note)
     {
       const char *tstr = dgettext (state == NULL ? NULL
-                                   : state->root_argp->argp_domain, "\
+                                   : ARGP_TEXT_DOMAIN, "\
 Mandatory or optional arguments to long options are also mandatory or \
 optional for any corresponding short options.");
       const char *fstr = filter_doc (tstr, ARGP_KEY_HELP_DUP_ARGS_NOTE,
@@ -1727,11 +1737,11 @@ _help (const struct argp *argp, const struct argp_state *state, FILE *stream,
 
           if (first_pattern)
             __argp_fmtstream_printf (fs, "%s %s",
-                                     dgettext (argp->argp_domain, "Usage:"),
+                                     dgettext (ARGP_TEXT_DOMAIN, "Usage:"),
                                      name);
           else
             __argp_fmtstream_printf (fs, "%s %s",
-                                     dgettext (argp->argp_domain, "  or: "),
+                                     dgettext (ARGP_TEXT_DOMAIN, "  or: "),
                                      name);
 
           /* We set the lmargin as well as the wmargin, because hol_usage
@@ -1742,7 +1752,7 @@ _help (const struct argp *argp, const struct argp_state *state, FILE *stream,
             /* Just show where the options go.  */
             {
               if (hol->num_entries > 0)
-                __argp_fmtstream_puts (fs, dgettext (argp->argp_domain,
+                __argp_fmtstream_puts (fs, dgettext (ARGP_TEXT_DOMAIN,
                                                      " [OPTION...]"));
             }
           else
@@ -1770,7 +1780,7 @@ _help (const struct argp *argp, const struct argp_state *state, FILE *stream,
 
   if (flags & ARGP_HELP_SEE)
     {
-      __argp_fmtstream_printf (fs, dgettext (argp->argp_domain, "\
+      __argp_fmtstream_printf (fs, dgettext (ARGP_TEXT_DOMAIN, "\
 Try '%s --help' or '%s --usage' for more information.\n"),
                                name, name);
       anything = 1;
@@ -1797,7 +1807,7 @@ Try '%s --help' or '%s --usage' for more information.\n"),
     {
       if (anything)
         __argp_fmtstream_putc (fs, '\n');
-      __argp_fmtstream_printf (fs, dgettext (argp->argp_domain,
+      __argp_fmtstream_printf (fs, dgettext (ARGP_TEXT_DOMAIN,
                                              "Report bugs to %s.\n"),
                                argp_program_bug_address);
       anything = 1;
@@ -1998,8 +2008,7 @@ __argp_failure (const struct argp_state *state, int status, int errnum,
 #  endif
 # endif
               if (! s && ! (s = strerror (errnum)))
-                s = dgettext (state->root_argp->argp_domain,
-                              "Unknown system error");
+                s = dgettext (ARGP_TEXT_DOMAIN, "Unknown system error");
               fputs_unlocked (s, stream);
 #endif
             }
diff --git a/gl/lib/argp-parse.c b/gl/lib/argp-parse.c
index 053495ec03..23f54f3aa7 100644
--- a/gl/lib/argp-parse.c
+++ b/gl/lib/argp-parse.c
@@ -40,6 +40,16 @@
 #endif
 #define N_(msgid) msgid
 
+#ifdef _LIBC
+# define ARGP_TEXT_DOMAIN "libc"
+#else
+# ifdef DEFAULT_TEXT_DOMAIN
+#  define ARGP_TEXT_DOMAIN DEFAULT_TEXT_DOMAIN
+# else
+#  define ARGP_TEXT_DOMAIN NULL
+# endif
+#endif
+
 #include "argp.h"
 #include "argp-namefrob.h"
 
@@ -135,7 +145,8 @@ argp_default_parser (int key, char *arg, struct argp_state *state)
 }
 
 static const struct argp argp_default_argp =
-  {argp_default_options, &argp_default_parser, NULL, NULL, NULL, NULL, "libc"};
+  {argp_default_options, &argp_default_parser, NULL, NULL, NULL, NULL,
+   ARGP_TEXT_DOMAIN};
 
 
 static const struct argp_option argp_version_options[] =
@@ -156,7 +167,7 @@ argp_version_parser (int key, char *arg, struct argp_state *state)
         fprintf (state->out_stream, "%s\n", argp_program_version);
       else
         __argp_error (state, "%s",
-                      dgettext (state->root_argp->argp_domain,
+                      dgettext (ARGP_TEXT_DOMAIN,
                                 "(PROGRAM ERROR) No version known!?"));
       if (! (state->flags & ARGP_NO_EXIT))
         exit (0);
@@ -168,7 +179,8 @@ argp_version_parser (int key, char *arg, struct argp_state *state)
 }
 
 static const struct argp argp_version_argp =
-  {argp_version_options, &argp_version_parser, NULL, NULL, NULL, NULL, "libc"};
+  {argp_version_options, &argp_version_parser, NULL, NULL, NULL, NULL,
+   ARGP_TEXT_DOMAIN};
 
 /* Returns the offset into the getopt long options array LONG_OPTIONS of a
    long option with called NAME, or -1 if none is found.  Passing NULL as
@@ -609,8 +621,7 @@ parser_finalize (struct parser *parser,
           if (!(parser->state.flags & ARGP_NO_ERRS)
               && parser->state.err_stream)
             fprintf (parser->state.err_stream,
-                     dgettext (parser->argp->argp_domain,
-                               "%s: Too many arguments\n"),
+                     dgettext (ARGP_TEXT_DOMAIN, "%s: Too many arguments\n"),
                      parser->state.name);
           err = EBADKEY;
         }
@@ -759,7 +770,7 @@ parser_parse_opt (struct parser *parser, int opt, char *val)
         N_("(PROGRAM ERROR) Option should have been recognized!?");
       if (group_key == 0)
         __argp_error (&parser->state, "-%c: %s", opt,
-                      dgettext (parser->argp->argp_domain, bad_key_err));
+                      dgettext (ARGP_TEXT_DOMAIN, bad_key_err));
       else
         {
           struct option *long_opt = parser->long_opts;
@@ -767,7 +778,7 @@ parser_parse_opt (struct parser *parser, int opt, char *val)
             long_opt++;
           __argp_error (&parser->state, "--%s: %s",
                         long_opt->name ? long_opt->name : "???",
-                        dgettext (parser->argp->argp_domain, bad_key_err));
+                        dgettext (ARGP_TEXT_DOMAIN, bad_key_err));
         }
     }