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

[PATCH] UTF-8 fourth round...

From: Marcus Comstedt <marcus_at_mc.pp.se>
Date: 2002-06-28 17:24:16 CEST

Ok, once again here's the UTF-8 patch, now merged with revision 2366.
News this time is that svnadmin and svnlook are fixed as well.
Otherwise it's basically the same as last time. The testsuite passes
(apart from commit_tests-8, which is not my fault), and I have
verified correct operation against a repository with a file://-URL
containing non-ASCII characters.

The following two implementation points are still not addressed
(text copied from previous post):

* 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.

* 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.

And we still have these design issues to resolve (eventually):

* 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?

There is still also the question of inexact translations in
apr_xlate. Again, I quote my previous post:

| 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?

Well, that's it I think. I hope I'll be able to get the mail throgh
the mailing list handler this time...

  // Marcus

Index: i18n/unix/xlate.c
===================================================================
RCS file: /home/cvspublic/apr/i18n/unix/xlate.c,v
retrieving revision 1.26
diff -u -r1.26 xlate.c
--- i18n/unix/xlate.c 8 Jun 2002 18:53:13 -0000 1.26
+++ i18n/unix/xlate.c 28 Jun 2002 14:52: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 Jun 14 18:50:20 2002
@@ -354,6 +354,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 Jun 12 16:24:59 2002
@@ -467,6 +467,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 Jun 26 17:52:10 2002
@@ -188,7 +188,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/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/externals.c
===================================================================
--- subversion/libsvn_client/externals.c
+++ subversion/libsvn_client/externals.c Wed Jun 26 18:02:57 2002
@@ -237,7 +237,6 @@
 
   if (err && (err->apr_err == SVN_ERR_WC_LEFT_LOCAL_MOD))
     {
- apr_status_t apr_err;
       apr_file_t *f;
       const char *new_path;
 
@@ -264,13 +263,10 @@
          in the meantime -- which would never happen in real life, so
          no big deal.
       */
- apr_file_remove (new_path, pool); /* toss error */
+ svn_io_remove_file (new_path, pool); /* toss error */
 
       /* Rename. */
- apr_err = apr_file_rename (path, new_path, pool);
- if (apr_err)
- return svn_error_createf (apr_err, 0, NULL, pool,
- "error renaming %s to %s", path, new_path);
+ SVN_ERR (svn_io_file_rename (path, new_path, pool));
     }
   else if (err)
     return err;
Index: subversion/libsvn_client/checkout.c
===================================================================
--- subversion/libsvn_client/checkout.c
+++ subversion/libsvn_client/checkout.c Wed Jun 26 18:12:12 2002
@@ -32,6 +32,7 @@
 #include "svn_types.h"
 #include "svn_error.h"
 #include "svn_path.h"
+#include "svn_io.h"
 #include "client.h"
 
 
@@ -124,17 +125,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/diff.c
===================================================================
--- subversion/libsvn_client/diff.c
+++ subversion/libsvn_client/diff.c Wed Jun 26 18:12:15 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");
 }
 
 
@@ -136,9 +135,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/copy.c
===================================================================
--- subversion/libsvn_client/copy.c
+++ subversion/libsvn_client/copy.c Fri Jun 28 15:26:56 2002
@@ -30,6 +30,7 @@
 #include "svn_pools.h"
 #include "svn_error.h"
 #include "svn_path.h"
+#include "svn_io.h"
 #include "client.h"
 
 
@@ -490,7 +491,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));
@@ -759,12 +761,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/repos_diff.c
===================================================================
--- subversion/libsvn_client/repos_diff.c
+++ subversion/libsvn_client/repos_diff.c Fri Jun 28 15:26:57 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"
 
@@ -139,7 +141,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;
 };
@@ -198,6 +200,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);
 }
 
@@ -231,7 +234,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);
@@ -551,27 +554,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/export.c
===================================================================
--- subversion/libsvn_client/export.c
+++ subversion/libsvn_client/export.c Sun Jun 16 19:50:35 2002
@@ -97,18 +97,11 @@
   if (entry)
     {
       apr_hash_index_t *hi;
- apr_status_t apr_err;
       apr_finfo_t finfo;
 
- apr_err = apr_stat (&finfo, from, APR_FINFO_PROT, subpool);
- if (apr_err)
- return svn_error_createf
- (apr_err, 0, NULL, subpool, "error stating dir `%s'", to);
+ SVN_ERR (svn_io_stat (&finfo, from, APR_FINFO_PROT, subpool));
 
- apr_err = apr_dir_make (to, finfo.protection, subpool);
- if (apr_err)
- return svn_error_createf
- (apr_err, 0, NULL, subpool, "error creating dir `%s'", to);
+ SVN_ERR (svn_io_dir_make (to, finfo.protection, subpool));
 
       SVN_ERR (svn_io_get_dirents (&dirents, from, pool));
 
Index: subversion/libsvn_client/update.c
===================================================================
--- subversion/libsvn_client/update.c
+++ subversion/libsvn_client/update.c Wed Jun 26 18:12:23 2002
@@ -29,6 +29,7 @@
 #include "svn_string.h"
 #include "svn_error.h"
 #include "svn_path.h"
+#include "svn_io.h"
 #include "client.h"
 
 
@@ -149,15 +150,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 Jun 26 18:12:26 2002
@@ -362,7 +362,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_client/commit_util.c
===================================================================
--- subversion/libsvn_client/commit_util.c
+++ subversion/libsvn_client/commit_util.c Fri Jun 28 15:26:57 2002
@@ -543,7 +543,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/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/commit.c
===================================================================
--- subversion/libsvn_client/commit.c
+++ subversion/libsvn_client/commit.c Wed Jun 26 18:12:35 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);
@@ -174,14 +171,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;
 
@@ -264,9 +260,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)))
@@ -449,13 +446,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),
@@ -747,7 +741,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;
@@ -885,7 +879,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_fs/fs.c
===================================================================
--- subversion/libsvn_fs/fs.c
+++ subversion/libsvn_fs/fs.c Wed Jun 26 18:15:19 2002
@@ -26,6 +26,7 @@
 #include "apr_file_io.h"
 
 #include "svn_pools.h"
+#include "svn_utf.h"
 #include "svn_fs.h"
 #include "fs.h"
 #include "err.h"
@@ -390,14 +391,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'",
@@ -407,7 +410,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"
@@ -428,7 +432,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);
@@ -447,7 +451,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
@@ -500,18 +504,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
@@ -562,6 +568,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)
@@ -577,10 +586,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);
@@ -603,13 +612,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_repos/repos.c
===================================================================
--- subversion/libsvn_repos/repos.c
+++ subversion/libsvn_repos/repos.c Wed Jun 12 19:18:41 2002
@@ -138,13 +138,11 @@
     const char *lockfile_path;
 
     lockfile_path = svn_repos_db_lockfile (repos, pool);
- apr_err = apr_file_open (&f, lockfile_path,
- (APR_WRITE | APR_CREATE | APR_EXCL),
- APR_OS_DEFAULT,
- pool);
- if (apr_err)
- return svn_error_createf (apr_err, 0, NULL, pool,
- "creating lock file `%s'", lockfile_path);
+ SVN_ERR_W (svn_io_file_open (&f, lockfile_path,
+ (APR_WRITE | APR_CREATE | APR_EXCL),
+ APR_OS_DEFAULT,
+ pool),
+ "creating lock file");
     
     contents =
       "DB lock file, representing locks on the versioned filesystem.\n"
@@ -195,13 +193,11 @@
                               svn_repos_start_commit_hook (repos, pool),
                               SVN_REPOS__HOOK_DESC_EXT);
     
