Attached is version 4 of the patch and corresponding log message that
address Daniel Shahaf's feedback from November 9.

Per a message from Julian
(http://article.gmane.org/gmane.comp.version-control.subversion.devel/124073)
and Daniel Shahaf
(http://article.gmane.org/gmane.comp.version-control.subversion.devel/124082),
I have removed the changes to optimize translate_newline() for now.

> There is value for a summary line --- just like the "Conflicts summary"
> in 'svn up' and friends (svn/notify.c): if someone runs 'svnsync sync'
> manually and doesn't pipe the output into a pager, they still know at
> the end something was wrong.

Good point.  I could do a summary at the end as well as more detailed
messages for each revision that is affected.

>> >> +/** Translate the data in @a value (assumed to be encoded in charset
>> >> + * @a encoding) to UTF8 and LF line-endings.  If @a encoding is @c NULL,
>> >> + * then assume that @a value is in the system-default character encoding.
>> >
>> > You changed 'language encoding' to 'character encoding'.
>>
>> Changed back.  Note that the docstring has been reworded since version
>> 2 of the patch.  I am now following the new wording and modified it as
>> appropriate.
>>
>
> I'm sorry: I wasn't clear.  I wasn't actually asking you to revert that,
> but just tried to ask why you made that change (because it is departs
> from the existing wording, but I didn't recall seeing the change
> mentioned anywhere).

Okay.

>> > Not related to your patch, but the above if/else block calls the UTF-8
>> > translation routines on value->data.  Since this is specifically the
>> > translate_string() API (and there is a separate translate_cstring()
>> > API), I think either we should fix this (the whole reason svn_string_t
>> > exists is to allow embedded NULs) or at least document this limitation
>> > in the API docs.
>>
>> value->data can be NULL?
>
> NUL != NULL.  In general, the 'data' member of an svn_string_t is never
> a NULL pointer.  However, the memory it points to --- value->data[0]
> through value->data[value->len-1] --- may contain NUL (aka ASCII 0,
> aka '\0') bytes.

I understand now.

> Also: I forgot to say this earlier, but parts of this subst.c code have
> been refactored on the 'performance' branch.  Some of those refactorings
> have been merged, but I'm not sure if all of them were.  Could you have
> a look there and see if there are any unmerged changes there?  And if
> so, how they relate to this patch?

Attached is a diff of subversion/libsvn_subr/subst.c from
tr...@1040648 to branches/performa...@1040648.  The unmerged changes
were to add static functions translated_stream_skip() and
translated_stream_buffered() and use them in
svn_subst_read_specialfile() when configuring the svn_stream_t S.  My
changes affect different parts of the file.

>>   (translation_baton): Added the TRANSLATED_EOL and TRANSLATE_NEWLINE_FN 
>> fields.
>>   (create_translation_baton): Added a new parameter TRANSLATED_EOL that is
>>     passed to the resulting translation_baton. Sets TRANSLATE_NEWLINE_FN to
>>     either &translate_newline or &translate_newline_alt as appropriate.
>>   (translate_chunk): Replaced the three calls to translate_newline() with
>>     calls to TRANSLATE_NEWLINE_FN.
>
> Present tense, so s/Added/Add/, etc.

Fixed.

>> * subversion/libsvn_subr/deprecated.c
>>   Received the implementation of the deprecated wrapper function
>>   svn_subst_translate_string().
>
> Write in the standard file-symbol syntax:
>
>  * subversion/libsvn_subr/deprecated.c
>    (svn_subst_translate_string): ...

Fixed.

>> Index: subversion/include/svn_subst.h
>> ===================================================================
>> --- subversion/include/svn_subst.h    (revision 1032431)
>> +++ subversion/include/svn_subst.h    (working copy)
>> @@ -592,19 +592,46 @@ svn_subst_stream_detranslated(svn_stream_t **strea
>>
>>  /* EOL conversion and character encodings */
>>
>> +/** @deprecated Provided for backward compatibility with the 1.6 API. 
>> Callers
>> + * should use svn_subst_translate_string2().
>> + *
>> + * Similar to svn_subst_translate_string2(), except that the information 
>> about
>> + * whether re-encoding or line ending translation were performed is 
>> discarded.
>> + */
>
> Okay, except that the two paragraphs are in the wrong order, and the
> "should use" comment isn't needed in this case.

Fixed.

>> +SVN_DEPRECATED
>> +svn_error_t *svn_subst_translate_string(svn_string_t **new_value,
>> +                                        const svn_string_t *value,
>> +                                        const char *encoding,
>> +                                        apr_pool_t *pool);
>> +
>>  /** Translate the string @a value from character encoding @a encoding to
>>   * UTF8, and also from its current line-ending style to LF line-endings.  If
>>   * @a encoding is @c NULL, translate from the system-default encoding.
>>   *
>> + * If @a translated_to_utf8 is not @c NULL, then
>> + * <code>*translated_to_utf8</code> is set to @c TRUE if at least one
>> + * character of @a value in the source character encoding was translated to
>> + * UTF-8;  to @c FALSE otherwise. If @a translated_line_endings is not @c 
>> NULL,
>> + * then <code>*translated_line_endings</code> is set to @c TRUE if at least 
>> one
>> + * line ending was changed to LF;  to @c FALSE otherwise.
>> + *
>
> Thanks for paragraphing this.  I'd add another paragraph break after the
> first "otherwise", so that each parameter is described in its own paragraph.

Fixed.

>> +   This function assumes that NEWLINE_BUF and EOL_STR are either "\n", 
>> "\r", or
>> +   "\r\n".
>
> I suggest
>  s/assumes that .* are/assumes that each of .* is/
> for clarity.

Changed.

>> +  assert((eol_str_len == 2 && eol_str[0] == '\r' && eol_str[1] == '\n') ||
>> +         (eol_str_len == 1 && (eol_str[0] == '\n' || eol_str[0] == '\r')));
>> +  assert((newline_len == 2 && newline_buf[0] == '\r' &&
>> +          newline_buf[1] == '\n') ||
>> +         (newline_len == 1 && (newline_buf[0] == '\n' ||
>> +                               newline_buf[0] == '\r')));
>> +
>
> s/assert/SVN_ERR_ASSERT/, because that's more friendly to library users.
>
> I'd like to see a comment on this assert, the condition is too long for me.
>
> Both here and in the "unsolicited" change above, perhaps introduce named
> macros would make the code more readable?
>
> #define SAME_EOL(eol_str1, eol_str2) /* ... */
> #defien STRING_IS_EOL(maybe_eol_str) /* ... */

Yes.  This is a good idea.  I added STRING_IS_EOL and
DIFFERENT_EOL_STRINGS with a doc string for each.

>> +      b->translate_newline_fn = &translate_newline_alt; // Now that
>> +                                                        // TRANSLATED_EOL 
>> has
>> +                                                        // been set to TRUE,
>> +                                                        // switch the
>> +                                                        // translate_newline
>> +                                                        // function that is 
>> used
>
> No C++ comments; we follow the C89 standard, which doesn't allow them.

Okay.

>> +  apr_pool_t *scratch_pool = svn_pool_create(result_pool);
>> +  svn_error_t *res = svn_subst_translate_string2(new_value, NULL, NULL, 
>> value,
>> +                                     encoding, result_pool, scratch_pool);
>> +  svn_pool_destroy(scratch_pool);
>
> Is it worth the overhead to create a subpool here?
>
> On the one hand, that's what the current code does.
>
> On the other hand, creating a subpool allocates 8KB right away (right?
> #subpool_question), and an svn_string_t is probably smaller than that.
> (Something larger would be transferred in a stream, I hope!)  So it
> seems a subpool is not worth the overhead, and it'll be better to just
> pass result_pool as both pool arguments.

Changed.
diff --git a/subversion/libsvn_subr/subst.c b/subversion/libsvn_subr/subst.c
index e32c253..5ad7ef9 100644
--- a/subversion/libsvn_subr/subst.c
+++ b/subversion/libsvn_subr/subst.c
@@ -1201,6 +1201,27 @@ translated_stream_read(void *baton,
   return SVN_NO_ERROR;
 }
 
+/* Implements svn_skip_fn_t. */
+static svn_error_t *
+translated_stream_skip(void *baton,
+                       apr_size_t *count)
+{
+  apr_size_t total_bytes_read = 0;
+  apr_size_t bytes_read;
+  char buffer[SVN__STREAM_CHUNK_SIZE];
+  svn_error_t *err = SVN_NO_ERROR;
+
+  while ((total_bytes_read < *count) && !err)
+    {
+      bytes_read = sizeof(buffer) < *count ? sizeof(buffer) : *count;
+      err = translated_stream_read(baton, buffer, &bytes_read);
+      total_bytes_read += bytes_read;
+    }
+
+  *count = total_bytes_read;
+  return err;
+}
+
 /* Implements svn_write_fn_t. */
 static svn_error_t *
 translated_stream_write(void *baton,
@@ -1312,6 +1333,14 @@ translated_stream_seek(void *baton, svn_stream_mark_t 
*mark)
   return SVN_NO_ERROR;
 }
 
+/* Implements svn_io_buffered_fn_t. */
+static svn_boolean_t
+translated_stream_buffered(void *baton)
+{
+  struct translated_stream_baton *b = baton;
+  return svn_stream_buffered(b->stream);
+}
+
 svn_error_t *
 svn_subst_read_specialfile(svn_stream_t **stream,
                            const char *path,
@@ -1409,10 +1438,12 @@ svn_subst_stream_translated(svn_stream_t *stream,
 
   /* Setup the stream methods */
   svn_stream_set_read(s, translated_stream_read);
+  svn_stream_set_skip(s, translated_stream_skip);
   svn_stream_set_write(s, translated_stream_write);
   svn_stream_set_close(s, translated_stream_close);
   svn_stream_set_mark(s, translated_stream_mark);
   svn_stream_set_seek(s, translated_stream_seek);
+  svn_stream_set_buffered(s, translated_stream_buffered);
 
   return s;
 }
Index: subversion/include/svn_subst.h
===================================================================
--- subversion/include/svn_subst.h      (revision 1040701)
+++ subversion/include/svn_subst.h      (working copy)
@@ -592,19 +592,47 @@ svn_subst_stream_detranslated(svn_stream_t **strea
 
 /* EOL conversion and character encodings */
 
+/** Similar to svn_subst_translate_string2(), except that the information about
+ * whether re-encoding or line ending translation were performed is discarded.
+ *
+ * @deprecated Provided for backward compatibility with the 1.6 API.
+ */
+SVN_DEPRECATED
+svn_error_t *svn_subst_translate_string(svn_string_t **new_value,
+                                        const svn_string_t *value,
+                                        const char *encoding,
+                                        apr_pool_t *pool);
+
 /** Translate the string @a value from character encoding @a encoding to
  * UTF8, and also from its current line-ending style to LF line-endings.  If
  * @a encoding is @c NULL, translate from the system-default encoding.
  *
+ * If @a translated_to_utf8 is not @c NULL, then
+ * <code>*translated_to_utf8</code> is set to @c TRUE if at least one
+ * character of @a value in the source character encoding was translated to
+ * UTF-8;  to @c FALSE otherwise.
+ *
+ * If @a translated_line_endings is not @c NULL, then
+ * <code>*translated_line_endings</code> is set to @c TRUE if at least one line
+ * ending was changed to LF;  to @c FALSE otherwise.
+ *
  * Recognized line endings are LF, CR, CRLF.  If @a value has inconsistent
  * line endings, return @c SVN_ERR_IO_INCONSISTENT_EOL.
  *
- * Set @a *new_value to the translated string, allocated in @a pool.
+ * Set @a *new_value to the translated string, allocated in @a result_pool.
+ *
+ * @a scratch_pool is used for temporary allocations.
+ *
+ * @since New in 1.7.
  */
-svn_error_t *svn_subst_translate_string(svn_string_t **new_value,
-                                        const svn_string_t *value,
-                                        const char *encoding,
-                                        apr_pool_t *pool);
+svn_error_t *
+svn_subst_translate_string2(svn_string_t **new_value,
+                            svn_boolean_t *translated_to_utf8,
+                            svn_boolean_t *translated_line_endings,
+                            const svn_string_t *value,
+                            const char *encoding,
+                            apr_pool_t *result_pool,
+                            apr_pool_t *scratch_pool);
 
 /** Translate the string @a value from UTF8 and LF line-endings into native
  * character encoding and native line-endings.  If @a for_output is TRUE,
Index: subversion/libsvn_subr/subst.c
===================================================================
--- subversion/libsvn_subr/subst.c      (revision 1040701)
+++ subversion/libsvn_subr/subst.c      (working copy)
@@ -606,10 +606,36 @@ translate_keyword(char *buf,
   return FALSE;
 }
 
+/* A boolean expression that evaluates to true if the first STR_LEN characters
+   of the string STR are one of the end-of-line strings LF, CR, or CRLF;
+   to false otherwise.  */
+#define STRING_IS_EOL(str, str_len) (((str_len) == 2 &&                        
\
+                                      (str)[0] == '\r' &&                      
\
+                                      (str)[1] == '\n') ||                     
\
+                                     ((str_len) == 1 &&                        
\
+                                      ((str)[0] == '\n' || (str)[0] == '\r')))
 
+/* A boolean expression that evaluates to true if the end-of-line string EOL1,
+   having length EOL1_LEN, and the end-of-line string EOL2, having length
+   EOL2_LEN, are different, assuming that EOL1 and EOL2 are both from the
+   set {"\n", "\r", "\r\n"};  to false otherwise.
+   
+   Given that EOL1 and EOL2 are either "\n", "\r", or "\r\n", then if
+   EOL1_LEN is not the same as EOL2_LEN, then EOL1 and EOL2 are of course
+   different. If EOL1_LEN and EOL2_LEN are both 2 then EOL1 and EOL2 are both
+   "\r\n" and *EOL1 == *EOL2. Otherwise, EOL1_LEN and EOL2_LEN are both 1.
+   We need only check the one character for equality to determine whether
+   EOL1 and EOL2 are different in that case. */
+#define DIFFERENT_EOL_STRINGS(eol1, eol1_len, eol2, eol2_len)                  
\
+  (((eol1_len) != (eol2_len)) || (*(eol1) != *(eol2)))
+
+
 /* Translate the newline string NEWLINE_BUF (of length NEWLINE_LEN) to
    the newline string EOL_STR (of length EOL_STR_LEN), writing the
    result (which is always EOL_STR) to the stream DST.
+   
+   This function assumes that each of NEWLINE_BUF and EOL_STR is either "\n",
+   "\r", or "\r\n".
 
    Also check for consistency of the source newline strings across
    multiple calls, using SRC_FORMAT (length *SRC_FORMAT_LEN) as a cache
@@ -620,6 +646,10 @@ translate_keyword(char *buf,
    newline in the file, and copy it to {SRC_FORMAT, *SRC_FORMAT_LEN} to
    use for later consistency checks.
 
+   Sets *TRANSLATED_EOL to TRUE if the newline string that was written
+   (EOL_STR) is not the same as the newline string that was translated
+   (NEWLINE_BUF).
+
    Note: all parameters are required even if REPAIR is TRUE.
    ### We could require that REPAIR must not change across a sequence of
        calls, and could then optimize by not using SRC_FORMAT at all if
@@ -633,17 +663,20 @@ translate_newline(const char *eol_str,
                   const char *newline_buf,
                   apr_size_t newline_len,
                   svn_stream_t *dst,
+                  svn_boolean_t *translated_eol,
                   svn_boolean_t repair)
 {
+  SVN_ERR_ASSERT(STRING_IS_EOL(eol_str, eol_str_len));
+  SVN_ERR_ASSERT(STRING_IS_EOL(newline_buf, newline_len));
+
   /* If we've seen a newline before, compare it with our cache to
      check for consistency, else cache it for future comparisons. */
   if (*src_format_len)
     {
       /* Comparing with cache.  If we are inconsistent and
          we are NOT repairing the file, generate an error! */
-      if ((! repair) &&
-          ((*src_format_len != newline_len) ||
-           (strncmp(src_format, newline_buf, newline_len))))
+      if ((! repair) && DIFFERENT_EOL_STRINGS(src_format, *src_format_len,
+                                              newline_buf, newline_len))
         return svn_error_create(SVN_ERR_IO_INCONSISTENT_EOL, NULL, NULL);
     }
   else
@@ -653,8 +686,15 @@ translate_newline(const char *eol_str,
       strncpy(src_format, newline_buf, newline_len);
       *src_format_len = newline_len;
     }
+  
   /* Write the desired newline */
-  return translate_write(dst, eol_str, eol_str_len);
+  SVN_ERR(translate_write(dst, eol_str, eol_str_len));
+  
+  if (translated_eol != NULL && DIFFERENT_EOL_STRINGS(eol_str, eol_str_len,
+                                                      newline_buf, 
newline_len))
+    *translated_eol = TRUE;
+
+  return SVN_NO_ERROR;
 }
 
 
@@ -765,10 +805,12 @@ svn_subst_keywords_differ2(apr_hash_t *a,
   return FALSE;
 }
 
+
 /* Baton for translate_chunk() to store its state in. */
 struct translation_baton
 {
   const char *eol_str;
+  svn_boolean_t *translated_eol;
   svn_boolean_t repair;
   apr_hash_t *keywords;
   svn_boolean_t expand;
@@ -813,6 +855,7 @@ struct translation_baton
  */
 static struct translation_baton *
 create_translation_baton(const char *eol_str,
+                         svn_boolean_t *translated_eol,
                          svn_boolean_t repair,
                          apr_hash_t *keywords,
                          svn_boolean_t expand,
@@ -826,6 +869,7 @@ create_translation_baton(const char *eol_str,
 
   b->eol_str = eol_str;
   b->eol_str_len = eol_str ? strlen(eol_str) : 0;
+  b->translated_eol = translated_eol;
   b->repair = repair;
   b->keywords = keywords;
   b->expand = expand;
@@ -924,7 +968,8 @@ translate_chunk(svn_stream_t *dst,
               SVN_ERR(translate_newline(b->eol_str, b->eol_str_len,
                                         b->src_format,
                                         &b->src_format_len, b->newline_buf,
-                                        b->newline_off, dst, b->repair));
+                                        b->newline_off, dst, b->translated_eol,
+                                        b->repair));
 
               b->newline_off = 0;
             }
@@ -1069,8 +1114,9 @@ translate_chunk(svn_stream_t *dst,
                   SVN_ERR(translate_newline(b->eol_str, b->eol_str_len,
                                             b->src_format,
                                             &b->src_format_len,
-                                            b->newline_buf,
-                                            b->newline_off, dst, b->repair));
+                                            b->newline_buf, 
+                                            b->newline_off, dst,
+                                            b->translated_eol, b->repair));
 
                   b->newline_off = 0;
                   break;
@@ -1086,7 +1132,7 @@ translate_chunk(svn_stream_t *dst,
           SVN_ERR(translate_newline(b->eol_str, b->eol_str_len,
                                     b->src_format, &b->src_format_len,
                                     b->newline_buf, b->newline_off,
-                                    dst, b->repair));
+                                    dst, b->translated_eol, b->repair));
           b->newline_off = 0;
         }
 
