svn_error_t * svn_subst_translate_to_normal_form(const char *src, const char *dst, svn_subst_eol_style_t eol_style, const char *eol_str, svn_boolean_t always_repair_eols, apr_hash_t *keywords, svn_boolean_t special, apr_pool_t *pool) { if (eol_style == svn_subst_eol_style_native) eol_str = SVN_SUBST_NATIVE_EOL_STR; else if (! (eol_style == svn_subst_eol_style_fixed || eol_style == svn_subst_eol_style_none)) return svn_error_create(SVN_ERR_IO_UNKNOWN_EOL, NULL, NULL); return svn_error_trace(svn_subst_copy_and_translate3( src, dst, eol_str, eol_style == svn_subst_eol_style_fixed || always_repair_eols, keywords, FALSE /* contract keywords */, special, pool)); }
/* Updates (by copying and translating) the eol style in OLD_TARGET returning the filename containing the correct eol style in NEW_TARGET, if an eol style change is contained in PROP_DIFF */ static svn_error_t * maybe_update_target_eols(const char **new_target, const char *old_target, svn_wc_adm_access_t *adm_access, const apr_array_header_t *prop_diff, apr_pool_t *pool) { const svn_prop_t *prop = get_prop(prop_diff, SVN_PROP_EOL_STYLE); if (prop && prop->value) { const char *eol; const char *tmp_new; svn_subst_eol_style_from_value(NULL, &eol, prop->value->data); SVN_ERR(svn_wc_create_tmp_file2(NULL, &tmp_new, svn_wc_adm_access_path(adm_access), svn_io_file_del_none, pool)); SVN_ERR(svn_subst_copy_and_translate3(old_target, tmp_new, eol, eol ? FALSE : TRUE, NULL, FALSE, FALSE, pool)); *new_target = tmp_new; } else *new_target = old_target; return SVN_NO_ERROR; }
svn_error_t * svn_subst_copy_and_translate2(const char *src, const char *dst, const char *eol_str, svn_boolean_t repair, const svn_subst_keywords_t *keywords, svn_boolean_t expand, svn_boolean_t special, apr_pool_t *pool) { apr_hash_t *kh = kwstruct_to_kwhash(keywords, pool); return svn_error_trace(svn_subst_copy_and_translate3(src, dst, eol_str, repair, kh, expand, special, pool)); }
/* Set up, run, and verify the results of a substitution. * * Create a file TEST_NAME.src using global `lines' as the initial * data, with SRC_EOL as the line separator, then convert it to file * TEST_NAME.dst (using DST_EOL, REPAIR, EXPAND, REV, AUTHOR, DATE, * and URL as svn_subst_copy_and_translate() does), and verify that the * conversion worked. Null SRC_EOL means create a mixed eol src * file. * * If the verification succeeds, remove both files and return * SVN_NO_ERROR. * * If the verification fails, leave the files for post-mortem. If the * failure is due to non-eol data being wrong, return * SVN_ERR_MALFORMED_FILE. If the problem is an incorrect eol marker, * return SVN_ERR_IO_UNKNOWN_EOL. If the problem is that a mixed eol * style was repaired even though no repair flag was passed, return * SVN_ERR_TEST_FAILED. * * Use POOL for temporary allocation. * * Note: as with svn_subst_copy_and_translate(), if any of DST_EOL, REV, * AUTHOR, DATE, and/or URL is null, then that substitution is not * performed. */ static svn_error_t * substitute_and_verify(const char *test_name, const char *src_eol, const char *dst_eol, svn_boolean_t repair, const char *rev, const char *date, const char *author, const char *url, svn_boolean_t expand, apr_pool_t *pool) { svn_error_t *err; svn_stringbuf_t *contents; apr_hash_t *keywords = apr_hash_make(pool); apr_size_t idx = 0; apr_size_t i; const char *expect[(sizeof(lines) / sizeof(*lines))]; const char *src_fname = apr_pstrcat(pool, test_name, ".src", NULL); const char *dst_fname = apr_pstrcat(pool, test_name, ".dst", NULL); svn_string_t *val; apr_pool_t *subpool = svn_pool_create(pool); /** Clean up from previous tests, set up src data, and convert. **/ SVN_ERR(remove_file(src_fname, pool)); SVN_ERR(remove_file(dst_fname, pool)); SVN_ERR(create_file(src_fname, src_eol, pool)); if (rev) { val = svn_string_create(rev, pool); apr_hash_set(keywords, SVN_KEYWORD_REVISION_LONG, APR_HASH_KEY_STRING, val); apr_hash_set(keywords, SVN_KEYWORD_REVISION_MEDIUM, APR_HASH_KEY_STRING, val); apr_hash_set(keywords, SVN_KEYWORD_REVISION_SHORT, APR_HASH_KEY_STRING, val); } if (date) { val = svn_string_create(date, pool); apr_hash_set(keywords, SVN_KEYWORD_DATE_LONG, APR_HASH_KEY_STRING, val); apr_hash_set(keywords, SVN_KEYWORD_DATE_SHORT, APR_HASH_KEY_STRING, val); } if (author) { val = svn_string_create(author, pool); apr_hash_set(keywords, SVN_KEYWORD_AUTHOR_LONG, APR_HASH_KEY_STRING, val); apr_hash_set(keywords, SVN_KEYWORD_AUTHOR_SHORT, APR_HASH_KEY_STRING, val); } if (url) { val = svn_string_create(url, pool); apr_hash_set(keywords, SVN_KEYWORD_URL_LONG, APR_HASH_KEY_STRING, val); apr_hash_set(keywords, SVN_KEYWORD_URL_SHORT, APR_HASH_KEY_STRING, val); } err = svn_subst_copy_and_translate3(src_fname, dst_fname, dst_eol, repair, keywords, expand, FALSE, subpool); svn_pool_destroy(subpool); /* Conversion should have failed, if src has mixed eol, and the repair flag was not set, and we requested eol translation. */ if ((! src_eol) && dst_eol && (! repair)) { if (! err) { return svn_error_createf (SVN_ERR_TEST_FAILED, NULL, "translation of '%s' should have failed, but didn't", src_fname); } else if (err->apr_err != SVN_ERR_IO_INCONSISTENT_EOL) { return svn_error_createf (SVN_ERR_TEST_FAILED, err, "translation of '%s' should fail, but not with this error", src_fname); } else { svn_error_clear(err); SVN_ERR(remove_file(src_fname, pool)); return SVN_NO_ERROR; } } else if (err) return err; /** Verify that the conversion worked. **/ for (i = 0; i < (sizeof(expect) / sizeof(*expect)); i++) expect[i] = lines[i]; /* Certain lines contain keywords; expect their expansions. */ if (rev) { if (expand) { expect[3 - 1] = apr_pstrcat(pool, "Line 3: ", "Valid $LastChangedRevision: ", rev, " $, started unexpanded.", NULL); expect[5 - 1] = apr_pstrcat(pool, "Line 5: ", "Valid $Rev: ", rev, " $, started unexpanded.", NULL); expect[26 - 1] = apr_pstrcat(pool, "Line 26: ", "Emptily expanded keyword $Rev: ", rev," $.", NULL); expect[29 - 1] = apr_pstrcat(pool, "Line 29: ", "Valid $LastChangedRevision: ", rev, " $, started expanded.", NULL); expect[30 - 1] = apr_pstrcat(pool, "Line 30: ", "Valid $Rev: ", rev, " $, started expanded.", NULL); } else /* unexpand */ { /* Lines 3 and 5 remain unchanged. */ expect[26 - 1] = "Line 26: Emptily expanded keyword $Rev$."; expect[29 - 1] = "Line 29: Valid $LastChangedRevision$, started expanded."; expect[30 - 1] = "Line 30: Valid $Rev$, started expanded."; } } if (date) { if (expand) { expect[12 - 1] = apr_pstrcat(pool, "Line 12: ", "Valid $LastChangedDate: ", date, " $, started unexpanded.", NULL); expect[13 - 1] = apr_pstrcat(pool, "Line 13: ", "Valid $Date: ", date, " $, started unexpanded.", NULL); expect[33 - 1] = apr_pstrcat(pool, "Line 33: ", "Valid $LastChangedDate: ", date, " $, started expanded.", NULL); expect[34 - 1] = apr_pstrcat(pool, "Line 34: ", "Valid $Date: ", date, " $, started expanded.", NULL); expect[51 - 1] = apr_pstrcat(pool, "Line 51: ", "same, but with embedded keyword ", "$$$$$$$$Date: ", date, " $$$$$$$$$$.", NULL); expect[52 - 1] = apr_pstrcat(pool, "Line 52: ", "same, with expanded, empty keyword ", "$$$$$$Date: ", date, " $$$$$$.", NULL); } else /* unexpand */ { /* Lines 12 and 13 remain unchanged. */ expect[33 - 1] = "Line 33: Valid $LastChangedDate$, started expanded."; expect[34 - 1] = "Line 34: Valid $Date$, started expanded."; expect[51 - 1] = "Line 51: same, but with embedded keyword $$$$$$$$Date$$$$$$$$$$."; expect[52 - 1] = "Line 52: same, with expanded, empty keyword $$$$$$Date$$$$$$."; } } if (author) { if (expand) { expect[8 - 1] = apr_pstrcat(pool, "Line 8: ", "Valid $LastChangedBy: ", author, " $, started unexpanded.", NULL); expect[9 - 1] = apr_pstrcat(pool, "Line 9: ", "Valid $Author: ", author, " $, started unexpanded.", NULL); expect[37 - 1] = apr_pstrcat(pool, "Line 37: ", "Valid $LastChangedBy: ", author, " $, started expanded.", NULL); expect[38 - 1] = apr_pstrcat(pool, "Line 38: ", "Valid $Author: ", author, " $, started expanded.", NULL); expect[46 - 1] = apr_pstrcat(pool, "Line 46: ", "Empty $Author: ", author, " $, started expanded.", NULL); expect[71 - 1] = apr_pstrcat(pool, ".$veR$Author: ", author, " $", NULL); expect[74 - 1] = apr_pstrcat(pool, "Line 74: ", "Valid $Author: ", author, " $, started expanded.", NULL); expect[79 - 1] = apr_pstrcat(pool, "Line 79: ", "Valid $Author: ", author, " $, started expanded.", NULL); expect[80 - 1] = apr_pstrcat(pool, "Line 80: ", "Valid $Author: ", author, " $, started expanded.", NULL); expect[81 - 1] = apr_pstrcat(pool, "Line 81: ", "Valid $Author: ", author, " $, started expanded.", NULL); expect[82 - 1] = apr_pstrcat(pool, "Line 82: ", "Valid $Author: ", author, " $, started expanded.", NULL); } else /* unexpand */ { /* Lines 8, 9, and 71 remain unchanged. */ expect[37 - 1] = "Line 37: Valid $LastChangedBy$, started expanded."; expect[38 - 1] = "Line 38: Valid $Author$, started expanded."; expect[46 - 1] = "Line 46: Empty $Author$, started expanded."; expect[74 - 1] = "Line 74: Valid $Author$, started expanded."; expect[79 - 1] = "Line 79: Valid $Author$, started expanded."; expect[80 - 1] = "Line 80: Valid $Author$, started expanded."; expect[81 - 1] = "Line 81: Valid $Author$, started expanded."; expect[82 - 1] = "Line 82: Valid $Author$, started expanded."; } } if (url) { if (expand) { expect[16 - 1] = apr_pstrcat(pool, "Line 16: ", "Valid $HeadURL: ", url, " $, started unexpanded.", NULL); expect[17 - 1] = apr_pstrcat(pool, "Line 17: ", "Valid $URL: ", url, " $, started unexpanded.", NULL); expect[41 - 1] = apr_pstrcat(pool, "Line 41: ", "Valid $HeadURL: ", url, " $, started expanded.", NULL); expect[42 - 1] = apr_pstrcat(pool, "Line 42: ", "Valid $URL: ", url, " $, started expanded.", NULL); expect[75 - 1] = apr_pstrcat(pool, "Line 75: ", "Valid $URL: ", url, " $, started expanded.", NULL); } else /* unexpand */ { /* Lines 16 and 17 and remain unchanged. */ expect[41 - 1] = "Line 41: Valid $HeadURL$, started expanded."; expect[42 - 1] = "Line 42: Valid $URL$, started expanded."; expect[75 - 1] = "Line 75: Valid $URL$, started expanded."; } } /* Handle lines 48, 49, and 70 specially, as they contains two valid keywords. */ if (rev && author) { if (expand) { expect[48 - 1] = apr_pstrcat(pool, "Line 48: ", "Two keywords back to back: " "$Author: ", author, " $" "$Rev: ", rev, " $.", NULL); expect[49 - 1] = apr_pstrcat(pool, "Line 49: ", "One keyword, one not, back to back: " "$Author: ", author, " $Rev$.", NULL); expect[70 - 1] = apr_pstrcat(pool, "$Author: ", author, " $Rev$.", NULL); } /* Else Lines 48, 49, and 70 remain unchanged. */ } else if (rev && (! author)) { if (expand) { expect[48 - 1] = apr_pstrcat(pool, "Line 48: ", "Two keywords back to back: " "$Author$$Rev: ", rev, " $.", NULL); expect[49 - 1] = apr_pstrcat(pool, "Line 49: ", "One keyword, one not, back to back: " "$Author$Rev: ", rev, " $.", NULL); expect[70 - 1] = apr_pstrcat(pool, "$Author$Rev: ", rev, " $.", NULL); } /* Else Lines 48, 49, and 70 remain unchanged. */ } else if ((! rev) && author) { if (expand) { expect[48 - 1] = apr_pstrcat(pool, "Line 48: ", "Two keywords back to back: " "$Author: ", author, " $$Rev$.", NULL); expect[49 - 1] = apr_pstrcat(pool, "Line 49: ", "One keyword, one not, back to back: " "$Author: ", author, " $Rev$.", NULL); expect[70 - 1] = apr_pstrcat(pool, "$Author: ", author, " $Rev$.", NULL); } /* Else Lines 48, 49, and 70 remain unchanged. */ } /* Else neither rev nor author, so Lines 48, 49, and 70 remain unchanged. */ /* Handle line 24 specially, as it contains two valid keywords. */ if (date && author) { if (expand) { expect[24 - 1] = apr_pstrcat(pool, "Line 24: ", "keyword in a keyword: $Author: ", author, " $Date$ $", NULL); } else /* unexpand */ { expect[24 - 1] = apr_pstrcat(pool, "Line 24: ", "keyword in a keyword: $Author$Date$ $", NULL); } } else if (date && (! author)) { if (expand) { expect[24 - 1] = apr_pstrcat(pool, "Line 24: ", "keyword in a keyword: $Author: $Date: ", date, " $ $", NULL); } /* Else Line 24 remains unchanged. */ } else if ((! date) && author) { if (expand) { expect[24 - 1] = apr_pstrcat(pool, "Line 24: ", "keyword in a keyword: $Author: ", author, " $Date$ $", NULL); } else /* unexpand */ { expect[24 - 1] = apr_pstrcat(pool, "Line 24: ", "keyword in a keyword: $Author$Date$ $", NULL); } } /* Else neither author nor date, so Line 24 remains unchanged. */ /** Ready to verify. **/ SVN_ERR(svn_stringbuf_from_file(&contents, dst_fname, pool)); for (i = 0; i < (sizeof(expect) / sizeof(*expect)); i++) { if (contents->len < idx) return svn_error_createf (SVN_ERR_MALFORMED_FILE, NULL, "'%s' has short contents at line %" APR_SIZE_T_FMT, dst_fname, i + 1); if (strncmp(contents->data + idx, expect[i], strlen(expect[i])) != 0) return svn_error_createf (SVN_ERR_MALFORMED_FILE, NULL, "'%s' has wrong contents at line %" APR_SIZE_T_FMT, dst_fname, i + 1); /* Else, the data is correct, at least up to the next eol. */ idx += strlen(expect[i]); if (dst_eol) /* verify the promised consistent eol style */ { if (strncmp(contents->data + idx, dst_eol, strlen(dst_eol)) != 0) return svn_error_createf (SVN_ERR_IO_UNKNOWN_EOL, NULL, "'%s' has wrong eol style at line %" APR_SIZE_T_FMT, dst_fname, i + 1); else idx += strlen(dst_eol); } else /* allow any eol style, even inconsistent ones, loosely */ { while ((*(contents->data + idx) == '\r') || (*(contents->data + idx) == '\n')) idx++; } } /* Clean up this test, since successful. */ SVN_ERR(remove_file(src_fname, pool)); SVN_ERR(remove_file(dst_fname, pool)); return SVN_NO_ERROR; }