- apr_err = apr_file_open (&f, this_path,
- (APR_WRITE | APR_CREATE | APR_EXCL),
- APR_OS_DEFAULT,
- pool);
- if (apr_err)
- return svn_error_createf (apr_err, 0, NULL, pool,
- "creating hook file `%s'", this_path);
+ SVN_ERR_W (svn_io_file_open (&f, this_path,
+ (APR_WRITE | APR_CREATE | APR_EXCL),
+ APR_OS_DEFAULT,
+ pool),
+ "creating hook file");
     
     contents =
       "#!/bin/sh\n"
@@ -266,13 +262,11 @@
                               svn_repos_pre_commit_hook (repos, pool),
                               SVN_REPOS__HOOK_DESC_EXT);
 
- apr_err = apr_file_open (&f, this_path,
- (APR_WRITE | APR_CREATE | APR_EXCL),
- APR_OS_DEFAULT,
- pool);
- if (apr_err)
- return svn_error_createf (apr_err, 0, NULL, pool,
- "creating hook file `%s'", this_path);
+ SVN_ERR_W (svn_io_file_open (&f, this_path,
+ (APR_WRITE | APR_CREATE | APR_EXCL),
+ APR_OS_DEFAULT,
+ pool),
+ "creating hook file");
 
     contents =
       "#!/bin/sh\n"
@@ -340,13 +334,11 @@
                               svn_repos_post_commit_hook (repos, pool),
                               SVN_REPOS__HOOK_DESC_EXT);
 
- apr_err = apr_file_open (&f, this_path,
- (APR_WRITE | APR_CREATE | APR_EXCL),
- APR_OS_DEFAULT,
- pool);
- if (apr_err)
- return svn_error_createf (apr_err, 0, NULL, pool,
- "creating hook file `%s'", this_path);
+ SVN_ERR_W (svn_io_file_open (&f, this_path,
+ (APR_WRITE | APR_CREATE | APR_EXCL),
+ APR_OS_DEFAULT,
+ pool),
+ "creating hook file");
     
     contents =
       "#!/bin/sh\n"
@@ -412,13 +404,11 @@
                               svn_repos_read_sentinel_hook (repos, pool),
                               SVN_REPOS__HOOK_DESC_EXT);
 
- apr_err = apr_file_open (&f, this_path,
- (APR_WRITE | APR_CREATE | APR_EXCL),
- APR_OS_DEFAULT,
- pool);
- if (apr_err)
- return svn_error_createf (apr_err, 0, NULL, pool,
- "creating hook file `%s'", this_path);
+ SVN_ERR_W (svn_io_file_open (&f, this_path,
+ (APR_WRITE | APR_CREATE | APR_EXCL),
+ APR_OS_DEFAULT,
+ pool),
+ "creating hook file");
     
     contents =
       "READ-SENTINEL\n"
@@ -444,13 +434,11 @@
                               svn_repos_write_sentinel_hook (repos, pool),
                               SVN_REPOS__HOOK_DESC_EXT);
 
- apr_err = apr_file_open (&f, this_path,
- (APR_WRITE | APR_CREATE | APR_EXCL),
- APR_OS_DEFAULT,
- pool);
- if (apr_err)
- return svn_error_createf (apr_err, 0, NULL, pool,
- "creating hook file `%s'", this_path);
+ SVN_ERR_W (svn_io_file_open (&f, this_path,
+ (APR_WRITE | APR_CREATE | APR_EXCL),
+ APR_OS_DEFAULT,
+ pool),
+ "creating hook file");
     
     contents =
       "WRITE-SENTINEL\n"
@@ -609,12 +597,9 @@
       "\n"
       "Visit http://subversion.tigris.org/ for more information.\n";
 
- apr_err = apr_file_open (&readme_file, readme_file_name,
- APR_WRITE | APR_CREATE, APR_OS_DEFAULT,
- pool);
- if (apr_err)
- return svn_error_createf (apr_err, 0, 0, pool,
- "opening `%s' for writing", readme_file_name);
+ SVN_ERR (svn_io_file_open (&readme_file, readme_file_name,
+ APR_WRITE | APR_CREATE, APR_OS_DEFAULT,
+ pool));
 
     apr_err = apr_file_write_full (readme_file, readme_contents,
                                    strlen (readme_contents), NULL);
@@ -661,12 +646,9 @@
 
     /* Get a filehandle for the repository's db lockfile. */
     lockfile_path = svn_repos_db_lockfile (repos, pool);
- apr_err = apr_file_open (&lockfile_handle, lockfile_path,
- APR_READ, APR_OS_DEFAULT, pool);
- if (apr_err)
- return svn_error_createf
- (apr_err, 0, NULL, pool,
- "svn_repos_open: error opening db lockfile `%s'", lockfile_path);
+ SVN_ERR_W (svn_io_file_open (&lockfile_handle, lockfile_path,
+ APR_READ, APR_OS_DEFAULT, pool),
+ "svn_repos_open: error opening db lockfile");
     
     /* Get shared lock on the filehandle. */
     apr_err = apr_file_lock (lockfile_handle, APR_FLOCK_SHARED);
Index: subversion/libsvn_subr/io.c
===================================================================
--- subversion/libsvn_subr/io.c
+++ subversion/libsvn_subr/io.c Wed Jun 26 18:21:15 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'",
@@ -321,10 +342,16 @@
 svn_error_t *
 svn_io_make_dir_recursively (const char *path, apr_pool_t *pool)
 {
+ const char *path_native;
+ apr_status_t status;
+
+ SVN_ERR (svn_utf_cstring_from_utf8 (path, &path_native, pool));
+
 #if 0
   /* ### Use this implementation if/when apr_dir_make_recursive is
      available on all platforms, not just on Unix. --xbc */
- apr_status_t apr_err = apr_dir_make_recursive (path, APR_OS_DEFAULT, pool);
+ apr_status_t apr_err = apr_dir_make_recursive (path_native, APR_OS_DEFAULT,
+ pool);
 
   if (apr_err)
     return svn_error_createf
@@ -337,7 +364,7 @@
   char *dir;
 
   /* Try to make PATH right out */
- apr_err = apr_dir_make (path, APR_OS_DEFAULT, pool);
+ apr_err = apr_dir_make (path_native, APR_OS_DEFAULT, pool);
 
   /* It's OK if PATH exists */
   if (!apr_err || APR_STATUS_IS_EEXIST(apr_err))
@@ -376,7 +403,7 @@
 
       if (!svn_err)
         {
- apr_err = apr_dir_make (path, APR_OS_DEFAULT, pool);
+ apr_err = apr_dir_make (path_native, APR_OS_DEFAULT, pool);
           if (apr_err)
             svn_err = svn_error_create (apr_err, 0, NULL, pool, path);
         }
@@ -399,8 +426,11 @@
 {
   apr_finfo_t finfo;
   apr_status_t apr_err;
+ const char *path_native;
 
- 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)
     return svn_error_createf
       (apr_err, 0, NULL, pool,
@@ -425,8 +455,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
@@ -437,7 +471,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. */
@@ -467,6 +501,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
@@ -474,7 +509,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,
@@ -523,7 +561,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);
@@ -541,7 +581,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);
@@ -560,14 +602,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);
@@ -864,6 +908,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
@@ -875,7 +920,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'",
@@ -929,10 +977,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;
@@ -949,11 +1002,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
@@ -979,8 +1034,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);
 
@@ -988,7 +1045,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)
         {
@@ -1018,7 +1080,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);
 
@@ -1038,6 +1100,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;
@@ -1046,7 +1109,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,
@@ -1062,7 +1127,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,
@@ -1111,7 +1178,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);
@@ -1134,7 +1203,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,
@@ -1175,8 +1246,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,
@@ -1230,6 +1312,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);
 
