~svn/ubuntu/raring/subversion/ppa

« back to all changes in this revision

Viewing changes to subversion/libsvn_ra/ra_loader.c

  • Committer: Bazaar Package Importer
  • Author(s): Adam Conrad
  • Date: 2005-12-05 01:26:14 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20051205012614-qom4xfypgtsqc2xq
Tags: 1.2.3dfsg1-3ubuntu1
Merge with the final Debian release of 1.2.3dfsg1-3, bringing in
fixes to the clean target, better documentation of the libdb4.3
upgrade and build fixes to work with swig1.3_1.3.27.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * ra_loader.c:  logic for loading different RA library implementations
 
3
 *
 
4
 * ====================================================================
 
5
 * Copyright (c) 2000-2004 CollabNet.  All rights reserved.
 
6
 *
 
7
 * This software is licensed as described in the file COPYING, which
 
8
 * you should have received as part of this distribution.  The terms
 
9
 * are also available at http://subversion.tigris.org/license-1.html.
 
10
 * If newer versions of this license are posted there, you may use a
 
11
 * newer version instead, at your option.
 
12
 *
 
13
 * This software consists of voluntary contributions made by many
 
14
 * individuals.  For exact contribution history, see the revision
 
15
 * history and logs, available at http://subversion.tigris.org/.
 
16
 * ====================================================================
 
17
 */
 
18
 
 
19
/* ==================================================================== */
 
20
 
 
21
/*** Includes. ***/
 
22
 
 
23
#include <string.h>
 
24
#include <apr.h>
 
25
#include <apr_strings.h>
 
26
#include <apr_pools.h>
 
27
#include <apr_hash.h>
 
28
#include <apr_dso.h>
 
29
 
 
30
#include "svn_version.h"
 
31
#include "svn_error.h"
 
32
#include "svn_pools.h"
 
33
#include "svn_ra.h"
 
34
#include "svn_xml.h"
 
35
#include "ra_loader.h"
 
36
#include "svn_private_config.h"
 
37
 
 
38
 
 
39
/* ### this file maps URL schemes to particular RA libraries. This is not
 
40
   ### entirely correct, as a single scheme could potentially be served
 
41
   ### by more than one loader. However, we can ignore that until we
 
42
   ### actually run into a conflict within the scheme portion of a URL. */
 
43
 
 
44
 
 
45
/* These are the URI schemes that the respective libraries *may* support.
 
46
 * The schemes actually supported may be a subset of the schemes listed below.
 
47
 * This can't be determine until the library is loaded.
 
48
 * (Currently, this applies to the https scheme of ra_dav, which is only
 
49
 * available if SSL is supported.) */
 
50
static const char * const dav_schemes[] = { "http", "https", NULL };
 
51
static const char * const svn_schemes[] = { "svn", NULL };
 
52
static const char * const local_schemes[] = { "file", NULL };
 
53
 
 
54
static const struct ra_lib_defn {
 
55
  /* the name of this RA library (e.g. "dav" or "local") */
 
56
  const char *ra_name;
 
57
 
 
58
  const char * const *schemes;
 
59
  /* the initialization function if linked in; otherwise, NULL */
 
60
  svn_ra__init_func_t initfunc;
 
61
  svn_ra_init_func_t compat_initfunc;
 
62
} ra_libraries[] = {
 
63
  {
 
64
    "dav",
 
65
    dav_schemes,
 
66
#ifdef SVN_LIBSVN_CLIENT_LINKS_RA_DAV
 
67
    svn_ra_dav__init,
 
68
    svn_ra_dav_init
 
69
#endif
 
70
  },
 
71
 
 
72
  {
 
73
    "svn",
 
74
    svn_schemes,
 
75
#ifdef SVN_LIBSVN_CLIENT_LINKS_RA_SVN
 
76
    svn_ra_svn__init,
 
77
    svn_ra_svn_init
 
78
#endif
 
79
  },
 
80
 
 
81
  {
 
82
    "local",
 
83
    local_schemes,
 
84
#ifdef SVN_LIBSVN_CLIENT_LINKS_RA_LOCAL
 
85
    svn_ra_local__init,
 
86
    svn_ra_local_init
 
87
#endif
 
88
  },
 
89
 
 
90
  /* ADD NEW RA IMPLEMENTATIONS HERE (as they're written) */
 
91
 
 
92
  /* sentinel */
 
93
  { NULL }
 
94
};
 
