Developing applications against the Subversion library APIs      is fairly straightforward.  All of the public header files live
      in the subversion/include directory of the
      source tree.  These headers are copied into your system
      locations when you build and install Subversion itself from
      source.  These headers represent the entirety of the functions
      and types meant to be accessible by users of the Subversion
      libraries.
The first thing you might notice is that Subversion's
      datatypes and functions are namespace protected.  Every public
      Subversion symbol name begins with svn_,
      followed by a short code for the library in which the symbol is
      defined (such as wc,
      client, fs, etc.),
      followed by a single underscore (_) and
      then the rest of the symbol name.  Semi-public functions (used
      among source files of a given library but not by code outside
      that library, and found inside the library directories
      themselves) differ from this naming scheme in that instead of a
      single underscore after the library code, they use a double
      underscore (__).  Functions that are private
      to a given source file have no special prefixing, and are declared
      static.  Of course, a compiler isn't
      interested in these naming conventions, but they help to clarify
      the scope of a given function or datatype.
Along with Subversion's own datatypes, you will see many
        references to datatypes that begin with
        apr_—symbols from the Apache
        Portable Runtime (APR) library.  APR is Apache's portability
        library, originally carved out of its server code as an
        attempt to separate the OS-specific bits from the
        OS-independent portions of the code.  The result was a library
        that provides a generic API for performing operations that
        differ mildly—or wildly—from OS to OS.  While the
        Apache HTTP Server was obviously the first user of the APR
        library, the Subversion developers immediately recognized the
        value of using APR as well.  This means that there are
        practically no OS-specific code portions in Subversion itself.
        Also, it means that the Subversion client compiles and runs
        anywhere that the server does.  Currently this list includes
        all flavors of Unix, Win32, BeOS, OS/2, and Mac OS X.
In addition to providing consistent implementations of
        system calls that differ across operating systems,
        [43]
        APR gives Subversion immediate access to many custom
        datatypes, such as dynamic arrays and hash tables.  Subversion
        uses these types extensively throughout the codebase.  But
        perhaps the most pervasive APR datatype, found in nearly every
        Subversion API prototype, is the
        apr_pool_t—the APR memory pool.
        Subversion uses pools internally for all its memory allocation
        needs (unless an external library requires a different memory
        management schema for data passed through its API),
        [44]
        and while a person coding against the Subversion APIs is
        not required to do the same, they are required to provide
        pools to the API functions that need them.  This means that
        users of the Subversion API must also link against APR, must
        call apr_initialize() to initialize the
        APR subsystem, and then must acquire a pool for use with
        Subversion API calls.  See the section called “Programming with Memory Pools”
        for more information.
With remote version control operation as the whole point
        of Subversion's existence, it makes sense that some attention
        has been paid to internationalization (i18n) support.  After
        all, while “remote” might mean “across the
        office”, it could just as well mean “across the
        globe.” To facilitate this, all of Subversion's public
        interfaces that accept path arguments expect those paths to be
        canonicalized, and encoded in UTF-8.  This means, for example,
        that any new client binary that drives the libsvn_client
        interface needs to first convert paths from the
        locale-specific encoding to UTF-8 before passing those paths
        to the Subversion libraries, and then re-convert any resultant
        output paths from Subversion back into the locale's encoding
        before using those paths for non-Subversion purposes.
        Fortunately, Subversion provides a suite of functions (see
        subversion/include/svn_utf.h) that can be
        used by any program to do these conversions.
Also, Subversion APIs require all URL parameters to be
        properly URI-encoded.  So, instead of passing file:///home/username/My File.txt as
        the URL of a file named My File.txt, you
        need to pass file:///home/username/My%20File.txt.
        Again, Subversion supplies helper functions that your
        application can
        use—svn_path_uri_encode() and
        svn_path_uri_decode(), for URI encoding and
        decoding, respectively.
If you are interested in using the Subversion libraries in
        conjunction with something other than a C program—say a
        Python or Perl script—Subversion has some support for this
        via the Simplified Wrapper and Interface Generator (SWIG).  The
        SWIG bindings for Subversion are located in
        subversion/bindings/swig and whilst still
        maturing, they are in a usable state.  These bindings allow you
        to call Subversion API functions indirectly, using wrappers that
        translate the datatypes native to your scripting language into
        the datatypes needed by Subversion's C libraries.
