[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

[PATCH] UTF-8 third round...

From: Marcus Comstedt <marcus_at_mc.pp.se>
Date: 2002-05-30 17:57:20 CEST

[ Hmm. The Mad MIMEr @ subversion.tigris.org ate my first mail,
  removing all parts and giving up because nothing was left.
  Trying again... ]

Ok, as promised, here is a new update of the UTF-8 patch. The
following things are known still not to be fixed:

* Config file reading. config_file.c uses stdio rather than APR, so I
  skipped over this file for the moment. UTF conversion of the paths
  can probably be omitted (with appropriate comments to that effect)
  as they don't seem to be shared with the rest of the code, but
  maybe the contents of the config file itself needs recoding?
  What needs to be done in config_win.c will have to be up to somebody
  in the Windows camp to decide.

* svnadmin/svnlook

* Server side? I don't know if mod_dav_svn needs to do anything
  special here or whether Apache will take care of everything.
  Repository URL:s are passed as UTF-8 to Neon. I have not audited
  what happens to them beyond that.

Things that need further consideration (although that can probably be
deferred for now):

* Property values. Currently, the command line client will recode all
  property values to UTF-8. This is needed for properties like
  svn:ignore, but not desirable for real binary properties. Some
  mechanism for distinguishing between text properties and binary
  properties will be needed.

* Keyword expansion. What should happen if a keyword expands to some
  non-ASCII string? If the charset of the file is known, then
  probably the string should be recoded to that charset. If not,
  should the locale-specific charset be used? Or maybe even refuse
  expansion with a warning?

Implementation note: I'm now using apr_xlate instead of calling iconv
directly. This means that it's now up to APR to worry about
portability. Unfortunately, apr_xlate seems to make several of the
mistakes that Ulrich cautioned about. In particular, it ignores
return codes greater than 0 from iconv. It should probably return
some other apr_status_t than APR_SUCCESS in this case, to indicate an
inexact translation. Of course, we'll need to decide on in which
cases an inexact translation is acceptable as well. For a pathname,
probably not. For an error message, probably. But what about a
property diff, for example?

I divided the patch into two parts this time, one for the libraries
and one for the command line client. The client patch depends on the
library patch, but not the other way around. There is also a small
patch to APR that should probably be sent somewhere else. It fixes
the case where a converter is requested that converts from a charset
to that very same charset. Previously apr_xlate_open would just pass
the request on to iconv_open, which at least on Solaris may refuse
such a conversion. Now it will instead simply make an internal
identity translator if topage and frompage are the same.

  // Marcus

Index: i18n/unix/xlate.c
===================================================================
RCS file: /home/cvspublic/apr/i18n/unix/xlate.c,v
retrieving revision 1.25
diff -u -r1.25 xlate.c
--- i18n/unix/xlate.c 16 Apr 2002 20:25:57 -0000 1.25
+++ i18n/unix/xlate.c 30 May 2002 14:18:34 -0000
@@ -219,6 +219,14 @@
 }
 #endif /* HAVE_ICONV */
 
+static void make_identity_table(apr_xlate_t *convset)
+{
+ int i;
+ convset->sbcs_table = apr_palloc(convset->pool, 256);
+ for (i=0; i<256; i++)
+ convset->sbcs_table[i] = i;
+}
+
 apr_status_t apr_xlate_open(apr_xlate_t **convset, const char *topage,
                             const char *frompage, apr_pool_t *pool)
 {
@@ -251,6 +259,12 @@
     set found to non-zero if found in the cache
 #endif
 
+ if (!found && !strcmp(topage, frompage)) {
+ /* to and from are the same */
+ found = 1;
+ make_identity_table(new);
+ }
+
 #ifdef HAVE_ICONV
     if (!found) {
         new->ich = iconv_open(topage, frompage);
@@ -259,7 +273,8 @@
         }
         found = 1;
         check_sbcs(new);
- }
+ } else
+ new->ich = (iconv_t)-1;
 #endif /* HAVE_ICONV */
 
     if (found) {

Index: ./configure.in
===================================================================
--- ./configure.in
+++ ./configure.in Fri May 17 17:19:18 2002
@@ -360,6 +360,16 @@
 AC_SUBST(SVN_RA_LIB_LINK)
 
 
+dnl descide whether we want to activate real UTF-8 translations
+AC_ARG_ENABLE(utf8,
+[ --enable-utf8 Turn on real UTF-8 strings],
+[
+ if test "$enableval" = "yes"; then
+ enable_utf8=yes
+ CFLAGS="$CFLAGS -DSVN_UTF8";
+ fi
+])
+
 dnl Pass some config data ----------------------------
 
 AC_SUBST(abs_builddir)
Index: ./subversion/include/svn_io.h
===================================================================
--- ./subversion/include/svn_io.h
+++ ./subversion/include/svn_io.h Wed May 29 00:00:35 2002
@@ -456,6 +456,44 @@
                                      apr_pool_t *pool);
                                       
 
+/* Just like apr_file_open, but handles charset conversion of the filename */
+svn_error_t *
+svn_io_file_open (apr_file_t **new_file, const char *fname,
+ apr_int32_t flag, apr_fileperms_t perm,
+ apr_pool_t *pool);
+
+/* Just like apr_stat, but handles charset conversion of the filename */
+svn_error_t *
+svn_io_stat (apr_finfo_t *finfo, const char *fname,
+ apr_int32_t wanted, apr_pool_t *pool);
+
+/* Just like apr_file_rename, but handles charset conversion of the filename */
+svn_error_t *
+svn_io_file_rename (const char *from_path, const char *to_path,
+ apr_pool_t *pool);
+
+/* Just like apr_dir_make, but handles charset conversion of the filename */
+svn_error_t *
+svn_io_dir_make (const char *path, apr_fileperms_t perm, apr_pool_t *pool);
+
+/* Just like apr_dir_open, but handles charset conversion of the filename */
+svn_error_t *
+svn_io_dir_open (apr_dir_t **new_dir, const char *dirname, apr_pool_t *pool);
+
+/* Just like apr_dir_remove, but handles charset conversion of the filename */
+/* No not confuse with svn_io_remove_dir, which is recursive. */
+svn_error_t *
+svn_io_dir_remove_nonrecursive (const char *dirname, apr_pool_t *pool);
+
+/* Just like apr_dir_read, but handles charset conversion of entry names */
+svn_error_t *
+svn_io_dir_read (apr_finfo_t *finfo, apr_int32_t wanted, apr_dir_t *thedir);
+
+/* Just like apr_file_printf, but handles charset conversion of the
+ printed data */
+svn_error_t *
+svn_io_file_printf (apr_file_t *fptr, const char *format, ...);
+
 
 #ifdef __cplusplus
 }
Index: ./subversion/include/svn_path.h
===================================================================
--- ./subversion/include/svn_path.h
+++ ./subversion/include/svn_path.h Wed May 29 17:17:09 2002
@@ -189,7 +189,7 @@
 /* Convert RELATIVE path to an absolute path and return the results in
    *PABSOLUTE, allocated in POOL. */
 svn_error_t *
-svn_path_get_absolute (char **pabsolute,
+svn_path_get_absolute (const char **pabsolute,
                        const char *relative,
                        apr_pool_t *pool);
 
Index: ./subversion/include/svn_utf.h
===================================================================
--- /dev/null Thu May 30 16:26:59 2002
+++ ./subversion/include/svn_utf.h Mon May 27 16:44:57 2002
@@ -0,0 +1,87 @@
+/* svn_utf.h: UTF-8 code shared by various Subversion libraries.
+ *
+ * ====================================================================
+ * Copyright (c) 2000-2002 CollabNet. All rights reserved.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://subversion.tigris.org/license-1.html.
+ * If newer versions of this license are posted there, you may use a
+ * newer version instead, at your option.
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals. For exact contribution history, see the revision
+ * history and logs, available at http://subversion.tigris.org/.
+ * ====================================================================
+ */
+
+
+
+#ifndef SVN_UTF_H
+#define SVN_UTF_H
+
+#include "svn_error.h"
+#include "svn_delta.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+/*** UTF-8 conversions ***/
+
+/* Convert a stringbuf from native character encoding to UTF-8 */
+svn_error_t *svn_utf_stringbuf_to_utf8 (const svn_stringbuf_t *src,
+ svn_stringbuf_t **dest,
+ apr_pool_t *pool);
+
+/* Convert a C string from native character encoding to an UTF-8 stringbuf */
+svn_error_t *svn_utf_cstring_to_utf8_stringbuf (const char *src,
+ svn_stringbuf_t **dest,
+ apr_pool_t *pool);
+
+/* Convert a C string from native character encoding to UTF-8 */
+svn_error_t *svn_utf_cstring_to_utf8 (const char *src, const char **dest,
+ apr_pool_t *pool);
+
+/* Convert a stringbuf from UTF-8 to native character encoding */
+svn_error_t *svn_utf_stringbuf_from_utf8 (const svn_stringbuf_t *src,
+ svn_stringbuf_t **dest,
+ apr_pool_t *pool);
+
+/* Convert a string from UTF-8 to native character encoding */
+svn_error_t *svn_utf_string_from_utf8 (const svn_string_t *src,
+ const svn_string_t **dest,
+ apr_pool_t *pool);
+
+/* Convert a C string from UTF-8 to native character encoding */
+svn_error_t *svn_utf_cstring_from_utf8 (const char *src, const char **dest,
+ apr_pool_t *pool);
+
+/* Convert an UTF-8 stringbuf to a C string with native character encoding */
+svn_error_t *svn_utf_cstring_from_utf8_stringbuf (const svn_stringbuf_t *src,
+ const char **dest, apr_pool_t *pool);
+
+/* Convert an UTF-8 stringf to a C string with native character encoding */
+svn_error_t *svn_utf_cstring_from_utf8_string (const svn_string_t *src,
+ const char **dest, apr_pool_t *pool);
+
+
+
+/* Convert a C string from UTF-8 to native character encoding */
+/* This function is for error message printing only... */
+const char *svn_utf_utf8_to_native (const char *utf8_string,
+ char *buf, apr_size_t bufsize);
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* SVN_XML_H */
+
+/* ----------------------------------------------------------------
+ * local variables:
+ * eval: (load-file "../../tools/dev/svn-dev.el")
+ * end:
+ */
Index: ./subversion/libsvn_client/add.c
===================================================================
--- ./subversion/libsvn_client/add.c
+++ ./subversion/libsvn_client/add.c Wed May 29 14:27:00 2002
@@ -29,6 +29,7 @@
 #include "svn_pools.h"
 #include "svn_error.h"
 #include "svn_path.h"
+#include "svn_io.h"
 #include "client.h"
 
 
@@ -43,7 +44,7 @@
 {
   apr_dir_t *dir;
   apr_finfo_t this_entry;
- apr_status_t apr_err;
+ svn_error_t *err;
   apr_pool_t *subpool;
   apr_int32_t flags = APR_FINFO_TYPE | APR_FINFO_NAME;
 
@@ -57,10 +58,10 @@
 
   /* Read the directory entries one by one and add those things to
      revision control. */
- apr_err = apr_dir_open (&dir, dirname, pool);
- for (apr_err = apr_dir_read (&this_entry, flags, dir);
- apr_err == APR_SUCCESS;
- apr_err = apr_dir_read (&this_entry, flags, dir))
+ SVN_ERR (svn_io_dir_open (&dir, dirname, pool));
+ for (err = svn_io_dir_read (&this_entry, flags, dir);
+ err == SVN_NO_ERROR;
+ err = svn_io_dir_read (&this_entry, flags, dir))
     {
       const char *fullpath;
 
@@ -90,23 +91,24 @@
       svn_pool_clear (subpool);
     }
 
- /* Destroy the per-iteration pool. */
- svn_pool_destroy (subpool);
-
   /* Check that the loop exited cleanly. */
- if (! (APR_STATUS_IS_ENOENT (apr_err)))
+ if (! (APR_STATUS_IS_ENOENT (err->apr_err)))
     {
       return svn_error_createf
- (apr_err, 0, NULL, subpool, "error during recursive add of `%s'",
- dirname);
+ (err->apr_err, err->src_err, err, subpool,
+ "error during recursive add of `%s'", dirname);
     }
   else /* Yes, it exited cleanly, so close the dir. */
     {
- apr_err = apr_dir_close (dir);
+ apr_status_t apr_err = apr_dir_close (dir);
       if (apr_err)
         return svn_error_createf
           (apr_err, 0, NULL, subpool, "error closing dir `%s'", dirname);
     }
+
+ /* Destroy the per-iteration pool. */
+ svn_pool_destroy (subpool);
+
   return SVN_NO_ERROR;
 }
 
@@ -145,8 +147,6 @@
                   void *notify_baton,
                   apr_pool_t *pool)
 {
- apr_status_t apr_err;
-
   /* If this is a URL, we want to drive a commit editor to create this
      directory. */
   if (svn_path_is_url (path))
@@ -229,9 +229,7 @@
     }
 
   /* This is a regular "mkdir" + "svn add" */
- apr_err = apr_dir_make (path, APR_OS_DEFAULT, pool);
- if (apr_err)
- return svn_error_create (apr_err, 0, NULL, pool, path);
+ SVN_ERR (svn_io_dir_make (path, APR_OS_DEFAULT, pool));
   
   return svn_wc_add (path, NULL, SVN_INVALID_REVNUM,
                      notify_func, notify_baton, pool);
Index: ./subversion/libsvn_client/apply_edits.c
===================================================================
--- ./subversion/libsvn_client/apply_edits.c
+++ ./subversion/libsvn_client/apply_edits.c Wed May 29 14:29:55 2002
@@ -29,6 +29,7 @@
 #include "svn_string.h"
 #include "svn_error.h"
 #include "svn_path.h"
+#include "svn_io.h"
 #include "client.h"
 
 