95
 
 
96
/* Ensure that the RA library NAME is loaded.
 
97
 *
 
98
 * If FUNC is non-NULL, set *FUNC to the address of the svn_ra_NAME__init
 
99
 * function of the library.
 
100
 *
 
101
 * If COMPAT_FUNC is non-NULL, set *COMPAT_FUNC to the address of the
 
102
 * svn_ra_NAME_init compatibility init function of the library.
 
103
 *
 
104
 * ### todo: Any RA libraries implemented from this point forward
 
105
 * ### don't really need an svn_ra_NAME_init compatibility function.
 
106
 * ### Currently, load_ra_module() will error if no such function is
 
107
 * ### found, but it might be more friendly to simply set *COMPAT_FUNC
 
108
 * ### to null (assuming COMPAT_FUNC itself is non-null).
 
109
 */
 
110
static svn_error_t *
 
111
load_ra_module (svn_ra__init_func_t *func,
 
112
                svn_ra_init_func_t *compat_func,
 
113
                const char *ra_name, apr_pool_t *pool)
 
114
{
 
115
  if (func)
 
116
    *func = NULL;
 
117
  if (compat_func)
 
118
    *compat_func = NULL;
 
119
 
 
120
#if APR_HAS_DSO
 
121
  {
 
122
    apr_dso_handle_t *dso;
 
123
    apr_dso_handle_sym_t symbol;
 
124
    const char *libname;
 
125
    const char *funcname;
 
126
    const char *compat_funcname;
 
127
    apr_status_t status;
 
128
 
 
129
    libname = apr_psprintf (pool, "libsvn_ra_%s-%d.so.0",
 
130
                            ra_name, SVN_VER_MAJOR);
 
131
    funcname = apr_psprintf (pool, "svn_ra_%s__init", ra_name);
 
132
    compat_funcname = apr_psprintf (pool, "svn_ra_%s_init", ra_name);
 
133
 
 
134
    /* find/load the specified library */
 
135
    status = apr_dso_load (&dso, libname, pool);
 
136
    if (status)
 
137
      {
 
138
#if 0
 
139
        char errbuf[200];
 
140
        apr_dso_error(dso, errbuf, sizeof(errbuf));
 
141
 
 
142
        fprintf(stderr, "DSO error: %s\n", errbuf);
 
143
#endif
 
144
 
 
145
        /* Just ignore the error. Assume the library isn't present */
 
146
        return SVN_NO_ERROR;
 
147
      }
 
148
    /* note: the library will be unloaded at pool cleanup */
 
149
 
 
150
    /* find the initialization routines */
 
151
    if (func)
 
152
      {
 
153
        status = apr_dso_sym (&symbol, dso, funcname);
 
154
        if (status)
 
155
          {
 
156
            return svn_error_wrap_apr (status,
 
157
                                       _("'%s' does not define '%s()'"),
 
158
                                       libname, funcname);
 
159
          }
 
160
 
 
161
        *func = (svn_ra__init_func_t) symbol;
 
162
      }
 
163
 
 
164
    if (compat_func)
 
165
      {
 
166
        status = apr_dso_sym (&symbol, dso, compat_funcname);
 
167
        if (status)
 
168
          {
 
169
            return svn_error_wrap_apr (status,
 
170
                                       _("'%s' does not define '%s()'"),
 
171
                                       libname, compat_funcname);
 
172
          }
 
173
 
 
174
        *compat_func = (svn_ra_init_func_t) symbol;
 
175
      }
 
176
  }
 
177
#endif /* APR_HAS_DSO */
 
178
 
 
179
  return SVN_NO_ERROR;
 
180
}
 
181
 
 
182
/* If DEFN may support URL, return the scheme.  Else, return NULL. */
 
183
static const char *
 
184
has_scheme_of (const struct ra_lib_defn *defn, const char *url)
 
