[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

PATCH: simple regexp support in mod_authz_svn

From: Josh Siegel <joshs_at_stormbirds.org>
Date: 2005-02-17 20:25:07 CET

These patches give you both simple regular expression support (unix
shell like) in mod_authz_svn as well as the ability to make all string
comparisons case insensitive. You turn on regular expression support by
setting AuthzSVNRegexp in your apache.conf file. Setting
AuthzSVNCaseInsensitiveNameMatches to On makes all checks case
insensitive.

Once you've done this, you can do things like

[foo:/tags/*/bar]
@group1 = r

[foo:/branches/*/bar]
@group1 = rw

Currently, the only shell regexp's it supports are * and ?. It does not
support {a,b,c}

Regards,
Josh Siegel

Index: subversion/mod_authz_svn/mod_authz_svn.c
===================================================================
--- subversion/mod_authz_svn/mod_authz_svn.c (revision 13038)
+++ subversion/mod_authz_svn/mod_authz_svn.c (working copy)
@@ -27,6 +27,7 @@
 #include <http_log.h>
 #include <ap_config.h>
 #include <apr_uri.h>
+#include <apr_hash.h>
 #include <mod_dav.h>
 
 #include "mod_dav_svn.h"
@@ -47,6 +48,8 @@
 typedef struct {
     int authoritative;
     int anonymous;
+ int regexp;
+ int caseInsensitiveNameMatches;
     const char *base_path;
     const char *access_file;
 } authz_svn_config_rec;
@@ -54,6 +57,7 @@
 struct parse_authz_baton {
     apr_pool_t *pool;
     svn_config_t *config;
+ authz_svn_config_rec *aconfig;
     const char *user;
     int allow;
     int deny;
@@ -77,7 +81,8 @@
     /* By default keep the fortress secure */
     conf->authoritative = 1;
     conf->anonymous = 1;
-
+ conf->regexp = 0;
+ conf->caseInsensitiveNameMatches = 0;
     return conf;
 }
 
@@ -97,6 +102,14 @@
                  OR_AUTHCFG,
                  "Set to 'Off' to skip access control when no authenticated "
                  "user is required. (default is On.)"),
+ AP_INIT_FLAG("AuthzSVNRegexp", ap_set_flag_slot,
+ (void *)APR_OFFSETOF(authz_svn_config_rec, regexp),
+ OR_AUTHCFG,
+ "Set to 'On' to enable regular expression matching "),
+ AP_INIT_FLAG("AuthzSVNCaseInsensitiveNameMatches", ap_set_flag_slot,
+ (void *)APR_OFFSETOF(authz_svn_config_rec, caseInsensitiveNameMatches),
+ OR_AUTHCFG,
+ "Set to 'On' to enable matching names to groups case insensitive"),
     { NULL }
 };
 
@@ -105,7 +118,7 @@
  * Access checking
  */
 