There is an obvious benefit to accessing the Subversion APIs via a language binding—simplicity. Generally speaking, languages such as Python and Perl are much more flexible and easy to use than C or C++. The sort of high-level datatypes and context-driven type checking provided by these languages are often better at handling information that comes from users. As you know, humans are proficient at botching up input to a program, and scripting languages tend to handle that misinformation more gracefully. Of course, often that flexibility comes at the cost of performance. That is why using a tightly-optimized, C-based interface and library suite, combined with a powerful, flexible binding language, is so appealing.
Let's look at a sample program that uses Subversion's Python SWIG bindings to recursively crawl the youngest repository revision, and print the various paths reached during the crawl.
Example 8.2. Using the Repository Layer with Python
#!/usr/bin/python
"""Crawl a repository, printing versioned object path names."""
import sys
import os.path
import svn.fs, svn.core, svn.repos
def crawl_filesystem_dir(root, directory, pool):
    """Recursively crawl DIRECTORY under ROOT in the filesystem, and return
    a list of all the paths at or below DIRECTORY.  Use POOL for all 
    allocations."""
    # Print the name of this path.
    print directory + "/"
    
    # Get the directory entries for DIRECTORY.
    entries = svn.fs.svn_fs_dir_entries(root, directory, pool)
    # Use an iteration subpool.
    subpool = svn.core.svn_pool_create(pool)
    # Loop over the entries.
    names = entries.keys()
    for name in names:
        # Clear the iteration subpool.
        svn.core.svn_pool_clear(subpool)
        # Calculate the entry's full path.
        full_path = directory + '/' + name
        # If the entry is a directory, recurse.  The recursion will return
        # a list with the entry and all its children, which we will add to
        # our running list of paths.
        if svn.fs.svn_fs_is_dir(root, full_path, subpool):
            crawl_filesystem_dir(root, full_path, subpool)
        else:
            # Else it's a file, so print its path here.
            print full_path
    # Destroy the iteration subpool.
    svn.core.svn_pool_destroy(subpool)
def crawl_youngest(pool, repos_path):
    """Open the repository at REPOS_PATH, and recursively crawl its
    youngest revision."""
    
    # Open the repository at REPOS_PATH, and get a reference to its
    # versioning filesystem.
    repos_obj = svn.repos.svn_repos_open(repos_path, pool)
    fs_obj = svn.repos.svn_repos_fs(repos_obj)
    # Query the current youngest revision.
    youngest_rev = svn.fs.svn_fs_youngest_rev(fs_obj, pool)
    
    # Open a root object representing the youngest (HEAD) revision.
    root_obj = svn.fs.svn_fs_revision_root(fs_obj, youngest_rev, pool)
    # Do the recursive crawl.
    crawl_filesystem_dir(root_obj, "", pool)
    
if __name__ == "__main__":
    # Check for sane usage.
    if len(sys.argv) != 2:
        sys.stderr.write("Usage: %s REPOS_PATH\n"
                         % (os.path.basename(sys.argv[0])))
        sys.exit(1)
    # Canonicalize (enough for Subversion, at least) the repository path.
    repos_path = os.path.normpath(sys.argv[1])
    if repos_path == '.': 
        repos_path = ''
    # Call the app-wrapper, which takes care of APR initialization/shutdown
    # and the creation and cleanup of our top-level memory pool.
    svn.core.run_app(crawl_youngest, repos_path)