185
{
 
186
  const char * const *schemes;
 
187
  apr_size_t len;
 
188
 
 
189
  for (schemes = defn->schemes; *schemes != NULL; ++schemes)
 
190
    {
 
191
      const char *scheme = *schemes;
 
192
      len = strlen (scheme);
 
193
      /* Case-insensitive comparison, per RFC 2396 section 3.1.  Allow
 
194
         URL to contain a trailing "+foo" section in the scheme, since
 
195
         that's how we specify tunnel schemes in ra_svn. */
 
196
      if (strncasecmp (scheme, url, len) == 0 &&
 
197
          (url[len] == ':' || url[len] == '+'))
 
198
        return scheme;
 
199
    }
 
200
 
 
201
  return NULL;
 
202
}
 
203
 
 
204
/* Return an error if RA_VERSION doesn't match the version of this library.
 
205
   Use SCHEME in the error message to describe the library that was loaded. */
 
206
static svn_error_t *
 
207
check_ra_version (const svn_version_t *ra_version, const char *scheme)
 
208
{
 
209
  const svn_version_t *my_version = svn_ra_version ();
 
210
  if (!svn_ver_equal (my_version, ra_version))
 
211
    return svn_error_createf (SVN_ERR_VERSION_MISMATCH, NULL,
 
212
                              _("Mismatched RA version for '%s':"
 
213
                                " found %d.%d.%d%s,"
 
214
                                " expected %d.%d.%d%s"),
 
215
                              scheme,
 
216
                              my_version->major, my_version->minor,
 
217
                              my_version->patch, my_version->tag,
 
218
                              ra_version->major, ra_version->minor,
 
219
                              ra_version->patch, ra_version->tag);
 
220
 
 
221
  return SVN_NO_ERROR;
 
222
}
 
223
 
 
224
/* -------------------------------------------------------------- */
 
225
 
 
226
/*** Public Interfaces ***/
 
227
 
 
228
svn_error_t *svn_ra_initialize (apr_pool_t *pool)
 
229
{
 
230
  return SVN_NO_ERROR;
 
231
}
 
232
 
 
233
svn_error_t *svn_ra_open (svn_ra_session_t **session_p,
 
234
                          const char *repos_URL,
 
235
                          const svn_ra_callbacks_t *callbacks,
 
236
                          void *callback_baton,
 
237
                          apr_hash_t *config,
 
238
                          apr_pool_t *pool)
 
239
{
 
240
  svn_ra_session_t *session;
 
241
  const struct ra_lib_defn *defn;
 
242
  const svn_ra__vtable_t *vtable = NULL;
 
243
 
 
244
  /* Find the library. */
 
245
  for (defn = ra_libraries; defn->ra_name != NULL; ++defn)
 
246
    {
 
247
      const char *scheme;
 
248
 
 
249
      if ((scheme = has_scheme_of (defn, repos_URL)))
 
250
        {
 
251
          svn_ra__init_func_t initfunc = defn->initfunc;
 
252
 
 
253
          if (! initfunc)
 
254
            SVN_ERR (load_ra_module (&initfunc, NULL, defn->ra_name,
 
255
                                     pool));
 
256
          if (! initfunc)
 
257
            /* Library not found. */
 
258
            break;
 
259
 
 
260
          SVN_ERR (initfunc (svn_ra_version (), &vtable, pool));
 
261
 
 
262
          SVN_ERR (check_ra_version (vtable->get_version (), scheme));
 
263
        }
 
264
    }
 
265
    
 
266
  if (vtable == NULL)
 
267
    return svn_error_createf (SVN_ERR_RA_ILLEGAL_URL, NULL,
 
268
                              _("Unrecognized URL scheme for '%s'"),
 
269
                              repos_URL);
 
270
 
 
271
  /* Create the session object. */
 
272
  session = apr_pcalloc (pool, sizeof (*session));
 
273
  session->vtable = vtable;
 
274
  session->pool = pool;
 
275
 
 
276
  /* Ask the library to open the session. */
 
277
  SVN_ERR (vtable->open (session, repos_URL, callbacks, callback_baton,
 
278
                         config, pool));
 
279
 
 
280
  *session_p = session;
 
281
  return SVN_NO_ERROR;
 
282
}
 