@@ -1270,7 +1353,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)
@@ -1297,6 +1382,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)
@@ -1333,8 +1419,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,
@@ -1370,6 +1458,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. */
@@ -1382,7 +1471,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'",
@@ -1436,6 +1527,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 Wed Jun 12 17:20:20 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/libsvn_subr.dsp
===================================================================
--- subversion/libsvn_subr/libsvn_subr.dsp
+++ subversion/libsvn_subr/libsvn_subr.dsp Fri Jun 28 15:30:44 2002
@@ -143,6 +143,10 @@
 # End Source File
 # Begin Source File
 
+SOURCE=.\utf.c
+# End Source File
+# Begin Source File
+
 SOURCE=.\xml.c
 # End Source File
 # End Group
Index: subversion/libsvn_wc/merge.c
===================================================================
--- subversion/libsvn_wc/merge.c
+++ subversion/libsvn_wc/merge.c Sun Jun 16 19:55:41 2002
@@ -254,26 +254,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 Fri Jun 28 15:39:03 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.");
@@ -1185,13 +1184,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/diff.c
===================================================================
--- subversion/libsvn_wc/diff.c
+++ subversion/libsvn_wc/diff.c Wed Jun 26 18:26:41 2002
@@ -794,12 +794,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/copy.c
===================================================================
--- subversion/libsvn_wc/copy.c
+++ subversion/libsvn_wc/copy.c Wed Jun 26 18:26:46 2002
@@ -81,7 +81,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/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/libsvn_wc/adm_crawler.c
===================================================================
--- subversion/libsvn_wc/adm_crawler.c
+++ subversion/libsvn_wc/adm_crawler.c Fri Jun 28 15:39:04 2002
@@ -393,9 +393,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;
     }
 
@@ -573,13 +572,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/log.c
===================================================================
--- subversion/libsvn_wc/log.c
+++ subversion/libsvn_wc/log.c Fri Jun 28 15:39:04 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;
 }
@@ -874,7 +863,6 @@
     if (kind == svn_node_file)
       {
         svn_boolean_t same;
- apr_status_t status;
         const char *chosen;
         
         /* We need to decide which prop-timestamp to use, just like we
@@ -921,10 +909,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/adm_ops.c
===================================================================
--- subversion/libsvn_wc/adm_ops.c
+++ subversion/libsvn_wc/adm_ops.c Fri Jun 28 15:39:05 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"
@@ -1354,7 +1355,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_something = FALSE;
@@ -1513,8 +1513,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_something" */
- apr_err = apr_dir_remove (path, subpool);
- if (apr_err)
+ err = svn_io_dir_remove_nonrecursive (path, subpool);
+ if (err)
             left_something = TRUE;
         }
     } /* end of directory case */
Index: subversion/libsvn_wc/adm_files.c
===================================================================
--- subversion/libsvn_wc/adm_files.c
+++ subversion/libsvn_wc/adm_files.c Wed Jun 12 16:52:27 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;
 }
 
 
@@ -507,7 +492,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. */
@@ -544,15 +528,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;
@@ -601,15 +584,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;
@@ -641,8 +619,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);
@@ -651,12 +627,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;
 }
 
 
@@ -1033,16 +1006,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/update_editor.c
===================================================================
--- subversion/libsvn_wc/update_editor.c
+++ subversion/libsvn_wc/update_editor.c Fri Jun 28 15:39:05 2002
@@ -1284,13 +1284,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/questions.c
===================================================================
--- subversion/libsvn_wc/questions.c
+++ subversion/libsvn_wc/questions.c Wed Jun 26 18:27:07 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"
@@ -209,25 +210,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 Jun 12 16:58:27 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/include/svn_utf.h
===================================================================
--- /dev/null Fri Jun 28 16:48:08 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_subr/utf.c
===================================================================
--- /dev/null Fri Jun 28 16:48:35 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/clients/cmdline/props.c
===================================================================
--- subversion/clients/cmdline/props.c
+++ subversion/clients/cmdline/props.c Wed Jun 26 17:19:06 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", (const char *) key, propval->data);
+ SVN_ERR (svn_utf_cstring_from_utf8 ((const 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", (const char *) key);
+ SVN_ERR (svn_utf_cstring_from_utf8 ((const char *) key, &key_native, pool));
+ printf (" %s\n", key_native);
     }
+ return SVN_NO_ERROR;
 }
 
 
Index: subversion/clients/cmdline/cl.h
===================================================================
--- subversion/clients/cmdline/cl.h
+++ subversion/clients/cmdline/cl.h Wed Jun 26 17:06:53 2002
@@ -70,9 +70,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? */
 
@@ -90,13 +90,13 @@
   svn_boolean_t very_verbose;
   svn_boolean_t update;
   svn_boolean_t strict;
- 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;
 
@@ -180,6 +180,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,
@@ -259,11 +261,39 @@
 
 /* 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
+ revision line to print; the SUPPRESS_FINAL_LINE flag indicates
+ whether to print the final revision line at all.
+
+ ### OBSOLETE, please do not use. Left only until issue #662 is
+ ### completed. */
+svn_error_t *
+svn_cl__get_trace_update_editor (const svn_delta_editor_t **editor,
+ void **edit_baton,
+ const char *initial_path, /* UTF-8! */
+ svn_boolean_t is_checkout,
+ svn_boolean_t suppress_final_line,
+ apr_pool_t *pool);
+
+
+/* Returns an editor that prints out events in a commit.
+ ### OBSOLETE, please do not use. Left only until issue #662 is
+ ### completed. */
+svn_error_t *
+svn_cl__get_trace_commit_editor (const svn_delta_editor_t **editor,
+ void **edit_baton,
+ const char *initial_path,
+ apr_pool_t *pool);
 
 
 /* Search for a text editor command in standard environment variables,
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/util.c
===================================================================
--- subversion/clients/cmdline/util.c
+++ subversion/clients/cmdline/util.c Fri Jun 14 18:42:38 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
@@ -98,7 +111,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;
@@ -123,7 +137,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;
@@ -144,7 +159,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;
@@ -157,11 +172,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;
@@ -197,7 +217,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
@@ -290,15 +313,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;
@@ -319,6 +343,9 @@
        "None of the environment variables "
        "SVN_EDITOR, VISUAL or EDITOR is set.");
 
+ /* 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,
@@ -328,15 +355,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,
@@ -344,9 +371,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)
     {
@@ -356,7 +387,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)
     {
@@ -368,7 +399,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)
     {
@@ -383,10 +414,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
     {
@@ -396,7 +428,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)
@@ -410,13 +442,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));
@@ -510,8 +542,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))
@@ -589,6 +620,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;
             }
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/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/log-cmd.c
===================================================================
--- subversion/clients/cmdline/log-cmd.c
+++ subversion/clients/cmdline/log-cmd.c Wed Jun 26 17:43:46 2002
@@ -35,6 +35,7 @@
 #include "svn_sorts.h"
 #include "svn_xml.h"
 #include "svn_time.h"
+#include "svn_utf.h"
 #include "cl.h"
 
 
@@ -115,6 +116,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;
@@ -128,6 +130,10 @@
       return SVN_NO_ERROR;
     }
 
+ 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));
+
   {
     /* Convert date to a format for humans. */
     apr_time_t time_temp;
@@ -145,9 +151,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)
     {
@@ -174,14 +180,15 @@
       for (i = 0; i < sorted_paths->nelts; i++)
         {
           svn_item_t *item = &(APR_ARRAY_IDX (sorted_paths, i, svn_item_t));
- const char *path = item->key;
+ const char *path_native, *path = item->key;
           char action = (char) ((int) apr_hash_get (changed_paths,
                                                     item->key, item->klen));
- printf (" %c %s\n", (action == 'R' ? 'U' : action), path);
+ SVN_ERR (svn_utf_cstring_from_utf8 (path, &path_native, pool));
+ printf (" %c %s\n", (action == 'R' ? 'U' : action), path_native);
         }
     }
   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/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/help-cmd.c
