It is quite annoying that some of the more common error messages, the

svn: invalid option: --gurgle

kind, are entirely untranslatable because they are printed directly by APR which does not have any concept of translation at all. (This was reported before but met with silence: http://svn.haxx.se/dev/archive-2008-05/1445.shtml)

It is not easy to fix it in a clean way; ideally, APR would return a detailed error code together with the required string parameters, but it doesn't. Even if we did change APR to that effect, it would be an incompatibility requiring a new APR version for use with Subversion.

This patch, instead, installs an apr_getopt_err_fn_t, acting as a replacement for fprintf. It is admittedly a hack, but quite a localised one -- it doesn't foul up any other code -- and does not have any negative effects that I can think of. In short, it should be a strict improvement.

Should APR's getopt error strings change, all that will happen is that they are shown untranslated, just like any other translated strings.

Index: subversion/libsvn_subr/cmdline.c
===================================================================
--- subversion/libsvn_subr/cmdline.c    (revision 1478474)
+++ subversion/libsvn_subr/cmdline.c    (working copy)
@@ -634,6 +634,65 @@
   return SVN_NO_ERROR;
 }
 
+/* Registered as apr_getopt_t->errfn, this fprintf-compatible function
+   is called by APR to emit option parsing error messages. We
+   intercept some of those here in order to make them available for
+   translation. */
+static void
+emit_option_error(void *baton, const char *fmt, ...)
+{
+  apr_pool_t *pool = baton;
+  svn_boolean_t match = TRUE;
+  svn_error_t *err = NULL;
+  va_list va;
+  va_start(va, fmt);
+  if (strcmp(fmt, "%s: %s: %s\n") == 0)
+    {
+      const char *prog = va_arg(va, const char *);
+      const char *msg = va_arg(va, const char *);
+      const char *par = va_arg(va, const char *);
+      if (strcmp(msg, "invalid option") == 0)
+        err = svn_cmdline_fprintf(stderr, pool,
+                                  _("%s: invalid option: %s\n"), prog, par);
+      else if (strcmp(msg, "missing argument") == 0)
+        err = svn_cmdline_fprintf(stderr, pool,
+                                  _("%s: missing argument: %s\n"), prog, par);
+      else if (strcmp(msg, "erroneous argument") == 0)
+        err = svn_cmdline_fprintf(stderr, pool,
+                                  _("%s: erroneous argument: %s\n"), prog, 
par);
+      else
+        match = FALSE;
+    }
+  else if (strcmp(fmt, "%s: %s: %c\n") == 0)
+    {
+      const char *prog = va_arg(va, const char *);
+      const char *msg = va_arg(va, const char *);
+      int par = va_arg(va, int);
+      if (strcmp(msg, "invalid option character") == 0)
+        err = svn_cmdline_fprintf(stderr, pool,
+                                  _("%s: invalid option character: %c\n"),
+                                  prog, par);
+      else if (strcmp(msg, "missing argument") == 0)
+        err = svn_cmdline_fprintf(stderr, pool,
+                                  _("%s: missing argument: %c\n"), prog, par);
+      else
+        match = FALSE;
+    }
+  else
+    match = FALSE;
+
+  if (err)
+    svn_error_clear(err);
+
+  if (!match)
+    {
+      /* This is what apr_getopt normally does with error messages, so it
+         should be safe. */
+      vfprintf(stderr, fmt, va);
+    }
+  va_end(va);
+}
+
 svn_error_t *
 svn_cmdline__getopt_init(apr_getopt_t **os,
                          int argc,
@@ -644,6 +703,8 @@
   if (apr_err)
     return svn_error_wrap_apr(apr_err,
                               _("Error initializing command line arguments"));
+  (*os)->errfn = emit_option_error;
+  (*os)->errarg = pool;
   return SVN_NO_ERROR;
 }
 

Reply via email to