283
 
 
284
svn_error_t *svn_ra_get_latest_revnum (svn_ra_session_t *session,
 
285
                                       svn_revnum_t *latest_revnum,
 
286
                                       apr_pool_t *pool)
 
287
{
 
288
  return session->vtable->get_latest_revnum (session, latest_revnum, pool);
 
289
}
 
290
 
 
291
svn_error_t *svn_ra_get_dated_revision (svn_ra_session_t *session,
 
292
                                        svn_revnum_t *revision,
 
293
                                        apr_time_t tm,
 
294
                                        apr_pool_t *pool)
 
295
{
 
296
  return session->vtable->get_dated_revision (session, revision, tm, pool);
 
297
}
 
298
 
 
299
svn_error_t *svn_ra_change_rev_prop (svn_ra_session_t *session,
 
300
                                     svn_revnum_t rev,
 
301
                                     const char *name,
 
302
                                     const svn_string_t *value,
 
303
                                     apr_pool_t *pool)
 
304
{
 
305
  return session->vtable->change_rev_prop (session, rev, name, value, pool);
 
306
}
 
307
 
 
308
svn_error_t *svn_ra_rev_proplist (svn_ra_session_t *session,
 
309
                                  svn_revnum_t rev,
 
310
                                  apr_hash_t **props,
 
311
                                  apr_pool_t *pool)
 
312
{
 
313
  return session->vtable->rev_proplist (session, rev, props, pool);
 
314
}
 
315
 
 
316
svn_error_t *svn_ra_rev_prop (svn_ra_session_t *session,
 
317
                              svn_revnum_t rev,
 
318
                              const char *name,
 
319
                              svn_string_t **value,
 
320
                              apr_pool_t *pool)
 
321
{
 
322
  return session->vtable->rev_prop (session, rev, name, value, pool);
 
323
}
 
324
 
 
325
svn_error_t *svn_ra_get_commit_editor (svn_ra_session_t *session,
 
326
                                       const svn_delta_editor_t **editor,
 
327
                                       void **edit_baton,
 
328
                                       const char *log_msg,
 
329
                                       svn_commit_callback_t callback,
 
330
                                       void *callback_baton,
 
331
                                       apr_hash_t *lock_tokens,
 
332
                                       svn_boolean_t keep_locks,
 
333
                                       apr_pool_t *pool)
 
334
{
 
335
  return session->vtable->get_commit_editor (session, editor, edit_baton,
 
336
                                             log_msg, callback, callback_baton,
 
337
                                             lock_tokens, keep_locks, pool);
 
338
}
 
339
 
 
340
svn_error_t *svn_ra_get_file (svn_ra_session_t *session,
 
341
                              const char *path,
 
342
                              svn_revnum_t revision,
 
343
                              svn_stream_t *stream,
 
344
                              svn_revnum_t *fetched_rev,
 
345
                              apr_hash_t **props,
 
346
                              apr_pool_t *pool)
 
347
{
 
348
  return session->vtable->get_file (session, path, revision, stream,
 
349
                                    fetched_rev, props, pool);
 
350
}
 
351
 
 
352
svn_error_t *svn_ra_get_dir (svn_ra_session_t *session,
 
353
                             const char *path,
 
354
                             svn_revnum_t revision,
 
355
                             apr_hash_t **dirents,
 
356
                             svn_revnum_t *fetched_rev,
 
357
                             apr_hash_t **props,
 
358
                             apr_pool_t *pool)
 
359
{
 
360
  return session->vtable->get_dir (session, path, revision, dirents,
 
361
                                   fetched_rev, props, pool);
 
362
}
 
363
 
 
364
svn_error_t *svn_ra_do_update (svn_ra_session_t *session,
 
365
                               const svn_ra_reporter2_t **reporter,
 
366
                               void **report_baton,
 
367
                               svn_revnum_t revision_to_update_to,
 
368
                               const char *update_target,
 
369
                               svn_boolean_t recurse,
 
370
                               const svn_delta_editor_t *update_editor,
 
371
                               void *update_baton,
 
372
                               apr_pool_t *pool)
 
373
{
 
374
  return session->vtable->do_update (session, reporter, report_baton,
 
375
                                     revision_to_update_to, update_target,
 
376
                                     recurse, update_editor, update_baton,
 
377
                                     pool);
 
378
}
 
