/* A boolean expression that evaluates to true if the string STR, having length STR_LEN, is 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". 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 the same in that case. */ #define DIFFERENT_EOL_STRINGS(eol1, eol1_len, eol2, eol2_len) \ (((eol1_len) != (eol2_len)) || (*(eol1) != *(eol2))) static svn_error_t * translate_newline_alt(const char *eol_str, apr_size_t eol_str_len, char *src_format, apr_size_t *src_format_len, const char *newline_buf, apr_size_t newline_len, svn_stream_t *dst, struct translation_baton *b); #define DEFINE_TRANSLATE_NEWLINE_FN(fn, is_alt) \ static svn_error_t * \ fn(const char *eol_str, \ apr_size_t eol_str_len, \ char *src_format, \ apr_size_t *src_format_len, \ const char *newline_buf, \ apr_size_t newline_len, \ svn_stream_t *dst, \ struct translation_baton *b) \ { \ 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 ((! b->repair) && \ ((*src_format_len != newline_len) || \ (strncmp(src_format, newline_buf, newline_len)))) \ return svn_error_create(SVN_ERR_IO_INCONSISTENT_EOL, NULL, NULL); \ } \ else \ { \ /* This is our first line ending, so cache it before \ handling it. */ \ strncpy(src_format, newline_buf, newline_len); \ *src_format_len = newline_len; \ } \ \ /* Translate the newline */ \ SVN_ERR(translate_write(dst, eol_str, eol_str_len)); \ \ if (!(is_alt)) \ { \ /* Set *b->translated_eol to TRUE if a different line ending string was \ written out. */ \ SVN_ERR_ASSERT(b->translated_eol != NULL); \ if (DIFFERENT_EOL_STRINGS(eol_str, eol_str_len, \ newline_buf, newline_len)) \ { \ *b->translated_eol = TRUE; \ \ /* Now that TRANSLATED_EOL has been set to TRUE, switch the \ translate_newline function that is used to the alternate which \ does not care about TRANSLATED_EOL */ \ b->translate_newline_fn = &translate_newline_alt; \ } \ } \ \ return SVN_NO_ERROR; \ } DEFINE_TRANSLATE_NEWLINE_FN(translate_newline, 0) DEFINE_TRANSLATE_NEWLINE_FN(translate_newline_alt, 1)