===================================================================
--- subversion/clients/cmdline/help-cmd.c
+++ subversion/clients/cmdline/help-cmd.c Wed Jun 12 16:38:55 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/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/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/main.c
===================================================================
--- subversion/clients/cmdline/main.c
+++ subversion/clients/cmdline/main.c Wed Jun 26 17:29:47 2002
@@ -41,6 +41,7 @@
 #include "svn_error.h"
 #include "svn_io.h"
 #include "svn_time.h"
+#include "svn_utf.h"
 #include "cl.h"
 
 
@@ -837,7 +838,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)
@@ -872,6 +875,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);
@@ -905,12 +909,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;
           }
@@ -919,11 +928,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;
           }
@@ -945,13 +959,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);
@@ -962,22 +991,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;
@@ -995,10 +1029,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;
@@ -1014,10 +1064,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;
@@ -1028,7 +1083,12 @@
         opt_state.strict = 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/feedback.c
===================================================================
--- subversion/clients/cmdline/feedback.c
+++ subversion/clients/cmdline/feedback.c Wed Jun 26 17:33:28 2002
@@ -29,6 +29,7 @@
 #include <apr_want.h>
 
 #include "svn_pools.h"
+#include "svn_utf.h"
 #include "cl.h"
 
 
@@ -57,29 +58,42 @@
   struct notify_baton *nb = baton;
   char statchar_buf[3] = "_ ";
 
+ /* 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");
+ svn_pool_destroy (subpool);
+ return;
+ }
   switch (action)
     {
     case svn_wc_notify_delete:
     case svn_wc_notify_update_delete:
       nb->received_some_change = TRUE;
- printf ("D %s\n", path);
+ printf ("D %s\n", path_native);
       break;
 
     case svn_wc_notify_update_add:
       nb->received_some_change = TRUE;
- printf ("A %s\n", path);
+ printf ("A %s\n", path_native);
       break;
 
     case svn_wc_notify_restore:
- printf ("Restored %s\n", path);
+ printf ("Restored %s\n", path_native);
       break;
 
     case svn_wc_notify_revert:
- printf ("Reverted %s\n", path);
+ printf ("Reverted %s\n", path_native);
       break;
 
     case svn_wc_notify_resolve:
- printf ("Resolved conflicted state of %s\n", path);
+ printf ("Resolved conflicted state of %s\n", path_native);
       break;
 
     case svn_wc_notify_add:
@@ -89,9 +103,9 @@
       if (mime_type
           && ((strlen (mime_type)) > 5)
           && ((strncmp (mime_type, "text/", 5)) != 0))
- printf ("A (bin) %s\n", path);
+ printf ("A (bin) %s\n", path_native);
       else
- printf ("A %s\n", path);
+ printf ("A %s\n", path_native);
       break;
 
     case svn_wc_notify_update_update:
@@ -123,7 +137,7 @@
             else if (prop_state == svn_wc_notify_state_modified)
               statchar_buf[1] = 'U';
 
- printf ("%s %s\n", statchar_buf, path);
+ printf ("%s %s\n", statchar_buf, path_native);
           }
       }
       break;
@@ -131,7 +145,7 @@
     case svn_wc_notify_update_external:
       /* Currently this is used for checkouts and switches too. If we
          want different output, we'll have to add new actions. */
- printf ("\nFetching external item into %s\n", path);
+ printf ("\nFetching external item into %s\n", path_native);
       break;
 
     case svn_wc_notify_update_completed:
@@ -166,24 +180,24 @@
       break;
 
     case svn_wc_notify_commit_modified:
- printf ("Sending %s\n", path);
+ printf ("Sending %s\n", path_native);
       break;
 
     case svn_wc_notify_commit_added:
       if (mime_type
           && ((strlen (mime_type)) > 5)
           && ((strncmp (mime_type, "text/", 5)) != 0))
- printf ("Adding (bin) %s\n", path);
+ printf ("Adding (bin) %s\n", path_native);
       else
- printf ("Adding %s\n", path);
+ printf ("Adding %s\n", path_native);
       break;
 
     case svn_wc_notify_commit_deleted:
- printf ("Deleting %s\n", path);
+ printf ("Deleting %s\n", path_native);
       break;
 
     case svn_wc_notify_commit_replaced:
- printf ("Replacing %s\n", path);
+ printf ("Replacing %s\n", path_native);
       break;
 
     case svn_wc_notify_commit_postfix_txdelta:
@@ -200,6 +214,8 @@
     default:
       break;
     }
+
+ svn_pool_destroy (subpool);
 }
 
 
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/info-cmd.c
===================================================================
--- subversion/clients/cmdline/info-cmd.c
+++ subversion/clients/cmdline/info-cmd.c Wed Jun 26 17:40:46 2002
@@ -27,6 +27,7 @@
 #include "svn_error.h"
 #include "svn_path.h"
 #include "svn_time.h"
+#include "svn_utf.h"
 #include "cl.h"
 
 
@@ -56,10 +57,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)
@@ -75,13 +78,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);
@@ -138,16 +146,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);
@@ -162,21 +175,35 @@
         svn_cl__info_print_time (entry->prop_time, "Properties Last Updated",
                                  pool);
 
- 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/svnadmin/svnadmin.h
===================================================================
--- subversion/svnadmin/svnadmin.h
+++ subversion/svnadmin/svnadmin.h Fri Jun 14 17:47:53 2002
@@ -35,6 +35,7 @@
 #include "svn_path.h"
 #include "svn_fs.h"
 #include "svn_repos.h"
+#include "svn_utf.h"
 
 #include "db.h"
 
@@ -63,7 +64,7 @@
   svn_fs_root_t *root;
 
   /* the current working directory */
- svn_stringbuf_t *cwd;
+ svn_stringbuf_t *cwd; /* UTF-8! */
 
   /* top-level pool, where cwd is allocated */
   apr_pool_t *pool;
Index: subversion/svnadmin/main.c
===================================================================
--- subversion/svnadmin/main.c
+++ subversion/svnadmin/main.c Fri Jun 14 18:35:59 2002
@@ -17,6 +17,7 @@
  */
 
 
+#include <locale.h>
 #include <apr_file_io.h>
 #include "svnadmin.h"
 
@@ -94,7 +95,7 @@
       apr_ssize_t keylen;
       void *val;
       svn_fs_dirent_t *this_entry;
- const char *this_full_path;
+ const char *this_full_path, *native_name;
       int is_dir;
       int i;
       const svn_fs_id_t *id;
@@ -109,7 +110,9 @@
       for (i = 0; i < indentation; i++)
         printf (" ");
 
- printf ("%s", this_entry->name);
+ SVN_ERR (svn_utf_cstring_from_utf8 (this_entry->name, &native_name,
+ pool));
+ printf ("%s", native_name);
       
       SVN_ERR (svn_fs_node_id (&id, root, this_full_path, pool));
       id_str = svn_fs_unparse_id (id, pool);
@@ -287,16 +290,19 @@
      ### is refactored. for now, let's just get the tool up and
      ### running. */
 
+ setlocale (LC_CTYPE, "");
+
   if (argc < 3)
     {
       usage (argv[0], 1);
       /* NOTREACHED */
     }
 
- path = argv[2];
   apr_initialize ();
   pool = svn_pool_create (NULL);
 
+ INT_ERR (svn_utf_cstring_to_utf8 (argv[2], &path, pool));
+
   command = parse_command (argv[1]);
   switch (command)
     {
@@ -348,7 +354,9 @@
           }
 
         paths = apr_array_make (pool, 1, sizeof (const char *));
- (*(const char **)apr_array_push(paths)) = argv[3];
+ INT_ERR (svn_utf_cstring_to_utf8 (argv[3],
+ (const char **)apr_array_push(paths),
+ pool));
 
         INT_ERR (svn_repos_open (&repos, path, pool));
         fs = svn_repos_fs (repos);