379
 
 
380
svn_error_t *svn_ra_do_switch (svn_ra_session_t *session,
 
381
                               const svn_ra_reporter2_t **reporter,
 
382
                               void **report_baton,
 
383
                               svn_revnum_t revision_to_switch_to,
 
384
                               const char *switch_target,
 
385
                               svn_boolean_t recurse,
 
386
                               const char *switch_url,
 
387
                               const svn_delta_editor_t *switch_editor,
 
388
                               void *switch_baton,
 
389
                               apr_pool_t *pool)
 
390
{
 
391
  return session->vtable->do_switch (session, reporter, report_baton,
 
392
                                     revision_to_switch_to, switch_target,
 
393
                                     recurse, switch_url, switch_editor,
 
394
                                     switch_baton, pool);
 
395
}
 
396
 
 
397
svn_error_t *svn_ra_do_status (svn_ra_session_t *session,
 
398
                               const svn_ra_reporter2_t **reporter,
 
399
                               void **report_baton,
 
400
                               const char *status_target,
 
401
                               svn_revnum_t revision,
 
402
                               svn_boolean_t recurse,
 
403
                               const svn_delta_editor_t *status_editor,
 
404
                               void *status_baton,
 
405
                               apr_pool_t *pool)
 
406
{
 
407
  return session->vtable->do_status (session, reporter, report_baton,
 
408
                                     status_target, revision, recurse,
 
409
                                     status_editor, status_baton, pool);
 
410
}
 
411
 
 
412
svn_error_t *svn_ra_do_diff (svn_ra_session_t *session,
 
413
                             const svn_ra_reporter2_t **reporter,
 
414
                             void **report_baton,
 
415
                             svn_revnum_t revision,
 
416
                             const char *diff_target,
 
417
                             svn_boolean_t recurse,
 
418
                             svn_boolean_t ignore_ancestry,
 
419
                             const char *versus_url,
 
420
                             const svn_delta_editor_t *diff_editor,
 
421
                             void *diff_baton,
 
422
                             apr_pool_t *pool)
 
423
{
 
424
  return session->vtable->do_diff (session, reporter, report_baton, revision,
 
425
                                   diff_target, recurse, ignore_ancestry,
 
426
                                   versus_url, diff_editor, diff_baton, pool);
 
427
}
 
428
 
 
429
svn_error_t *svn_ra_get_log (svn_ra_session_t *session,
 
430
                             const apr_array_header_t *paths,
 
431
                             svn_revnum_t start,
 
432
                             svn_revnum_t end,
 
433
                             int limit,
 
434
                             svn_boolean_t discover_changed_paths,
 
435
                             svn_boolean_t strict_node_history,
 
436
                             svn_log_message_receiver_t receiver,
 
437
                             void *receiver_baton,
 
438
                             apr_pool_t *pool)
 
439
{
 
440
  return session->vtable->get_log (session, paths, start, end, limit,
 
441
                                   discover_changed_paths, strict_node_history,
 
442
                                   receiver, receiver_baton, pool);
 
443
}
 
444
 
 
445
svn_error_t *svn_ra_check_path (svn_ra_session_t *session,
 
446
                                const char *path,
 
447
                                svn_revnum_t revision,
 
448
                                svn_node_kind_t *kind,
 
449
                                apr_pool_t *pool)
 
450
{
 
451
  return session->vtable->check_path (session, path, revision, kind, pool);
 
452
}
 
453
 
 
454
svn_error_t *svn_ra_stat (svn_ra_session_t *session,
 
455
                          const char *path,
 
456
                          svn_revnum_t revision,
 
457
                          svn_dirent_t **dirent,
 
458
                          apr_pool_t *pool)
 
459
{
 
460
  return session->vtable->stat (session, path, revision, dirent, pool);
 
461
}
 
462
 
 
463
svn_error_t *svn_ra_get_uuid (svn_ra_session_t *session,
 
464
                              const char **uuid,
 
465
                              apr_pool_t *pool)
 
466
{
 
467
  return session->vtable->get_uuid (session, uuid, pool);
 
468
}
 
