void svn_cl__xml_tagged_cdata(svn_stringbuf_t **sb, apr_pool_t *pool, const char *tagname, const char *string) { if (string) { svn_xml_make_open_tag(sb, pool, svn_xml_protect_pcdata, tagname, SVN_VA_NULL); svn_xml_escape_cdata_cstring(sb, string, pool); svn_xml_make_close_tag(sb, pool, tagname); } }
/* This implements `svn_log_entry_receiver_t', printing the logs in XML. * * BATON is of type `struct log_receiver_baton'. * * Here is an example of the output; note that the "<log>" and * "</log>" tags are not emitted by this function: * * $ svn log --xml -r 1648:1649 * <log> * <logentry * revision="1648"> * <author>david</author> * <date>2002-04-06T16:34:51.428043Z</date> * <msg> * packages/rpm/subversion.spec : Now requires apache 2.0.36. * </msg> * </logentry> * <logentry * revision="1649"> * <author>cmpilato</author> * <date>2002-04-06T17:01:28.185136Z</date> * <msg>Fix error handling when the $EDITOR is needed but unavailable. Ah * ... now that's *much* nicer. * * * subversion/clients/cmdline/util.c * (svn_cl__edit_externally): Clean up the "no external editor" * error message. * (svn_cl__get_log_message): Wrap "no external editor" * errors with helpful hints about the -m and -F options. * * * subversion/libsvn_client/commit.c * (svn_client_commit): Actually capture and propogate "no external * editor" errors.</msg> * </logentry> * </log> * */ static svn_error_t * log_entry_receiver_xml(void *baton, svn_log_entry_t *log_entry, apr_pool_t *pool) { struct log_receiver_baton *lb = baton; /* Collate whole log message into sb before printing. */ svn_stringbuf_t *sb = svn_stringbuf_create("", pool); char *revstr; const char *author; const char *date; const char *message; if (lb->cancel_func) SVN_ERR(lb->cancel_func(lb->cancel_baton)); svn_compat_log_revprops_out(&author, &date, &message, log_entry->revprops); if (author) author = svn_xml_fuzzy_escape(author, pool); if (date) date = svn_xml_fuzzy_escape(date, pool); if (message) message = svn_xml_fuzzy_escape(message, pool); if (log_entry->revision == 0 && message == NULL) return SVN_NO_ERROR; if (! SVN_IS_VALID_REVNUM(log_entry->revision)) { svn_xml_make_close_tag(&sb, pool, "logentry"); SVN_ERR(svn_cl__error_checked_fputs(sb->data, stdout)); apr_array_pop(lb->merge_stack); return SVN_NO_ERROR; } revstr = apr_psprintf(pool, "%ld", log_entry->revision); /* <logentry revision="xxx"> */ svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "logentry", "revision", revstr, NULL); /* <author>xxx</author> */ svn_cl__xml_tagged_cdata(&sb, pool, "author", author); /* Print the full, uncut, date. This is machine output. */ /* According to the docs for svn_log_entry_receiver_t, either NULL or the empty string represents no date. Avoid outputting an empty date element. */ if (date && date[0] == '\0') date = NULL; /* <date>xxx</date> */ svn_cl__xml_tagged_cdata(&sb, pool, "date", date); if (log_entry->changed_paths) { apr_hash_index_t *hi; char *path; /* <paths> */ svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "paths", NULL); for (hi = apr_hash_first(pool, log_entry->changed_paths); hi != NULL; hi = apr_hash_next(hi)) { void *val; char action[2]; svn_log_changed_path_t *log_item; apr_hash_this(hi, (void *) &path, NULL, &val); log_item = val; action[0] = log_item->action; action[1] = '\0'; if (log_item->copyfrom_path && SVN_IS_VALID_REVNUM(log_item->copyfrom_rev)) { /* <path action="X" copyfrom-path="xxx" copyfrom-rev="xxx"> */ svn_stringbuf_t *escpath = svn_stringbuf_create("", pool); svn_xml_escape_attr_cstring(&escpath, log_item->copyfrom_path, pool); revstr = apr_psprintf(pool, "%ld", log_item->copyfrom_rev); svn_xml_make_open_tag(&sb, pool, svn_xml_protect_pcdata, "path", "action", action, "copyfrom-path", escpath->data, "copyfrom-rev", revstr, NULL); } else { /* <path action="X"> */ svn_xml_make_open_tag(&sb, pool, svn_xml_protect_pcdata, "path", "action", action, NULL); } /* xxx</path> */ svn_xml_escape_cdata_cstring(&sb, path, pool); svn_xml_make_close_tag(&sb, pool, "path"); } /* </paths> */ svn_xml_make_close_tag(&sb, pool, "paths"); } if (message != NULL) { /* <msg>xxx</msg> */ svn_cl__xml_tagged_cdata(&sb, pool, "msg", message); } svn_compat_log_revprops_clear(log_entry->revprops); if (log_entry->revprops && apr_hash_count(log_entry->revprops) > 0) { svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "revprops", NULL); SVN_ERR(svn_cl__print_xml_prop_hash(&sb, log_entry->revprops, FALSE, /* name_only */ pool)); svn_xml_make_close_tag(&sb, pool, "revprops"); } if (log_entry->has_children) APR_ARRAY_PUSH(lb->merge_stack, svn_revnum_t) = log_entry->revision; else svn_xml_make_close_tag(&sb, pool, "logentry"); SVN_ERR(svn_cl__error_checked_fputs(sb->data, stdout)); return SVN_NO_ERROR; }