This same program in C would need to deal with custom datatypes (such as those provided by the APR library) for representing the hash of entries and the list of paths, but Python has hashes (called “dictionaries”) and lists as built-in datatypes, and provides a rich collection of functions for operating on those types. So SWIG (with the help of some customizations in Subversion's language bindings layer) takes care of mapping those custom datatypes into the native datatypes of the target language. This provides a more intuitive interface for users of that language.
The Subversion Python bindings can be used for working
        copy operations, too.  In the previous section of this
        chapter, we mentioned the libsvn_client
        interface, and how it exists for the sole purpose of
        simplifying the process of writing a Subversion client.  The
        following is a brief example of how that library can be
        accessed via the SWIG bindings to recreate a scaled-down
        version of the svn status command.
Example 8.3. A Python Status Crawler
#!/usr/bin/env python
"""Crawl a working copy directory, printing status information."""
import sys
import os.path
import getopt
import svn.core, svn.client, svn.wc
def generate_status_code(status):
    """Translate a status value into a single-character status code,
    using the same logic as the Subversion command-line client."""
    if status == svn.wc.svn_wc_status_none:
        return ' '
    if status == svn.wc.svn_wc_status_normal:
        return ' '
    if status == svn.wc.svn_wc_status_added:
        return 'A'
    if status == svn.wc.svn_wc_status_missing:
        return '!'
    if status == svn.wc.svn_wc_status_incomplete:
        return '!'
    if status == svn.wc.svn_wc_status_deleted:
        return 'D'
    if status == svn.wc.svn_wc_status_replaced:
        return 'R'
    if status == svn.wc.svn_wc_status_modified:
        return 'M'
    if status == svn.wc.svn_wc_status_merged:
        return 'G'
    if status == svn.wc.svn_wc_status_conflicted:
        return 'C'
    if status == svn.wc.svn_wc_status_obstructed:
        return '~'
    if status == svn.wc.svn_wc_status_ignored:
        return 'I'
    if status == svn.wc.svn_wc_status_external:
        return 'X'
    if status == svn.wc.svn_wc_status_unversioned:
        return '?'
    return '?'
def do_status(pool, wc_path, verbose):
    # Calculate the length of the input working copy path.
    wc_path_len = len(wc_path)
    # Build a client context baton.
    ctx = svn.client.svn_client_ctx_t()
    def _status_callback(path, status, root_path_len=wc_path_len):
        """A callback function for svn_client_status."""
        # Print the path, minus the bit that overlaps with the root of
        # the status crawl
        text_status = generate_status_code(status.text_status)
        prop_status = generate_status_code(status.prop_status)
        print '%s%s  %s' % (text_status, prop_status, path[wc_path_len + 1:])
        
    # Do the status crawl, using _status_callback() as our callback function.
    svn.client.svn_client_status(wc_path, None, _status_callback,
                                 1, verbose, 0, 0, ctx, pool)
def usage_and_exit(errorcode):
    """Print usage message, and exit with ERRORCODE."""
    stream = errorcode and sys.stderr or sys.stdout
    stream.write("""Usage: %s OPTIONS WC-PATH
Options:
  --help, -h    : Show this usage message
  --verbose, -v : Show all statuses, even uninteresting ones
""" % (os.path.basename(sys.argv[0])))
    sys.exit(errorcode)
    
if __name__ == '__main__':
    # Parse command-line options.
    try:
        opts, args = getopt.getopt(sys.argv[1:], "hv", ["help", "verbose"])
    except getopt.GetoptError:
        usage_and_exit(1)
    verbose = 0
    for opt, arg in opts:
        if opt in ("-h", "--help"):
            usage_and_exit(0)
        if opt in ("-v", "--verbose"):
            verbose = 1
    if len(args) != 1:
        usage_and_exit(2)
            
    # Canonicalize (enough for Subversion, at least) the working copy path.
    wc_path = os.path.normpath(args[0])
    if wc_path == '.': 
        wc_path = ''
    # Call the app-wrapper, which takes care of APR initialization/shutdown
    # and the creation and cleanup of our top-level memory pool.
    svn.core.run_app(do_status, wc_path, verbose)
Subversion's language bindings unfortunately tend to lack the level of attention given to the core Subversion modules. However, there have been significant efforts towards creating functional bindings for Python, Perl, and Ruby. To some extent, the work done preparing the SWIG interface files for these languages is reusable in efforts to generate bindings for other languages supported by SWIG (which includes versions of C#, Guile, Java, MzScheme, OCaml, PHP, Tcl, and others). However, some extra programming is required to compensate for complex APIs that SWIG needs some help interfacing with. For more information on SWIG itself, see the project's website at http://www.swig.org/.