469
 
 
470
svn_error_t *svn_ra_get_repos_root (svn_ra_session_t *session,
 
471
                                    const char **url,
 
472
                                    apr_pool_t *pool)
 
473
{
 
474
  return session->vtable->get_repos_root (session, url, pool);
 
475
}
 
476
 
 
477
svn_error_t *svn_ra_get_locations (svn_ra_session_t *session,
 
478
                                   apr_hash_t **locations,
 
479
                                   const char *path,
 
480
                                   svn_revnum_t peg_revision,
 
481
                                   apr_array_header_t *location_revisions,
 
482
                                   apr_pool_t *pool)
 
483
{
 
484
  return session->vtable->get_locations (session, locations, path,
 
485
                                         peg_revision, location_revisions,
 
486
                                         pool);
 
487
}
 
488
 
 
489
svn_error_t *svn_ra_get_file_revs (svn_ra_session_t *session,
 
490
                                   const char *path,
 
491
                                   svn_revnum_t start,
 
492
                                   svn_revnum_t end,
 
493
                                   svn_ra_file_rev_handler_t handler,
 
494
                                   void *handler_baton,
 
495
                                   apr_pool_t *pool)
 
496
{
 
497
  return session->vtable->get_file_revs (session, path, start, end, handler,
 
498
                                         handler_baton, pool);
 
499
}
 
500
 
 
501
svn_error_t *svn_ra_lock (svn_ra_session_t *session,
 
502
                          apr_hash_t *path_revs,
 
503
                          const char *comment,
 
504
                          svn_boolean_t steal_lock,
 
505
                          svn_ra_lock_callback_t lock_func, 
 
506
                          void *lock_baton,
 
507
                          apr_pool_t *pool)
 
508
{
 
509
  if (comment && ! svn_xml_is_xml_safe(comment, strlen(comment)))
 
510
    return svn_error_create
 
511
      (SVN_ERR_XML_UNESCAPABLE_DATA, NULL,
 
512
       _("Lock comment has illegal characters"));
 
513
  
 
514
  return session->vtable->lock (session, path_revs, comment, steal_lock,
 
515
                                lock_func, lock_baton, pool);
 
516
}
 
517
 
 
518
svn_error_t *svn_ra_unlock (svn_ra_session_t *session,
 
519
                            apr_hash_t *path_tokens,
 
520
                            svn_boolean_t break_lock,
 
521
                            svn_ra_lock_callback_t lock_func, 
 
522
                            void *lock_baton,
 
523
                            apr_pool_t *pool)
 
524
{
 
525
  return session->vtable->unlock (session, path_tokens, break_lock,
 
526
                                  lock_func, lock_baton, pool);
 
527
}
 
528
 
 
529
svn_error_t *svn_ra_get_lock (svn_ra_session_t *session,
 
530
                              svn_lock_t **lock,
 
531
                              const char *path,
 
532
                              apr_pool_t *pool)
 
533
{
 
534
  return session->vtable->get_lock (session, lock, path, pool);
 
535
}
 
536
 
 
537
svn_error_t *svn_ra_get_locks (svn_ra_session_t *session,
 
538
                               apr_hash_t **locks,
 
539
                               const char *path,
 
540
                               apr_pool_t *pool)
 
541
{
 
542
  return session->vtable->get_locks (session, locks, path, pool);
 
543
}
 
544
 
 
545
 
 
546
 
 
547
svn_error_t *
 
548
svn_ra_print_modules (svn_stringbuf_t *output,
 
549
                      apr_pool_t *pool)
 