@@ -126,20 +127,16 @@
           svn_boolean_t is_update)
 {
   svn_error_t *err;
- apr_status_t apr_err;
   apr_file_t *in = NULL;
 
   assert (path != NULL);
   assert (xml_src != NULL);
 
   /* Open the XML source file. */
- apr_err = apr_file_open (&in, xml_src,
- (APR_READ | APR_CREATE),
- APR_OS_DEFAULT,
- pool);
- if (apr_err)
- return svn_error_createf (apr_err, 0, NULL, pool,
- "unable to open %s", xml_src);
+ SVN_ERR (svn_io_file_open (&in, xml_src,
+ (APR_READ | APR_CREATE),
+ APR_OS_DEFAULT,
+ pool));
 
   /* Check out the delta. */
   err = apply_delta (before_editor,
Index: ./subversion/libsvn_client/auth.c
===================================================================
--- ./subversion/libsvn_client/auth.c
+++ ./subversion/libsvn_client/auth.c Wed May 29 00:00:53 2002
@@ -32,6 +32,7 @@
 #include "svn_error.h"
 #include "svn_io.h"
 #include "svn_path.h"
+#include "svn_utf.h"
 
 #include "client.h"
 
@@ -99,7 +100,7 @@
           apr_uid_t uid;
           apr_gid_t gid;
           apr_status_t status;
-
+
           status = apr_current_userid (&uid, &gid, pool);
           if (status)
             return
@@ -110,7 +111,8 @@
           if (status)
             return svn_error_create(status, 0, NULL, pool,
                                     "Error in UID->username.");
- *username = un;
+
+ SVN_ERR (svn_utf_cstring_to_utf8 (un, (const char **)username, pool));
         }
 
       /* Store a copy of the username in the auth_baton too. */
Index: ./subversion/libsvn_client/checkout.c
===================================================================
--- ./subversion/libsvn_client/checkout.c
+++ ./subversion/libsvn_client/checkout.c Thu May 30 15:52:35 2002
@@ -32,6 +32,7 @@
 #include "svn_types.h"
 #include "svn_error.h"
 #include "svn_path.h"
+#include "svn_io.h"
 #include "client.h"
 
 
@@ -272,17 +273,14 @@
   /* else we're checking out from xml */
   else
     {
- apr_status_t apr_err;
       apr_file_t *in = NULL;
       void *wrap_edit_baton;
       const svn_delta_edit_fns_t *wrap_editor;
 
       /* Open xml file. */
- apr_err = apr_file_open (&in, xml_src, (APR_READ | APR_CREATE),
- APR_OS_DEFAULT, pool);
- if (apr_err)
- return svn_error_createf (apr_err, 0, NULL, pool,
- "unable to open %s", xml_src);
+ SVN_ERR (svn_io_file_open (&in, xml_src,
+ (APR_READ | APR_CREATE),
+ APR_OS_DEFAULT, pool));
 
       /* ### todo: This is a TEMPORARY wrapper around our editor so we
          can use it with an old driver. */
Index: ./subversion/libsvn_client/commit.c
===================================================================
--- ./subversion/libsvn_client/commit.c
+++ ./subversion/libsvn_client/commit.c Wed May 29 17:30:15 2002
@@ -63,10 +63,7 @@
   apr_status_t apr_err;
 
   /* Get an apr file for PATH. */
- apr_err = apr_file_open (&f, path, APR_READ, APR_OS_DEFAULT, pool);
- if (apr_err)
- return svn_error_createf (apr_err, 0, NULL, pool,
- "error opening `%s' for reading", path);
+ SVN_ERR (svn_io_file_open (&f, path, APR_READ, APR_OS_DEFAULT, pool));
   
   /* Get a readable stream of the file's contents. */
   contents = svn_stream_from_aprfile (f, pool);
@@ -146,14 +143,13 @@
   apr_finfo_t finfo;
   apr_status_t apr_err;
   apr_int32_t flags = APR_FINFO_TYPE | APR_FINFO_NAME;
+ svn_error_t *err;
+
+ SVN_ERR (svn_io_dir_open (&dir, path, pool));
 
- if ((apr_err = apr_dir_open (&dir, path, pool)))
- return svn_error_createf (apr_err, 0, NULL, pool,
- "unable to open directory %s", path);
-
- for (apr_err = apr_dir_read (&finfo, flags, dir);
- apr_err == APR_SUCCESS;
- svn_pool_clear (subpool), apr_err = apr_dir_read (&finfo, flags, dir))
+ for (err = svn_io_dir_read (&finfo, flags, dir);
+ err == SVN_NO_ERROR;
+ svn_pool_clear (subpool), err = svn_io_dir_read (&finfo, flags, dir))
     {
       const char *this_path, *this_edit_path;
 
@@ -214,9 +210,10 @@
     }
 
   /* Check that the loop exited cleanly. */
- if (! (APR_STATUS_IS_ENOENT (apr_err)))
+ if (! (APR_STATUS_IS_ENOENT (err->apr_err)))
     return svn_error_createf
- (apr_err, 0, NULL, subpool, "error during import of `%s'", path);
+ (err->apr_err, err->src_err, err, subpool,
+ "error during import of `%s'", path);
 
   /* Yes, it exited cleanly, so close the dir. */
   else if ((apr_err = apr_dir_close (dir)))
@@ -347,13 +344,10 @@
                 const char *xml_file,
                 apr_pool_t *pool)
 {
- apr_status_t apr_err;
-
   /* Open the xml file for writing. */
- if ((apr_err = apr_file_open (xml_hnd, xml_file, (APR_WRITE | APR_CREATE),
- APR_OS_DEFAULT, pool)))
- return svn_error_createf (apr_err, 0, NULL, pool,
- "error opening %s", xml_file);
+ SVN_ERR (svn_io_file_open (xml_hnd, xml_file,
+ (APR_WRITE | APR_CREATE),
+ APR_OS_DEFAULT, pool));
   
   /* ... we need an XML commit editor. */
   return svn_delta_get_xml_editor (svn_stream_from_aprfile (*xml_hnd, pool),
@@ -656,7 +650,7 @@
   const char *committed_author = NULL;
   svn_ra_plugin_t *ra_lib;
   const char *base_dir;
- char *base_url;
+ const char *base_url;
   apr_array_header_t *rel_targets;
   apr_hash_t *committables, *locked_dirs, *tempfiles = NULL;
   apr_array_header_t *commit_items;
@@ -801,7 +795,7 @@
 
   /* Determine prefix to strip from the commit notify messages */
   /* ### this cast is a kluge */
- if ((cmt_err = svn_path_get_absolute ((char **) &display_dir,
+ if ((cmt_err = svn_path_get_absolute (&display_dir,
                                         display_dir, pool)))
     goto cleanup;
   display_dir = svn_path_get_longest_ancestor (display_dir, base_dir, pool);
Index: ./subversion/libsvn_client/commit_util.c
===================================================================
--- ./subversion/libsvn_client/commit_util.c
+++ ./subversion/libsvn_client/commit_util.c Wed May 29 17:30:21 2002
@@ -541,7 +541,7 @@
 
 
 svn_error_t *
-svn_client__condense_commit_items (char **base_url,
+svn_client__condense_commit_items (const char **base_url,
                                    apr_array_header_t *commit_items,
                                    apr_pool_t *pool)
 {
Index: ./subversion/libsvn_client/copy.c
===================================================================
--- ./subversion/libsvn_client/copy.c
+++ ./subversion/libsvn_client/copy.c Wed May 29 17:30:25 2002
@@ -30,6 +30,7 @@
 #include "svn_pools.h"
 #include "svn_error.h"
 #include "svn_path.h"
+#include "svn_io.h"
 #include "client.h"
 
 
@@ -464,7 +465,8 @@
   apr_array_header_t *commit_items;
   svn_error_t *cmt_err = NULL, *unlock_err = NULL, *cleanup_err = NULL;
   svn_boolean_t commit_in_progress = FALSE;
- char *base_path, *base_url;
+ const char *base_path;
+ const char *base_url;
 
   /* Check the SRC_PATH. */
   SVN_ERR (svn_io_check_path (src_path, &src_kind, pool));
@@ -745,12 +747,10 @@
       apr_hash_index_t *hi;
       
       /* Open DST_PATH for writing. */
- status = apr_file_open (&fp, dst_path, (APR_CREATE | APR_WRITE),
- APR_OS_DEFAULT, pool);
- if (status)
- return svn_error_createf (status, 0, NULL, pool,
- "failed to open file '%s' for writing.",
- dst_path);
+ SVN_ERR_W (svn_io_file_open (&fp, dst_path,
+ (APR_CREATE | APR_WRITE),
+ APR_OS_DEFAULT, pool),
+ "failed to open file for writing.");
 
       /* Create a generic stream that operates on this file. */
       fstream = svn_stream_from_aprfile (fp, pool);
Index: ./subversion/libsvn_client/diff.c
===================================================================
--- ./subversion/libsvn_client/diff.c
+++ ./subversion/libsvn_client/diff.c Wed May 29 00:00:56 2002
@@ -54,9 +54,9 @@
 {
   int i;
 
- apr_file_printf (file, "\nProperty changes on: %s\n", path);
- apr_file_printf (file,
- "___________________________________________________________________\n");
+ SVN_ERR (svn_io_file_printf (file, "\nProperty changes on: %s\n", path));
+ SVN_ERR (svn_io_file_printf (file,
+ "___________________________________________________________________\n"));
 
   for (i = 0; i < propchanges->nelts; i++)
     {
@@ -71,18 +71,17 @@
       else
         original_value = NULL;
       
- apr_file_printf (file, "Name: %s\n", propchange->name);
+ SVN_ERR (svn_io_file_printf (file, "Name: %s\n", propchange->name));
 
       if (original_value != NULL)
- apr_file_printf (file, " - %s\n", original_value->data);
+ SVN_ERR (svn_io_file_printf (file, " - %s\n", original_value->data));
 
       if (propchange->value != NULL)
- apr_file_printf (file, " + %s\n", propchange->value->data);
+ SVN_ERR (svn_io_file_printf (file, " + %s\n",
+ propchange->value->data));
     }
 
- apr_file_printf (file, "\n");
-
- return SVN_NO_ERROR;
+ return svn_io_file_printf (file, "\n");
 }
 
 
@@ -135,9 +134,9 @@
     }
 
   /* Print out the diff header. */
- apr_file_printf (outfile, "Index: %s\n", label ? label : tmpfile1);
- apr_file_printf (outfile,
- "===================================================================\n");
+ SVN_ERR (svn_io_file_printf (outfile, "Index: %s\n", label? label:tmpfile1));
+ SVN_ERR (svn_io_file_printf (outfile,
+ "===================================================================\n"));
 
   SVN_ERR (svn_io_run_diff (".", args, nargs, path,
                             tmpfile1, tmpfile2,
Index: ./subversion/libsvn_client/repos_diff.c
===================================================================
--- ./subversion/libsvn_client/repos_diff.c
+++ ./subversion/libsvn_client/repos_diff.c Wed May 29 16:12:41 2002
@@ -32,6 +32,8 @@
 #include "svn_wc.h"
 #include "svn_pools.h"
 #include "svn_path.h"
+#include "svn_io.h"
+#include "svn_utf.h"
 
 #include "client.h"
 
@@ -135,7 +137,7 @@
 /* Data used by the apr pool temp file cleanup handler */
 struct temp_file_cleanup_s {
   /* The path to the file to be deleted */
- const char *path;
+ const char *path; /* Note: _not_ UTF-8! */
   /* The pool to which the deletion of the file is linked. */
   apr_pool_t *pool;
 };
@@ -194,6 +196,7 @@
 {
   struct temp_file_cleanup_s *s = arg;
 
+ /* This is ok, path has already been de-UTF-8-ized. */
   return apr_file_remove (s->path, s->pool);
 }
 
@@ -227,7 +230,7 @@
                             apr_pool_t *pool)
 {
   struct temp_file_cleanup_s *s = apr_palloc (pool, sizeof (*s));
- s->path = path;
+ SVN_ERR (svn_utf_cstring_from_utf8 (path, &s->path, pool));
   s->pool = pool;
   apr_pool_cleanup_register (s->pool, s, temp_file_plain_cleanup_handler,
                              temp_file_child_cleanup_handler);
@@ -526,27 +529,18 @@
                  void **handler_baton)
 {
   struct file_baton *b = file_baton;
- apr_status_t status;
 
   /* Open the file to be used as the base for second revision */
- status = apr_file_open (&(b->file_start_revision),
- b->path_start_revision,
- APR_READ, APR_OS_DEFAULT, b->pool);
- if (status)
- return svn_error_createf (status, 0, NULL, b->pool,
- "failed to open file '%s'",
- b->path_start_revision);
+ SVN_ERR (svn_io_file_open (&(b->file_start_revision),
+ b->path_start_revision,
+ APR_READ, APR_OS_DEFAULT, b->pool));
 
   /* Open the file that will become the second revision after applying the
      text delta, it starts empty */
   SVN_ERR (create_empty_file (&(b->path_end_revision), b->pool));
   SVN_ERR (temp_file_cleanup_register (b->path_end_revision, b->pool));
- status = apr_file_open (&(b->file_end_revision), b->path_end_revision,
- APR_WRITE, APR_OS_DEFAULT, b->pool);
- if (status)
- return svn_error_createf (status, 0, NULL, b->pool,
- "failed to open file '%s'",
- b->path_end_revision);
+ SVN_ERR (svn_io_file_open (&(b->file_end_revision), b->path_end_revision,
+ APR_WRITE, APR_OS_DEFAULT, b->pool));
 
   svn_txdelta_apply (svn_stream_from_aprfile (b->file_start_revision, b->pool),
                      svn_stream_from_aprfile (b->file_end_revision, b->pool),
Index: ./subversion/libsvn_client/update.c
===================================================================
--- ./subversion/libsvn_client/update.c
+++ ./subversion/libsvn_client/update.c Wed May 29 15:02:15 2002
@@ -29,6 +29,7 @@
 #include "svn_string.h"
 #include "svn_error.h"
 #include "svn_path.h"
+#include "svn_io.h"
 #include "client.h"
 
 
@@ -177,15 +178,12 @@
   /* Else we're checking out from xml */
   else
     {
- apr_status_t apr_err;
       apr_file_t *in = NULL;
 
       /* Open xml file. */
- apr_err = apr_file_open (&in, xml_src, (APR_READ | APR_CREATE),
- APR_OS_DEFAULT, pool);
- if (apr_err)
- return svn_error_createf (apr_err, 0, NULL, pool,
- "unable to open %s", xml_src);
+ SVN_ERR (svn_io_file_open (&in, xml_src,
+ (APR_READ | APR_CREATE),
+ APR_OS_DEFAULT, pool));
 
       /* Do an update by xml-parsing the stream. An invalid revnum
          means that there will be a revision number in the <delta-pkg>
Index: ./subversion/libsvn_client/client.h
===================================================================
--- ./subversion/libsvn_client/client.h
+++ ./subversion/libsvn_client/client.h Wed May 29 17:28:07 2002
@@ -349,7 +349,7 @@
    Afterwards, some of the items in COMMIT_ITEMS may contain data
    allocated in POOL. */
 svn_error_t *
-svn_client__condense_commit_items (char **base_url,
+svn_client__condense_commit_items (const char **base_url,
                                    apr_array_header_t *commit_items,
                                    apr_pool_t *pool);
 
Index: ./subversion/libsvn_fs/fs.c
===================================================================
--- ./subversion/libsvn_fs/fs.c
+++ ./subversion/libsvn_fs/fs.c Wed May 29 18:22:07 2002
@@ -25,6 +25,7 @@
 #include "apr_file_io.h"
 
 #include "svn_pools.h"
+#include "svn_utf.h"
 #include "db.h"
 #include "svn_fs.h"
 #include "fs.h"
@@ -388,14 +389,16 @@
 {
   apr_status_t apr_err;
   svn_error_t *svn_err;
+ const char *path_native;
 
   SVN_ERR (check_already_open (fs));
 
   /* Initialize the fs's path. */
   fs->path = apr_pstrdup (fs->pool, path);
+ SVN_ERR (svn_utf_cstring_from_utf8 (fs->path, &path_native, fs->pool));
 
   /* Create the directory for the new Berkeley DB environment. */
- apr_err = apr_dir_make (fs->path, APR_OS_DEFAULT, fs->pool);
+ apr_err = apr_dir_make (path_native, APR_OS_DEFAULT, fs->pool);
   if (apr_err != APR_SUCCESS)
     return svn_error_createf (apr_err, 0, 0, fs->pool,
                               "creating Berkeley DB environment dir `%s'",
@@ -405,7 +408,8 @@
   {
     apr_file_t *dbconfig_file = NULL;
     const char *dbconfig_file_name = apr_psprintf (fs->pool,
- "%s/DB_CONFIG", path);
+ "%s/DB_CONFIG",
+ path_native);
     static const char * const dbconfig_contents =
       "# This is the configuration file for the Berkeley DB environment\n"
       "# used by your Subversion repository.\n"
@@ -426,7 +430,7 @@
                              fs->pool);
     if (apr_err != APR_SUCCESS)
       return svn_error_createf (apr_err, 0, 0, fs->pool,
- "opening `%s' for writing", dbconfig_file_name);
+ "opening `%s/DB_CONFIG' for writing", path);
 
     apr_err = apr_file_write_full (dbconfig_file, dbconfig_contents,
                                    strlen (dbconfig_contents), NULL);
@@ -445,7 +449,7 @@
 
   /* Create the Berkeley DB environment. */
   svn_err = DB_WRAP (fs, "creating environment",
- fs->env->open (fs->env, fs->path,
+ fs->env->open (fs->env, path_native,
                                     (DB_CREATE
                                      | DB_INIT_LOCK
                                      | DB_INIT_LOG
@@ -494,18 +498,20 @@
 svn_fs_open_berkeley (svn_fs_t *fs, const char *path)
 {
   svn_error_t *svn_err;
+ const char *path_native;
 
   SVN_ERR (check_already_open (fs));
 
   /* Initialize paths. */
   fs->path = apr_pstrdup (fs->pool, path);
+ SVN_ERR (svn_utf_cstring_from_utf8 (fs->path, &path_native, fs->pool));
 
   svn_err = allocate_env (fs);
   if (svn_err) goto error;
 
   /* Open the Berkeley DB environment. */
   svn_err = DB_WRAP (fs, "opening environment",
- fs->env->open (fs->env, fs->path,
+ fs->env->open (fs->env, path_native,
                                     (DB_INIT_LOCK
                                      | DB_INIT_LOG
                                      | DB_INIT_MPOOL
@@ -552,6 +558,9 @@
 {
   int db_err;
   DB_ENV *env;
+ const char *path_native;
+
+ SVN_ERR (svn_utf_cstring_from_utf8 (path, &path_native, pool));
 
   db_err = db_env_create (&env, 0);
   if (db_err)
@@ -567,10 +576,10 @@
      we leave the region around, the application that should create
      it will simply join it instead, and will then be running with
      incorrectly sized (and probably terribly small) caches. */
- db_err = env->open (env, path, (DB_RECOVER | DB_CREATE
- | DB_INIT_LOCK | DB_INIT_LOG
- | DB_INIT_MPOOL | DB_INIT_TXN
- | DB_PRIVATE),
+ db_err = env->open (env, path_native, (DB_RECOVER | DB_CREATE
+ | DB_INIT_LOCK | DB_INIT_LOG
+ | DB_INIT_MPOOL | DB_INIT_TXN
+ | DB_PRIVATE),
                       0666);
   if (db_err)
     return svn_fs__dberr (pool, db_err);
@@ -593,13 +602,16 @@
 {
   int db_err;
   DB_ENV *env;
+ const char *path_native;
+
+ SVN_ERR (svn_utf_cstring_from_utf8 (path, &path_native, pool));
 
   /* First, use the Berkeley DB library function to remove any shared
      memory segments. */
   db_err = db_env_create (&env, 0);
   if (db_err)
     return svn_fs__dberr (pool, db_err);
- db_err = env->remove (env, path, DB_FORCE);
+ db_err = env->remove (env, path_native, DB_FORCE);
   if (db_err)
     return svn_fs__dberr (pool, db_err);
 
Index: ./subversion/libsvn_subr/io.c
===================================================================
--- ./subversion/libsvn_subr/io.c
+++ ./subversion/libsvn_subr/io.c Wed May 29 15:55:35 2002
@@ -36,6 +36,7 @@
 #include "svn_io.h"
 #include "svn_base64.h"
 #include "svn_pools.h"
+#include "svn_utf.h"
 #include "svn_private_config.h" /* for SVN_CLIENT_DIFF */
 
 
@@ -55,11 +56,14 @@
 {
   apr_finfo_t finfo;
   apr_status_t apr_err;
+ const char *path_native;
 
   if (path[0] == '\0')
     path = ".";
 
- apr_err = apr_stat (&finfo, path, APR_FINFO_MIN, pool);
+ SVN_ERR (svn_utf_cstring_from_utf8 (path, &path_native, pool));
+
+ apr_err = apr_stat (&finfo, path_native, APR_FINFO_MIN, pool);
 
   if (apr_err && !APR_STATUS_IS_ENOENT(apr_err))
     return svn_error_createf
@@ -95,6 +99,7 @@
   char number_buf[6];
   int i;
   apr_size_t iterating_portion_idx;
+ const char *unique_name_native;
   svn_stringbuf_t *unique_name_buf;
 
   /* The random portion doesn't have to be very random; it's just to
@@ -146,7 +151,11 @@
       unique_name_buf->data[iterating_portion_idx + 3] = number_buf[3];
       unique_name_buf->data[iterating_portion_idx + 4] = number_buf[4];
 
- apr_err = apr_file_open (f, unique_name_buf->data, flag,
+ SVN_ERR (svn_utf_cstring_from_utf8_stringbuf (unique_name_buf,
+ &unique_name_native,
+ pool));
+
+ apr_err = apr_file_open (f, unique_name_native, flag,
                                APR_OS_DEFAULT, pool);
 
       if (APR_STATUS_IS_EEXIST(apr_err))
@@ -200,7 +209,11 @@
   apr_int32_t options = APR_OS_DEFAULT;
 #endif
 
- apr_err = apr_file_copy (src, dst, options, pool);
+ const char *src_native, *dst_native;
+ SVN_ERR (svn_utf_cstring_from_utf8 (src, &src_native, pool));
+ SVN_ERR (svn_utf_cstring_from_utf8 (dst, &dst_native, pool));
+
+ apr_err = apr_file_copy (src_native, dst_native, options, pool);
   if (apr_err)
     return svn_error_createf
       (apr_err, 0, NULL, pool, "svn_io_copy_file: copying %s to %s", src, dst);
@@ -213,8 +226,13 @@
 svn_io_append_file (const char *src, const char *dst, apr_pool_t *pool)
 {
   apr_status_t apr_err;
+ const char *src_native, *dst_native;
+
+ SVN_ERR (svn_utf_cstring_from_utf8 (src, &src_native, pool));
+ SVN_ERR (svn_utf_cstring_from_utf8 (dst, &dst_native, pool));
 
- apr_err = apr_file_append (src, dst, APR_OS_DEFAULT, pool);
+ apr_err = apr_file_append (src_native, dst_native,
+ APR_OS_DEFAULT, pool);
   if (apr_err)
     {
       const char *msg
@@ -238,6 +256,7 @@
   apr_hash_t *dirents;
   apr_hash_index_t *hi;
   const char *dst_path;
+ const char *dst_path_native;
 
   /* Make a subpool for recursion */
   apr_pool_t *subpool = svn_pool_create (pool);
@@ -264,9 +283,11 @@
     return svn_error_createf (SVN_ERR_ENTRY_EXISTS, 0, NULL, subpool,
                               "'%s' already exists.", dst_path);
   
+ SVN_ERR (svn_utf_cstring_from_utf8 (dst_path, &dst_path_native, pool));
+
   /* Create the new directory. */
   /* ### TODO: copy permissions? */
- status = apr_dir_make (dst_path, APR_OS_DEFAULT, pool);
+ status = apr_dir_make (dst_path_native, APR_OS_DEFAULT, pool);
   if (status)
     return svn_error_createf (status, 0, NULL, pool,
                               "Unable to create directory '%s'",
@@ -330,8 +351,11 @@
 {
   apr_finfo_t finfo;
   apr_status_t apr_err;
+ const char *path_native;
+
+ SVN_ERR (svn_utf_cstring_from_utf8 (path, &path_native, pool));
 
- apr_err = apr_stat (&finfo, path, APR_FINFO_MIN, pool);
+ apr_err = apr_stat (&finfo, path_native, APR_FINFO_MIN, pool);
   if (apr_err)
     return svn_error_createf
       (apr_err, 0, NULL, pool,
@@ -356,8 +380,12 @@
   apr_finfo_t finfo2;
   apr_status_t status;
 
+ const char *file1_native, *file2_native;
+ SVN_ERR (svn_utf_cstring_from_utf8 (file1, &file1_native, pool));
+ SVN_ERR (svn_utf_cstring_from_utf8 (file2, &file2_native, pool));
+
   /* Stat both files */
- status = apr_stat (&finfo1, file1, APR_FINFO_MIN, pool);
+ status = apr_stat (&finfo1, file1_native, APR_FINFO_MIN, pool);
   if (status)
     {
       /* If we got an error stat'ing a file, it could be because the
@@ -368,7 +396,7 @@
       return SVN_NO_ERROR;
     }
 
- status = apr_stat (&finfo2, file2, APR_FINFO_MIN, pool);
+ status = apr_stat (&finfo2, file2_native, APR_FINFO_MIN, pool);
   if (status)
     {
       /* See previous comment. */
@@ -398,6 +426,7 @@
   unsigned char digest[MD5_DIGESTSIZE];
   char buf[BUFSIZ]; /* What's a good size for a read chunk? */
   svn_stringbuf_t *md5str;
+ const char *file_native;
 
   /* ### The apr_md5 functions return apr_status_t, but they only
      return success, and really, what could go wrong? So below, we
@@ -405,7 +434,10 @@
 
   apr_md5_init (&context);
 
- apr_err = apr_file_open (&f, file, APR_READ, APR_OS_DEFAULT, pool);
+ SVN_ERR (svn_utf_cstring_from_utf8 (file, &file_native, pool));
+
+ apr_err = apr_file_open (&f, file_native, APR_READ, APR_OS_DEFAULT,
+ pool);
   if (apr_err)
     return svn_error_createf
       (apr_err, 0, NULL, pool,
@@ -454,7 +486,9 @@
                            apr_pool_t *pool)
 {
   apr_status_t status;
- status = apr_file_attrs_set (path,
+ const char *path_native;
+ SVN_ERR (svn_utf_cstring_from_utf8 (path, &path_native, pool));
+ status = apr_file_attrs_set (path_native,
                                APR_FILE_ATTR_READONLY,
                                APR_FILE_ATTR_READONLY,
                                pool);
@@ -472,7 +506,9 @@
                             apr_pool_t *pool)
 {
   apr_status_t status;
- status = apr_file_attrs_set (path,
+ const char *path_native;
+ SVN_ERR (svn_utf_cstring_from_utf8 (path, &path_native, pool));
+ status = apr_file_attrs_set (path_native,
                                0,
                                APR_FILE_ATTR_READONLY,
                                pool);
@@ -491,14 +527,16 @@
                             apr_pool_t *pool)
 {
   apr_status_t status;
+ const char *path_native;
+ SVN_ERR (svn_utf_cstring_from_utf8 (path, &path_native, pool));
 
   if (executable)
- status = apr_file_attrs_set (path,
+ status = apr_file_attrs_set (path_native,
                                  APR_FILE_ATTR_EXECUTABLE,
                                  APR_FILE_ATTR_EXECUTABLE,
                                  pool);
   else
- status = apr_file_attrs_set (path,
+ status = apr_file_attrs_set (path_native,
                                  0,
                                  APR_FILE_ATTR_EXECUTABLE,
                                  pool);
@@ -795,6 +833,7 @@
 {
   apr_status_t apr_err;
   apr_file_t *f = NULL;
+ const char *filename_native;
 
   /* If user passed '-', use stdin. We could use apr_file_open_stdin here, and
    * in fact, it does work. Problem is that if the same command invokes the
@@ -806,7 +845,10 @@
         (SVN_ERR_UNSUPPORTED_FEATURE, 0, NULL, pool,
          "reading from stdin is currently broken, so disabled");
 
- apr_err = apr_file_open (&f, filename, APR_READ, APR_OS_DEFAULT, pool);
+ SVN_ERR (svn_utf_cstring_from_utf8 (filename, &filename_native, pool));
+
+ apr_err = apr_file_open (&f, filename_native, APR_READ,
+ APR_OS_DEFAULT, pool);
   if (apr_err)
     return svn_error_createf (apr_err, 0, NULL, pool,
                               "read_from_file: failed to open '%s'",
@@ -860,10 +902,15 @@
     }
 
   /* Having read all the data we *expect* EOF */
- if (!APR_STATUS_IS_EOF(apr_err))
+ if (!APR_STATUS_IS_EOF(apr_err)) {
+ const char *fname_utf8;
+
+ SVN_ERR (svn_utf_cstring_to_utf8 (fname, &fname_utf8, pool));
+
     return svn_error_createf
       (apr_err, 0, NULL, pool,
- "svn_string_from_aprfile: EOF not seen for '%s'", fname);
+ "svn_string_from_aprfile: EOF not seen for '%s'", fname_utf8);
+ }
 
   /* Null terminate the stringbuf. */
   res->data[res->len] = 0;
@@ -880,11 +927,13 @@
 svn_io_remove_file (const char *path, apr_pool_t *pool)
 {
   apr_status_t apr_err;
+ const char *path_native;
 
   /* Remove read-only flag on terminated file. */
   SVN_ERR (svn_io_set_file_read_write (path, TRUE, pool));
 
- apr_err = apr_file_remove (path, pool);
+ SVN_ERR (svn_utf_cstring_from_utf8 (path, &path_native, pool));
+ apr_err = apr_file_remove (path_native, pool);
 
   if (apr_err)
     return svn_error_createf
@@ -910,8 +959,10 @@
   apr_finfo_t this_entry;
   apr_pool_t *subpool = svn_pool_create (pool);
   apr_int32_t flags = APR_FINFO_TYPE | APR_FINFO_NAME;
+ const char *path_native;
 
- status = apr_dir_open (&this_dir, path, subpool);
+ SVN_ERR (svn_utf_cstring_from_utf8 (path, &path_native, subpool));
+ status = apr_dir_open (&this_dir, path_native, subpool);
   if (status)
     return svn_error_createf (status, 0, NULL, subpool, err_msg_fmt, path);
 
@@ -919,7 +970,12 @@
        status == APR_SUCCESS;
        status = apr_dir_read (&this_entry, flags, this_dir))
     {
- char *fullpath = apr_pstrcat (subpool, path, "/", this_entry.name, NULL);
+ const char *fullpath, *entry_utf8;
+
+ SVN_ERR (svn_utf_cstring_to_utf8 (this_entry.name,
+ &entry_utf8, subpool));
+
+ fullpath = apr_pstrcat (subpool, path, "/", entry_utf8, NULL);
 
       if (this_entry.filetype == APR_DIR)
         {
@@ -949,7 +1005,7 @@
         return svn_error_createf (status, 0, NULL, subpool, err_msg_fmt, path);
     }
 
- status = apr_dir_remove (path, subpool);
+ status = apr_dir_remove (path_native, subpool);
   if (status)
     return svn_error_createf (status, 0, NULL, subpool, err_msg_fmt, path);
 
@@ -969,6 +1025,7 @@
   apr_dir_t *this_dir;
   apr_finfo_t this_entry;
   apr_int32_t flags = APR_FINFO_TYPE | APR_FINFO_NAME;
+ const char *path_native;
 
   /* These exist so we can use their addresses as hash values! */
   static const enum svn_node_kind static_svn_node_file = svn_node_file;
@@ -977,7 +1034,9 @@
 
   *dirents = apr_hash_make (pool);
   
- status = apr_dir_open (&this_dir, path, pool);
+ SVN_ERR (svn_utf_cstring_from_utf8 (path, &path_native, pool));
+
+ status = apr_dir_open (&this_dir, path_native, pool);
   if (status)
     return
       svn_error_createf (status, 0, NULL, pool,
@@ -993,7 +1052,9 @@
         continue;
       else
         {
- const char *name = apr_pstrdup (pool, this_entry.name);
+ const char *name;
+
+ SVN_ERR (svn_utf_cstring_to_utf8 (this_entry.name, &name, pool));
           
           if (this_entry.filetype == APR_REG)
             apr_hash_set (*dirents, name, APR_HASH_KEY_STRING,
@@ -1042,7 +1103,9 @@
   apr_proc_t cmd_proc;
   apr_procattr_t *cmdproc_attr;
   apr_exit_why_e exitwhy_val;
- int exitcode_val;
+ int exitcode_val, num_args;
+ const char **args_native;
+ const char *cmd_native;
 
   /* Create the process attributes. */
   apr_err = apr_procattr_create (&cmdproc_attr, pool);
@@ -1065,7 +1128,9 @@
   /* Set the process's working directory. */
   if (path)
     {
- apr_err = apr_procattr_dir_set (cmdproc_attr, path);
+ const char *path_native;
+ SVN_ERR (svn_utf_cstring_from_utf8 (path, &path_native, pool));
+ apr_err = apr_procattr_dir_set (cmdproc_attr, path_native);
       if (apr_err)
         return svn_error_createf
           (apr_err, 0, NULL, pool,
@@ -1106,8 +1171,19 @@
            cmd);
     }
 
+ /* Convert cmd and args from UTF-8 */
+ SVN_ERR (svn_utf_cstring_from_utf8 (cmd, &cmd_native, pool));
+ for (num_args = 0; args[num_args]; num_args++);
+ args_native = apr_palloc(pool, (num_args + 1) * sizeof(char *));
+ args_native[num_args] = NULL;
+ while (num_args--)
+ SVN_ERR (svn_utf_cstring_from_utf8 (args[num_args],
+ &args_native[num_args],
+ pool));
+
   /* Start the cmd command. */
- apr_err = apr_proc_create (&cmd_proc, cmd, args, NULL, cmdproc_attr, pool);
+ apr_err = apr_proc_create (&cmd_proc, cmd_native, args_native, NULL,
+ cmdproc_attr, pool);
   if (apr_err)
     return svn_error_createf
       (apr_err, 0, NULL, pool,
@@ -1161,6 +1237,7 @@
   int i;
   int exitcode;
   int nargs = 4; /* the diff command itself, two paths, plus a trailing NULL */
+ const char *diff_utf8;
 
   apr_pool_t *subpool = svn_pool_create (pool);
 
@@ -1201,7 +1278,9 @@
 
   assert (i == nargs);
 
- SVN_ERR (svn_io_run_cmd (dir, SVN_CLIENT_DIFF, args, pexitcode, NULL, FALSE,
+ SVN_ERR (svn_utf_cstring_to_utf8 (SVN_CLIENT_DIFF, &diff_utf8, pool));
+
+ SVN_ERR (svn_io_run_cmd (dir, diff_utf8, args, pexitcode, NULL, FALSE,
                            NULL, outfile, errfile, subpool));
 
   if (*pexitcode < 0 || *pexitcode > 2)
@@ -1228,6 +1307,7 @@
                   apr_pool_t *pool)
 {
   const char *args[14];
+ const char *diff3_utf8;
 
   /* Labels fall back to sensible defaults if not specified. */
   if (mine_label == NULL)
@@ -1264,8 +1344,10 @@
   args[12] = NULL;
 #endif
 
+ SVN_ERR (svn_utf_cstring_to_utf8 (SVN_CLIENT_DIFF3, &diff3_utf8, pool));
+
   /* Run diff3, output the merged text into the scratch file. */
- SVN_ERR (svn_io_run_cmd (dir, SVN_CLIENT_DIFF3, args,
+ SVN_ERR (svn_io_run_cmd (dir, diff3_utf8, args,
                            exitcode, NULL,
                            FALSE, /* clean environment */
                            NULL, merged, NULL,
@@ -1301,6 +1383,7 @@
   apr_status_t apr_err;
   unsigned char block[1024];
   apr_size_t amt_read = sizeof (block);
+ const char *path_native;
 
 
   /* Default return value is NULL. */
@@ -1313,7 +1396,9 @@
                               "Can't detect mimetype of non-file '%s'",
                               file);
 
- apr_err = apr_file_open (&fh, file, APR_READ, 0, pool);
+ SVN_ERR (svn_utf_cstring_from_utf8 (file, &path_native, pool));
+
+ apr_err = apr_file_open (&fh, path_native, APR_READ, 0, pool);
   if (apr_err)
     return svn_error_createf (apr_err, 0, NULL, pool,
                               "svn_io_detect_mimetype: error opening '%s'",
@@ -1367,6 +1452,171 @@
     }
   
   return SVN_NO_ERROR;
+}
+
+
+/* Simple wrappers for apr_file_open, apr_stat, apr_file_rename,
+ apr_dir_make, and apr_dir_open that handle filename charset conversion. */
+
+svn_error_t *
+svn_io_file_open (apr_file_t **new_file, const char *fname,
+ apr_int32_t flag, apr_fileperms_t perm,
+ apr_pool_t *pool)
+{
+ const char *fname_native;
+ apr_status_t status;
+
+ SVN_ERR (svn_utf_cstring_from_utf8 (fname, &fname_native, pool));
+
+ status = apr_file_open (new_file, fname_native, flag, perm, pool);
+
+ if (status)
+ return svn_error_createf (status, 0, NULL, pool,
+ "can't open `%s'", fname);
+ else
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_io_stat (apr_finfo_t *finfo, const char *fname,
+ apr_int32_t wanted, apr_pool_t *pool)
+{
+ const char *fname_native;
+ apr_status_t status;
+
+ SVN_ERR (svn_utf_cstring_from_utf8 (fname, &fname_native, pool));
+
+ status = apr_stat (finfo, fname_native, wanted, pool);
+
+ if (status)
+ return svn_error_createf (status, 0, NULL, pool,
+ "couldn't stat '%s'...", fname);
+ else
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_io_file_rename (const char *from_path, const char *to_path,
+ apr_pool_t *pool)
+{
+ const char *from_path_native, *to_path_native;
+ apr_status_t status;
+
+ SVN_ERR (svn_utf_cstring_from_utf8 (from_path, &from_path_native, pool));
+ SVN_ERR (svn_utf_cstring_from_utf8 (to_path, &to_path_native, pool));
+
+ status = apr_file_rename (from_path_native, to_path_native, pool);
+
+ if (status)
+ return svn_error_createf (status, 0, NULL, pool,
+ "can't move '%s' to '%s'", from_path, to_path);
+ else
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_io_dir_make (const char *path, apr_fileperms_t perm, apr_pool_t *pool)
+{
+ const char *path_native;
+ apr_status_t status;
+
+ SVN_ERR (svn_utf_cstring_from_utf8 (path, &path_native, pool));
+
+ status = apr_dir_make (path_native, perm, pool);
+
+ if (status)
+ return svn_error_createf (status, 0, NULL, pool,
+ "can't create directory '%s'", path);
+ else
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_io_dir_open (apr_dir_t **new_dir, const char *dirname, apr_pool_t *pool)
+{
+ const char *dirname_native;
+ apr_status_t status;
+
+ SVN_ERR (svn_utf_cstring_from_utf8 (dirname, &dirname_native, pool));
+
+ status = apr_dir_open (new_dir, dirname_native, pool);
+
+ if (status)
+ return svn_error_createf (status, 0, NULL, pool,
+ "unable to open directory '%s'", dirname);
+ else
+ return SVN_NO_ERROR;
+}
+
+/* This is a wrapper around apr_dir_remove just like the wrappers above.
+ It's called like this to avoid confusion with svn_io_remove_dir
+ (which is recursive). */
+
+svn_error_t *
+svn_io_dir_remove_nonrecursive (const char *dirname, apr_pool_t *pool)
+{
+ const char *dirname_native;
+ apr_status_t status;
+
+ SVN_ERR (svn_utf_cstring_from_utf8 (dirname, &dirname_native, pool));
+
+ status = apr_dir_remove (dirname_native, pool);
+
+ if (status)
+ return svn_error_createf (status, 0, NULL, pool,
+ "unable to remove directory '%s'", dirname);
+ else
+ return SVN_NO_ERROR;
+}
+
+/* A wrapper for apr_dir_read that converts the fname and name fields
+ to UTF-8 */
+
+svn_error_t *
+svn_io_dir_read (apr_finfo_t *finfo, apr_int32_t wanted, apr_dir_t *thedir)
+{
+ apr_status_t status;
+
+ /* YUCK! Why isn't there an apr_dir_pool_get()?
+ When there is one: FIXME!! */
+ apr_pool_t *pool = *(apr_pool_t **)thedir;
+
+ status = apr_dir_read (finfo, wanted, thedir);
+
+ if (status)
+ return svn_error_create (status, 0, NULL, pool,
+ "error reading directory");
+
+ if (finfo->fname)
+ SVN_ERR (svn_utf_cstring_to_utf8 (finfo->fname, &finfo->fname,
+ pool));
+ if (finfo->name)
+ SVN_ERR (svn_utf_cstring_to_utf8 (finfo->name, &finfo->name,
+ pool));
+ return SVN_NO_ERROR;
+}
+
+/* A replacement for apr_file_printf that converts the output to the native
+ character set before sending it to the stream. */
+
+svn_error_t *
+svn_io_file_printf (apr_file_t *fptr, const char *format, ...)
+{
+ apr_status_t status;
+ va_list ap;
+ const char *buf, *buf_native;
+
+ va_start (ap, format);
+ buf = apr_pvsprintf (apr_file_pool_get (fptr), format, ap);
+ va_end(ap);
+ SVN_ERR (svn_utf_cstring_from_utf8 (buf, &buf_native,
+ apr_file_pool_get (fptr)));
+ status = apr_file_puts(buf_native, fptr);
+ if (status)
+ return svn_error_create (status, 0, NULL, apr_file_pool_get (fptr),
+ "unable to print to file");
+ else
+ return SVN_NO_ERROR;
 }
 
 
Index: ./subversion/libsvn_subr/svn_error.c
===================================================================
--- ./subversion/libsvn_subr/svn_error.c
+++ ./subversion/libsvn_subr/svn_error.c Thu May 30 16:10:03 2002
@@ -29,6 +29,8 @@
 #include "svn_pools.h"
 #include "svn_error.h"
 #include "svn_io.h"
+#include "svn_utf.h"
+
 
 /* Key for the error pool itself. */
 static const char SVN_ERROR_POOL[] = "svn-error-pool";
@@ -314,14 +316,16 @@
 void
 svn_handle_error (svn_error_t *err, FILE *stream, svn_boolean_t fatal)
 {
- char buf[200];
+ char buf[200], buf2[2000];
 
   /* Pretty-print the error */
   /* Note: we can also log errors here someday. */
 
 #ifdef SVN_DEBUG
   if (err->file)
- fprintf (stream, "\n%s:%ld\n", err->file, err->line);
+ fprintf (stream, "\n%s:%ld\n",
+ svn_utf_utf8_to_native (err->file, buf2, sizeof (buf2)),
+ err->line);
   else
     fprintf (stream, "\n%s\n", SVN_FILE_LINE_UNDEFINED);
 #else
@@ -332,7 +336,9 @@
   if ((err->apr_err > APR_OS_START_USEERR)
       && (err->apr_err <= APR_OS_START_CANONERR))
     fprintf (stream, "svn_error: #%d : <%s>\n", err->apr_err,
- svn_strerror (err->apr_err, buf, sizeof (buf)));
+ svn_utf_utf8_to_native (svn_strerror (err->apr_err,
+ buf, sizeof (buf)),
+ buf2, sizeof(buf2)));
 
   /* Otherwise, this must be an APR error code. */
   else
@@ -342,7 +348,8 @@
              apr_strerror (err->apr_err, buf, sizeof(buf)));
 
   if (err->message)
- fprintf (stream, " %s", err->message);
+ fprintf (stream, " %s",
+ svn_utf_utf8_to_native (err->message, buf2, sizeof(buf2)));
 
   fputc ('\n', stream);
   fflush (stream);
@@ -361,12 +368,22 @@
 {
   va_list ap;
 
+ apr_pool_t *pool = svn_pool_create (NULL);
+ svn_stringbuf_t *msg, *msg_utf8;
+ svn_error_t *err;
+
   va_start (ap, fmt);
- vfprintf (stderr, fmt, ap);
+ msg_utf8 = svn_stringbuf_create (apr_pvsprintf (pool, fmt, ap), pool);
   va_end (ap);
 
- fprintf (stderr, "\n");
+ err = svn_utf_stringbuf_from_utf8 (msg_utf8, &msg, pool);
+ if (err)
+ svn_handle_error (err, stderr, FALSE);
+ else
+ fprintf (stderr, "%s\n", msg->data);
   fflush (stderr);
+
+ svn_pool_destroy (pool);
 }
 
 
Index: ./subversion/libsvn_subr/target.c
===================================================================
--- ./subversion/libsvn_subr/target.c
+++ ./subversion/libsvn_subr/target.c Wed May 29 17:24:17 2002
@@ -27,13 +27,14 @@
 #include "svn_pools.h"
 #include "svn_error.h"
 #include "svn_path.h"
+#include "svn_utf.h"
 #include "apr_file_info.h"
 
 
 /*** Code. ***/
 
 svn_error_t *
-svn_path_get_absolute(char **pabsolute,
+svn_path_get_absolute(const char **pabsolute,
                       const char *relative,
                       apr_pool_t *pool)
 {
@@ -44,17 +45,24 @@
      without const vs non-const issues. */
 
   char * buffer;
- int apr_err = apr_filepath_merge(&buffer, NULL,
- svn_path_canonicalize_nts (relative, pool),
- APR_FILEPATH_NOTRELATIVE
- | APR_FILEPATH_TRUENAME,
- pool);
+ apr_status_t apr_err;
+ const char *path_native;
+
+ SVN_ERR (svn_utf_cstring_from_utf8 (svn_path_canonicalize_nts (relative,
+ pool),
+ &path_native, pool));
+
+ apr_err = apr_filepath_merge(&buffer, NULL,
+ path_native,
+ APR_FILEPATH_NOTRELATIVE
+ | APR_FILEPATH_TRUENAME,
+ pool);
   if (apr_err)
     return svn_error_createf(SVN_ERR_BAD_FILENAME, apr_err, NULL, pool,
                              "Couldn't determine absolute path of %s.",
                              relative);
 
- *pabsolute = buffer;
+ return svn_utf_cstring_to_utf8 (buffer, pabsolute, pool);
 
   return SVN_NO_ERROR;
 }
@@ -69,10 +77,11 @@
   /* ### This belongs in path.c! */
 
   apr_finfo_t finfo;
- apr_status_t apr_err = apr_stat(&finfo, path, APR_FINFO_TYPE, pool);
- if (apr_err != APR_SUCCESS)
+ svn_error_t *err;
+ err = svn_io_stat(&finfo, path, APR_FINFO_TYPE, pool);
+ if (err != SVN_NO_ERROR)
     {
- return svn_error_createf(SVN_ERR_BAD_FILENAME, apr_err, NULL,
+ return svn_error_createf(SVN_ERR_BAD_FILENAME, 0, err,
                               pool, "Couldn't determine if %s was a file or "
                               "directory.", path);
     }
@@ -129,7 +138,7 @@
         = apr_array_make (pool, targets->nelts, sizeof (const char *));
       
       /* ### this cast is a kluge */
- SVN_ERR (svn_path_get_absolute ((char **) pbasedir,
+ SVN_ERR (svn_path_get_absolute (pbasedir,
                                       ((const char **) targets->elts)[0],
                                       pool));
       
@@ -138,7 +147,7 @@
       for (i = 1; i < targets->nelts; ++i)
         {
           const char *rel = ((const char **)targets->elts)[i];
- char *absolute;
+ const char *absolute;
           SVN_ERR (svn_path_get_absolute (&absolute, rel, pool));
           (*((const char **)apr_array_push (abs_targets))) = absolute;
           *pbasedir = svn_path_get_longest_ancestor (*pbasedir,
@@ -286,7 +295,7 @@
   for (i = 0; i < targets->nelts; i++)
     {
       const char *rel_path = ((const char **)targets->elts)[i];
- char *abs_path;
+ const char *abs_path;
       int j;
       svn_boolean_t keep_me;
 
Index: ./subversion/libsvn_subr/utf.c
===================================================================
--- /dev/null Thu May 30 17:21:39 2002
+++ ./subversion/libsvn_subr/utf.c Mon May 27 17:13:24 2002
@@ -0,0 +1,405 @@
+/*
+ * utf.c: UTF-8 helper code shared among the Subversion libraries.
+ *
+ * ====================================================================
+ * Copyright (c) 2000-2002 CollabNet. All rights reserved.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://subversion.tigris.org/license-1.html.
+ * If newer versions of this license are posted there, you may use a
+ * newer version instead, at your option.
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals. For exact contribution history, see the revision
+ * history and logs, available at http://subversion.tigris.org/.
+ * ====================================================================
+ */
+
+
+
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include <apr_strings.h>
+#include <apr_xlate.h>
+
+#include "svn_string.h"
+#include "svn_error.h"
+#include "svn_pools.h"
+#include "svn_utf.h"
+
+
+#ifdef SVN_UTF8
+
+#define SVN_UTF_NTOU_XLATE_HANDLE "svn-utf-ntou-xlate-handle"
+#define SVN_UTF_UTON_XLATE_HANDLE "svn-utf-uton-xlate-handle"
+
+/* Return the apr_xlate handle for converting native characters to UTF-8.
+ Create one if it doesn't exist. */
+static svn_error_t *
+get_ntou_xlate_handle (apr_xlate_t **ret, apr_pool_t *pool)
+{
+ void *old_handle = NULL;
+ apr_pool_t *parent, *global_pool;
+ apr_status_t apr_err;
+
+ /* Find the global pool */
+ for (global_pool = pool;
+ (parent = apr_pool_get_parent (global_pool));
+ global_pool = parent) ;
+
+ /* If we already have a handle, just return it. */
+ apr_pool_userdata_get (&old_handle, SVN_UTF_NTOU_XLATE_HANDLE, global_pool);
+ if (old_handle != NULL) {
+ *ret = old_handle;
+ return SVN_NO_ERROR;
+ }
+
+ /* Try to create one. */
+ apr_err = apr_xlate_open (ret, "UTF-8", APR_LOCALE_CHARSET, global_pool);
+
+ if (apr_err != APR_SUCCESS)
+ return svn_error_create (apr_err, 0, NULL, pool,
+ "failed to create a converter to UTF-8");
+
+ /* Save it for later. */
+ apr_pool_userdata_set (*ret, SVN_UTF_NTOU_XLATE_HANDLE,
+ apr_pool_cleanup_null, global_pool);
+
+ return SVN_NO_ERROR;
+}
+
+/* Return the apr_xlate handle for converting UTF-8 to native characters.
+ Create one if it doesn't exist. */
+static svn_error_t *
+get_uton_xlate_handle (apr_xlate_t **ret, apr_pool_t *pool)
+{
+ void *old_handle = NULL;
+ apr_pool_t *parent, *global_pool;
+ apr_status_t apr_err;
+
+ /* Find the global pool */
+ for (global_pool = pool;
+ (parent = apr_pool_get_parent (global_pool));
+ global_pool = parent) ;
+
+ /* If we already have a handle, just return it. */
+ apr_pool_userdata_get (&old_handle, SVN_UTF_UTON_XLATE_HANDLE, global_pool);
+ if (old_handle != NULL) {
+ *ret = old_handle;
+ return SVN_NO_ERROR;
+ }
+
+ /* Try to create one. */
+ apr_err = apr_xlate_open (ret, APR_LOCALE_CHARSET, "UTF-8", global_pool);
+
+ if (apr_err != APR_SUCCESS)
+ return svn_error_create (apr_err, 0, NULL, pool,
+ "failed to create a converter from UTF-8");
+
+ /* Save it for later. */
+ apr_pool_userdata_set (*ret, SVN_UTF_UTON_XLATE_HANDLE,
+ apr_pool_cleanup_null, global_pool);
+
+ return SVN_NO_ERROR;
+}
+
+
+static svn_error_t *
+svn_utf_convert_to_stringbuf (apr_xlate_t *convset, const char *src_data,
+ apr_size_t src_length, svn_stringbuf_t **dest,
+ apr_pool_t *pool)
+{
+ /* 2 bytes per character will be enough in most cases.
+ If not, we'll make a larger buffer and try again. */
+ apr_size_t buflen = src_length * 2;
+
+ apr_status_t apr_err;
+ apr_size_t srclen, destlen;
+
+ *dest = svn_stringbuf_create ("", pool);
+
+ do {
+ /* Set up state variables for xlate */
+ srclen = src_length;
+ destlen = buflen;
+
+ svn_stringbuf_ensure (*dest, buflen+1);
+
+ /* Attempt the conversion */
+ apr_err = apr_xlate_conv_buffer (convset, src_data, &srclen,
+ (*dest)->data, &destlen);
+
+ /* Conversion succeeded, trim result */
+ if (apr_err == APR_SUCCESS && !srclen)
+ (*dest)->data[(*dest)->len = buflen - destlen] = '\0';
+
+ /* In case we got here because the buffer was too small,
+ double the size for the next iteration... */
+ buflen *= 2;
+
+ } while (apr_err == APR_SUCCESS && srclen);
+
+ if (apr_err)
+ return svn_error_create (apr_err, 0, NULL, pool,
+ "failure during string recoding");
+ else
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_utf_stringbuf_to_utf8 (const svn_stringbuf_t *src,
+ svn_stringbuf_t **dest,
+ apr_pool_t *pool)
+{
+ /* Get a converter from the native character encoding to UTF-8 */
+ apr_xlate_t *convset;
+ SVN_ERR (get_ntou_xlate_handle (&convset, pool));
+
+ return svn_utf_convert_to_stringbuf (convset, src->data, src->len,
+ dest, pool);
+}
+
+svn_error_t *
+svn_utf_cstring_to_utf8_stringbuf (const char *src,
+ svn_stringbuf_t **dest,
+ apr_pool_t *pool)
+{
+ /* Get a converter from the native character encoding to UTF-8 */
+ apr_xlate_t *convset;
+ SVN_ERR (get_ntou_xlate_handle (&convset, pool));
+
+ return svn_utf_convert_to_stringbuf (convset, src, strlen (src),
+ dest, pool);
+}
+
+svn_error_t *
+svn_utf_cstring_to_utf8 (const char *src, const char **dest,
+ apr_pool_t *pool)
+{
+ svn_stringbuf_t *destbuf;
+ SVN_ERR (svn_utf_cstring_to_utf8_stringbuf (src, &destbuf, pool));
+ *dest = destbuf->data;
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_utf_stringbuf_from_utf8 (const svn_stringbuf_t *src,
+ svn_stringbuf_t **dest,
+ apr_pool_t *pool)
+{
+ /* Get a converter from UTF-8 to the native character encoding */
+ apr_xlate_t *convset;
+ SVN_ERR (get_uton_xlate_handle (&convset, pool));
+
+ return svn_utf_convert_to_stringbuf (convset, src->data, src->len,
+ dest, pool);
+}
+
+svn_error_t *
+svn_utf_string_from_utf8 (const svn_string_t *src,
+ const svn_string_t **dest,
+ apr_pool_t *pool)
+{
+ svn_stringbuf_t *destbuf;
+
+ /* Get a converter from UTF-8 to the native character encoding */
+ apr_xlate_t *convset;
+ SVN_ERR (get_uton_xlate_handle (&convset, pool));
+ SVN_ERR (svn_utf_convert_to_stringbuf (convset, src->data, src->len,
+ &destbuf, pool));
+ *dest = svn_string_create_from_buf (destbuf, pool);
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_utf_cstring_from_utf8 (const char *src, const char **dest, apr_pool_t *pool)
+{
+ svn_stringbuf_t *destbuf;
+
+ /* Get a converter from UTF-8 to the native character encoding */
+ apr_xlate_t *convset;
+ SVN_ERR (get_uton_xlate_handle (&convset, pool));
+ SVN_ERR (svn_utf_convert_to_stringbuf (convset, src, strlen (src),
+ &destbuf, pool));
+ *dest = destbuf->data;
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_utf_cstring_from_utf8_stringbuf (const svn_stringbuf_t *src, const char **dest,
+ apr_pool_t *pool)
+{
+ svn_stringbuf_t *destbuf;
+ SVN_ERR (svn_utf_stringbuf_from_utf8 (src, &destbuf, pool));
+ *dest = destbuf->data;
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_utf_cstring_from_utf8_string (const svn_string_t *src,
+ const char **dest, apr_pool_t *pool)
+{
+ svn_stringbuf_t *destbuf;
+
+ /* Get a converter from UTF-8 to the native character encoding */
+ apr_xlate_t *convset;
+ SVN_ERR (get_uton_xlate_handle (&convset, pool));
+ SVN_ERR (svn_utf_convert_to_stringbuf (convset, src->data, src->len,
+ &destbuf, pool));
+ *dest = destbuf->data;
+ return SVN_NO_ERROR;
+}
+
+
+const char *
+svn_utf_utf8_to_native (const char *utf8_string,
+ char *buf, apr_size_t bufsize)
+{
+ /* Set up state variables for xlate */
+ apr_size_t srclen = strlen (utf8_string);
+ apr_size_t destlen = bufsize-1;
+
+ /* Ick. Need a pool here so that we can call apr_xlate_open. */
+ apr_pool_t *pool = svn_pool_create (NULL);
+
+ /* Get a converter from UTF-8 to the native character encoding */
+ apr_xlate_t *convset;
+ if (get_uton_xlate_handle (&convset, pool) != SVN_NO_ERROR) {
+ svn_pool_destroy (pool);
+ return "(charset translator procurement failed)";
+ }
+
+ /* Attempt the conversion */
+ if (apr_xlate_conv_buffer(convset, utf8_string, &srclen, buf, &destlen) ==
+ APR_SUCCESS) {
+ /* Conversion succeeded. Zero-terminate and return buffer */
+ buf[bufsize-1-destlen] = '\0';
+ svn_pool_destroy (pool);
+ return buf;
+ }
+
+ svn_pool_destroy (pool);
+ return "(charset conversion failed)";
+}
+
+#else
+
+static svn_error_t *
+check_non_ascii (const char *data, apr_size_t len, apr_pool_t *pool)
+{
+ for (; len > 0; --len, data++)
+ if (*(unsigned char *)data >= 128 ||
+ *(unsigned char *)data == 27 /* Detect ISO-2022 etc */)
+ return svn_error_create (0, 0, NULL, pool,
+ "non-ascii characters detected, "
+ "please compile with --enable-utf8");
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_utf_stringbuf_to_utf8 (const svn_stringbuf_t *src,
+ svn_stringbuf_t **dest,
+ apr_pool_t *pool)
+{
+ SVN_ERR (check_non_ascii (src->data, src->len, pool));
+ *dest = svn_stringbuf_dup (src, pool);
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_utf_cstring_to_utf8_stringbuf (const char *src,
+ svn_stringbuf_t **dest,
+ apr_pool_t *pool)
+{
+ SVN_ERR (check_non_ascii (src, strlen (src), pool));
+ *dest = svn_stringbuf_create (src, pool);
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_utf_cstring_to_utf8 (const char *src, const char **dest,
+ apr_pool_t *pool)
+{
+ SVN_ERR (check_non_ascii (src, strlen (src), pool));
+ *dest = src;
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_utf_stringbuf_from_utf8 (const svn_stringbuf_t *src,
+ svn_stringbuf_t **dest,
+ apr_pool_t *pool)
+{
+ SVN_ERR (check_non_ascii (src->data, src->len, pool));
+ *dest = svn_stringbuf_dup (src, pool);
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_utf_string_from_utf8 (const svn_string_t *src,
+ const svn_string_t **dest,
+ apr_pool_t *pool)
+{
+ SVN_ERR (check_non_ascii (src->data, src->len, pool));
+ *dest = src;
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_utf_cstring_from_utf8 (const char *src, const char **dest, apr_pool_t *pool)
+{
+ SVN_ERR (check_non_ascii (src, strlen (src), pool));
+ *dest = src;
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_utf_cstring_from_utf8_stringbuf (const svn_stringbuf_t *src, const char **dest,
+ apr_pool_t *pool)
+{
+ SVN_ERR (check_non_ascii (src->data, src->len, pool));
+ *dest = src->data;
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_utf_cstring_from_utf8_string (const svn_string_t *src,
+ const char **dest, apr_pool_t *pool)
+{
+ SVN_ERR (check_non_ascii (src->data, src->len, pool));
+ *dest = src->data;
+ return SVN_NO_ERROR;
+}
+
+const char *
+svn_utf_utf8_to_native (const char *utf8_string,
+ char *buf, apr_size_t bufsize)
+{
+ int i;
+
+ /* Just replace non-ASCII characters with '?' here... */
+
+ for (i=0; i<bufsize && *utf8_string; utf8_string++)
+ if (*(unsigned char *)utf8_string < 128)
+ /* ASCII character */
+ buf[i++] = *utf8_string;
+ else if(*(unsigned char *)utf8_string >= 192)
+ /* First octet of a multibyte sequence */
+ buf[i++] = '?';
+
+ buf[i>=bufsize? bufsize-1 : i] = '\0';
+ return buf;
+}
+
+#endif /* SVN_UTF8 */
+
+
+/*
+ * local variables:
+ * eval: (load-file "../../tools/dev/svn-dev.el")
+ * end:
+ */
Index: ./subversion/libsvn_wc/adm_crawler.c
===================================================================
--- ./subversion/libsvn_wc/adm_crawler.c
+++ ./subversion/libsvn_wc/adm_crawler.c Wed May 29 15:03:54 2002
@@ -352,9 +352,8 @@
   if (entry->schedule != svn_wc_schedule_delete)
     {
       apr_finfo_t info;
- apr_status_t apr_err;
- apr_err = apr_stat (&info, path, APR_FINFO_MIN, pool);
- if (APR_STATUS_IS_ENOENT(apr_err))
+ err = svn_io_stat (&info, path, APR_FINFO_MIN, pool);
+ if (err && APR_STATUS_IS_ENOENT(err->apr_err))
         missing = TRUE;
     }
 
@@ -546,13 +545,9 @@
     }
 
   /* Open a filehandle for tmp text-base. */
- if ((status = apr_file_open (&localfile, tmp_base,
- APR_READ, APR_OS_DEFAULT, pool)))
- {
- return svn_error_createf (status, 0, NULL, pool,
- "do_apply_textdelta: error opening '%s'",
- tmp_base);
- }
+ SVN_ERR_W (svn_io_file_open (&localfile, tmp_base,
+ APR_READ, APR_OS_DEFAULT, pool),
+ "do_apply_textdelta: error opening local file");
 
   /* Create a text-delta stream object that pulls data out of the two
      files. */
Index: ./subversion/libsvn_wc/adm_files.c
===================================================================
--- ./subversion/libsvn_wc/adm_files.c
+++ ./subversion/libsvn_wc/adm_files.c Wed May 29 15:20:32 2002
@@ -180,14 +180,12 @@
 
   if (type == svn_node_file)
     {
- apr_err = apr_file_open (&f, path,
- (APR_WRITE | APR_CREATE | APR_EXCL),
- perms,
- pool);
+ err = svn_io_file_open (&f, path,
+ (APR_WRITE | APR_CREATE | APR_EXCL),
+ perms,
+ pool);
 
- if (apr_err)
- err = svn_error_create (apr_err, 0, NULL, pool, path);
- else
+ if (!err)
         {
           /* Creation succeeded, so close immediately. */
           apr_err = apr_file_close (f);
@@ -197,9 +195,7 @@
     }
   else if (type == svn_node_dir)
     {
- apr_err = apr_dir_make (path, perms, pool);
- if (apr_err)
- err = svn_error_create (apr_err, 0, NULL, pool, path);
+ err = svn_io_dir_make (path, perms, pool);
     }
   else /* unknown type argument, wrongness */
     {
@@ -231,21 +227,16 @@
     {
       /* SRC doesn't exist, create DST empty. */
       apr_file_t *f = NULL;
- apr_err = apr_file_open (&f,
- dst,
- (APR_WRITE | APR_CREATE),
- APR_OS_DEFAULT,
- pool);
+ SVN_ERR (svn_io_file_open (&f,
+ dst,
+ (APR_WRITE | APR_CREATE),
+ APR_OS_DEFAULT,
+ pool));
+ apr_err = apr_file_close (f);
       if (apr_err)
         return svn_error_create (apr_err, 0, NULL, pool, dst);
       else
- {
- apr_err = apr_file_close (f);
- if (apr_err)
- return svn_error_create (apr_err, 0, NULL, pool, dst);
- else
- return SVN_NO_ERROR;
- }
+ return SVN_NO_ERROR;
     }
   else /* SRC exists, so copy it to DST. */
     {
@@ -271,7 +262,6 @@
      given how C va_lists work. */
 
   const char *tmp_path;
- apr_status_t apr_err;
   va_list ap;
   
   /* Extend tmp name. */
@@ -288,15 +278,10 @@
   SVN_ERR (svn_io_set_file_read_write (path, TRUE, pool));
  
   /* Rename. */
- apr_err = apr_file_rename (tmp_path, path, pool);
- if (! apr_err)
- SVN_ERR (svn_io_set_file_read_only (path, FALSE, pool));
+ SVN_ERR (svn_io_file_rename (tmp_path, path, pool));
+ SVN_ERR (svn_io_set_file_read_only (path, FALSE, pool));
 
- if (apr_err)
- return svn_error_createf (apr_err, 0, NULL, pool,
- "error renaming %s to %s", tmp_path, path);
- else
- return SVN_NO_ERROR;
+ return SVN_NO_ERROR;
 }
 
 
@@ -512,7 +497,6 @@
                ...)
 {
   svn_error_t *err = NULL;
- apr_status_t apr_err = 0;
   va_list ap;
 
   /* If we're writing, always do it to a tmp file. */
@@ -549,15 +533,14 @@
       va_end (ap);
     }
 
- apr_err = apr_file_open (handle, path, flags, APR_OS_DEFAULT, pool);
- if (apr_err)
+ err = svn_io_file_open (handle, path, flags, APR_OS_DEFAULT, pool);
+ if (err)
     {
       /* Oddly enough, APR will set *HANDLE even if the open failed.
          You'll get a filehandle whose descriptor is -1. There must
          be a reason this is useful... Anyway, we don't want the
          handle. */
       *handle = NULL;
- err = svn_error_create (apr_err, 0, NULL, pool, path);
     }
 
   return err;
@@ -606,15 +589,10 @@
       SVN_ERR (svn_io_set_file_read_write (path, TRUE, pool));
       
       /* Rename. */
- apr_err = apr_file_rename (tmp_path, path, pool);
- if (! apr_err)
- SVN_ERR (svn_io_set_file_read_only (path, FALSE, pool));
+ SVN_ERR (svn_io_file_rename (tmp_path, path, pool));
+ SVN_ERR (svn_io_set_file_read_only (path, FALSE, pool));
       
- if (apr_err)
- return svn_error_createf (apr_err, 0, NULL, pool,
- "error renaming %s to %s", tmp_path, path);
- else
- return SVN_NO_ERROR;
+ return SVN_NO_ERROR;
     }
 
   return SVN_NO_ERROR;
@@ -646,8 +624,6 @@
 svn_error_t *
 svn_wc__remove_adm_file (const char *path, apr_pool_t *pool, ...)
 {
- svn_error_t *err = NULL;
- apr_status_t apr_err = 0;
   va_list ap;
 
   va_start (ap, pool);
@@ -656,12 +632,9 @@
       
   /* Remove read-only flag on path. */
   SVN_ERR(svn_io_set_file_read_write (path, FALSE, pool));
+ SVN_ERR(svn_io_remove_file (path, pool));
 
- apr_err = apr_file_remove (path, pool);
- if (apr_err)
- err = svn_error_create (apr_err, 0, NULL, pool, path);
-
- return err;
+ return SVN_NO_ERROR;
 }
 
 
@@ -1038,16 +1011,11 @@
 static svn_error_t *
 make_empty_adm (const char *path, apr_pool_t *pool)
 {
- svn_error_t *err = NULL;
- apr_status_t apr_err;
-
   path = extend_with_adm_name (path, NULL, 0, pool, NULL);
 
- apr_err = apr_dir_make (path, APR_OS_DEFAULT, pool);
- if (apr_err)
- err = svn_error_create (apr_err, 0, NULL, pool, path);
+ SVN_ERR (svn_io_dir_make (path, APR_OS_DEFAULT, pool));
 
- return err;
+ return SVN_NO_ERROR;
 }
 
 
Index: ./subversion/libsvn_wc/adm_ops.c
===================================================================
--- ./subversion/libsvn_wc/adm_ops.c
+++ ./subversion/libsvn_wc/adm_ops.c Wed May 29 15:23:58 2002
@@ -35,6 +35,7 @@
 #include "svn_hash.h"
 #include "svn_path.h"
 #include "svn_wc.h"
+#include "svn_io.h"
 
 #include "wc.h"
 #include "log.h"
@@ -1295,7 +1296,6 @@
                                      svn_boolean_t destroy_wf,
                                      apr_pool_t *pool)
 {
- apr_status_t apr_err;
   svn_error_t *err;
   svn_boolean_t is_file;
   svn_boolean_t left_a_file = FALSE;
@@ -1443,8 +1443,8 @@
              *non*-recursive dir_remove should work. If it doesn't,
              no big deal. Just assume there are unversioned items in
              there and set "left_a_file" */
- apr_err = apr_dir_remove (path, subpool);
- if (apr_err)
+ err = svn_io_dir_remove_nonrecursive (path, subpool);
+ if (err)
             left_a_file = TRUE;
         }
     } /* end of directory case */
Index: ./subversion/libsvn_wc/copy.c
===================================================================
--- ./subversion/libsvn_wc/copy.c
+++ ./subversion/libsvn_wc/copy.c Wed May 29 15:25:40 2002
@@ -83,7 +83,7 @@
       if (current_entry->kind == svn_node_file)
         {
           SVN_ERR (svn_wc__wcprop_path (&wcprop_path, child_path, 0, subpool));
- (void) apr_file_remove (wcprop_path, subpool);
+ (void) svn_io_remove_file (wcprop_path, subpool);
           /* ignoring any error value from the removal; most likely,
              apr_file_remove will complain about trying to a remove a
              file that's not there. But this more efficient than
Index: ./subversion/libsvn_wc/diff.c
===================================================================
--- ./subversion/libsvn_wc/diff.c
+++ ./subversion/libsvn_wc/diff.c Wed May 29 15:28:24 2002
@@ -789,12 +789,15 @@
 temp_file_cleanup_handler (void *arg)
 {
   struct file_baton *b = arg;
+ svn_error_t *err;
 
   /* The path to the temporary copy of the pristine repository version. */
   const char *temp_file_path
     = svn_wc__text_base_path (b->wc_path, TRUE, b->pool);
 
- return apr_file_remove (temp_file_path, b->pool);
+ err = svn_io_remove_file (temp_file_path, b->pool);
+
+ return (err? err->apr_err : APR_SUCCESS);
 }
 
 /* This removes the temp_file_cleanup_handler in the child process before
Index: ./subversion/libsvn_wc/log.c
===================================================================
--- ./subversion/libsvn_wc/log.c
+++ ./subversion/libsvn_wc/log.c Wed May 29 15:38:17 2002
@@ -29,6 +29,7 @@
 #include "svn_string.h"
 #include "svn_xml.h"
 #include "svn_pools.h"
+#include "svn_io.h"
 
 #include "wc.h"
 #include "log.h"
@@ -79,7 +80,7 @@
                       enum svn_wc__xfer_action action,
                       apr_pool_t *pool)
 {
- apr_status_t status;
+ svn_error_t *err;
   const char *full_from_path, *full_dest_path;
 
   full_from_path = svn_path_join (path, name, pool);
@@ -144,16 +145,15 @@
       /* Remove read-only flag on destination. */
       SVN_ERR (svn_io_set_file_read_write (full_dest_path, TRUE, pool));
 
- status = apr_file_rename (full_from_path,
- full_dest_path, pool);
+ err = svn_io_file_rename (full_from_path,
+ full_dest_path, pool);
 
       /* If we got an ENOENT, that's ok; the move has probably
          already completed in an earlier run of this log. */
- if (status && (! APR_STATUS_IS_ENOENT(status)))
- return svn_error_createf (status, 0, NULL, pool,
- "file_xfer_under_path: "
- "can't move %s to %s",
- name, dest);
+ if (err && (! APR_STATUS_IS_ENOENT(err->apr_err)))
+ return svn_error_quick_wrap (err,
+ "file_xfer_under_path: "
+ "can't move from to dest");
   }
 
   return SVN_NO_ERROR;
@@ -306,7 +306,6 @@
                 const XML_Char **atts)
 {
   svn_error_t *err;
- apr_status_t apr_err;
   const char
     *infile_name,
     *outfile_name,
@@ -340,11 +339,9 @@
       const char *infile_path
         = svn_path_join (loggy->path, infile_name, loggy->pool);
       
- apr_err = apr_file_open (&infile, infile_path, APR_READ,
- APR_OS_DEFAULT, loggy->pool);
- if (apr_err)
- return svn_error_createf (apr_err, 0, NULL, loggy->pool,
- "error opening %s", infile_path);
+ SVN_ERR_W (svn_io_file_open (&infile, infile_path, APR_READ,
+ APR_OS_DEFAULT, loggy->pool),
+ "error opening infile");
     }
   
   if (outfile_name)
@@ -354,12 +351,10 @@
       
       /* kff todo: always creates and overwrites, currently.
          Could append if file exists... ? Consider. */
- apr_err = apr_file_open (&outfile, outfile_path,
- (APR_WRITE | APR_CREATE),
- APR_OS_DEFAULT, loggy->pool);
- if (apr_err)
- return svn_error_createf (apr_err, 0, NULL, loggy->pool,
- "error opening %s", outfile_path);
+ SVN_ERR_W (svn_io_file_open (&outfile, outfile_path,
+ (APR_WRITE | APR_CREATE),
+ APR_OS_DEFAULT, loggy->pool),
+ "error opening outfile");
     }
   
   if (errfile_name)
@@ -369,12 +364,10 @@
       
       /* kff todo: always creates and overwrites, currently.
          Could append if file exists... ? Consider. */
- apr_err = apr_file_open (&errfile, errfile_path,
- (APR_WRITE | APR_CREATE),
- APR_OS_DEFAULT, loggy->pool);
- if (apr_err)
- return svn_error_createf (apr_err, 0, NULL, loggy->pool,
- "error opening %s", errfile_path);
+ SVN_ERR_W (svn_io_file_open (&errfile, errfile_path,
+ (APR_WRITE | APR_CREATE),
+ APR_OS_DEFAULT, loggy->pool),
+ "error opening errfile");
     }
   
   err = svn_io_run_cmd (loggy->path, name, args, NULL, NULL, FALSE,
@@ -477,13 +470,9 @@
 static svn_error_t *
 log_do_rm (struct log_runner *loggy, const char *name)
 {
- apr_status_t apr_err;
   const char *full_path = svn_path_join (loggy->path, name, loggy->pool);
 
- apr_err = apr_file_remove (full_path, loggy->pool);
- if (apr_err)
- return svn_error_createf (apr_err, 0, NULL, loggy->pool,
- "apr_file_remove couldn't remove %s", name);
+ SVN_ERR (svn_io_remove_file (full_path, loggy->pool));
 
   return SVN_NO_ERROR;
 }
@@ -853,7 +842,6 @@
     if (kind == svn_node_file)
       {
         svn_boolean_t same;
- apr_status_t status;
         const char *chosen;
 
         /* Get property file pathnames (not from the `tmp' area) depending
@@ -914,10 +902,7 @@
         /* Make the tmp prop file the new pristine one. Note that we
            have to temporarily set the file permissions for writability. */
         SVN_ERR (svn_io_set_file_read_write (basef, TRUE, pool));
- if ((status = apr_file_rename (tmpf, basef, pool)))
- return svn_error_createf (status, 0, NULL, pool,
- "error renaming `%s' to `%s'",
- tmpf, basef);
+ SVN_ERR (svn_io_file_rename (tmpf, basef, pool));
         SVN_ERR (svn_io_set_file_read_only (basef, FALSE, pool));
       }
   }
Index: ./subversion/libsvn_wc/merge.c
===================================================================
--- ./subversion/libsvn_wc/merge.c
+++ ./subversion/libsvn_wc/merge.c Wed May 29 15:39:37 2002
@@ -262,26 +262,14 @@
 
       /* Don't forget to clean up tmp_target, result_target, tmp_left,
          tmp_right. There are a lot of scratch files lying around. */
- apr_err = apr_file_remove (tmp_target, pool);
- if (apr_err)
- return svn_error_createf
- (apr_err, 0, NULL, pool,
- "svn_wc_merge: unable to delete tmp file `%s'", tmp_target);
- apr_err = apr_file_remove (result_target, pool);
- if (apr_err)
- return svn_error_createf
- (apr_err, 0, NULL, pool,
- "svn_wc_merge: unable to delete tmp file `%s'", result_target);
- apr_err = apr_file_remove (tmp_left, pool);
- if (apr_err)
- return svn_error_createf
- (apr_err, 0, NULL, pool,
- "svn_wc_merge: unable to delete tmp file `%s'", tmp_left);
- apr_err = apr_file_remove (tmp_right, pool);
- if (apr_err)
- return svn_error_createf
- (apr_err, 0, NULL, pool,
- "svn_wc_merge: unable to delete tmp file `%s'", tmp_right);
+ SVN_ERR_W (svn_io_remove_file (tmp_target, pool),
+ "svn_wc_merge: unable to delete tmp file");
+ SVN_ERR_W (svn_io_remove_file (result_target, pool),
+ "svn_wc_merge: unable to delete tmp file");
+ SVN_ERR_W (svn_io_remove_file (tmp_left, pool),
+ "svn_wc_merge: unable to delete tmp file");
+ SVN_ERR_W (svn_io_remove_file (tmp_right, pool),
+ "svn_wc_merge: unable to delete tmp file");
 
     } /* end of merging for text files */
 
Index: ./subversion/libsvn_wc/props.c
===================================================================
--- ./subversion/libsvn_wc/props.c
+++ ./subversion/libsvn_wc/props.c Wed May 29 16:10:20 2002
@@ -40,6 +40,7 @@
 #include "svn_hash.h"
 #include "svn_wc.h"
 #include "svn_time.h"
+#include "svn_utf.h"
 
 #include "wc.h"
 #include "log.h"
@@ -239,12 +240,9 @@
       apr_status_t status;
       apr_file_t *propfile = NULL;
 
- status = apr_file_open (&propfile, propfile_path,
- APR_READ, APR_OS_DEFAULT, pool);
- if (status)
- return svn_error_createf (status, 0, NULL, pool,
- "load_prop_file: can't open `%s'",
- propfile_path);
+ SVN_ERR_W (svn_io_file_open (&propfile, propfile_path,
+ APR_READ, APR_OS_DEFAULT, pool),
+ "load_prop_file: can't open propfile");
 
       status = svn_hash_read (hash, svn_pack_bytestring,
                               propfile, pool);
@@ -275,13 +273,10 @@
   apr_status_t apr_err;
   apr_file_t *prop_tmp;
 
- apr_err = apr_file_open (&prop_tmp, propfile_path,
- (APR_WRITE | APR_CREATE | APR_TRUNCATE),
- APR_OS_DEFAULT, pool);
- if (apr_err)
- return svn_error_createf (apr_err, 0, NULL, pool,
- "save_prop_file: can't open `%s'",
- propfile_path);
+ SVN_ERR_W (svn_io_file_open (&prop_tmp, propfile_path,
+ (APR_WRITE | APR_CREATE | APR_TRUNCATE),
+ APR_OS_DEFAULT, pool),
+ "save_prop_file: can't open propfile");
 
   apr_err = svn_hash_write (hash, svn_unpack_bytestring,
                             prop_tmp, pool);
@@ -315,9 +310,13 @@
      timestamp or something? */
   apr_size_t written;
   apr_status_t status;
+ const svn_string_t *conflict_description_native;
 
- status = apr_file_write_full (fp, conflict_description->data,
- conflict_description->len, &written);
+ SVN_ERR (svn_utf_string_from_utf8 (conflict_description,
+ &conflict_description_native,
+ pool));
+ status = apr_file_write_full (fp, conflict_description_native->data,
+ conflict_description_native->len, &written);
   if (status)
     return svn_error_create (status, 0, NULL, pool,
                              "append_prop_conflict: apr_file_write_full failed.");
@@ -1134,13 +1133,8 @@
   else
     {
       apr_finfo_t finfo;
- apr_status_t status;
 
- status = apr_stat (&finfo, path_to_prop_file, APR_FINFO_MIN, pool);
- if (status)
- return svn_error_createf (status, 0, NULL, pool,
- "couldn't stat '%s'...",
- path_to_prop_file);
+ SVN_ERR (svn_io_stat (&finfo, path_to_prop_file, APR_FINFO_MIN, pool));
 
       /* If we remove props from a propfile, eventually the file will
          contain nothing but "END\n" */
Index: ./subversion/libsvn_wc/questions.c
===================================================================
--- ./subversion/libsvn_wc/questions.c
+++ ./subversion/libsvn_wc/questions.c Wed May 29 00:00:48 2002
@@ -31,6 +31,7 @@
 #include "svn_path.h"
 #include "svn_time.h"
 #include "svn_wc.h"
+#include "svn_io.h"
 
 #include "wc.h"
 #include "adm_files.h"
@@ -202,25 +203,19 @@
                       const char *file2,
                       apr_pool_t *pool)
 {
- apr_status_t status;
+ apr_status_t status = 0;
   apr_size_t bytes_read1, bytes_read2;
   char buf1[BUFSIZ], buf2[BUFSIZ];
   apr_file_t *file1_h = NULL;
   apr_file_t *file2_h = NULL;
 
- status = apr_file_open (&file1_h, file1,
- APR_READ, APR_OS_DEFAULT, pool);
- if (status)
- return svn_error_createf
- (status, 0, NULL, pool,
- "contents_identical_p: apr_file_open failed on `%s'", file1);
-
- status = apr_file_open (&file2_h, file2, APR_READ,
- APR_OS_DEFAULT, pool);
- if (status)
- return svn_error_createf
- (status, 0, NULL, pool,
- "contents_identical_p: apr_file_open failed on `%s'", file2);
+ SVN_ERR_W (svn_io_file_open (&file1_h, file1, APR_READ, APR_OS_DEFAULT,
+ pool),
+ "contents_identical_p: apr_file_open failed on file 1");
+
+ SVN_ERR_W (svn_io_file_open (&file2_h, file2, APR_READ, APR_OS_DEFAULT,
+ pool),
+ "contents_identical_p: apr_file_open failed on file 2");
 
   *identical_p = TRUE; /* assume TRUE, until disproved below */
   while (!APR_STATUS_IS_EOF(status))
Index: ./subversion/libsvn_wc/translate.c
===================================================================
--- ./subversion/libsvn_wc/translate.c
+++ ./subversion/libsvn_wc/translate.c Wed May 29 00:00:48 2002
@@ -444,20 +444,20 @@
     return svn_io_copy_file (src, dst, FALSE, pool);
 
   /* Open source file. */
- apr_err = apr_file_open (&s, src, APR_READ | APR_BUFFERED,
- APR_OS_DEFAULT, pool);
- if (apr_err)
- return translate_err (apr_err, "opening", src, pool);
+ err = svn_io_file_open (&s, src, APR_READ | APR_BUFFERED,
+ APR_OS_DEFAULT, pool);
+ if (err)
+ return svn_error_quick_wrap (err, "opening source file");
   
   /* Open dest file. */
- apr_err
- = apr_file_open (&d, dst,
- APR_WRITE | APR_CREATE | APR_TRUNCATE | APR_BUFFERED,
- APR_OS_DEFAULT, pool);
- if (apr_err)
+ err
+ = svn_io_file_open (&d, dst,
+ APR_WRITE | APR_CREATE | APR_TRUNCATE | APR_BUFFERED,
+ APR_OS_DEFAULT, pool);
+ if (err)
     {
       apr_file_close (s); /* toss */
- return translate_err (apr_err, "opening", dst, pool);
+ return svn_error_quick_wrap (err, "opening dest file");
     }
 
   /*** Any errors after this point require us to close the two files and
@@ -696,7 +696,7 @@
     apr_file_close (s); /* toss error */
   if (d)
     apr_file_close (d); /* toss error */
- apr_file_remove (dst, pool); /* toss error */
+ svn_io_remove_file (dst, pool); /* toss error */
   return err;
 #endif /* ! SVN_TRANSLATE */
 }
Index: ./subversion/libsvn_wc/update_editor.c
===================================================================
--- ./subversion/libsvn_wc/update_editor.c
+++ ./subversion/libsvn_wc/update_editor.c Wed May 29 16:04:34 2002
@@ -1155,13 +1155,9 @@
          pointing to parent_dir/.svn/tmp/text-base/basename. */
       if (strcmp (final_location, new_text_path))
         {
- apr_err = apr_file_rename (new_text_path, final_location,
- pool);
- if (apr_err)
- return svn_error_createf (apr_err, 0, NULL, pool,
- "svn_wc_install_file: "
- "can't move %s to %s",
- new_text_path, final_location);
+ SVN_ERR_W (svn_io_file_rename (new_text_path, final_location,
+ pool),
+ "svn_wc_install_file: move failed");
 
           new_text_path = final_location;
         }
Index: ./subversion/libsvn_wc/util.c
===================================================================
--- ./subversion/libsvn_wc/util.c
+++ ./subversion/libsvn_wc/util.c Wed May 29 15:44:45 2002
@@ -53,18 +53,17 @@
     {
       /* The dir doesn't exist, and it's our job to change that. */
 
- apr_status_t apr_err =
- apr_dir_make (path, APR_OS_DEFAULT, pool);
+ err = svn_io_dir_make (path, APR_OS_DEFAULT, pool);
 
- if (apr_err && !APR_STATUS_IS_ENOENT(apr_err))
+ if (err && !APR_STATUS_IS_ENOENT(err->apr_err))
         {
           /* Tried to create the dir, and encountered some problem
              other than non-existence of intermediate dirs. We can't
              ensure the desired directory's existence, so just return
              the error. */
- return svn_error_create (apr_err, 0, NULL, pool, path);
+ return err;
         }
- else if (APR_STATUS_IS_ENOENT(apr_err))
+ else if (err && APR_STATUS_IS_ENOENT(err->apr_err))
         /* (redundant conditional and comment) */
         {
           /* Okay, so the problem is a missing intermediate
@@ -89,8 +88,8 @@
             }
         }
 
- if (apr_err)
- return svn_error_create (apr_err, 0, NULL, pool, path);
+ if (err)
+ return err;
     }
   else /* No problem, the dir already existed, so just leave. */
     assert (kind == svn_node_dir);
Index: ./subversion/svnlook/main.c
===================================================================
--- ./subversion/svnlook/main.c
+++ ./subversion/svnlook/main.c Wed May 29 17:24:01 2002
@@ -505,7 +505,7 @@
       apr_file_t *outhandle;
       apr_status_t apr_err;
       const char *label;
- char *abs_path;
+ const char *abs_path;
       int exitcode;
 
       if (! is_copy)

Index: ./subversion/clients/cmdline/cl.h
===================================================================
--- ./subversion/clients/cmdline/cl.h
+++ ./subversion/clients/cmdline/cl.h Wed May 29 12:20:02 2002
@@ -69,9 +69,9 @@
 
   const char *message; /* log message */
 
- const char *xml_file; /* F in "svn blah --xml-file F" */
+ const char *xml_file; /* F in "svn blah --xml-file F" */ /* UTF-8! */
 
- const char *target; /* Target dir, T in "svn co -d T" */
+ const char *target; /* Target dir, T in "svn co -d T" */ /* UTF-8! */
 
   const char *ancestor_path; /* ### todo: who sets this? */
 
@@ -88,13 +88,13 @@
   svn_boolean_t verbose;
   svn_boolean_t very_verbose;
   svn_boolean_t update;
- apr_array_header_t *args;
+ apr_array_header_t *args; /* UTF-8! */
   svn_stringbuf_t *filedata;
   svn_boolean_t help;
- const char *auth_username;
- const char *auth_password;
- const char *extensions; /* for extension args to subprocesses */
- apr_array_header_t *targets; /* when target list supplied from file */
+ const char *auth_username; /* UTF-8! */
+ const char *auth_password; /* UTF-8! */
+ const char *extensions; /* for extension args to subprocesses */ /* UTF-8! */
+ apr_array_header_t *targets; /* when target list supplied from file */ /* UTF-8! */
   svn_boolean_t xml; /* output in xml, e.g., "svn log --xml" */
 } svn_cl__opt_state_t;
 
@@ -177,6 +177,8 @@
   found, it will overwrite the value of opt_state->start_revision. If
   a second one is found, it will overwrite opt_state->end_revision.
   (Extra revisions beyond that are ignored.)
+
+ The array of targets will be in UTF-8 format.
   */
 apr_array_header_t*
 svn_cl__args_to_target_array (apr_getopt_t *os,
@@ -256,11 +258,13 @@
 
 /* Print a hash that maps property names (char *) to property values
    (svn_stringbuf_t *). */
-void svn_cl__print_prop_hash (apr_hash_t *prop_hash, apr_pool_t *pool);
+svn_error_t *
+svn_cl__print_prop_hash (apr_hash_t *prop_hash, apr_pool_t *pool);
 
 /* Print out the property names in a hash that maps property names (char *)
    to property values (svn_stringbuf_t *). */
-void svn_cl__print_prop_names (apr_hash_t *prop_hash, apr_pool_t *pool);
+svn_error_t *
+svn_cl__print_prop_names (apr_hash_t *prop_hash, apr_pool_t *pool);
 
 /* Returns an editor that prints out events in an update or checkout.
    The IS_CHECKOUT boolean tells the editor what kind of final
@@ -269,7 +273,7 @@
 svn_error_t *
 svn_cl__get_trace_update_editor (const svn_delta_editor_t **editor,
                                  void **edit_baton,
- const char *initial_path,
+ const char *initial_path, /* UTF-8! */
                                  svn_boolean_t is_checkout,
                                  svn_boolean_t suppress_final_line,
                                  apr_pool_t *pool);
Index: ./subversion/clients/cmdline/feedback.c
===================================================================
--- ./subversion/clients/cmdline/feedback.c
+++ ./subversion/clients/cmdline/feedback.c Wed May 29 12:39:59 2002
@@ -29,6 +29,7 @@
 #include <apr_want.h>
 
 #include "svn_pools.h"
+#include "svn_utf.h"
 #include "cl.h"
 
 
@@ -40,19 +41,15 @@
 
 
 static void
-notify_added (void *baton, const char *path)
+notify_added (const char *path, const char *path_utf8, apr_pool_t *pool)
 {
- struct notify_baton *nb = (struct notify_baton *) baton;
-
- /* the pool (BATON) is typically the global pool; don't keep filling it */
- apr_pool_t *subpool = svn_pool_create (nb->pool);
   svn_wc_entry_t *entry;
   svn_error_t *err;
   const char *type = " "; /* fill with "binary" if binary, etc */
 
   /* ### this sucks. we have to open/parse the entries file to get this
      ### information. when adding thousands of files, this blows... */
- err = svn_wc_entry (&entry, path, FALSE, subpool);
+ err = svn_wc_entry (&entry, path_utf8, FALSE, pool);
   if (err)
     {
       printf ("WARNING: error fetching entry for %s\n", path);
@@ -69,7 +66,7 @@
       const svn_string_t *value;
 
       /* ### and again: open/parse a properties file. urk... */
- err = svn_wc_prop_get (&value, SVN_PROP_MIME_TYPE, path, subpool);
+ err = svn_wc_prop_get (&value, SVN_PROP_MIME_TYPE, path_utf8, pool);
       if (err)
         {
           printf ("WARNING: error fetching %s property for %s\n",
@@ -86,7 +83,7 @@
   printf ("A %s %s\n", type, path);
 
  done:
- svn_pool_destroy (subpool);
+ ;
 }
 
 
@@ -112,55 +109,73 @@
                      svn_wc_notify_action_t action,
                      const char *path)
 {
+ struct notify_baton *nb = (struct notify_baton *) baton;
+
+ /* the pool (BATON) is typically the global pool; don't keep filling it */
+ apr_pool_t *subpool = svn_pool_create (nb->pool);
+
+ const char *path_native;
+ svn_error_t *err;
+
+ err = svn_utf_cstring_from_utf8 (path, &path_native, subpool);
+ if (err)
+ {
+ printf ("WARNING: error decoding UTF-8 for ?\n");
+ goto done;
+ }
+
   switch (action)
     {
     case svn_wc_notify_add:
- notify_added (baton, path);
- return;
+ notify_added (path_native, path, subpool);
+ break;
 
     case svn_wc_notify_delete:
- printf ("D %s\n", path);
- return;
+ printf ("D %s\n", path_native);
+ break;
 
     case svn_wc_notify_restore:
- printf ("Restored %s\n", path);
- return;
+ printf ("Restored %s\n", path_native);
+ break;
 
     case svn_wc_notify_revert:
- printf ("Reverted %s\n", path);
- return;
+ printf ("Reverted %s\n", path_native);
+ break;
 
     case svn_wc_notify_resolve:
- printf ("Resolved conflicted state of %s\n", path);
- return;
+ printf ("Resolved conflicted state of %s\n", path_native);
+ break;
 
     case svn_wc_notify_update:
- printf ("U %s\n", path);
- return;
+ printf ("U %s\n", path_native);
+ break;
 
     case svn_wc_notify_commit_modified:
- printf ("Sending %s\n", path);
- return;
+ printf ("Sending %s\n", path_native);
+ break;
 
     case svn_wc_notify_commit_added:
- printf ("Adding %s\n", path);
- return;
+ printf ("Adding %s\n", path_native);
+ break;
 
     case svn_wc_notify_commit_deleted:
- printf ("Deleting %s\n", path);
- return;
+ printf ("Deleting %s\n", path_native);
+ break;
 
     case svn_wc_notify_commit_replaced:
- printf ("Replacing %s\n", path);
- return;
+ printf ("Replacing %s\n", path_native);
+ break;
 
     case svn_wc_notify_commit_postfix_txdelta:
- notify_commit_postfix_txdelta (baton, path);
- return;
+ notify_commit_postfix_txdelta (baton, path_native);
+ break;
 
     default:
       break;
     }
+
+ done:
+ svn_pool_destroy (subpool);
 }
 
 
Index: ./subversion/clients/cmdline/help-cmd.c
===================================================================
--- ./subversion/clients/cmdline/help-cmd.c
+++ ./subversion/clients/cmdline/help-cmd.c Wed May 29 12:43:26 2002
@@ -26,6 +26,7 @@
 #include "svn_string.h"
 #include "svn_error.h"
 #include "svn_version.h"
+#include "svn_utf.h"
 #include "cl.h"
 
 
@@ -36,6 +37,7 @@
 {
   void *ra_baton;
   svn_stringbuf_t *descriptions;
+ const char *descriptions_native;
   static const char info[] =
     "Copyright (C) 2000-2002 CollabNet.\n"
     "Subversion is open source software, see http://subversion.tigris.org/\n";
@@ -52,7 +54,10 @@
   /* Get a descriptive list of them. */
   SVN_ERR (svn_ra_print_ra_libraries (&descriptions, ra_baton, pool));
 
- printf ("%s\n", descriptions->data);
+ SVN_ERR (svn_utf_cstring_from_utf8_stringbuf (descriptions,
+ &descriptions_native, pool));
+
+ printf ("%s\n", descriptions_native);
 
   return SVN_NO_ERROR;
 }
@@ -82,7 +87,11 @@
     for (i = 0; i < targets->nelts; i++)
       {
         const char *this = (((const char **) (targets)->elts))[i];
- svn_cl__subcommand_help (this, pool);
+ const char *this_native;
+ /* This is a bit silly, but svn_cl__args_to_target_array()
+ converts the args to UTF-8, so we have to convert them back. */
+ SVN_ERR (svn_utf_cstring_from_utf8 (this, &this_native, pool));
+ svn_cl__subcommand_help (this_native, pool);
       }
   else if (opt_state && opt_state->version) /* just -v or --version */
     SVN_ERR (print_version_info (pool));
Index: ./subversion/clients/cmdline/info-cmd.c
===================================================================
--- ./subversion/clients/cmdline/info-cmd.c
+++ ./subversion/clients/cmdline/info-cmd.c Wed May 29 12:51:32 2002
@@ -26,6 +26,7 @@
 #include "svn_string.h"
 #include "svn_error.h"
 #include "svn_path.h"
+#include "svn_utf.h"
 #include "cl.h"
 
 
@@ -64,10 +65,12 @@
   for (i = 0; i < targets->nelts; i++)
     {
       const char *target = ((const char **) (targets->elts))[i];
+ const char *native;
       svn_wc_entry_t *entry;
       svn_boolean_t text_conflict = FALSE, props_conflict = FALSE;
 
- printf ("Path: %s\n", target);
+ SVN_ERR (svn_utf_cstring_from_utf8 (target, &native, pool));
+ printf ("Path: %s\n", native);
 
       SVN_ERR (svn_wc_entry (&entry, target, FALSE, pool));
       if (! entry)
@@ -83,13 +86,18 @@
 
       if ((entry->name)
           && strcmp (entry->name, SVN_WC_ENTRY_THIS_DIR))
- printf ("Name: %s\n", entry->name);
+ SVN_ERR (svn_utf_cstring_from_utf8 (entry->name, &native, pool));
+ printf ("Name: %s\n", native);
       
- if (entry->url)
- printf ("Url: %s\n", entry->url);
-
- if (entry->repos)
- printf ("Repository: %s\n", entry->repos);
+ if (entry->url) {
+ SVN_ERR (svn_utf_cstring_from_utf8 (entry->url, &native, pool));
+ printf ("Url: %s\n", native);
+ }
+
+ if (entry->repos) {
+ SVN_ERR (svn_utf_cstring_from_utf8 (entry->repos, &native, pool));
+ printf ("Repository: %s\n", native);
+ }
 
       if (SVN_IS_VALID_REVNUM (entry->revision))
         printf ("Revision: %" SVN_REVNUM_T_FMT "\n", entry->revision);
@@ -146,16 +154,21 @@
 
       if (entry->copied)
         {
- if (entry->copyfrom_url)
- printf ("Copied From Url: %s\n", entry->copyfrom_url);
+ if (entry->copyfrom_url) {
+ SVN_ERR (svn_utf_cstring_from_utf8 (entry->copyfrom_url,
+ &native, pool));
+ printf ("Copied From Url: %s\n", native);
+ }
 
           if (SVN_IS_VALID_REVNUM (entry->copyfrom_rev))
             printf ("Copied From Rev: %" SVN_REVNUM_T_FMT "\n",
                     entry->copyfrom_rev);
         }
 
- if (entry->cmt_author)
- printf ("Last Changed Author: %s\n", entry->cmt_author);
+ if (entry->cmt_author) {
+ SVN_ERR (svn_utf_cstring_from_utf8 (entry->cmt_author, &native, pool));
+ printf ("Last Changed Author: %s\n", native);
+ }
 
       if (SVN_IS_VALID_REVNUM (entry->cmt_rev))
         printf ("Last Changed Rev: %" SVN_REVNUM_T_FMT "\n", entry->cmt_rev);
@@ -169,21 +182,35 @@
       if (entry->prop_time)
         svn_cl__info_print_time (entry->prop_time, "Properties Last Updated");
 
- if (entry->checksum)
- printf ("Checksum: %s\n", entry->checksum);
-
- if (text_conflict && entry->conflict_old)
- printf ("Conflict Previous Base File: %s\n", entry->conflict_old);
-
- if (text_conflict && entry->conflict_wrk)
+ if (entry->checksum) {
+ SVN_ERR (svn_utf_cstring_from_utf8 (entry->checksum, &native, pool));
+ printf ("Checksum: %s\n", native);
+ }
+
+ if (text_conflict && entry->conflict_old) {
+ SVN_ERR (svn_utf_cstring_from_utf8 (entry->conflict_old,
+ &native, pool));
+ printf ("Conflict Previous Base File: %s\n", native);
+ }
+
+ if (text_conflict && entry->conflict_wrk) {
+ SVN_ERR (svn_utf_cstring_from_utf8 (entry->conflict_wrk,
+ &native, pool));
         printf ("Conflict Previous Working File: %s\n",
- entry->conflict_wrk);
-
- if (text_conflict && entry->conflict_new)
- printf ("Conflict Current Base File: %s\n", entry->conflict_new);
+ native);
+ }
 
- if (props_conflict && entry->prejfile)
- printf ("Conflict Properties File: %s\n", entry->prejfile);
+ if (text_conflict && entry->conflict_new) {
+ SVN_ERR (svn_utf_cstring_from_utf8 (entry->conflict_new,
+ &native, pool));
+ printf ("Conflict Current Base File: %s\n", native);
+ }
+
+ if (props_conflict && entry->prejfile) {
+ SVN_ERR (svn_utf_cstring_from_utf8 (entry->prejfile,
+ &native, pool));
+ printf ("Conflict Properties File: %s\n", native);
+ }
 
       /* Print extra newline separator. */
       printf ("\n");
Index: ./subversion/clients/cmdline/log-cmd.c
===================================================================
--- ./subversion/clients/cmdline/log-cmd.c
+++ ./subversion/clients/cmdline/log-cmd.c Wed May 29 00:01:13 2002
@@ -33,6 +33,7 @@
 #include "svn_error.h"
 #include "svn_pools.h"
 #include "svn_xml.h"
+#include "svn_utf.h"
 #include "cl.h"
 
 
@@ -154,6 +155,7 @@
                       apr_pool_t *pool)
 {
   struct log_message_receiver_baton *lb = baton;
+ const char *author_native, *date_native, *msg_native;
 
   /* Number of lines in the msg. */
   int lines;
@@ -167,7 +169,11 @@
       return SVN_NO_ERROR;
     }
 
- humanize_date (dbuf, date);
+ SVN_ERR (svn_utf_cstring_from_utf8 (author, &author_native, pool));
+ SVN_ERR (svn_utf_cstring_from_utf8 (date, &date_native, pool));
+ SVN_ERR (svn_utf_cstring_from_utf8 (msg, &msg_native, pool));
+
+ humanize_date (dbuf, date_native);
 
 #define SEP_STRING \
   "------------------------------------------------------------------------\n"
@@ -178,9 +184,9 @@
       lb->first_call = 0;
     }
 
- lines = num_lines (msg);
+ lines = num_lines (msg_native);
   printf ("rev %" SVN_REVNUM_T_FMT ": %s | %s | %d line%s\n",
- rev, author, dbuf, lines, (lines > 1) ? "s" : "");
+ rev, author_native, dbuf, lines, (lines > 1) ? "s" : "");
   if (changed_paths)
     {
       apr_hash_index_t *hi;
@@ -211,7 +217,7 @@
         }
     }
   printf ("\n"); /* A blank line always precedes the log message. */
- printf ("%s\n", msg);
+ printf ("%s\n", msg_native);
   printf (SEP_STRING);
 
   return SVN_NO_ERROR;
Index: ./subversion/clients/cmdline/main.c
===================================================================
--- ./subversion/clients/cmdline/main.c
+++ ./subversion/clients/cmdline/main.c Wed May 29 12:59:32 2002
@@ -41,6 +41,7 @@
 #include "svn_error.h"
 #include "svn_io.h"
 #include "svn_time.h"
+#include "svn_utf.h"
 #include "cl.h"
 
 
@@ -809,7 +810,9 @@
      (Actually, this is a no-op; according to the C standard, "C" is
      the default locale at program startup.) */
   setlocale (LC_ALL, "C");
-
+ /* For APR_LOCALE_CHARSET to do the right thing, we need to at least
+ let LC_CTYPE be set from the environment. */
+ setlocale (LC_CTYPE, "");
 
   apr_err = apr_initialize ();
   if (apr_err)
@@ -844,6 +847,7 @@
     {
       const char *opt_arg;
       svn_boolean_t ret;
+ const char *utf8_opt_arg;
 
       /* Parse the next option. */
       apr_err = apr_getopt_long (os, svn_cl__options, &opt_id, &opt_arg);
@@ -877,12 +881,17 @@
         ret = svn_cl__parse_revision (&opt_state, opt_arg, pool);
         if (ret)
           {
- svn_handle_error (svn_error_createf
- (SVN_ERR_CL_ARG_PARSING_ERROR,
- 0, NULL, pool,
- "Syntax error in revision argument \"%s\"",
- opt_arg),
- stderr, FALSE);
+ err = svn_utf_cstring_to_utf8 (opt_arg, &utf8_opt_arg, pool);
+
+ if (err)
+ svn_handle_error (err, stderr, FALSE);
+ else
+ svn_handle_error (svn_error_createf
+ (SVN_ERR_CL_ARG_PARSING_ERROR,
+ 0, NULL, pool,
+ "Syntax error in revision argument \"%s\"",
+ utf8_opt_arg),
+ stderr, FALSE);
             svn_pool_destroy (pool);
             return EXIT_FAILURE;
           }
@@ -891,11 +900,16 @@
         ret = parse_date (&opt_state, opt_arg, pool);
         if (ret)
           {
- svn_handle_error (svn_error_createf
- (SVN_ERR_CL_ARG_PARSING_ERROR,
- 0, NULL, pool,
- "Unable to parse \"%s\"", opt_arg),
- stderr, FALSE);
+ err = svn_utf_cstring_to_utf8 (opt_arg, &utf8_opt_arg, pool);
+
+ if (err)
+ svn_handle_error (err, stderr, FALSE);
+ else
+ svn_handle_error (svn_error_createf
+ (SVN_ERR_CL_ARG_PARSING_ERROR,
+ 0, NULL, pool,
+ "Unable to parse \"%s\"", utf8_opt_arg),
+ stderr, FALSE);
             svn_pool_destroy (pool);
             return EXIT_FAILURE;
           }
@@ -917,13 +931,28 @@
         opt_state.quiet = TRUE;
         break;
       case svn_cl__xml_file_opt:
- opt_state.xml_file = apr_pstrdup (pool, opt_arg);
+ err = svn_utf_cstring_to_utf8 (opt_arg, &opt_state.xml_file, pool);
+ if (err)
+ {
+ svn_handle_error (err, stdout, FALSE);
+ svn_pool_destroy (pool);
+ return EXIT_FAILURE;
+ }
         break;
       case 'd':
- opt_state.target = apr_pstrdup (pool, opt_arg);
+ err = svn_utf_cstring_to_utf8 (opt_arg, &opt_state.target, pool);
+ if (err)
+ {
+ svn_handle_error (err, stdout, FALSE);
+ svn_pool_destroy (pool);
+ return EXIT_FAILURE;
+ }
         break;
       case 'F':
- err = svn_string_from_file (&(opt_state.filedata), opt_arg, pool);
+ err = svn_utf_cstring_to_utf8 (opt_arg, &utf8_opt_arg, pool);
+ if (!err)
+ err = svn_string_from_file (&(opt_state.filedata),
+ utf8_opt_arg, pool);
         if (err)
           {
             svn_handle_error (err, stdout, FALSE);
@@ -934,22 +963,27 @@
         {
           svn_wc_entry_t *e;
 
- err = svn_wc_entry (&e, opt_arg, FALSE, pool);
+ err = svn_wc_entry (&e, utf8_opt_arg, FALSE, pool);
+
           if ((err == SVN_NO_ERROR) && e)
             log_under_version_control = TRUE;
         }
         break;
       case svn_cl__targets_opt:
         {
- svn_stringbuf_t *buffer;
- err = svn_string_from_file (&buffer, opt_arg, pool);
+ svn_stringbuf_t *buffer, *buffer_utf8;
+ err = svn_utf_cstring_to_utf8 (opt_arg, &utf8_opt_arg, pool);
+ if (!err)
+ err = svn_string_from_file (&buffer, utf8_opt_arg, pool);
+ if (!err)
+ err = svn_utf_stringbuf_to_utf8 (buffer, &buffer_utf8, pool);
           if (err)
             {
               svn_handle_error (err, stdout, FALSE);
               svn_pool_destroy (pool);
               return EXIT_FAILURE;
             }
- opt_state.targets = svn_cstring_split (buffer->data, "\n\r",
+ opt_state.targets = svn_cstring_split (buffer_utf8->data, "\n\r",
                                                  TRUE, pool);
         }
         break;
@@ -967,10 +1001,26 @@
         opt_state.help = TRUE;
         break;
       case svn_cl__auth_username_opt:
- opt_state.auth_username = apr_pstrdup (pool, opt_arg);
+ err = svn_utf_cstring_to_utf8 (opt_arg,
+ &opt_state.auth_username,
+ pool);
+ if (err)
+ {
+ svn_handle_error (err, stdout, FALSE);
+ svn_pool_destroy (pool);
+ return EXIT_FAILURE;
+ }
         break;
       case svn_cl__auth_password_opt:
- opt_state.auth_password = apr_pstrdup (pool, opt_arg);
+ err = svn_utf_cstring_to_utf8 (opt_arg,
+ &opt_state.auth_password,
+ pool);
+ if (err)
+ {
+ svn_handle_error (err, stdout, FALSE);
+ svn_pool_destroy (pool);
+ return EXIT_FAILURE;
+ }
         break;
       case svn_cl__locale_opt:
         /* The only locale name that ISO C defines is the "C" locale;
@@ -986,10 +1036,15 @@
         */
         if (NULL == setlocale (LC_ALL, opt_arg))
           {
- err = svn_error_createf (SVN_ERR_CL_ARG_PARSING_ERROR,
- 0, NULL, pool,
- "The locale `%s' can not be set",
- opt_arg);
+ err = svn_utf_cstring_to_utf8 (opt_arg, &utf8_opt_arg, pool);
+
+ if (err)
+ svn_handle_error (err, stderr, FALSE);
+ else
+ err = svn_error_createf (SVN_ERR_CL_ARG_PARSING_ERROR,
+ 0, NULL, pool,
+ "The locale `%s' can not be set",
+ utf8_opt_arg);
             svn_handle_error (err, stderr, FALSE);
           }
         break;
@@ -997,7 +1052,12 @@
         opt_state.xml = TRUE;
         break;
       case 'x':
- opt_state.extensions = apr_pstrdup (pool, opt_arg);
+ err = svn_utf_cstring_to_utf8 (opt_arg, &opt_state.extensions, pool);
+ if (err) {
+ svn_handle_error (err, stderr, FALSE);
+ svn_pool_destroy (pool);
+ return EXIT_FAILURE;
+ }
         break;
       default:
         /* Hmmm. Perhaps this would be a good place to squirrel away
Index: ./subversion/clients/cmdline/prompt.c
===================================================================
--- ./subversion/clients/cmdline/prompt.c
+++ ./subversion/clients/cmdline/prompt.c Wed May 29 00:01:12 2002
@@ -28,6 +28,7 @@
 #include "svn_path.h"
 #include "svn_delta.h"
 #include "svn_error.h"
+#include "svn_utf.h"
 #include "cl.h"
 
 #include "apr_lib.h"
@@ -79,6 +80,7 @@
   apr_status_t status;
   apr_file_t *fp;
   char c;
+ const char *native_prompt;
 
   /* ### baton is NULL... the commandline client app doesn't need one,
    but a GUI app probably would. */
@@ -91,11 +93,13 @@
       svn_error_create (status, 0, NULL, pool,
                         "svn_cl__prompt_user: couldn't open stdin.");
 
+ SVN_ERR (svn_utf_cstring_from_utf8 (prompt, &native_prompt, pool));
+
   /* ### implement the HIDE flag later using apr_getpassword or
      something. */
   if (! hide)
     {
- printf (prompt);
+ printf (native_prompt);
       fflush (stdout);
 
       while (1)
@@ -116,7 +120,7 @@
       svn_stringbuf_ensure (strbuf, bufsize);
 
       /* Hopefully this won't echo to the screen. */
- status = apr_password_get (prompt, strbuf->data, &bufsize);
+ status = apr_password_get (native_prompt, strbuf->data, &bufsize);
       if (status)
         return svn_error_create (status, 0, NULL, pool,
                                  "error from apr_password_get().");
@@ -128,7 +132,8 @@
       printf ("\n");
     }
 
- *result = strbuf->data;
+ SVN_ERR (svn_utf_cstring_to_utf8 (strbuf->data, (const char **)result,
+ pool));
 
   return SVN_NO_ERROR;
 }
Index: ./subversion/clients/cmdline/propdel-cmd.c
===================================================================
--- ./subversion/clients/cmdline/propdel-cmd.c
+++ ./subversion/clients/cmdline/propdel-cmd.c Wed May 29 13:09:11 2002
@@ -28,6 +28,7 @@
 #include "svn_path.h"
 #include "svn_delta.h"
 #include "svn_error.h"
+#include "svn_utf.h"
 #include "cl.h"
 
 
@@ -60,10 +61,14 @@
       SVN_ERR (svn_client_propset (pname, NULL, target,
                                    opt_state->recursive, pool));
 
- if (! opt_state->quiet)
- printf ("property `%s' deleted %s from '%s'.\n", pname,
+ if (! opt_state->quiet) {
+ const char *pname_native, *target_native;
+ SVN_ERR (svn_utf_cstring_from_utf8 (pname, &pname_native, pool));
+ SVN_ERR (svn_utf_cstring_from_utf8 (target, &target_native, pool));
+ printf ("property `%s' deleted %s from '%s'.\n", pname_native,
                 opt_state->recursive ? "(recursively)" : "",
- target);
+ target_native);
+ }
     }
 
   return SVN_NO_ERROR;
Index: ./subversion/clients/cmdline/propedit-cmd.c
===================================================================
--- ./subversion/clients/cmdline/propedit-cmd.c
+++ ./subversion/clients/cmdline/propedit-cmd.c Wed May 29 13:32:27 2002
@@ -28,6 +28,7 @@
 #include "svn_path.h"
 #include "svn_delta.h"
 #include "svn_error.h"
+#include "svn_utf.h"
 #include "cl.h"
 
 
@@ -62,6 +63,7 @@
       svn_string_t *propval;
       const char *new_propval;
       const char *base_dir = target;
+ const char *propname_native, *target_native;
       svn_wc_entry_t *entry;
 
       /* Fetch the current property. */
@@ -90,6 +92,9 @@
                                         propval->data,
                                         pool));
 
+ SVN_ERR (svn_utf_cstring_from_utf8 (propname, &propname_native, pool));
+ SVN_ERR (svn_utf_cstring_from_utf8 (target, &target_native, pool));
+
       /* ...and re-set the property's value accordingly. */
       if (new_propval)
         {
@@ -101,12 +106,12 @@
                                        FALSE,
                                        pool));
           printf ("Set new value for property `%s' on `%s'\n",
- propname, target);
+ propname_native, target_native);
         }
       else
         {
           printf ("No changes to property `%s' on `%s'\n",
- propname, target);
+ propname_native, target_native);
         }
     }
 
Index: ./subversion/clients/cmdline/propget-cmd.c
===================================================================
--- ./subversion/clients/cmdline/propget-cmd.c
+++ ./subversion/clients/cmdline/propget-cmd.c Wed May 29 00:01:13 2002
@@ -28,6 +28,7 @@
 #include "svn_path.h"
 #include "svn_delta.h"
 #include "svn_error.h"
+#include "svn_utf.h"
 #include "cl.h"
 
 
@@ -70,13 +71,25 @@
         {
           const char * filename;
           const svn_string_t *propval;
+ const char *filename_native, *propval_native;
+
           apr_hash_this(hi, (const void **)&filename, NULL, (void **)&propval);
 
           /* ### this won't handle binary property values */
- if (print_filenames)
- printf ("%s - %s\n", filename, propval->data);
- else
- printf ("%s\n", propval->data);
+ if (print_filenames) {
+ SVN_ERR (svn_utf_cstring_from_utf8 (filename,
+ &filename_native,
+ pool));
+ SVN_ERR (svn_utf_cstring_from_utf8_string (propval,
+ &propval_native,
+ pool));
+ printf ("%s - %s\n", filename_native, propval_native);
+ } else {
+ SVN_ERR (svn_utf_cstring_from_utf8_string (propval,
+ &propval_native,
+ pool));
+ printf ("%s\n", propval_native);
+ }
         }
     }
 
Index: ./subversion/clients/cmdline/proplist-cmd.c
===================================================================
--- ./subversion/clients/cmdline/proplist-cmd.c
+++ ./subversion/clients/cmdline/proplist-cmd.c Wed May 29 00:01:19 2002
@@ -28,6 +28,7 @@
 #include "svn_path.h"
 #include "svn_delta.h"
 #include "svn_error.h"
+#include "svn_utf.h"
 #include "cl.h"
 
 
@@ -59,11 +60,15 @@
         {
           svn_client_proplist_item_t *item
               = ((svn_client_proplist_item_t **)props->elts)[j];
- printf("Properties on '%s':\n", item->node_name->data);
+ const char *node_name_native;
+ SVN_ERR (svn_utf_cstring_from_utf8_stringbuf (item->node_name,
+ &node_name_native,
+ pool));
+ printf("Properties on '%s':\n", node_name_native);
           if (opt_state->verbose)
- svn_cl__print_prop_hash (item->prop_hash, pool);
+ SVN_ERR (svn_cl__print_prop_hash (item->prop_hash, pool));
           else
- svn_cl__print_prop_names (item->prop_hash, pool);
+ SVN_ERR (svn_cl__print_prop_names (item->prop_hash, pool));
         }
     }
 
Index: ./subversion/clients/cmdline/props.c
===================================================================
--- ./subversion/clients/cmdline/props.c
+++ ./subversion/clients/cmdline/props.c Wed May 29 13:39:12 2002
@@ -29,12 +29,13 @@
 #include "svn_path.h"
 #include "svn_delta.h"
 #include "svn_error.h"
+#include "svn_utf.h"
 #include "cl.h"
 
 
 
 
-void
+svn_error_t *
 svn_cl__print_prop_hash (apr_hash_t *prop_hash,
                          apr_pool_t *pool)
 {
@@ -45,16 +46,21 @@
       const void *key;
       void *val;
       svn_stringbuf_t *propval;
+ const char *key_native, *val_native;
 
       apr_hash_this (hi, &key, NULL, &val);
       propval = (svn_stringbuf_t *) val;
 
- printf (" %s : %s\n", (char *) key, propval->data);
+ SVN_ERR (svn_utf_cstring_from_utf8 ((char *) key, &key_native, pool));
+ SVN_ERR (svn_utf_cstring_from_utf8 (propval->data, &val_native, pool));
+
+ printf (" %s : %s\n", key_native, val_native);
     }
+ return SVN_NO_ERROR;
 }
 
 
-void
+svn_error_t *
 svn_cl__print_prop_names (apr_hash_t *prop_hash,
                           apr_pool_t *pool)
 {
@@ -63,9 +69,12 @@
   for (hi = apr_hash_first (pool, prop_hash); hi; hi = apr_hash_next (hi))
     {
       const void *key;
+ const char *key_native;
       apr_hash_this (hi, &key, NULL, NULL);
- printf (" %s\n", (char *) key);
+ SVN_ERR (svn_utf_cstring_from_utf8 ((char *) key, &key_native, pool));
+ printf (" %s\n", key_native);
     }
+ return SVN_NO_ERROR;
 }
 
 
Index: ./subversion/clients/cmdline/propset-cmd.c
===================================================================
--- ./subversion/clients/cmdline/propset-cmd.c
+++ ./subversion/clients/cmdline/propset-cmd.c Wed May 29 16:14:36 2002
@@ -28,6 +28,7 @@
 #include "svn_path.h"
 #include "svn_delta.h"
 #include "svn_error.h"
+#include "svn_utf.h"
 #include "cl.h"
 
 
@@ -45,7 +46,9 @@
   int num_args_wanted = 2;
 
   if (opt_state->filedata) {
- propval = svn_string_create_from_buf (opt_state->filedata, pool);
+ svn_stringbuf_t *buf_utf8;
+ SVN_ERR (svn_utf_stringbuf_to_utf8 (opt_state->filedata, &buf_utf8, pool));
+ propval = svn_string_create_from_buf (buf_utf8, pool);
     num_args_wanted = 1;
   }
   /* PROPNAME and PROPVAL expected as first 2 arguments if filedata
@@ -72,11 +75,16 @@
       SVN_ERR (svn_client_propset(propname, propval, target,
                                   opt_state->recursive, pool));
 
- if (! opt_state->quiet)
+ if (! opt_state->quiet) {
+ const char *propname_native, *target_native;
+ SVN_ERR (svn_utf_cstring_from_utf8 (propname, &propname_native, pool));
+ SVN_ERR (svn_utf_cstring_from_utf8 (target, &target_native, pool));
         printf ("property `%s' set%s on '%s'\n",
- propname,
+ propname_native,
+
                 opt_state->recursive ? " (recursively)" : "",
- target);
+ target_native);
+ }
     }
 
   return SVN_NO_ERROR;
Index: ./subversion/clients/cmdline/status.c
===================================================================
--- ./subversion/clients/cmdline/status.c
+++ ./subversion/clients/cmdline/status.c Wed May 29 00:01:14 2002
@@ -26,6 +26,7 @@
 #include "svn_sorts.h"
 #include "svn_wc.h"
 #include "svn_string.h"
+#include "svn_utf.h"
 #include "cl.h"
 
 
@@ -241,6 +242,8 @@
   for (i = 0; i < statusarray->nelts; i++)
     {
       const svn_item_t *item;
+ const char *path;
+ svn_error_t *err;
 
       item = &APR_ARRAY_IDX(statusarray, i, const svn_item_t);
       status = item->value;
@@ -248,10 +251,14 @@
       if ((skip_unrecognized) && (! status->entry))
         continue;
 
+ err = svn_utf_cstring_from_utf8 (item->key, &path, pool);
+ if (err)
+ svn_handle_error (err, stderr, FALSE);
+
       if (detailed)
- print_long_format (item->key, show_last_committed, status);
+ print_long_format (path, show_last_committed, status);
       else
- print_short_format (item->key, status);
+ print_short_format (path, status);
     }
 
   /* If printing in detailed format, we might have a head revision to
Index: ./subversion/clients/cmdline/trace-commit.c
===================================================================
--- ./subversion/clients/cmdline/trace-commit.c
+++ ./subversion/clients/cmdline/trace-commit.c Wed May 29 13:45:55 2002
@@ -31,6 +31,7 @@
 #include "svn_pools.h"
 #include "svn_path.h"
 #include "svn_string.h"
+#include "svn_utf.h"
 
 #include "cl.h"
 
@@ -85,7 +86,7 @@
 
 struct edit_baton
 {
- const char *path;
+ const char *path; /* UTF-8! */
   apr_pool_t *pool;
   svn_boolean_t started_sending_txdeltas;
 };
@@ -95,7 +96,7 @@
 {
   struct edit_baton *edit_baton;
   struct dir_baton *parent_dir_baton;
- const char *path;
+ const char *path; /* UTF-8! */
   svn_boolean_t prop_changed;
   apr_hash_t *entrymods;
   apr_pool_t *pool;
@@ -106,7 +107,7 @@
 {
   struct edit_baton *edit_baton;
   struct dir_baton *parent_dir_baton;
- const char *path;
+ const char *path; /* UTF-8! */
 };
 
 
@@ -253,19 +254,22 @@
   struct dir_baton *pb = db->parent_dir_baton;
   apr_hash_index_t *hi;
   void *vp = NULL;
+ const char *path_native;
 
   /* See if there is an entry in the parent's hash for this
      directory. */
   if (pb)
     vp = apr_hash_get (pb->entrymods, db->path, APR_HASH_KEY_STRING);
 
+ SVN_ERR (svn_utf_cstring_from_utf8 (db->path, &path_native, db->pool));
+
   /* If this item was added to its parent's hash, print such. Else,
      if it has propchanges, print that. Otherwise, it should have
      just been 'open'ed, and that's not interesting enough to print. */
   if (vp == ITEM_ADDED)
- printf ("Adding %s\n", db->path);
+ printf ("Adding %s\n", path_native);
   else if (db->prop_changed)
- printf ("Sending %s\n", db->path);
+ printf ("Sending %s\n", path_native);
 
   /* Now remove this from the parent's hash. */
   if (vp)
@@ -280,9 +284,13 @@
       const char *pattern;
       const void *key;
       void *val;
+ const char *key_native;
       
       apr_hash_this (hi, &key, NULL, &val);
       
+ SVN_ERR (svn_utf_cstring_from_utf8 ((const char *)key,
+ &key_native, db->pool));
+
       if (val == ITEM_REPLACED)
         pattern = "Replacing %s\n";
       else if (val == ITEM_REPLACED_BINARY)
@@ -298,7 +306,7 @@
       else
         abort(); /* this should never happen */
       
- printf (pattern, (const char *)key);
+ printf (pattern, key_native);
     }
 
   return SVN_NO_ERROR;
@@ -439,7 +447,7 @@
 svn_error_t *
 svn_cl__get_trace_commit_editor (const svn_delta_editor_t **editor,
                                  void **edit_baton,
- const char *initial_path,
+ const char *initial_path /* UTF-8! */,
                                  apr_pool_t *pool)
 {
   /* Allocate an edit baton to be stored in every directory baton. */
Index: ./subversion/clients/cmdline/trace-update.c
===================================================================
--- ./subversion/clients/cmdline/trace-update.c
+++ ./subversion/clients/cmdline/trace-update.c Wed May 29 13:59:19 2002
@@ -26,13 +26,14 @@
 #include "svn_pools.h"
 #include "svn_path.h"
 #include "svn_string.h"
+#include "svn_utf.h"
 #include "cl.h"
 
 
 
 struct edit_baton
 {
- const char *path;
+ const char *path; /* UTF-8! */
   apr_pool_t *pool;
   svn_revnum_t target_revision;
   svn_boolean_t is_checkout;
@@ -45,7 +46,7 @@
 {
   struct edit_baton *edit_baton;
   struct dir_baton *parent_dir_baton;
- const char *path;
+ const char *path; /* UTF-8! */
   svn_boolean_t prop_changed;
 };
 
@@ -54,7 +55,7 @@
 {
   struct edit_baton *edit_baton;
   struct dir_baton *parent_dir_baton;
- const char *path;
+ const char *path; /* UTF-8! */
   svn_boolean_t added;
   svn_boolean_t text_changed;
   svn_boolean_t prop_changed;
@@ -142,7 +143,10 @@
   struct dir_baton *pb = parent_baton;
   struct edit_baton *eb = pb->edit_baton;
   eb->received_some_change = TRUE;
- printf ("D %s\n", svn_path_join (eb->path, path, pool));
+ const char *path_native;
+ SVN_ERR (svn_utf_cstring_from_utf8 (svn_path_join (eb->path, path, pool),
+ &path_native, pool));
+ printf ("D %s\n", path_native);
   return SVN_NO_ERROR;
 }
 
@@ -158,9 +162,11 @@
   struct dir_baton *pb = parent_baton;
   struct edit_baton *eb = pb->edit_baton;
   struct dir_baton *new_db = make_dir_baton (path, eb, pb, pool);
+ const char *path_native;
 
   eb->received_some_change = TRUE;
- printf ("A %s\n", new_db->path);
+ SVN_ERR (svn_utf_cstring_from_utf8 (new_db->path, &path_native, pool));
+ printf ("A %s\n", path_native);
   *child_baton = new_db;
   return SVN_NO_ERROR;
 }
@@ -191,6 +197,7 @@
   struct dir_baton *db = dir_baton;
   struct edit_baton *eb = db->edit_baton;
   char statchar_buf[3] = "_ ";
+ const char *path_native;
 
   if (db->prop_changed)
     {
@@ -211,7 +218,8 @@
       else
         statchar_buf[1] = 'U';
 
- printf ("%s %s\n", statchar_buf, db->path);
+ SVN_ERR (svn_utf_cstring_from_utf8 (db->path, &path_native, subpool));
+ printf ("%s %s\n", statchar_buf, path_native);
 
       /* Destroy the subpool. */
       svn_pool_destroy (subpool);
@@ -227,6 +235,7 @@
   struct file_baton *fb = file_baton;
   struct edit_baton *eb = fb->edit_baton;
   char statchar_buf[3] = "_ ";
+ const char *path_native;
 
   if (fb->added)
     statchar_buf[0] = 'A';
@@ -276,7 +285,8 @@
     svn_pool_destroy (subpool);
   }
 
- printf ("%s %s\n", statchar_buf, fb->path);
+ SVN_ERR (svn_utf_cstring_from_utf8 (fb->path, &path_native, eb->pool));
+ printf ("%s %s\n", statchar_buf, path_native);
 
   return SVN_NO_ERROR;
 }
@@ -390,7 +400,7 @@
 svn_error_t *
 svn_cl__get_trace_update_editor (const svn_delta_editor_t **editor,
                                  void **edit_baton,
- const char *initial_path,
+ const char *initial_path /* UTF-8! */,
                                  svn_boolean_t is_checkout,
                                  svn_boolean_t suppress_final_line,
                                  apr_pool_t *pool)
Index: ./subversion/clients/cmdline/util.c
===================================================================
--- ./subversion/clients/cmdline/util.c
+++ ./subversion/clients/cmdline/util.c Wed May 29 16:16:41 2002
@@ -41,6 +41,7 @@
 #include "svn_error.h"
 #include "svn_io.h"
 #include "svn_pools.h"
+#include "svn_utf.h"
 #include "cl.h"
 
 
@@ -62,6 +63,18 @@
   (*((const char **) apr_array_push (array))) = apr_pstrdup (pool, str);
 }
 
+/* Same as above, but make UTF-8 while we're at it */
+static svn_error_t *
+array_push_str_utf8 (apr_array_header_t *array,
+ const char *str,
+ apr_pool_t *pool)
+{
+ const char *str_utf8;
+ SVN_ERR (svn_utf_cstring_to_utf8 (str, &str_utf8, pool));
+ (*((const char **) apr_array_push (array))) = str_utf8;
+ return SVN_NO_ERROR;
+}
+
 
 /* Some commands take an implicit "." string argument when invoked
  * with no arguments. Those commands make use of this function to
@@ -99,7 +112,8 @@
           return svn_error_create (SVN_ERR_CL_ARG_PARSING_ERROR,
                                    0, 0, pool, "");
         }
- array_push_str (opt_state->args, os->argv[os->ind++], pool);
+ SVN_ERR (array_push_str_utf8 (opt_state->args,
+ os->argv[os->ind++], pool));
     }
 
   return SVN_NO_ERROR;
@@ -125,7 +139,8 @@
 
   while (os->ind < os->argc)
     {
- array_push_str (opt_state->args, os->argv[os->ind++], pool);
+ SVN_ERR (array_push_str_utf8 (opt_state->args,
+ os->argv[os->ind++], pool));
     }
 
   return SVN_NO_ERROR;
@@ -146,7 +161,7 @@
 static svn_error_t *
 parse_path (svn_client_revision_t *rev,
             const char **truepath,
- const char *path,
+ const char *path /* UTF-8! */,
             apr_pool_t *pool)
 {
   int i;
@@ -159,11 +174,16 @@
     {
       if (path[i] == '@')
         {
- if (svn_cl__parse_revision (os, path + i + 1, subpool))
+ const char *native_rev;
+
+ SVN_ERR (svn_utf_cstring_from_utf8 (path + i + 1,
+ &native_rev, subpool));
+
+ if (svn_cl__parse_revision (os, native_rev, subpool))
             return svn_error_createf (SVN_ERR_CL_ARG_PARSING_ERROR,
                                       0, NULL, subpool,
                                       "Syntax error parsing revision \"%s\"",
- path + 1);
+ path + i + 1);
 
           *truepath = apr_pstrndup (pool, path, i);
           rev->kind = os->start_revision.kind;
@@ -199,7 +219,10 @@
   /* Command line args take precedence. */
   for (; os->ind < os->argc; os->ind++)
     {
- const char *target = apr_pstrdup (pool, os->argv[os->ind]);
+ const char *target;
+
+ /* FIXME: need to handle errors here... */
+ svn_utf_cstring_to_utf8 (os->argv[os->ind], &target, pool);
 
       /* If this path looks like it would work as a URL in one of the
          currently available RA libraries, we add it unconditionally
@@ -292,15 +315,16 @@
 
 
 svn_error_t *
-svn_cl__edit_externally (const char **edited_contents,
- const char *base_dir,
- const char *contents,
+svn_cl__edit_externally (const char **edited_contents /* UTF-8! */,
+ const char *base_dir /* UTF-8! */,
+ const char *contents /* UTF-8! */,
                          apr_pool_t *pool)
 {
   const char *editor = NULL;
   const char *cmd;
   apr_file_t *tmp_file;
   const char *tmpfile_name;
+ const char *contents_native, *tmpfile_native;
   apr_status_t apr_err, apr_err2;
   apr_size_t written;
   apr_finfo_t finfo_before, finfo_after;
@@ -324,6 +348,9 @@
   /* By now, we had better have an EDITOR to work with. */
   assert (editor);
 
+ /* Convert file contents from UTF-8 */
+ SVN_ERR (svn_utf_cstring_from_utf8 (contents, &contents_native, pool));
+
   /* Ask the working copy for a temporary file based on BASE_DIR */
   SVN_ERR (svn_io_open_unique_file
            (&tmp_file, &tmpfile_name,
@@ -333,15 +360,15 @@
        the file we just created!! ***/
 
   /* Dump initial CONTENTS to TMP_FILE. */
- apr_err = apr_file_write_full (tmp_file, contents,
- strlen (contents), &written);
+ apr_err = apr_file_write_full (tmp_file, contents_native,
+ strlen (contents_native), &written);
 
   apr_err2 = apr_file_close (tmp_file);
   if (! apr_err)
     apr_err = apr_err2;
   
   /* Make sure the whole CONTENTS were written, else return an error. */
- if (apr_err || (written != strlen (contents)))
+ if (apr_err || (written != strlen (contents_native)))
     {
       err = svn_error_createf
         (apr_err ? apr_err : SVN_ERR_INCOMPLETE_DATA, 0, NULL, pool,
@@ -349,9 +376,13 @@
       goto cleanup;
     }
 
+ err = svn_utf_cstring_from_utf8 (tmpfile_name, &tmpfile_native, pool);
+ if (err)
+ goto cleanup;
+
   /* Get information about the temporary file before the user has
      been allowed to edit its contents. */
- apr_err = apr_stat (&finfo_before, tmpfile_name,
+ apr_err = apr_stat (&finfo_before, tmpfile_native,
                       APR_FINFO_MTIME | APR_FINFO_SIZE, pool);
   if (apr_err)
     {
@@ -361,7 +392,7 @@
     }
 
   /* Now, run the editor command line. */
- cmd = apr_psprintf (pool, "%s %s", editor, tmpfile_name);
+ cmd = apr_psprintf (pool, "%s %s", editor, tmpfile_native);
   sys_err = system (cmd);
   if (sys_err != 0)
     {
@@ -373,7 +404,7 @@
     }
   
   /* Get information about the temporary file after the assumed editing. */
- apr_err = apr_stat (&finfo_after, tmpfile_name,
+ apr_err = apr_stat (&finfo_after, tmpfile_native,
                       APR_FINFO_MTIME | APR_FINFO_SIZE, pool);
   if (apr_err)
     {
@@ -388,10 +419,11 @@
     {
       svn_stringbuf_t *edited_contents_s;
       err = svn_string_from_file (&edited_contents_s, tmpfile_name, pool);
+ if (!err)
+ err = svn_utf_cstring_to_utf8 (edited_contents_s->data,
+ edited_contents, pool);
       if (err)
         goto cleanup; /* In case more code gets added before cleanup... */
-
- *edited_contents = edited_contents_s->data;
     }
   else
     {
@@ -401,7 +433,7 @@
 
  cleanup:
 
- apr_err = apr_file_remove (tmpfile_name, pool);
+ apr_err = apr_file_remove (tmpfile_native, pool);
 
   /* Only report remove error if there was no previous error. */
   if (! err && apr_err)
@@ -415,13 +447,13 @@
 struct log_msg_baton
 {
   const char *message;
- const char *base_dir;
+ const char *base_dir; /* UTF-8! */
 };
 
 
 void *
 svn_cl__make_log_msg_baton (svn_cl__opt_state_t *opt_state,
- const char *base_dir,
+ const char *base_dir /* UTF-8! */,
                             apr_pool_t *pool)
 {
   struct log_msg_baton *baton = apr_palloc (pool, sizeof (*baton));
@@ -515,8 +547,7 @@
 
   if (lmb->message)
     {
- *log_msg = apr_pstrdup (pool, lmb->message);
- return SVN_NO_ERROR;
+ return svn_utf_cstring_to_utf8 (lmb->message, log_msg, pool);
     }
 
   if (! (commit_items || commit_items->nelts))
@@ -594,6 +625,8 @@
 
           for (len = message->len; len >= 0; len--)
             {
+ /* FIXME: should really use an UTF-8 whitespace test
+ rather than apr_isspace, which is locale dependant */
               if (! apr_isspace (message->data[len]))
                 break;
             }

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org
Received on Sat Jun 1 14:37:36 2002

This is an archived mail posted to the Subversion Dev mailing list.

This site is subject to the Apache Privacy Policy and the Apache Public Forum Archive Policy.