Index: subversion/libsvn_diff/diff_memory.c
==================================================================--- subversion/libsvn_diff/diff_memory.c	(revision 38523)
+++ subversion/libsvn_diff/diff_memory.c	(working copy)
@@ -424,9 +424,12 @@ output_unified_token_range(output_baton_t *btn,
 }

 /* Flush the hunk currently built up in BATON
-   into the baton's output_stream */
+   into the BATON's output_stream.
+   Use the specified HUNK_DELIMITER.
+   If HUNK_DELIMITER is NULL, fall back to the default delimiter. */
 static svn_error_t *
-output_unified_flush_hunk(output_baton_t *baton)
+output_unified_flush_hunk(output_baton_t *baton,
+                          const char *hunk_delimiter)
 {
   apr_off_t target_token;
   apr_size_t hunk_len;
@@ -442,34 +445,49 @@ static svn_error_t *
   SVN_ERR(output_unified_token_range(baton, 0 /*original*/,
                                      unified_output_context,
                                      baton->next_token, target_token));
+  if (hunk_delimiter == NULL)
+    hunk_delimiter = "@@";

   /* Write the hunk header */
   if (baton->hunk_length[0] > 0)
     /* Convert our 0-based line numbers into unidiff 1-based numbers */
     baton->hunk_start[0]++;
-  SVN_ERR(svn_stream_printf_from_utf8
-          (baton->output_stream, baton->header_encoding,
-           baton->pool,
-           /* Hunk length 1 is implied, don't show the
-              length field if we have a hunk that long */
-           (baton->hunk_length[0] == 1)
-           ? ("@@ -%" APR_OFF_T_FMT)
-           : ("@@ -%" APR_OFF_T_FMT ",%" APR_OFF_T_FMT),
-           baton->hunk_start[0], baton->hunk_length[0]));
+  SVN_ERR(svn_stream_printf_from_utf8(
+            baton->output_stream, baton->header_encoding,
+            baton->pool,
+            /* Hunk length 1 is implied, don't show the
+               length field if we have a hunk that long */
+            (baton->hunk_length[0] == 1)
+            ? ("%s -%" APR_OFF_T_FMT)
+            : ("%s -%" APR_OFF_T_FMT ",%" APR_OFF_T_FMT),
+            hunk_delimiter,
+            baton->hunk_start[0], baton->hunk_length[0]));

   if (baton->hunk_length[1] > 0)
     /* Convert our 0-based line numbers into unidiff 1-based numbers */
     baton->hunk_start[1]++;
-  SVN_ERR(svn_stream_printf_from_utf8
-          (baton->output_stream, baton->header_encoding,
-           baton->pool,
-           /* Hunk length 1 is implied, don't show the
-              length field if we have a hunk that long */
-           (baton->hunk_length[1] == 1)
-           ? (" +%" APR_OFF_T_FMT " @@" APR_EOL_STR)
-           : (" +%" APR_OFF_T_FMT ",%" APR_OFF_T_FMT " @@" APR_EOL_STR),
-           baton->hunk_start[1], baton->hunk_length[1]));

+
+  /* Hunk length 1 is implied, don't show the
+     length field if we have a hunk that long */
+  if (baton->hunk_length[1] == 1)
+    {
+      SVN_ERR(svn_stream_printf_from_utf8(
+                baton->output_stream, baton->header_encoding,
+                baton->pool,
+                " +%" APR_OFF_T_FMT " %s" APR_EOL_STR,
+                baton->hunk_start[1], hunk_delimiter));
+    }
+  else
+    {
+      SVN_ERR(svn_stream_printf_from_utf8(
+                baton->output_stream, baton->header_encoding,
+                baton->pool,
+                " +%" APR_OFF_T_FMT ",%" APR_OFF_T_FMT " %s" APR_EOL_STR,
+                baton->hunk_start[1], baton->hunk_length[1],
+                hunk_delimiter));
+    }
+
   hunk_len = baton->hunk->len;
   SVN_ERR(svn_stream_write(baton->output_stream,
                            baton->hunk->data, &hunk_len));
@@ -498,7 +516,7 @@ output_unified_diff_modified(void *baton,
   targ_mod = modified_start;

   if (btn->next_token + SVN_DIFF__UNIFIED_CONTEXT_SIZE < targ_orig)
-    SVN_ERR(output_unified_flush_hunk(btn));
+    SVN_ERR(output_unified_flush_hunk(btn, NULL));

   if (btn->hunk_length[0] == 0
       && btn->hunk_length[1] == 0)
@@ -530,14 +548,16 @@ static const svn_diff_output_fns_t mem_output_unif


 svn_error_t *
-svn_diff_mem_string_output_unified(svn_stream_t *output_stream,
-                                   svn_diff_t *diff,
-                                   const char *original_header,
-                                   const char *modified_header,
-                                   const char *header_encoding,
-                                   const svn_string_t *original,
-                                   const svn_string_t *modified,
-                                   apr_pool_t *pool)
+svn_diff_mem_string_output_unified2(svn_stream_t *output_stream,
+                                    svn_diff_t *diff,
+                                    svn_boolean_t with_diff_header,
+                                    const char *hunk_delimiter,
+                                    const char *original_header,
+                                    const char *modified_header,
+                                    const char *header_encoding,
+                                    const svn_string_t *original,
+                                    const svn_string_t *modified,
+                                    apr_pool_t *pool)
 {

   if (svn_diff_contains_diffs(diff))
@@ -563,23 +583,51 @@ svn_error_t *
       fill_source_tokens(&baton.sources[0], original, pool);
       fill_source_tokens(&baton.sources[1], modified, pool);

-      SVN_ERR(svn_stream_printf_from_utf8
-              (output_stream, header_encoding, pool,
-               "--- %s" APR_EOL_STR
-               "+++ %s" APR_EOL_STR,
-               original_header, modified_header));
+      if (with_diff_header)
+        {
+          SVN_ERR(svn_stream_printf_from_utf8(output_stream,
+                                              header_encoding, pool,
+                                              "--- %s" APR_EOL_STR
+                                              "+++ %s" APR_EOL_STR,
+                                              original_header,
+                                              modified_header));
+        }

       SVN_ERR(svn_diff_output(diff, &baton,
                               &mem_output_unified_vtable));
-      SVN_ERR(output_unified_flush_hunk(&baton));

+      SVN_ERR(output_unified_flush_hunk(&baton, hunk_delimiter));
+
       svn_pool_destroy(baton.pool);
     }

   return SVN_NO_ERROR;
 }

+svn_error_t *
+svn_diff_mem_string_output_unified(svn_stream_t *output_stream,
+                                   svn_diff_t *diff,
+                                   const char *original_header,
+                                   const char *modified_header,
+                                   const char *header_encoding,
+                                   const svn_string_t *original,
+                                   const svn_string_t *modified,
+                                   apr_pool_t *pool)
+{
+  SVN_ERR(svn_diff_mem_string_output_unified2(output_stream,
+                                              diff,
+                                              TRUE,
+                                              NULL,
+                                              original_header,
+                                              modified_header,
+                                              header_encoding,
+                                              original,
+                                              modified,
+                                              pool));
+  return SVN_NO_ERROR;
+}

+
 
 /* diff3 merge output */

Index: subversion/include/svn_diff.h
==================================================================--- subversion/include/svn_diff.h	(revision 38523)
+++ subversion/include/svn_diff.h	(working copy)
@@ -667,15 +667,37 @@ svn_diff_mem_string_diff4(svn_diff_t **diff,
                           const svn_diff_file_options_t *options,
                           apr_pool_t *pool);

-
 /** Outputs the @a diff object generated by svn_diff_mem_string_diff()
  * in unified diff format on @a output_stream, using @a original
  * and @a modified for the text in the output.
- * Outputs the header and markers in @a header_encoding.
+ * A diff header is only written to the output if @a with_diff_header
+ * is TRUE.
  *
+ * Outputs the header and hunk delimiters in @a header_encoding.
+ * A @a hunk_delimiter can optionally be specified.
+ * If @a hunk_delimiter is NULL, use the default hunk delimiter "@@".
+ *
  * @a original_header and @a modified header are
  * used to fill the field after the "---" and "+++" header markers.
  *
+ * @since New in 1.7.
+ */
+svn_error_t *
+svn_diff_mem_string_output_unified2(svn_stream_t *output_stream,
+                                    svn_diff_t *diff,
+                                    svn_boolean_t with_diff_header,
+                                    const char *hunk_delimiter,
+                                    const char *original_header,
+                                    const char *modified_header,
+                                    const char *header_encoding,
+                                    const svn_string_t *original,
+                                    const svn_string_t *modified,
+                                    apr_pool_t *pool);
+
+/** Similar to svn_diff_mem_string_output_unified2() but with
+ * @a with_diff_header always set to TRUE and @a hunk_delimiter always
+ * set to NULL.
+ *
  * @since New in 1.5.
  */
 svn_error_t *
Index: subversion/libsvn_client/diff.c
==================================================================--- subversion/libsvn_client/diff.c	(revision 38523)
+++ subversion/libsvn_client/diff.c	(working copy)
@@ -49,6 +49,7 @@
 #include "svn_time.h"
 #include "svn_sorts.h"
 #include "svn_base64.h"
+#include "svn_subst.h"
 #include "client.h"

 #include "private/svn_wc_private.h"
@@ -167,6 +168,35 @@ display_mergeinfo_diff(const char *old_mergeinfo_v
                           _("Path '%s' must be an immediate child of " \
                             "the directory '%s'"), path, relative_to_dir)

+/* A helper function used by display_prop_diffs.
+   TOKEN is a string holding a property value.
+   If TOKEN is empty, or is already terminated by an EOL marker,
+   return TOKEN unmodified. Else, return a new string consisting
+   of the concatenation of TOKEN and the system's default EOL marker.
+   The new string is allocated from POOL. */
+static const svn_string_t *
+maybe_append_eol(const svn_string_t *token, apr_pool_t *pool)
+{
+  const char *curp;
+
+  if (token->len == 0)
+    return token;
+
+  curp = token->data + token->len - 1;
+  if (*curp == '\r')
+    {
+      return token;
+    }
+  else if (*curp != '\n')
+    {
+      return svn_string_createf(pool, "%s%s", token->data, APR_EOL_STR);
+    }
+  else
+    {
+      return token;
+    }
+}
+
 /* A helper func that writes out verbal descriptions of property diffs
    to FILE.   Of course, the apr_file_t will probably be the 'outfile'
    passed to svn_client_diff5, which is probably stdout. */
@@ -242,53 +272,43 @@ display_prop_diffs(const apr_array_header_t *propc
           continue;
         }

-      /* For now, we have a rather simple heuristic: if this is an
-         "svn:" property, then assume the value is UTF-8 and must
-         therefore be converted before printing.  Otherwise, just
-         print whatever's there and hope for the best. */
       {
-        svn_boolean_t val_is_utf8 = svn_prop_is_svn_prop(propchange->name);
+        svn_stream_t *os = svn_stream_from_aprfile2(file, TRUE, pool);
+        svn_diff_t *diff;
+        svn_diff_file_options_t options;
+        const svn_string_t *tmp;
+        const svn_string_t *orig;
+        const svn_string_t *val;

-        if (original_value != NULL)
-          {
-            if (val_is_utf8)
-              {
-                SVN_ERR(file_printf_from_utf8
-                        (file, encoding,
-                         "   - %s" APR_EOL_STR, original_value->data));
-              }
-            else
-              {
-                /* ### todo: check for error? */
-                apr_file_printf
-                  (file, "   - %s" APR_EOL_STR, original_value->data);
-              }
-          }
+        /* The last character in a property is often not a newline.
+           Since the diff is not useful anyway for patching properties an
+           eol character is appended when needed to remove those pescious
+           ' \ No newline at end of file' lines. */
+        tmp = original_value ? original_value : svn_string_create("", pool);
+        orig = maybe_append_eol(tmp, pool);

-        if (propchange->value != NULL)
-          {
-            if (val_is_utf8)
-              {
-                SVN_ERR(file_printf_from_utf8
-                        (file, encoding, "   + %s" APR_EOL_STR,
-                         propchange->value->data));
-              }
-            else
-              {
-                /* ### todo: check for error? */
-                apr_file_printf(file, "   + %s" APR_EOL_STR,
-                                propchange->value->data);
-              }
-          }
+        tmp = propchange->value ? propchange->value :
+                                  svn_string_create("", pool);
+        val = maybe_append_eol(tmp, pool);
+
+        SVN_ERR(svn_diff_mem_string_diff(&diff, orig, val, &options, pool));
+
+        /* UNIX patch will try to apply a diff even if the diff header
+         * is missing. It tries to be helpful by asking the user for a
+         * target filename when it can't determine the target filename
+         * from the diff header. But there usually are no files which
+         * UNIX patch could apply the property diff to, so we use "##"
+         * instead of "@@" as the default hunk delimiter for property diffs.
+         * We also supress the diff header. */
+        SVN_ERR(svn_diff_mem_string_output_unified2(os, diff, FALSE, "##",
+                                           svn_dirent_local_style(path, pool),
+                                           svn_dirent_local_style(path, pool),
+                                           encoding, orig, val, pool));
+        SVN_ERR(svn_stream_close(os));
+
       }
     }

-  /* ### todo [issue #1533]: Use file_printf_from_utf8() to convert this
-     to native encoding, at least conditionally?  Or is it better to
-     have under_string always output the same eol, so programs can
-     find it consistently?  Also, what about checking for error? */
-  apr_file_printf(file, APR_EOL_STR);
-
   return SVN_NO_ERROR;
 }


