Prompted by Julian's review of this freshly-minted public API on IRC:

1. Question to API consumers (eg, client developers): would you find
this API useful?  For reference, the current docstring is attached.

2. Should we print the symbolic name in release builds?  For example:

    % $svn upgrade /
    svn: E155019 (WC_INVALID_OP_ON_CWD): Can't upgrade '/' as it is not a 
working copy root
    svn: E000002: Working copy database '/.svn/wc.db' not found
    svn: E000002: Additional errors:
    svn: E000002: Can't open file '/.svn/entries': No such file or directory
    zsh: exit 1     $svn upgrade /
    ### (in maintainer mode, this would show
    ###     subversion/libsvn_wc/wc_db.c:15006: 
(apr_err=SVN_ERR_WC_INVALID_OP_ON_CWD)
    ### as well.)

3. Should the API return the error code, or the error code without the
"SVN_ERR_" prefix?  I think stripping the error code is better because
then users who search for the error code will be more likely to reach
the users@ archive (with helpful posts) than commits@ archive (which
are unlikely to contain the information they seek).  Julian disagrees,
but I'll let him present his own case :-)

I also attached a patch which implements (2), in case we want it.
(It'll be trivial to modify it to suit whichever route we pick for (2)
and (3).)
/**
 * Return the symbolic name of an error code.  If the error code
 * is in svn_error_codes.h, return the name of the macro as a string.
 * If the error number is not recognised, return @c NULL.
 *
 * An error number may not be recognised because it was defined in a future
 * version of Subversion (e.g., a 1.9.x server may transmit a defined-in-1.9.0
 * error number to a 1.8.x client).
 *
 * An error number may be recognised @em incorrectly if the @c apr_status_t
 * value originates in another library (such as libserf) which also uses APR.
 * (This is a theoretical concern only: the @c apr_err member of #svn_error_t
 * should never contain a "foreign" @c apr_status_t value, and
 * in any case Subversion and Serf use non-overlapping subsets of the
 * @c APR_OS_START_USERERR range.)
 *
 * Support for error codes returned by APR itself (i.e., not in the
 * @c APR_OS_START_USERERR range, as defined in apr_errno.h) may be implemented
 * in the future.
 *
 * @note In rare cases, a single numeric code has more than one symbolic name.
 * (For example, #SVN_ERR_WC_NOT_DIRECTORY and #SVN_ERR_WC_NOT_WORKING_COPY).
 * In those cases, it is not guaranteed which symbolic name is returned.
 *
 * @since New in 1.8.
 */
const char *
svn_error_symbolic_name(apr_status_t statcode);
Index: subversion/libsvn_subr/error.c
===================================================================
--- subversion/libsvn_subr/error.c      (revision 1467305)
+++ subversion/libsvn_subr/error.c      (working copy)
@@ -483,9 +483,22 @@ print_error(svn_error_t *err, FILE *stream, const
 
   {
     const char *symbolic_name = svn_error_symbolic_name(err->apr_err);
+    const char *start;
+
+    /* ### Inside knowledge: re-add the SVN_ERR_ prefix.
+       (We could iterate error_table, but it's unlikely we'll add more error
+       codes that don't start with "SVN_ERR_" beyond these two.) */
+    if (symbolic_name
+        && !strcmp(symbolic_name, "SVN_WARNING")
+        && !strcmp(symbolic_name, "SVN_NO_ERROR"))
+      start = "";
+    else
+      start = "SVN_ERR_";
+
     if (symbolic_name)
       svn_error_clear(svn_cmdline_fprintf(stream, err->pool,
-                                          ": (apr_err=%s)\n", symbolic_name));
+                                          ": (apr_err=%s%s)\n",
+                                          start, symbolic_name));
     else
       svn_error_clear(svn_cmdline_fprintf(stream, err->pool,
                                           ": (apr_err=%d)\n", err->apr_err));
@@ -500,12 +513,19 @@ print_error(svn_error_t *err, FILE *stream, const
   /* Only print the same APR error string once. */
   else if (err->message)
     {
+      const char *symbolic_name = svn_error_symbolic_name(err->apr_err);
       svn_error_clear(svn_cmdline_fprintf(stream, err->pool,
-                                          "%sE%06d: %s\n",
-                                          prefix, err->apr_err, err->message));
+                                          "%sE%06d%s%s%s: %s\n",
+                                          prefix, err->apr_err,
+                                          symbolic_name ? " (" : "",
+                                          symbolic_name ? symbolic_name : "",
+                                          symbolic_name ? ")" : "",
+                                          err->message));
     }
   else
     {
+      const char *symbolic_name = svn_error_symbolic_name(err->apr_err);
+
       /* Is this a Subversion-specific error code? */
       if ((err->apr_err > APR_OS_START_USEERR)
           && (err->apr_err <= APR_OS_START_CANONERR))
@@ -520,8 +540,12 @@ print_error(svn_error_t *err, FILE *stream, const
         }
 
       svn_error_clear(svn_cmdline_fprintf(stream, err->pool,
-                                          "%sE%06d: %s\n",
-                                          prefix, err->apr_err, err_string));
+                                          "%sE%06d%s%s%s: %s\n",
+                                          prefix, err->apr_err,
+                                          symbolic_name ? " (" : "",
+                                          symbolic_name ? symbolic_name : "",
+                                          symbolic_name ? ")" : "",
+                                          err->message));
     }
 }
 
@@ -670,7 +694,12 @@ svn_error_symbolic_name(apr_status_t statcode)
 
   for (defn = error_table; defn->errdesc != NULL; ++defn)
     if (defn->errcode == (svn_errno_t)statcode)
-      return defn->errname;
+     {
+      if (!strncmp(defn->errname, "SVN_ERR_", 8))
+        return defn->errname + 8;
+      else
+        return defn->errname;
+     }
 
   /* "No error" is not in error_table. */
   if (statcode == SVN_NO_ERROR)

Reply via email to