You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by gs...@apache.org on 2012/05/13 09:01:19 UTC
svn commit: r1337788 - in /subversion/trunk/subversion/libsvn_ra_serf:
getlocks.c ra_serf.h xml.c
Author: gstein
Date: Sun May 13 07:01:18 2012
New Revision: 1337788
URL: http://svn.apache.org/viewvc?rev=1337788&view=rev
Log:
Convert the get-locks report over to v2 xml processing.
This also tweaks the "note" feature to store a note on a parent state,
rather than "this" state.
* subversion/libsvn_ra_serf/ra_serf.h:
(svn_ra_serf__xml_note): add a state parameter and document
* subversion/libsvn_ra_serf/xml.c:
(svn_ra_serf__xml_note): new implementation, with new param
* subversion/libsvn_ra_serf/getlocks.c:
(lock_state_e): remove typedef/enum name. rename NONE to INITIAL.
(lock_info_t): removed; obsolete.
(lock_context_t): remove DONE element
(push_state, start_getlocks, end_getlocks, cdata_getlocks): removed.
obsolete.
(getlocks_ttable): new transition table
(getlocks_closed): new callback to process the response
(svn_ra_serf__get_locks): switch to new xml parsing. use run_one().
Modified:
subversion/trunk/subversion/libsvn_ra_serf/getlocks.c
subversion/trunk/subversion/libsvn_ra_serf/ra_serf.h
subversion/trunk/subversion/libsvn_ra_serf/xml.c
Modified: subversion/trunk/subversion/libsvn_ra_serf/getlocks.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_ra_serf/getlocks.c?rev=1337788&r1=1337787&r2=1337788&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_ra_serf/getlocks.c (original)
+++ subversion/trunk/subversion/libsvn_ra_serf/getlocks.c Sun May 13 07:01:18 2012
@@ -46,8 +46,8 @@
/*
* This enum represents the current state of our XML parsing for a REPORT.
*/
-typedef enum lock_state_e {
- NONE = 0,
+enum {
+ INITIAL = 0,
REPORT,
LOCK,
PATH,
@@ -56,18 +56,7 @@ typedef enum lock_state_e {
COMMENT,
CREATION_DATE,
EXPIRATION_DATE
-} lock_state_e;
-
-typedef struct lock_info_t {
- /* Temporary pool */
- apr_pool_t *pool;
-
- svn_lock_t *lock;
-
- /* The currently collected value as we build it up */
- svn_stringbuf_t *cdata;
-
-} lock_info_t;
+};
typedef struct lock_context_t {
apr_pool_t *pool;
@@ -79,107 +68,55 @@ typedef struct lock_context_t {
/* return hash */
apr_hash_t *hash;
- /* are we done? */
- svn_boolean_t done;
-
} lock_context_t;
-
-static lock_info_t *
-push_state(svn_ra_serf__xml_parser_t *parser,
- lock_context_t *lock_ctx,
- lock_state_e state)
-{
- svn_ra_serf__xml_push_state(parser, state);
+#define D_ "DAV:"
+#define S_ SVN_XML_NAMESPACE
+static const svn_ra_serf__xml_transition_t getlocks_ttable[] = {
+ { INITIAL, S_, "get-locks-report", REPORT,
+ FALSE, { NULL }, FALSE, FALSE },
- if (state == LOCK)
- {
- lock_info_t *info;
+ { REPORT, S_, "lock", LOCK,
+ FALSE, { NULL }, FALSE, TRUE },
- info = apr_pcalloc(parser->state->pool, sizeof(*info));
+ { LOCK, S_, "path", PATH,
+ TRUE, { NULL }, FALSE, TRUE },
- info->pool = lock_ctx->pool;
- info->lock = svn_lock_create(lock_ctx->pool);
- info->cdata = svn_stringbuf_create_empty(info->pool);
+ { LOCK, S_, "token", TOKEN,
+ TRUE, { NULL }, FALSE, TRUE },
- parser->state->private = info;
- }
-
- return parser->state->private;
-}
+ { LOCK, S_, "owner", OWNER,
+ TRUE, { NULL }, FALSE, TRUE },
-static svn_error_t *
-start_getlocks(svn_ra_serf__xml_parser_t *parser,
- svn_ra_serf__dav_props_t name,
- const char **attrs,
- apr_pool_t *scratch_pool)
-{
- lock_context_t *lock_ctx = parser->user_data;
- lock_state_e state;
+ { LOCK, S_, "comment", COMMENT,
+ TRUE, { NULL }, FALSE, TRUE },
- state = parser->state->current_state;
+ { LOCK, S_, SVN_DAV__CREATIONDATE, CREATION_DATE,
+ TRUE, { NULL }, FALSE, TRUE },
- if (state == NONE &&
- strcmp(name.name, "get-locks-report") == 0)
- {
- push_state(parser, lock_ctx, REPORT);
- }
- else if (state == REPORT &&
- strcmp(name.name, "lock") == 0)
- {
- push_state(parser, lock_ctx, LOCK);
- }
- else if (state == LOCK)
- {
- if (strcmp(name.name, "path") == 0)
- {
- push_state(parser, lock_ctx, PATH);
- }
- else if (strcmp(name.name, "token") == 0)
- {
- push_state(parser, lock_ctx, TOKEN);
- }
- else if (strcmp(name.name, "owner") == 0)
- {
- push_state(parser, lock_ctx, OWNER);
- }
- else if (strcmp(name.name, "comment") == 0)
- {
- push_state(parser, lock_ctx, COMMENT);
- }
- else if (strcmp(name.name, SVN_DAV__CREATIONDATE) == 0)
- {
- push_state(parser, lock_ctx, CREATION_DATE);
- }
- else if (strcmp(name.name, "expirationdate") == 0)
- {
- push_state(parser, lock_ctx, EXPIRATION_DATE);
- }
- }
+ { LOCK, S_, "expirationdate", EXPIRATION_DATE,
+ TRUE, { NULL }, FALSE, TRUE },
- return SVN_NO_ERROR;
-}
+ { 0 }
+};
+
+/* Conforms to svn_ra_serf__xml_closed_t */
static svn_error_t *
-end_getlocks(svn_ra_serf__xml_parser_t *parser,
- svn_ra_serf__dav_props_t name,
- apr_pool_t *scratch_pool)
+getlocks_closed(svn_ra_serf__xml_estate_t *xes,
+ void *baton,
+ int leaving_state,
+ const svn_string_t *cdata,
+ apr_hash_t *attrs,
+ apr_pool_t *scratch_pool)
{
- lock_context_t *lock_ctx = parser->user_data;
- lock_state_e state;
- lock_info_t *info;
-
- state = parser->state->current_state;
- info = parser->state->private;
+ lock_context_t *lock_ctx = baton;
- if (state == REPORT &&
- strcmp(name.name, "get-locks-report") == 0)
- {
- svn_ra_serf__xml_pop_state(parser);
- }
- else if (state == LOCK &&
- strcmp(name.name, "lock") == 0)
+ if (leaving_state == LOCK)
{
+ const char *path = apr_hash_get(attrs, "path", APR_HASH_KEY_STRING);
+ svn_boolean_t save_lock = FALSE;
+
/* Filter out unwanted paths. Since Subversion only allows
locks on files, we can treat depth=immediates the same as
depth=files for filtering purposes. Meaning, we'll keep
@@ -190,108 +127,81 @@ end_getlocks(svn_ra_serf__xml_parser_t *
c) we've asked for depth=files or depth=immediates, and this
lock is on an immediate child of our query path.
*/
- if ((strcmp(lock_ctx->path, info->lock->path) == 0)
- || (lock_ctx->requested_depth == svn_depth_infinity))
+ if (strcmp(lock_ctx->path, path) == 0
+ || lock_ctx->requested_depth == svn_depth_infinity)
{
- apr_hash_set(lock_ctx->hash, info->lock->path,
- APR_HASH_KEY_STRING, info->lock);
+ save_lock = TRUE;
}
- else if ((lock_ctx->requested_depth == svn_depth_files) ||
- (lock_ctx->requested_depth == svn_depth_immediates))
+ else if (lock_ctx->requested_depth == svn_depth_files
+ || lock_ctx->requested_depth == svn_depth_immediates)
{
- const char *rel_path = svn_fspath__skip_ancestor(lock_ctx->path,
- info->lock->path);
- if (rel_path && (svn_path_component_count(rel_path) == 1))
- apr_hash_set(lock_ctx->hash, info->lock->path,
- APR_HASH_KEY_STRING, info->lock);
- }
+ const char *relpath = svn_fspath__skip_ancestor(lock_ctx->path,
+ path);
+ if (relpath && (svn_path_component_count(relpath) == 1))
+ save_lock = TRUE;
+ }
+
+ if (save_lock)
+ {
+ /* We get to put the structure on the stack rather than using
+ svn_lock_create(). Bwahahaha.... */
+ svn_lock_t lock = { 0 };
+ const char *date;
+ svn_lock_t *result_lock;
+
+ /* Note: these "attributes" came from child elements. Some of
+ them may have not been sent, so the value will be NULL. */
+
+ lock.path = path;
+ lock.token = apr_hash_get(attrs, "token", APR_HASH_KEY_STRING);
+ lock.owner = apr_hash_get(attrs, "owner", APR_HASH_KEY_STRING);
+ lock.comment = apr_hash_get(attrs, "comment", APR_HASH_KEY_STRING);
+
+ date = apr_hash_get(attrs, SVN_DAV__CREATIONDATE,
+ APR_HASH_KEY_STRING);
+ if (date)
+ SVN_ERR(svn_time_from_cstring(&lock.creation_date, date,
+ scratch_pool));
+
+ date = apr_hash_get(attrs, "expirationdate",
+ APR_HASH_KEY_STRING);
+ if (date)
+ SVN_ERR(svn_time_from_cstring(&lock.expiration_date, date,
+ scratch_pool));
+
+ result_lock = svn_lock_dup(&lock, lock_ctx->pool);
+ apr_hash_set(lock_ctx->hash, result_lock->path, APR_HASH_KEY_STRING,
+ result_lock);
+ }
+ }
+ else
+ {
+ const char *name;
+
+ SVN_ERR_ASSERT(cdata != NULL);
+
+ if (leaving_state == PATH)
+ name = "path";
+ else if (leaving_state == TOKEN)
+ name = "token";
+ else if (leaving_state == OWNER)
+ name = "owner";
+ else if (leaving_state == COMMENT)
+ name = "comment";
+ else if (leaving_state == CREATION_DATE)
+ name = SVN_DAV__CREATIONDATE;
+ else if (leaving_state == EXPIRATION_DATE)
+ name = "expirationdate";
+ else
+ SVN_ERR_MALFUNCTION();
- svn_ra_serf__xml_pop_state(parser);
- }
- else if (state == PATH &&
- strcmp(name.name, "path") == 0)
- {
- info->lock->path = apr_pstrmemdup(info->pool,
- info->cdata->data, info->cdata->len);
- svn_stringbuf_setempty(info->cdata);
- svn_ra_serf__xml_pop_state(parser);
- }
- else if (state == TOKEN &&
- strcmp(name.name, "token") == 0)
- {
- info->lock->token = apr_pstrmemdup(info->pool,
- info->cdata->data, info->cdata->len);
- svn_stringbuf_setempty(info->cdata);
- svn_ra_serf__xml_pop_state(parser);
- }
- else if (state == OWNER &&
- strcmp(name.name, "owner") == 0)
- {
- info->lock->owner = apr_pstrmemdup(info->pool,
- info->cdata->data, info->cdata->len);
- svn_stringbuf_setempty(info->cdata);
- svn_ra_serf__xml_pop_state(parser);
- }
- else if (state == COMMENT &&
- strcmp(name.name, "comment") == 0)
- {
- info->lock->comment = apr_pstrmemdup(info->pool,
- info->cdata->data,
- info->cdata->len);
- svn_stringbuf_setempty(info->cdata);
- svn_ra_serf__xml_pop_state(parser);
- }
- else if (state == CREATION_DATE &&
- strcmp(name.name, SVN_DAV__CREATIONDATE) == 0)
- {
- SVN_ERR(svn_time_from_cstring(&info->lock->creation_date,
- info->cdata->data, info->pool));
- svn_stringbuf_setempty(info->cdata);
- svn_ra_serf__xml_pop_state(parser);
- }
- else if (state == EXPIRATION_DATE &&
- strcmp(name.name, "expirationdate") == 0)
- {
- SVN_ERR(svn_time_from_cstring(&info->lock->expiration_date,
- info->cdata->data, info->pool));
- svn_stringbuf_setempty(info->cdata);
- svn_ra_serf__xml_pop_state(parser);
+ /* Store the lock information onto the LOCK elemstate. */
+ svn_ra_serf__xml_note(xes, LOCK, name, cdata->data);
}
return SVN_NO_ERROR;
}
-static svn_error_t *
-cdata_getlocks(svn_ra_serf__xml_parser_t *parser,
- const char *data,
- apr_size_t len,
- apr_pool_t *scratch_pool)
-{
- lock_context_t *lock_ctx = parser->user_data;
- lock_state_e state;
- lock_info_t *info;
-
- UNUSED_CTX(lock_ctx);
-
- state = parser->state->current_state;
- info = parser->state->private;
-
- switch (state)
- {
- case PATH:
- case TOKEN:
- case OWNER:
- case COMMENT:
- case CREATION_DATE:
- case EXPIRATION_DATE:
- svn_stringbuf_appendbytes(info->cdata, data, len);
- break;
- default:
- break;
- }
-
- return SVN_NO_ERROR;
-}
/* Implements svn_ra_serf__request_body_delegate_t */
static svn_error_t *
@@ -324,7 +234,7 @@ svn_ra_serf__get_locks(svn_ra_session_t
lock_context_t *lock_ctx;
svn_ra_serf__session_t *session = ra_session->priv;
svn_ra_serf__handler_t *handler;
- svn_ra_serf__xml_parser_t *parser_ctx;
+ svn_ra_serf__xml_context_t *xmlctx;
const char *req_url, *rel_path;
req_url = svn_path_url_add_component2(session->session_url.path, path, pool);
@@ -336,37 +246,24 @@ svn_ra_serf__get_locks(svn_ra_session_t
lock_ctx->path = apr_pstrcat(pool, "/", rel_path, (char *)NULL);
lock_ctx->requested_depth = depth;
lock_ctx->hash = apr_hash_make(pool);
- lock_ctx->done = FALSE;
- handler = apr_pcalloc(pool, sizeof(*handler));
+ xmlctx = svn_ra_serf__xml_context_create(getlocks_ttable,
+ NULL, getlocks_closed, lock_ctx,
+ pool);
+ handler = svn_ra_serf__create_expat_handler(xmlctx, pool);
- handler->handler_pool = pool;
handler->method = "REPORT";
handler->path = req_url;
handler->body_type = "text/xml";
handler->conn = session->conns[0];
handler->session = session;
- parser_ctx = apr_pcalloc(pool, sizeof(*parser_ctx));
-
- parser_ctx->pool = pool;
- parser_ctx->user_data = lock_ctx;
- parser_ctx->start = start_getlocks;
- parser_ctx->end = end_getlocks;
- parser_ctx->cdata = cdata_getlocks;
- parser_ctx->done = &lock_ctx->done;
-
handler->body_delegate = create_getlocks_body;
handler->body_delegate_baton = lock_ctx;
- handler->response_handler = svn_ra_serf__handle_xml_parser;
- handler->response_baton = parser_ctx;
-
- svn_ra_serf__request_create(handler);
-
/* ### use svn_ra_serf__error_on_status() ? */
- SVN_ERR(svn_ra_serf__context_run_wait(&lock_ctx->done, session, pool));
+ SVN_ERR(svn_ra_serf__context_run_one(handler, pool));
*locks = lock_ctx->hash;
Modified: subversion/trunk/subversion/libsvn_ra_serf/ra_serf.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_ra_serf/ra_serf.h?rev=1337788&r1=1337787&r2=1337788&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_ra_serf/ra_serf.h (original)
+++ subversion/trunk/subversion/libsvn_ra_serf/ra_serf.h Sun May 13 07:01:18 2012
@@ -715,8 +715,20 @@ svn_ra_serf__xml_gather_since(svn_ra_ser
int stop_state);
+/* Attach the NAME/VALUE pair onto this/parent state identified by STATE.
+ The name and value will be copied into the target state's pool.
+
+ These values will be available to the CLOSED_CB for the target state,
+ or part of the gathered state via xml_gather_since().
+
+ Typically, this function is used by a child state's close callback,
+ or within an opening callback to store additional data.
+
+ Note: if the state is not found, then a programmer error has occurred,
+ so the function will invoke SVN_ERR_MALFUNCTION(). */
void
svn_ra_serf__xml_note(svn_ra_serf__xml_estate_t *xes,
+ int state,
const char *name,
const char *value);
Modified: subversion/trunk/subversion/libsvn_ra_serf/xml.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_ra_serf/xml.c?rev=1337788&r1=1337787&r2=1337788&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_ra_serf/xml.c (original)
+++ subversion/trunk/subversion/libsvn_ra_serf/xml.c Sun May 13 07:01:18 2012
@@ -493,12 +493,30 @@ svn_ra_serf__xml_gather_since(svn_ra_ser
void
svn_ra_serf__xml_note(svn_ra_serf__xml_estate_t *xes,
+ int state,
const char *name,
const char *value)
{
- ensure_pool(xes);
+ svn_ra_serf__xml_estate_t *scan;
+
+ for (scan = xes; scan != NULL && scan->state != state; scan = scan->prev)
+ /* pass */ ;
+
+ SVN_ERR_ASSERT_NO_RETURN(scan != NULL);
- /* ### copy into attrs */
+ /* Make sure the target state has a pool. */
+ ensure_pool(scan);
+
+ /* ... and attribute storage. */
+ if (scan->attrs == NULL)
+ scan->attrs = apr_hash_make(scan->state_pool);
+
+ /* In all likelihood, NAME is a string constant. But we can't really
+ be sure. And it isn't like we're storing a billion of these into
+ the state pool. */
+ apr_hash_set(scan->attrs,
+ apr_pstrdup(scan->state_pool, name), APR_HASH_KEY_STRING,
+ apr_pstrdup(scan->state_pool, value));
}