@@ -379,7 +387,7 @@
                 /* NOTREACHED */
               }
             show_extra = TRUE;
- path = argv[3];
+ INT_ERR (svn_utf_cstring_to_utf8 (argv[3], &path, pool));
           }
 
         INT_ERR (svn_repos_open (&repos, path, pool));
@@ -401,6 +409,8 @@
                 apr_pool_t *this_pool = svn_pool_create (pool);
                 const svn_fs_id_t *root_id;
                 svn_string_t *id_str;
+ const char *txn_name_native, *datestamp_native;
+ const char *author_native, *log_native;
                 
                 INT_ERR (svn_fs_open_txn (&txn, fs, txn_name, this_pool));
                 INT_ERR (svn_fs_txn_root (&this_root, txn, this_pool));
@@ -420,11 +430,21 @@
                 if (! log)
                   log = svn_string_create ("", this_pool);
                 
- printf ("Txn %s:\n", txn_name);
- printf ("Created: %s\n", datestamp->data);
- printf ("Author: %s\n", author->data);
+ INT_ERR (svn_utf_cstring_from_utf8 (txn_name, &txn_name_native,
+ this_pool));
+ INT_ERR (svn_utf_cstring_from_utf8 (datestamp->data,
+ &datestamp_native,
+ this_pool));
+ INT_ERR (svn_utf_cstring_from_utf8 (author->data,
+ &author_native, this_pool));
+ INT_ERR (svn_utf_cstring_from_utf8 (log->data, &log_native,
+ this_pool));
+
+ printf ("Txn %s:\n", txn_name_native);
+ printf ("Created: %s\n", datestamp_native);
+ printf ("Author: %s\n", author_native);
                 printf ("Log (%" APR_SIZE_T_FMT " bytes):\n%s\n",
- log->len, log->data);
+ log->len, log_native);
                 printf ("==========================================\n");
                 INT_ERR (svn_fs_node_id (&root_id, this_root, "", pool));
                 id_str = svn_fs_unparse_id (root_id, pool);
@@ -476,6 +496,7 @@
             apr_pool_t *this_pool = svn_pool_create (pool);
             const svn_fs_id_t *root_id;
             svn_string_t *id_str;
+ const char *datestamp_native, *author_native, *log_native;
 
             INT_ERR (svn_fs_revision_root (&this_root, fs, this, this_pool));
             INT_ERR (svn_fs_revision_prop (&datestamp, fs, this,
@@ -491,11 +512,19 @@
             if (! log)
               log = svn_string_create ("", this_pool);
             
+ INT_ERR (svn_utf_cstring_from_utf8 (datestamp->data,
+ &datestamp_native,
+ this_pool));
+ INT_ERR (svn_utf_cstring_from_utf8 (author->data,
+ &author_native, this_pool));
+ INT_ERR (svn_utf_cstring_from_utf8 (log->data, &log_native,
+ this_pool));
+
             printf ("Revision %" SVN_REVNUM_T_FMT "\n", this);
- printf ("Created: %s\n", datestamp->data);
- printf ("Author: %s\n", author->data);
+ printf ("Created: %s\n", datestamp_native);
+ printf ("Author: %s\n", author_native);
             printf ("Log (%" APR_SIZE_T_FMT " bytes):\n%s\n",
- log->len, log->data);
+ log->len, log_native);
             printf ("==========================================\n");
             INT_ERR (svn_fs_node_id (&root_id, this_root, "", pool));
             id_str = svn_fs_unparse_id (root_id, pool);
@@ -582,7 +611,9 @@
         /* All the rest of the arguments are transaction names. */
         for (i = 3; i < argc; i++)
           {
- INT_ERR (svn_fs_open_txn (&txn, fs, argv[i], pool));
+ const char *txn_name_utf8;
+ INT_ERR (svn_utf_cstring_to_utf8 (argv[i], &txn_name_utf8, pool));
+ INT_ERR (svn_fs_open_txn (&txn, fs, txn_name_utf8, pool));
             INT_ERR (svn_fs_abort_txn (txn));
           }
       }
@@ -608,8 +639,9 @@
     case svnadmin_cmd_setlog:
       {
         svn_revnum_t the_rev;
- svn_stringbuf_t *file_contents;
+ svn_stringbuf_t *file_contents, *file_contents_utf8;
         svn_string_t log_contents;
+ const char *filename_utf8;
 
         if (argc != 5)
           {
@@ -619,9 +651,12 @@
       
         /* get revision and file from argv[] */
         the_rev = SVN_STR_TO_REV (argv[3]);
- INT_ERR (svn_string_from_file (&file_contents, argv[4], pool));
- log_contents.data = file_contents->data;
- log_contents.len = file_contents->len;
+ INT_ERR (svn_utf_cstring_to_utf8 (argv[4], &filename_utf8, pool));
+ INT_ERR (svn_string_from_file (&file_contents, filename_utf8, pool));
+ INT_ERR (svn_utf_stringbuf_to_utf8 (file_contents, &file_contents_utf8,
+ pool));
+ log_contents.data = file_contents_utf8->data;
+ log_contents.len = file_contents_utf8->len;
 
         /* open the filesystem */
         INT_ERR (svn_repos_open (&repos, path, pool));
@@ -650,7 +685,7 @@
 
         /* get revision and path from argv[] */
         the_rev = SVN_STR_TO_REV (argv[3]);
- node = argv[4];
+ INT_ERR (svn_utf_cstring_to_utf8 (argv[4], &node, pool));
 
         /* open the filesystem */
         INT_ERR (svn_repos_open (&repos, path, pool));
@@ -665,7 +700,7 @@
 
         /* do the (un-)deltification */
         printf ("%seltifying `%s' in revision %" SVN_REVNUM_T_FMT "...",
- is_deltify ? "D" : "Und", node, the_rev);
+ is_deltify ? "D" : "Und", argv[4], the_rev);
         if (is_deltify)
           {
             INT_ERR (svn_fs_deltify (rev_root, node, is_dir ? 1 : 0, pool));
@@ -689,6 +724,9 @@
         const char *lockfile_path, *env_path;
         apr_file_t *lockfile_handle = NULL;
         svn_error_t *err;
+ const char *progname_utf8;
+
+ INT_ERR (svn_utf_cstring_to_utf8 (argv[0], &progname_urf8, pool));
 
         /* Don't use svn_repos_open() here, because we don't want the
            usual locking behavior. */
@@ -700,13 +738,13 @@
         /* Exclusively lock the repository. This blocks on other locks,
            including shared locks. */
         lockfile_path = svn_fs_db_lockfile (fs, pool);
- apr_err = apr_file_open (&lockfile_handle, lockfile_path,
- (APR_WRITE | APR_APPEND), APR_OS_DEFAULT, pool);
- if (apr_err)
+ err = svn_io_file_open (&lockfile_handle, lockfile_path,
+ (APR_WRITE | APR_APPEND), APR_OS_DEFAULT, pool);
+ if (err)
           {
             err = svn_error_createf
- (apr_err, 0, NULL, pool,
- "%s: error opening db lockfile `%s'", argv[0], lockfile_path);
+ (err->apr_err, err->src_err, err, pool,
+ "%s: error opening db lockfile `%s'", progname_utf8, lockfile_path);
             goto error;
           }
 
@@ -715,7 +753,7 @@
           {
             err = svn_error_createf
               (apr_err, 0, NULL, pool,
- "%s: exclusive lock on `%s' failed", argv[0], lockfile_path);
+ "%s: exclusive lock on `%s' failed", progname_utf8, lockfile_path);
             goto error;
           }
 
@@ -734,7 +772,7 @@
           {
             err = svn_error_createf
               (apr_err, 0, NULL, pool,
- "%s: error unlocking `%s'", argv[0], lockfile_path);
+ "%s: error unlocking `%s'", progname_utf8, lockfile_path);
             goto error;
           }
 