550
{
 
551
  const struct ra_lib_defn *defn;
 
552
  const char * const *schemes;
 
553
  svn_ra__init_func_t initfunc;
 
554
  const svn_ra__vtable_t *vtable;
 
555
  apr_pool_t *iterpool = svn_pool_create (pool);
 
556
 
 
557
  for (defn = ra_libraries; defn->ra_name != NULL; ++defn)
 
558
    {
 
559
      char *line;
 
560
 
 
561
      svn_pool_clear (iterpool);
 
562
 
 
563
      initfunc = defn->initfunc;
 
564
      if (! initfunc)
 
565
        SVN_ERR (load_ra_module (&initfunc, NULL, defn->ra_name,
 
566
                                 iterpool));
 
567
 
 
568
      if (initfunc)
 
569
        {
 
570
          SVN_ERR (initfunc (svn_ra_version(), &vtable, iterpool));
 
571
 
 
572
          SVN_ERR (check_ra_version (vtable->get_version (), defn->ra_name));
 
573
 
 
574
          line = apr_psprintf (iterpool, "* ra_%s : %s\n",
 
575
                               defn->ra_name,
 
576
                               vtable->get_description());
 
577
          svn_stringbuf_appendcstr (output, line);
 
578
 
 
579
          for (schemes = vtable->get_schemes(iterpool); *schemes != NULL;
 
580
               ++schemes)
 
581
            {
 
582
              line = apr_psprintf (iterpool, _("  - handles '%s' scheme\n"),
 
583
                                   *schemes);
 
584
              svn_stringbuf_appendcstr (output, line);
 
585
            }
 
586
        }
 
587
    }
 
588
 
 
589
  svn_pool_destroy (iterpool);
 
590
 
 
591
  return SVN_NO_ERROR;
 
592
}
 
593
 
 
594
 
 
595
svn_error_t *
 
596
svn_ra_print_ra_libraries (svn_stringbuf_t **descriptions,
 
597
                           void *ra_baton,
 
598
                           apr_pool_t *pool)
 
599
{
 
600
  *descriptions = svn_stringbuf_create ("", pool);
 
601
  return svn_ra_print_modules (*descriptions, pool);
 
602
}
 
603
 
 
604
 
 
605
/* Return the library version number. */
 
606
const svn_version_t *
 
607
svn_ra_version (void)
 
608
{
 
609
  SVN_VERSION_BODY;
 
610
}
 
611
 
 
612
 
 
613
/*** Compatibility Interfaces **/
 
614
svn_error_t *
 
615
svn_ra_init_ra_libs (void **ra_baton,
 
616
                     apr_pool_t *pool)
 
617
{
 
618
  *ra_baton = pool;
 
619
  return SVN_NO_ERROR;
 
620
}
 
621
 
 
622
svn_error_t *
 
623
svn_ra_get_ra_library (svn_ra_plugin_t **library,
 
624
                       void *ra_baton,
 
625
                       const char *url,
 
626
                       apr_pool_t *pool)
 
627
{
 
628
  const struct ra_lib_defn *defn;
 
629
  apr_pool_t *load_pool = ra_baton;
 
630
  apr_hash_t *ht = apr_hash_make (pool);
 
631
 
 
632
  /* Figure out which RA library key matches URL. */
 
633
  for (defn = ra_libraries; defn->ra_name != NULL; ++defn)
 
634
    {
 
635
      const char *scheme;
 
636
      if ((scheme = has_scheme_of (defn, url)))
 
637
        {
 
638
          svn_ra_init_func_t compat_initfunc = defn->compat_initfunc;
 
639
 
 
640
          if (! compat_initfunc)
 
641
            {
 
642
              SVN_ERR (load_ra_module
 
643
                       (NULL, &compat_initfunc, defn->ra_name, load_pool));
 
644
            }
 
645
          if (! compat_initfunc)
 
646
            {
 
647
              break;
 
648
            }
 
649
 
 
650
          SVN_ERR (compat_initfunc (SVN_RA_ABI_VERSION, load_pool, ht));
 
651
 
 
652
          *library = apr_hash_get (ht, scheme, APR_HASH_KEY_STRING);
 
653
 
 
654
          /* The library may support just a subset of the schemes listed,
 
655
             so we have to check here too. */
 
656
          if (! *library)
 
657
            break;
 
658
 
 
659
          SVN_ERR (check_ra_version ((*library)->get_version (), scheme));
 
660
 
 
661
          return SVN_NO_ERROR;
 
662
        }
 
663
    }
 
664
    
 
665
  /* Couldn't find a match... */
 
666
  *library = NULL;
 
667
  return svn_error_createf (SVN_ERR_RA_ILLEGAL_URL, NULL,
 
668
                            _("Unrecognized URL scheme '%s'"), url);
 
669
}
 
670