-static int group_contains_user_internal(svn_config_t *cfg,
+static int group_contains_user_internal(svn_config_t *cfg, const int caseInsensitive,
     const char *group, const char *user, apr_hash_t *checked_groups,
     apr_pool_t *pool)
 {
@@ -131,11 +144,12 @@
            apr_hash_set(checked_groups, &group_user[1],
                         APR_HASH_KEY_STRING, "");
 
- if (group_contains_user_internal(cfg, &group_user[1], user,
+ if (group_contains_user_internal(cfg, caseInsensitive,
+ &group_user[1], user,
                                             checked_groups, pool))
                return 1;
 
- } else if (!strcmp(user, group_user)) {
+ } else if (!(caseInsensitive ? strcasecmp(user, group_user) : strcmp(user, group_user))) {
            return 1;
        }
     }
@@ -143,10 +157,10 @@
     return 0;
 }
 
-static int group_contains_user(svn_config_t *cfg,
+static int group_contains_user(svn_config_t *cfg, const int caseInsensitive,
     const char *group, const char *user, apr_pool_t *pool)
 {
- return group_contains_user_internal(cfg, group, user,
+ return group_contains_user_internal(cfg, caseInsensitive, group, user,
                                         apr_hash_make(pool), pool);
 }
 
@@ -161,10 +175,10 @@
         }
 
         if (*name == '@') {
- if (!group_contains_user(b->config, &name[1], b->user, b->pool))
+ if (!group_contains_user(b->config, b->aconfig->caseInsensitiveNameMatches, &name[1], b->user, b->pool))
                 return TRUE;
         }
- else if (strcmp(name, b->user)) {
+ else if (b->aconfig->caseInsensitiveNameMatches ? strcasecmp(name, b->user) : strcmp(name, b->user)) {
             return TRUE;
         }
     }
@@ -193,7 +207,7 @@
 /*
  * Return TRUE when ACCESS has been determined.
  */
-static int parse_authz_lines(svn_config_t *cfg,
+static int parse_authz_lines(svn_config_t *cfg, authz_svn_config_rec *acfg,
                              const char *repos_name, const char *repos_path,
                              const char *user,
                              int required_access, int *granted_access,
@@ -204,12 +218,18 @@
 
     baton.pool = pool;
     baton.config = cfg;
+ baton.aconfig = acfg;
     baton.user = user;
 
     /* First try repos specific */
     qualified_repos_path = apr_pstrcat(pool, repos_name, ":", repos_path,
                                        NULL);
- svn_config_enumerate(cfg, qualified_repos_path,
+
+ if (acfg->regexp)
+ svn_config_enumerate_regexp(cfg, qualified_repos_path,
+ acfg->caseInsensitiveNameMatches ? 0x5 : 0x4, parse_authz_line, &baton);
+ else
+ svn_config_enumerate(cfg, qualified_repos_path,
                          parse_authz_line, &baton);
     *granted_access = !(baton.deny & required_access)
                       || (baton.allow & required_access);
@@ -218,7 +238,11 @@
         || (baton.allow & required_access))
         return TRUE;
 
- svn_config_enumerate(cfg, repos_path,
+ if (acfg->regexp)
+ svn_config_enumerate_regexp(cfg, repos_path,
+ acfg->caseInsensitiveNameMatches ? 0x5 : 0x4, parse_authz_line, &baton);
+ else
+ svn_config_enumerate(cfg, repos_path,
                          parse_authz_line, &baton);
     *granted_access = !(baton.deny & required_access)
                       || (baton.allow & required_access);
@@ -233,12 +257,22 @@
   struct parse_authz_baton *b = baton;
   int conclusive;
 
- if (strncmp(section_name, b->qualified_repos_path,
- strlen(b->qualified_repos_path))
- && strncmp(section_name, b->repos_path,
- strlen(b->repos_path))) {
- /* No match, move on to the next section. */
- return TRUE;
+ if (b->aconfig->regexp == 0) {
+ if (strncmp(section_name, b->qualified_repos_path,
+ strlen(b->qualified_repos_path))
+ && strncmp(section_name, b->repos_path,
+ strlen(b->repos_path))) {
+ /* No match, move on to the next section. */
+ return TRUE;
+ }
+ } else {
+ if (!svn_config_regexp(b->qualified_repos_path, section_name,
+ b->aconfig->caseInsensitiveNameMatches ? 0x1 : 0x0) &&
+ !svn_config_regexp(b->repos_path, section_name,
+ b->aconfig->caseInsensitiveNameMatches ? 0x1 : 0x0)) {
+ /* No match, move on to the next section. */
+ return TRUE;
+ }
   }
 
   b->allow = b->deny = 0;
@@ -256,7 +290,7 @@
   return b->access;
 }
 
-static int parse_authz_sections(svn_config_t *cfg,
+static int parse_authz_sections(svn_config_t *cfg, authz_svn_config_rec *acfg,
                                 const char *repos_name, const char *repos_path,
                                 const char *user,
                                 int required_access,
@@ -266,6 +300,7 @@
 
     baton.pool = pool;
     baton.config = cfg;
+ baton.aconfig = acfg;
     baton.user = user;
     baton.required_access = required_access;
     baton.repos_path = repos_path;
@@ -278,7 +313,8 @@
     return baton.access;
 }
 
-static int check_access(svn_config_t *cfg, const char *repos_name,
+static int check_access(svn_config_t *cfg, authz_svn_config_rec *acfg,
+ const char *repos_name,
                         const char *repos_path, const char *user,
                         int required_access, apr_pool_t *pool)
 {
@@ -295,7 +331,7 @@
     }
 
     base_name = repos_path;
- while (!parse_authz_lines(cfg, repos_name, repos_path,
+ while (!parse_authz_lines(cfg, acfg, repos_name, repos_path,
                               user, required_access, &granted_access,
                               pool)) {
         if (base_name[0] == '/' && base_name[1] == '\0') {
@@ -308,7 +344,7 @@
 
     if (granted_access && (required_access & AUTHZ_SVN_RECURSIVE) != 0) {
         /* Check access on entries below the current repos path */
- granted_access = parse_authz_sections(cfg,
+ granted_access = parse_authz_sections(cfg, acfg,
                                               repos_name, original_repos_path,
                                               user, required_access,
                                               pool);
@@ -475,7 +511,7 @@
                               NULL, r->connection->pool);
     }
 
- if (!check_access(access_conf,
+ if (!check_access(access_conf, conf,
                       repos_name, repos_path,
                       r->user, authz_svn_type,
                       r->pool)) {
@@ -498,7 +534,7 @@
     }
 
     /* Check access on the first repos_path */
- if (!check_access(access_conf,
+ if (!check_access(access_conf, conf,
                       dest_repos_name, dest_repos_path,
                       r->user, AUTHZ_SVN_WRITE|AUTHZ_SVN_RECURSIVE,
                       r->pool)) {
Index: subversion/include/svn_config.h
===================================================================
--- subversion/include/svn_config.h (revision 13038)
+++ subversion/include/svn_config.h (working copy)
@@ -235,6 +235,43 @@
                           svn_config_enumerator_t callback, void *baton);
 
 
+/**
+ * The regular expression matcher used by svn_config_enumerate_regexp
+ *
+ * This uses regular expressions similer to directory paths. It supports
+ * the '*' and the '?' modifier. It does not support the bracket "{a,b,c}" notation
+ * yet.
+ *
+ * flags:
+ * 0x1 - case insensitive search
+ *
+ * returns:
+ * 0 - does not match
+ * 1 - matches entire string
+ * 2 - left text after matching the pattern
+ */
+int svn_config_regexp(const char * str, const char *pattern, const int flags);
+
+/** Enumerate the sections, treating each section header as a regular expressio,
+ * passing @a baton and the current section's name to
+ * @a callback.
+ *
+ * Return the number of times @a callback was called.
+ *
+ * ### See kff's comment to @c svn_config_enumerate. It applies to this
+ * function, too. ###
+ *
+ * @a callback's @a name and @a name parameters are only valid for the
+ * duration of the call.
+ *
+ * flags:
+ * 0x1 - case insensitive search
+ * 0x2 - stop on first match
+ * 0x4 - only match entire string
+ */
+int svn_config_enumerate_regexp (svn_config_t *cfg, const char *section, const int flags,
+ svn_config_enumerator_t callback, void *baton);
+
 /** Enumerate the group @a master_section in @a cfg. Each variable
  * value is interpreted as a list of glob patterns (separated by comma
  * and optional whitespace). Return the name of the first variable
Index: subversion/libsvn_subr/config.c
===================================================================
--- subversion/libsvn_subr/config.c (revision 13038)
+++ subversion/libsvn_subr/config.c (working copy)
@@ -682,9 +682,76 @@
   return count;
 }
 
+
+int svn_config_regexp(const char * str, const char *pattern, const int flags) {
+ while (1) {
+ switch (pattern[0]) {
+ case '\0':
+ if (str[0] == '\0')
+ return 1;
+ else
+ return 2;
+ case '*':
+ while (str[0] != '\0') {
+ if (str[0] == '/') {
+ pattern++;
+ break;
+ } if (pattern[1] == '\0')
+ return 1;
+ else {
+ int ret = svn_config_regexp(str, pattern + 1, flags);
+ if (ret > 0)
+ return ret;
+ }
+ ++str;
+ }
+ if (pattern[1] == '\0') return 1;
+ else if (str[0] == '\0') return 0;
+ default:
+ if ((flags & 0x1) ? (tolower(str[0]) != tolower(pattern[0])) : (str[0] != pattern[0]))
+ return 0;
+ case '?':
+ pattern++;
+ str++;
+ break;
+ }
+ }
+}
 
 
 int
+svn_config_enumerate_regexp (svn_config_t *cfg, const char *section, const int flags,
+ svn_config_enumerator_t callback,
+ void *baton)
+{
+ apr_hash_index_t *sec_ndx;
+ int count = 0;
+
+ for (sec_ndx = apr_hash_first (cfg->x_pool, cfg->sections);
+ sec_ndx != NULL;
+ sec_ndx = apr_hash_next (sec_ndx))
+ {
+ void *sec_ptr;
+ cfg_section_t *sec;
+ int ret;
+
+ apr_hash_this (sec_ndx, NULL, NULL, &sec_ptr);
+ sec = sec_ptr;
+
+ ret = svn_config_regexp(section, sec->name, flags);
+ if ((ret == 0) || ((flags & 0x4) && (ret == 2)))
+ continue;
+
+ count += svn_config_enumerate(cfg, sec->name, callback, baton);
+ if (flags & 0x2)
+ break;
+ }
+
+ return count;
+}
+
+
+int
 svn_config_enumerate (svn_config_t *cfg, const char *section,
                       svn_config_enumerator_t callback, void *baton)
 {

Index: subversion/mod_authz_svn/mod_authz_svn.c
===================================================================
--- subversion/mod_authz_svn/mod_authz_svn.c (revision 13048)
+++ subversion/mod_authz_svn/mod_authz_svn.c (working copy)
@@ -27,6 +27,7 @@
 #include <http_log.h>
 #include <ap_config.h>
 #include <apr_uri.h>
+#include <apr_hash.h>
 #include <mod_dav.h>
 
 #include "mod_dav_svn.h"
@@ -48,6 +49,8 @@
 typedef struct {
     int authoritative;
     int anonymous;
+ int regexp;
+ int caseInsensitiveNameMatches;
     const char *base_path;
     const char *access_file;
 } authz_svn_config_rec;
@@ -55,6 +58,7 @@
 struct parse_authz_baton {
     apr_pool_t *pool;
     svn_config_t *config;
+ authz_svn_config_rec *aconfig;
     const char *user;
     int allow;
     int deny;
@@ -78,7 +82,8 @@
     /* By default keep the fortress secure */
     conf->authoritative = 1;
     conf->anonymous = 1;
-
+ conf->regexp = 0;
+ conf->caseInsensitiveNameMatches = 0;
     return conf;
 }
 
@@ -98,6 +103,14 @@
                  OR_AUTHCFG,
                  "Set to 'Off' to skip access control when no authenticated "
                  "user is required. (default is On.)"),
+ AP_INIT_FLAG("AuthzSVNRegexp", ap_set_flag_slot,
+ (void *)APR_OFFSETOF(authz_svn_config_rec, regexp),
+ OR_AUTHCFG,
+ "Set to 'On' to enable regular expression matching "),
+ AP_INIT_FLAG("AuthzSVNCaseInsensitiveNameMatches", ap_set_flag_slot,
+ (void *)APR_OFFSETOF(authz_svn_config_rec, caseInsensitiveNameMatches),
+ OR_AUTHCFG,
+ "Set to 'On' to enable matching names to groups case insensitive"),
     { NULL }
 };
 
@@ -106,7 +119,7 @@
  * Access checking
  */
 
-static int group_contains_user(svn_config_t *cfg,
+static int group_contains_user(svn_config_t *cfg, int caseInsensitive,
     const char *group, const char *user, apr_pool_t *pool)
 {
     const char *value;
@@ -118,7 +131,7 @@
 
     for (i = 0; i < list->nelts; i++) {
        const char *group_user = APR_ARRAY_IDX(list, i, char *);
- if (!strcmp(user, group_user))
+ if (!(caseInsensitive ? strcasecmp(user, group_user) : strcmp(user, group_user)))
            return 1;
     }
 
@@ -136,10 +149,10 @@
         }
 
         if (*name == '@') {
- if (!group_contains_user(b->config, &name[1], b->user, b->pool))
+ if (!group_contains_user(b->config, b->aconfig->caseInsensitiveNameMatches, &name[1], b->user, b->pool))
                 return TRUE;
         }
- else if (strcmp(name, b->user)) {
+ else if (b->aconfig->caseInsensitiveNameMatches ? strcasecmp(name, b->user) : strcmp(name, b->user)) {
             return TRUE;
         }
     }
@@ -168,7 +181,7 @@
 /*
  * Return TRUE when ACCESS has been determined.
  */
-static int parse_authz_lines(svn_config_t *cfg,
+static int parse_authz_lines(svn_config_t *cfg, authz_svn_config_rec *acfg,
                              const char *repos_name, const char *repos_path,
                              const char *user,
                              int required_access, int *access,
@@ -179,13 +192,19 @@
 
     baton.pool = pool;
     baton.config = cfg;
+ baton.aconfig = acfg;
     baton.user = user;
 
     /* First try repos specific */
     qualified_repos_path = apr_pstrcat(pool, repos_name, ":", repos_path,
                                        NULL);
- svn_config_enumerate(cfg, qualified_repos_path,
- parse_authz_line, &baton);
+
+ if (acfg->regexp)
+ svn_config_enumerate_regexp(cfg, qualified_repos_path,
+ acfg->caseInsensitiveNameMatches ? 0x5 : 0x4, parse_authz_line, &baton);
+ else
+ svn_config_enumerate(cfg, qualified_repos_path, parse_authz_line, &baton);
+
     *access = !(baton.deny & required_access)
               || (baton.allow & required_access);
 
@@ -193,8 +212,12 @@
         || (baton.allow & required_access))
         return TRUE;
 
- svn_config_enumerate(cfg, repos_path,
- parse_authz_line, &baton);
+ if (acfg->regexp)
+ svn_config_enumerate_regexp(cfg, repos_path,
+ acfg->caseInsensitiveNameMatches ? 0x5 : 0x4, parse_authz_line, &baton);
+ else
+ svn_config_enumerate(cfg, repos_path, parse_authz_line, &baton);
+
     *access = !(baton.deny & required_access)
               || (baton.allow & required_access);
 
@@ -208,12 +231,22 @@
   struct parse_authz_baton *b = baton;
   int conclusive;
 
- if (strncmp(section_name, b->qualified_repos_path,
- strlen(b->qualified_repos_path))
- && strncmp(section_name, b->repos_path,
- strlen(b->repos_path))) {
- /* No match, move on to the next section. */
- return TRUE;
+ if (b->aconfig->regexp == 0) {
+ if (strncmp(section_name, b->qualified_repos_path,
+ strlen(b->qualified_repos_path))
+ && strncmp(section_name, b->repos_path,
+ strlen(b->repos_path))) {
+ /* No match, move on to the next section. */
+ return TRUE;
+ }
+ } else {
+ if (!svn_config_regexp(b->qualified_repos_path, section_name,
+ b->aconfig->caseInsensitiveNameMatches ? 0x1 : 0x0) &&
+ !svn_config_regexp(b->repos_path, section_name,
+ b->aconfig->caseInsensitiveNameMatches ? 0x1 : 0x0)) {
+ /* No match, move on to the next section. */
+ return TRUE;
+ }
   }
 
   b->allow = b->deny = 0;
@@ -231,7 +264,7 @@
   return b->access;
 }
 
-static int parse_authz_sections(svn_config_t *cfg,
+static int parse_authz_sections(svn_config_t *cfg, authz_svn_config_rec *acfg,
                                 const char *repos_name, const char *repos_path,
                                 const char *user,
                                 int required_access,
@@ -241,6 +274,7 @@
 
     baton.pool = pool;
     baton.config = cfg;
+ baton.aconfig = acfg;
     baton.user = user;
     baton.required_access = required_access;
     baton.repos_path = repos_path;
@@ -253,7 +287,8 @@
     return baton.access;
 }
 
-static int check_access(svn_config_t *cfg, const char *repos_name,
+static int check_access(svn_config_t *cfg, authz_svn_config_rec *acfg,
+ const char *repos_name,
                         const char *repos_path, const char *user,
                         int required_access, apr_pool_t *pool)
 {
@@ -270,7 +305,7 @@
     }
 
     base_name = repos_path;
- while (!parse_authz_lines(cfg, repos_name, repos_path,
+ while (!parse_authz_lines(cfg, acfg, repos_name, repos_path,
                               user, required_access, &access,
                               pool)) {
         if (base_name[0] == '/' && base_name[1] == '\0') {
@@ -283,7 +318,7 @@
 
     if (access && (required_access & AUTHZ_SVN_RECURSIVE) != 0) {
         /* Check access on entries below the current repos path */
- access = parse_authz_sections(cfg,
+ access = parse_authz_sections(cfg, acfg,
                                       repos_name, original_repos_path,
                                       user, required_access,
                                       pool);
@@ -450,7 +485,7 @@
                               NULL, r->connection->pool);
     }
 
- if (!check_access(access_conf,
+ if (!check_access(access_conf, conf,
                       repos_name, repos_path,
                       r->user, authz_svn_type,
                       r->pool)) {
@@ -473,7 +508,7 @@
     }
 
     /* Check access on the first repos_path */
- if (!check_access(access_conf,
+ if (!check_access(access_conf, conf,
                       dest_repos_name, dest_repos_path,
                       r->user, AUTHZ_SVN_WRITE|AUTHZ_SVN_RECURSIVE,
                       r->pool)) {
Index: subversion/include/svn_config.h
===================================================================
--- subversion/include/svn_config.h (revision 13048)
+++ subversion/include/svn_config.h (working copy)
@@ -235,6 +235,43 @@
                           svn_config_enumerator_t callback, void *baton);
 
 
+/**
+ * The regular expression matcher used by svn_config_enumerate_regexp
+ *
+ * This uses regular expressions similer to directory paths. It supports
+ * the '*' and the '?' modifier. It does not support the bracket "{a,b,c}" notation
+ * yet.
+ *
+ * flags:
+ * 0x1 - case insensitive search
+ *
+ * returns:
+ * 0 - does not match
+ * 1 - matches entire string
+ * 2 - left text after matching the pattern
+ */
+int svn_config_regexp(const char * str, const char *pattern, const int flags);
+
+/** Enumerate the sections, treating each section header as a regular expressio,
+ * passing @a baton and the current section's name to
+ * @a callback.
+ *
+ * Return the number of times @a callback was called.
+ *
+ * ### See kff's comment to @c svn_config_enumerate. It applies to this
+ * function, too. ###
+ *
+ * @a callback's @a name and @a name parameters are only valid for the
+ * duration of the call.
+ *
+ * flags:
+ * 0x1 - case insensitive search
+ * 0x2 - stop on first match
+ * 0x4 - only match entire string
+ */
+int svn_config_enumerate_regexp (svn_config_t *cfg, const char *section, const int flags,
+ svn_config_enumerator_t callback, void *baton);
+
 /** Enumerate the group @a master_section in @a cfg. Each variable
  * value is interpreted as a list of glob patterns (separated by comma
  * and optional whitespace). Return the name of the first variable
Index: subversion/libsvn_subr/config.c
===================================================================
--- subversion/libsvn_subr/config.c (revision 13048)
+++ subversion/libsvn_subr/config.c (working copy)
@@ -680,9 +680,76 @@
   return count;
 }
 
+
+int svn_config_regexp(const char * str, const char *pattern, const int flags) {
+ while (1) {
+ switch (pattern[0]) {
+ case '\0':
+ if (str[0] == '\0')
+ return 1;
+ else
+ return 2;
+ case '*':
+ while (str[0] != '\0') {
+ if (str[0] == '/') {
+ pattern++;
+ break;
+ } if (pattern[1] == '\0')
+ return 1;
+ else {
+ int ret = svn_config_regexp(str, pattern + 1, flags);
+ if (ret > 0)
+ return ret;
+ }
+ ++str;
+ }
+ if (pattern[1] == '\0') return 1;
+ else if (str[0] == '\0') return 0;
+ default:
+ if ((flags & 0x1) ? (tolower(str[0]) != tolower(pattern[0])) : (str[0] != pattern[0]))
+ return 0;
+ case '?':
+ pattern++;
+ str++;
+ break;
+ }
+ }
+}
 
 
 int
+svn_config_enumerate_regexp (svn_config_t *cfg, const char *section, const int flags,
+ svn_config_enumerator_t callback,
+ void *baton)
+{
+ apr_hash_index_t *sec_ndx;
+ int count = 0;
+
+ for (sec_ndx = apr_hash_first (cfg->x_pool, cfg->sections);
+ sec_ndx != NULL;
+ sec_ndx = apr_hash_next (sec_ndx))
+ {
+ void *sec_ptr;
+ cfg_section_t *sec;
+ int ret;
+
+ apr_hash_this (sec_ndx, NULL, NULL, &sec_ptr);
+ sec = sec_ptr;
+
+ ret = svn_config_regexp(section, sec->name, flags);
+ if ((ret == 0) || ((flags & 0x4) && (ret == 2)))
+ continue;
+
+ count += svn_config_enumerate(cfg, sec->name, callback, baton);
+ if (flags & 0x2)
+ break;
+ }
+
+ return count;
+}
+
+
+int
 svn_config_enumerate (svn_config_t *cfg, const char *section,
                       svn_config_enumerator_t callback, void *baton)
 {

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org
Received on Thu Feb 17 20:27:03 2005

This is an archived mail posted to the Subversion Dev mailing list.