@@ -743,7 +781,7 @@
           {
             err = svn_error_createf
               (apr_err, 0, NULL, pool,
- "%s: error closing `%s'", argv[0], lockfile_path);
+ "%s: error closing `%s'", progname_utf8, lockfile_path);
             goto error;
           }
 
Index: subversion/svnadmin/shell.c
===================================================================
--- subversion/svnadmin/shell.c
+++ subversion/svnadmin/shell.c Fri Jun 14 17:59:14 2002
@@ -25,7 +25,7 @@
 /* Helper */
 static svn_error_t *
 path_stat (svn_boolean_t *exists,
- svn_stringbuf_t *path,
+ svn_stringbuf_t *path /* UTF-8! */,
            shcxt_t *shcxt,
            apr_pool_t *pool)
 {
@@ -67,9 +67,9 @@
    Do a sanity check: if the *NEW_PATH dosen't actually exist in the
    current filesytem revision, then set it to NULL! */
 static svn_error_t *
-compute_new_path (svn_stringbuf_t **new_path,
- svn_stringbuf_t *current_path,
- char *given_path,
+compute_new_path (svn_stringbuf_t **new_path /* UTF-8! */,
+ svn_stringbuf_t *current_path /* UTF-8! */,
+ const char *given_path /* UTF-8! */,
                   shcxt_t *shcxt,
                   apr_pool_t *pool)
 {
@@ -142,8 +142,11 @@
   else
     {
       svn_stringbuf_t *new_path;
+ const char *path_utf8;
 
- SVN_ERR (compute_new_path (&new_path, shcxt->cwd, path,
+ SVN_ERR (svn_utf_cstring_to_utf8 (path, &path_utf8, pool));
+
+ SVN_ERR (compute_new_path (&new_path, shcxt->cwd, path_utf8,
                                  shcxt, shcxt->pool));
 
       if (new_path == NULL)
@@ -215,7 +218,7 @@
 
 /* Helper: print a single dirent nicely. */
 static svn_error_t *
-print_dirent (svn_stringbuf_t *abs_path,
+print_dirent (svn_stringbuf_t *abs_path /* UTF-8! */,
               svn_fs_dirent_t *entry,
               shcxt_t *shcxt,
               apr_pool_t *pool)
@@ -226,6 +229,7 @@
   svn_string_t *id_str;
   svn_boolean_t has_props;
   apr_hash_t *props;
+ const char *name_native;
 
   /* directory or file? */
   SVN_ERR (svn_fs_is_dir (&is_dir, shcxt->root, abs_path->data, pool));
@@ -252,11 +256,12 @@
   else
     has_props = FALSE;
 
+ SVN_ERR (svn_utf_cstring_from_utf8 (entry->name, &name_native, pool ));
 
   /* Now PRINT all this information. */
   printf (" <%8s> [%6ld] %1d %10ld",
           id_str->data, created_rev, has_props, (long int) size);
- printf (" %s", entry->name);
+ printf (" %s", name_native);
   if (is_dir)
     printf ("/");
   printf ("\n");
@@ -282,8 +287,11 @@
     {
       /* we want to list some dir -other- than CWD */
       svn_stringbuf_t *new_path;
-
- SVN_ERR (compute_new_path (&new_path, shcxt->cwd, path,
+ const char *path_utf8;
+
+ SVN_ERR (svn_utf_cstring_to_utf8 (path, &path_utf8, pool));
+
+ SVN_ERR (compute_new_path (&new_path, shcxt->cwd, path_utf8,
                                  shcxt, pool));
       
       if (new_path == NULL)
@@ -327,14 +335,22 @@
 /** Main routines **/
 
 /* Print the SHCXT info in a prompt. */
-static void
+static svn_error_t *
 display_prompt (shcxt_t *shcxt)
 {
   /* this could be more sophisticated, or configurable, I suppose. */
 
+ apr_pool_t *subpool = svn_pool_create (shcxt->pool);
+ const char *cwd_native;
+
+ SVN_ERR (svn_utf_cstring_from_utf8 (shcxt->cwd->data, &cwd_native, subpool));
+
   printf ("<%" SVN_REVNUM_T_FMT ": %s>$ ",
- shcxt->current_rev, shcxt->cwd->data);
+ shcxt->current_rev, cwd_native);
   fflush (stdout);
+
+ svn_pool_destroy (subpool);
+ return SVN_NO_ERROR;
 }
 
 
@@ -445,7 +461,7 @@
       svn_stringbuf_t *input;
 
       /* display a prompt. */
- display_prompt (shcxt);
+ SVN_ERR (display_prompt (shcxt));
 
       /* get input from user. */
       SVN_ERR (get_input (&input, subpool));
Index: subversion/svnlook/main.c
===================================================================
--- subversion/svnlook/main.c
+++ subversion/svnlook/main.c Wed Jun 26 17:46:36 2002
@@ -16,6 +16,7 @@
  * ====================================================================
  */
 
+#include <locale.h>
 #include <apr_general.h>
 #include <apr_pools.h>
 #include <apr_time.h>
@@ -34,6 +35,7 @@
 #include "svn_fs.h"
 #include "svn_repos.h"
 #include "svn_time.h"
+#include "svn_utf.h"
 
 
 /*** Some convenience macros and types. ***/
@@ -68,7 +70,7 @@
   svn_boolean_t is_revision;
   svn_revnum_t rev_id;
   svn_fs_txn_t *txn;
- char *txn_name;
+ const char *txn_name /* UTF-8! */;
 
 } svnlook_ctxt_t;
 
@@ -78,7 +80,7 @@
 static svn_error_t *
 get_property (svn_string_t **prop_value,
               svnlook_ctxt_t *c,
- const char *prop_name,
+ const char *prop_name /* UTF-8! */,
               apr_pool_t *pool)
 {
   /* Fetch transaction property... */
@@ -155,9 +157,9 @@
 
 /* Recursively print only directory nodes that either a) have property
    mods, or b) contains files that have changed. */
-static void
+static svn_error_t *
 print_dirs_changed_tree (svn_repos_node_t *node,
- svn_stringbuf_t *path,
+ svn_stringbuf_t *path /* UTF-8! */,
                          apr_pool_t *pool)
 {
   svn_repos_node_t *tmp_node;
@@ -165,11 +167,11 @@
   svn_stringbuf_t *full_path;
 
   if (! node)
- return;
+ return SVN_NO_ERROR;
 
   /* Not a directory? We're not interested. */
   if (node->kind != svn_node_dir)
- return;
+ return SVN_NO_ERROR;
 
   /* Got prop mods? Excellent. */
   if (node->prop_mod)
@@ -205,34 +207,36 @@
   /* Print the node if it qualifies. */
   if (print_me)
     {
+ const char *path_native;
+ SVN_ERR (svn_utf_cstring_from_utf8 (path->data, &path_native, pool));
       printf ("%s/\n", path->data);
     }
 
   /* Recursively handle the node's children. */
   tmp_node = node->child;
   if (! tmp_node)
- return;
+ return SVN_NO_ERROR;
 
   full_path = svn_stringbuf_dup (path, pool);
   svn_path_add_component_nts (full_path, tmp_node->name);
- print_dirs_changed_tree (tmp_node, full_path, pool);
+ SVN_ERR (print_dirs_changed_tree (tmp_node, full_path, pool));
   while (tmp_node->sibling)
     {
       tmp_node = tmp_node->sibling;
       svn_stringbuf_set (full_path, path->data);
       svn_path_add_component_nts (full_path, tmp_node->name);
- print_dirs_changed_tree (tmp_node, full_path, pool);
+ SVN_ERR (print_dirs_changed_tree (tmp_node, full_path, pool));
     }
 
- return;
+ return SVN_NO_ERROR;
 }
 
 
 /* Recursively print all nodes in the tree that have been modified
    (do not include directories affected only by "bubble-up"). */
-static void
+static svn_error_t *
 print_changed_tree (svn_repos_node_t *node,
- svn_stringbuf_t *path,
+ svn_stringbuf_t *path /* UTF-8! */,
                     apr_pool_t *pool)
 {
   svn_repos_node_t *tmp_node;
@@ -241,7 +245,7 @@
   int print_me = 1;
 
   if (! node)
- return;
+ return SVN_NO_ERROR;
 
   /* Print the node. */
   tmp_node = node;
@@ -263,47 +267,51 @@
 
   /* Print this node unless told to skip it. */
   if (print_me)
- printf ("%s %s%s\n",
- status,
- path->data,
- tmp_node->kind == svn_node_dir ? "/" : "");
+ {
+ const char *path_native;
+ SVN_ERR (svn_utf_cstring_from_utf8 (path->data, &path_native, pool));
+ printf ("%s %s%s\n",
+ status,
+ path_native,
+ tmp_node->kind == svn_node_dir ? "/" : "");
+ }
   
   /* Return here if the node has no children. */
   tmp_node = tmp_node->child;
   if (! tmp_node)
- return;
+ return SVN_NO_ERROR;
 
   /* Recursively handle the node's children. */
   full_path = svn_stringbuf_dup (path, pool);
   svn_path_add_component_nts (full_path, tmp_node->name);
- print_changed_tree (tmp_node, full_path, pool);
+ SVN_ERR (print_changed_tree (tmp_node, full_path, pool));
   while (tmp_node->sibling)
     {
       tmp_node = tmp_node->sibling;
       svn_stringbuf_set (full_path, path->data);
       svn_path_add_component_nts (full_path, tmp_node->name);
- print_changed_tree (tmp_node, full_path, pool);
+ SVN_ERR (print_changed_tree (tmp_node, full_path, pool));
     }
 
- return;
+ return SVN_NO_ERROR;
 }
 
 
 static svn_error_t *
 open_writable_binary_file (apr_file_t **fh,
- const char *path,
+ const char *path /* UTF-8! */,
                            apr_pool_t *pool)
 {
   apr_array_header_t *path_pieces;
- apr_status_t apr_err;
+ svn_error_t *err;
   int i;
   const char *full_path, *dir;
   
   /* Try the easy way to open the file. */
- apr_err = apr_file_open (fh, path,
- APR_WRITE | APR_CREATE | APR_TRUNCATE | APR_BINARY,
- APR_OS_DEFAULT, pool);
- if (! apr_err)
+ err = svn_io_file_open (fh, path,
+ APR_WRITE | APR_CREATE | APR_TRUNCATE | APR_BINARY,
+ APR_OS_DEFAULT, pool);
+ if (! err)
     return SVN_NO_ERROR;
 
   svn_path_split_nts (path, &dir, NULL, pool);
@@ -311,12 +319,12 @@
   /* If the file path has no parent, then we've already tried to open
      it as best as we care to try above. */
   if (svn_path_is_empty_nts (dir))
- return svn_error_createf (apr_err, 0, NULL, pool,
+ return svn_error_createf (err->apr_err, err->src_err, err, pool,
                               "Error opening writable file %s", path);
 
   path_pieces = svn_path_decompose (dir, pool);
   if (! path_pieces->nelts)
- return APR_SUCCESS;
+ return SVN_NO_ERROR;
 
   full_path = "";
   for (i = 0; i < path_pieces->nelts; i++)
@@ -329,16 +337,12 @@
       /* Does this path component exist at all? */
       if (kind == svn_node_none)
         {
- apr_err = apr_dir_make (full_path, APR_OS_DEFAULT, pool);
- if (apr_err)
- return svn_error_createf (apr_err, 0, NULL, pool,
- "Error creating dir %s",
- full_path);
+ SVN_ERR (svn_io_dir_make (full_path, APR_OS_DEFAULT, pool));
         }
       else if (kind != svn_node_dir)
         {
- if (apr_err)
- return svn_error_createf (apr_err, 0, NULL, pool,
+ if (err)
+ return svn_error_createf (err->apr_err, err->src_err, err, pool,
                                       "Error creating dir %s (path exists)",
                                       full_path);
         }
@@ -346,11 +350,11 @@
 
   /* Now that we are ensured that the parent path for this file
      exists, try once more to open it. */
- apr_err = apr_file_open (fh, path,
- APR_WRITE | APR_CREATE | APR_TRUNCATE | APR_BINARY,
- APR_OS_DEFAULT, pool);
- if (apr_err)
- return svn_error_createf (apr_err, 0, NULL, pool,
+ err = svn_io_file_open (fh, path,
+ APR_WRITE | APR_CREATE | APR_TRUNCATE | APR_BINARY,
+ APR_OS_DEFAULT, pool);
+ if (err)
+ return svn_error_createf (err->apr_err, err->src_err, err, pool,
                               "Error opening writable file %s", path);
     
   return SVN_NO_ERROR;
@@ -360,7 +364,7 @@
 static svn_error_t *
 dump_contents (apr_file_t *fh,
                svn_fs_root_t *root,
- const char *path,
+ const char *path /* UTF-8! */,
                apr_pool_t *pool)
 {
   apr_status_t apr_err;
@@ -398,8 +402,8 @@
 print_diff_tree (svn_fs_root_t *root,
                  svn_fs_root_t *base_root,
                  svn_repos_node_t *node,
- const char *path,
- const char *base_path,
+ const char *path /* UTF-8! */,
+ const char *base_path /* UTF-8! */,
                  apr_pool_t *pool)
 {
   svn_repos_node_t *tmp_node;
@@ -417,6 +421,8 @@
   if ((SVN_IS_VALID_REVNUM (tmp_node->copyfrom_rev))
       && (tmp_node->copyfrom_path != NULL))
     {
+ const char *base_path_native;
+
       /* This is ... a copy. */
       is_copy = TRUE;
 
@@ -429,8 +435,10 @@
       else
         base_path = apr_pstrdup (pool, tmp_node->copyfrom_path);
 
+ SVN_ERR (svn_utf_cstring_from_utf8 (base_path, &base_path_native, pool));
+
       printf ("Copied: %s (from rev %" SVN_REVNUM_T_FMT ", %s)\n",
- tmp_node->name, tmp_node->copyfrom_rev, base_path);
+ tmp_node->name, tmp_node->copyfrom_rev, base_path_native);
 
       SVN_ERR (svn_fs_revision_root (&base_root,
                                      svn_fs_root_fs (base_root),
@@ -505,16 +513,19 @@
       apr_file_t *outhandle;
       apr_status_t apr_err;
       const char *label;
- char *abs_path;
+ const char *abs_path;
       int exitcode;
+ const char *path_native;
 
       if (! is_copy)
         {
+ SVN_ERR (svn_utf_cstring_from_utf8 (path, &path_native, pool));
+
           printf ("%s: %s\n",
                   ((tmp_node->action == 'A') ? "Added" :
                    ((tmp_node->action == 'D') ? "Deleted" :
                     ((tmp_node->action == 'R') ? "Modified" : "Index"))),
- path);
+ path_native);
         }
       printf ("===============================================================\
 ===============\n");
@@ -546,9 +557,9 @@
     
   /* Now, delete any temporary files. */
   if (orig_path)
- apr_file_remove (orig_path, pool);
+ svn_io_remove_file (orig_path, pool);
   if (new_path)
- apr_file_remove (new_path, pool);
+ svn_io_remove_file (new_path, pool);
 
   /* Return here if the node has no children. */
   tmp_node = tmp_node->child;
@@ -592,10 +603,10 @@
  * time why it even takes the arguments it takes, or why it does what
  * it does with them. See issue #540. -kff
  */
-static void
+static svn_error_t *
 print_ids_tree (svn_repos_node_t *node,
                 svn_fs_root_t *root,
- svn_stringbuf_t *path,
+ svn_stringbuf_t *path /* UTF-8! */,
                 int indentation,
                 apr_pool_t *pool)
 {
@@ -605,9 +616,10 @@
   const svn_fs_id_t *id;
   svn_string_t *unparsed_id = NULL;
   apr_pool_t *subpool;
+ const char *name_native;
 
   if (! node)
- return;
+ return SVN_NO_ERROR;
 
   /* Print the indentation. */
   for (i = 0; i < indentation; i++)
@@ -622,45 +634,50 @@
     unparsed_id = svn_fs_unparse_id (id, pool);
   
   /* Print the node. */
+ SVN_ERR (svn_utf_cstring_from_utf8 (tmp_node->name, &name_native, pool));
   printf ("%s%s <%s>\n",
- tmp_node->name,
+ name_native,
           tmp_node->kind == svn_node_dir ? "/" : "",
           unparsed_id ? unparsed_id->data : "unknown");
 
   /* Return here if the node has no children. */
   tmp_node = tmp_node->child;
   if (! tmp_node)
- return;
+ return SVN_NO_ERROR;
 
   /* Recursively handle the node's children. */
   subpool = svn_pool_create (pool);
   full_path = svn_stringbuf_dup (path, subpool);
   svn_path_add_component_nts (full_path, tmp_node->name);
- print_ids_tree (tmp_node, root, full_path, indentation + 1, subpool);
+ SVN_ERR (print_ids_tree (tmp_node, root, full_path, indentation + 1,
+ subpool));
   while (tmp_node->sibling)
     {
       tmp_node = tmp_node->sibling;
       svn_stringbuf_set (full_path, path->data);
       svn_path_add_component_nts (full_path, tmp_node->name);
- print_ids_tree (tmp_node, root, full_path, indentation + 1, subpool);
+ SVN_ERR (print_ids_tree (tmp_node, root, full_path, indentation + 1,
+ subpool));
     }
   svn_pool_destroy (subpool);
 
- return;
+ return SVN_NO_ERROR;
 }
 
 
 /* Recursively print all nodes in the tree. If SHOW_IDS is non-zero,
    print the id of each node next to its name. */
-static void
+static svn_error_t *
 print_tree (svn_repos_node_t *node,
- int indentation)
+ int indentation,
+ apr_pool_t *pool)
 {
   svn_repos_node_t *tmp_node;
   int i;
+ const char *name_native;
 
   if (! node)
- return;
+ return SVN_NO_ERROR;
 
   /* Print the indentation. */
   for (i = 0; i < indentation; i++)
@@ -670,24 +687,25 @@
 
   /* Print the node. */
   tmp_node = node;
+ SVN_ERR (svn_utf_cstring_from_utf8 (tmp_node->name, &name_native, pool));
   printf ("%s%s\n",
- tmp_node->name,
+ name_native,
           tmp_node->kind == svn_node_dir ? "/" : "");
 
   /* Return here if the node has no children. */
   tmp_node = tmp_node->child;
   if (! tmp_node)
- return;
+ return SVN_NO_ERROR;
 
   /* Recursively handle the node's children. */
- print_tree (tmp_node, indentation + 1);
+ SVN_ERR (print_tree (tmp_node, indentation + 1, pool));
   while (tmp_node->sibling)
     {
       tmp_node = tmp_node->sibling;
- print_tree (tmp_node, indentation + 1);
+ SVN_ERR (print_tree (tmp_node, indentation + 1, pool));
     }
 
- return;
+ return SVN_NO_ERROR;
 }
 
 
@@ -705,12 +723,15 @@
 
   if (prop_value && prop_value->data)
     {
+ const char *log_native;
+
       if (print_size)
         {
           printf ("%" APR_SIZE_T_FMT "\n", prop_value->len);
         }
 
- printf ("%s", prop_value->data);
+ SVN_ERR (svn_utf_cstring_from_utf8 (prop_value->data, &log_native, pool));
+ printf ("%s", log_native);
     }
   else if (print_size)
     {
@@ -757,8 +778,12 @@
 
   SVN_ERR (get_property (&prop_value, c, SVN_PROP_REVISION_AUTHOR, pool));
 
- if (prop_value && prop_value->data)
- printf ("%s", prop_value->data);
+ if (prop_value && prop_value->data) {
+ const char *author_native;
+ SVN_ERR (svn_utf_cstring_from_utf8 (prop_value->data, &author_native,
+ pool));
+ printf ("%s", author_native);
+ }
   
   printf ("\n");
   return SVN_NO_ERROR;
@@ -788,7 +813,8 @@
   
   SVN_ERR (generate_delta_tree (&tree, c->repos, root, base_rev_id, pool));
   if (tree)
- print_dirs_changed_tree (tree, svn_stringbuf_create ("", pool), pool);
+ SVN_ERR (print_dirs_changed_tree (tree, svn_stringbuf_create ("", pool),
+ pool));
 
   return SVN_NO_ERROR;
 }
@@ -817,7 +843,7 @@
   
   SVN_ERR (generate_delta_tree (&tree, c->repos, root, base_rev_id, pool));
   if (tree)
- print_changed_tree (tree, svn_stringbuf_create ("", pool), pool);
+ SVN_ERR (print_changed_tree (tree, svn_stringbuf_create ("", pool), pool));
 
   return SVN_NO_ERROR;
 }
@@ -870,12 +896,12 @@
     {
       if (show_ids)
         {
- print_ids_tree (tree, root,
- svn_stringbuf_create ("", pool), 0, pool);
+ SVN_ERR (print_ids_tree (tree, root,
+ svn_stringbuf_create ("", pool), 0, pool));
         }
       else
         {
- print_tree (tree, 0);
+ SVN_ERR (print_tree (tree, 0, pool));
         }
     }
 
@@ -960,12 +986,15 @@
 main (int argc, const char * const *argv)
 {
   apr_pool_t *pool;
- const char *repos_path = NULL;
+ const char *repos_path = NULL, *repos_path_utf8;
+ const char *txn_name = NULL;
   int cmd_offset = 4;
   svnlook_cmd_t command;
   svnlook_ctxt_t c;
   svn_boolean_t was_success = FALSE;
 
+ setlocale (LC_CTYPE, "");
+
   /* Initialize context variable. */
   memset (&c, 0, sizeof (c));
   c.rev_id = SVN_INVALID_REVNUM;
@@ -989,7 +1018,7 @@
       if (! strcmp (argv[2], "txn")) /* transaction */
         {
           c.is_revision = FALSE;
- c.txn_name = (char *)argv[3];
+ txn_name = (char *)argv[3];
         }
       else if (! strcmp (argv[2], "rev")) /* revision */
         {
@@ -1051,8 +1080,13 @@
   apr_initialize ();
   pool = svn_pool_create (NULL);
 
+ /* Convert repository path and txn name (if present) to UTF-8 */
+ INT_ERR (svn_utf_cstring_to_utf8 (repos_path, &repos_path_utf8, pool));
+ if(txn_name)
+ INT_ERR (svn_utf_cstring_to_utf8 (txn_name, &c.txn_name, pool));
+
   /* Open the repository with the given path. */
- INT_ERR (svn_repos_open (&(c.repos), repos_path, pool));
+ INT_ERR (svn_repos_open (&(c.repos), repos_path_utf8, pool));
   c.fs = svn_repos_fs (c.repos);
 
   /* If this is a transaction, open the transaction. */

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org
Received on Fri Jun 28 17:30:24 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.