@@ -1350,13 +1396,14 @@ svn_subst_read_specialfile(svn_stream_t **stream,
 }
 
 
-svn_stream_t *
-svn_subst_stream_translated(svn_stream_t *stream,
-                            const char *eol_str,
-                            svn_boolean_t repair,
-                            apr_hash_t *keywords,
-                            svn_boolean_t expand,
-                            apr_pool_t *result_pool)
+static svn_stream_t *
+stream_translated(svn_stream_t *stream,
+                  const char *eol_str,
+                  svn_boolean_t *translated_eol,
+                  svn_boolean_t repair,
+                  apr_hash_t *keywords,
+                  svn_boolean_t expand,
+                  apr_pool_t *result_pool)
 {
   struct translated_stream_baton *baton
     = apr_palloc(result_pool, sizeof(*baton));
@@ -1398,9 +1445,11 @@ svn_subst_read_specialfile(svn_stream_t **stream,
   /* Setup the baton fields */
   baton->stream = stream;
   baton->in_baton
-    = create_translation_baton(eol_str, repair, keywords, expand, result_pool);
+    = create_translation_baton(eol_str, translated_eol, repair, keywords,
+                               expand, result_pool);
   baton->out_baton
-    = create_translation_baton(eol_str, repair, keywords, expand, result_pool);
+    = create_translation_baton(eol_str, translated_eol, repair, keywords,
+                               expand, result_pool);
   baton->written = FALSE;
   baton->readbuf = svn_stringbuf_create("", result_pool);
   baton->readbuf_off = 0;
@@ -1417,15 +1466,28 @@ svn_subst_read_specialfile(svn_stream_t **stream,
   return s;
 }
 
+svn_stream_t *
+svn_subst_stream_translated(svn_stream_t *stream,
+                            const char *eol_str,
+                            svn_boolean_t repair,
+                            apr_hash_t *keywords,
+                            svn_boolean_t expand,
+                            apr_pool_t *result_pool)
+{
+  return stream_translated(stream, eol_str, NULL, repair, keywords, expand,
+                           result_pool);
+}
 
-svn_error_t *
-svn_subst_translate_cstring2(const char *src,
-                             const char **dst,
-                             const char *eol_str,
-                             svn_boolean_t repair,
-                             apr_hash_t *keywords,
-                             svn_boolean_t expand,
-                             apr_pool_t *pool)
+
+static svn_error_t *
+translate_cstring(const char **dst,
+                  svn_boolean_t *translated_eol,
+                  const char *src,
+                  const char *eol_str,
+                  svn_boolean_t repair,
+                  apr_hash_t *keywords,
+                  svn_boolean_t expand,
+                  apr_pool_t *pool)
 {
   svn_stringbuf_t *dst_stringbuf;
   svn_stream_t *dst_stream;
@@ -1442,9 +1504,12 @@ svn_subst_read_specialfile(svn_stream_t **stream,
   dst_stringbuf = svn_stringbuf_create("", pool);
   dst_stream = svn_stream_from_stringbuf(dst_stringbuf, pool);
 
+  if (translated_eol)
+    *translated_eol = FALSE;
+
   /* Another wrapper to translate the content. */
-  dst_stream = svn_subst_stream_translated(dst_stream, eol_str, repair,
-                                           keywords, expand, pool);
+  dst_stream = stream_translated(dst_stream, eol_str, translated_eol, repair,
+                                 keywords, expand, pool);
 
   /* Jam the text into the destination stream (to translate it). */
   SVN_ERR(svn_stream_write(dst_stream, src, &len));
@@ -1456,6 +1521,19 @@ svn_subst_read_specialfile(svn_stream_t **stream,
   return SVN_NO_ERROR;
 }
 
+svn_error_t *
+svn_subst_translate_cstring2(const char *src,
+                             const char **dst,
+                             const char *eol_str,
+                             svn_boolean_t repair,
+                             apr_hash_t *keywords,
+                             svn_boolean_t expand,
+                             apr_pool_t *pool)
+{
+  return translate_cstring(dst, NULL, src, eol_str, repair, keywords, expand,
+                            pool);
+}
+
 /* Given a special file at SRC, generate a textual representation of
    it in a normal file at DST.  Perform all allocations in POOL. */
 /* ### this should be folded into svn_subst_copy_and_translate3 */
@@ -1768,14 +1846,16 @@ svn_subst_stream_from_specialfile(svn_stream_t **s
 
 /*** String translation */
 svn_error_t *
-svn_subst_translate_string(svn_string_t **new_value,
-                           const svn_string_t *value,
-                           const char *encoding,
-                           apr_pool_t *pool)
+svn_subst_translate_string2(svn_string_t **new_value,
+                            svn_boolean_t *translated_to_utf8,
+                            svn_boolean_t *translated_line_endings,
+                            const svn_string_t *value,
+                            const char *encoding,
+                            apr_pool_t *result_pool,
+                            apr_pool_t *scratch_pool)
 {
   const char *val_utf8;
   const char *val_utf8_lf;
-  apr_pool_t *scratch_pool = svn_pool_create(pool);
 
   if (value == NULL)
     {
@@ -1793,16 +1873,19 @@ svn_error_t *
       SVN_ERR(svn_utf_cstring_to_utf8(&val_utf8, value->data, scratch_pool));
     }
 
-  SVN_ERR(svn_subst_translate_cstring2(val_utf8,
-                                       &val_utf8_lf,
-                                       "\n",  /* translate to LF */
-                                       FALSE, /* no repair */
-                                       NULL,  /* no keywords */
-                                       FALSE, /* no expansion */
-                                       scratch_pool));
+  if (translated_to_utf8)
+    *translated_to_utf8 = (strcmp(value->data, val_utf8) != 0);
 
-  *new_value = svn_string_create(val_utf8_lf, pool);
-  svn_pool_destroy(scratch_pool);
+  SVN_ERR(translate_cstring(&val_utf8_lf,
+                            translated_line_endings,
+                            val_utf8,
+                            "\n",  /* translate to LF */
+                            FALSE, /* no repair */
+                            NULL,  /* no keywords */
+                            FALSE, /* no expansion */
+                            scratch_pool));
+
+  *new_value = svn_string_create(val_utf8_lf, result_pool);
   return SVN_NO_ERROR;
 }
 
Index: subversion/libsvn_subr/deprecated.c
===================================================================
--- subversion/libsvn_subr/deprecated.c (revision 1040701)
+++ subversion/libsvn_subr/deprecated.c (working copy)
@@ -250,6 +250,16 @@ svn_subst_stream_translated_to_normal_form(svn_str
 }
 
 svn_error_t *
+svn_subst_translate_string(svn_string_t **new_value,
+                           const svn_string_t *value,
+                           const char *encoding,
+                           apr_pool_t *pool)
+{
+  return svn_subst_translate_string2(new_value, NULL, NULL, value,
+                                     encoding, pool, pool);
+}
+
+svn_error_t *
 svn_subst_stream_detranslated(svn_stream_t **stream_p,
                               const char *src,
                               svn_subst_eol_style_t eol_style,
[[[
Add a public API function, svn_subst_translate_string2(), an extension of
svn_subst_translate_string(), that has two additional output parameters for
determining whether re-encoding and/or line ending translation were performed.


As discussed at:
  http://thread.gmane.org/gmane.comp.version-control.subversion.devel/122550
  http://thread.gmane.org/gmane.comp.version-control.subversion.devel/123020


The essential changes are to the translate_newline() function, which now takes
an svn_boolean_t pointer, the value at which is set to TRUE if the pointer is
non-NULL and a different newline is written out. Most other changes are to pass
the svn_boolean_t pointer through to translate_newline().


* subversion/include/svn_subst.h
  (svn_subst_translate_string2): New function.
  (svn_subst_translate_string): Deprecate in favor of
    svn_subst_translate_string2().

* subversion/libsvn_subr/subst.c
  (STRING_IS_EOL): New macro that tests whether a string is an end-of-line
    string ("\n", "\r", "\r\n").
  (DIFFERENT_EOL_STRINGS): New macro that tests whether two end-of-line strings
    are different.
  (translate_newline): Add the TRANSLATED_EOL parameter. If the function
    writes out a different newline, then it sets TRANSLATED_EOL to TRUE.
  (translation_baton): Add the TRANSLATED_EOL field.
  (create_translation_baton): Add a new parameter TRANSLATED_EOL that is
    passed to the resulting translation_baton.
  (translate_chunk): When calling translate_newline(), pass TRANSLATED_EOL from
    the translation_baton.
  (stream_translated): New static function. Its implementation is the old
    implementation of svn_subst_stream_translated(), but accepting another
    parameter, TRANSLATED_EOL, that is passed to the in/out translation batons
    that it creates.
  (svn_subst_stream_translated): Now a wrapper for stream_translated().
  (translate_cstring): New static function. Its implementation is the old
    implementation of svn_subst_translate_cstring2(), but modified to accept
    another parameter, TRANSLATED_EOL, that is passed to stream_translated().
  (svn_subst_translate_cstring2): Now a wrapper for translate_cstring().
  (svn_subst_translate_string): Move to deprecated.c.
  (svn_subst_translate_string2): New function. It takes three additional
    parameters: TRANSLATED_TO_UTF8, TRANSLATED_LINE_ENDINGS, and another pool
    parameter. The task of recording whether it translates a line ending is
    delegated to translate_cstring().

* subversion/libsvn_subr/deprecated.c
  (svn_subst_translate_string): Now a wrapper for svn_subst_translate_string2().
]]]

Reply via email to