Login
Artifact [1a0a96e18a]
Login

Artifact 1a0a96e18a8f7b495526f9d925e678b2af99e6be:


/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 
/* vim: set ts=2 et sw=2 tw=80: */
#if !defined(NET_FOSSIL_SCM_FOSSIL2_H_INCLUDED)
#define NET_FOSSIL_SCM_FOSSIL2_H_INCLUDED
/*
** Copyright (c) 2013 D. Richard Hipp
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the Simplified BSD License (also
** known as the "2-Clause License" or "FreeBSD License".)
**
** This program is distributed in the hope that it will be useful,
** but without any warranty; without even the implied warranty of
** merchantability or fitness for a particular purpose.
**
** Author contact information:
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*******************************************************************************
**
*/
#include <stdio.h> /* FILE type */
#include "config.h"

/*
** This file sketches out a potential API for a library form of the
** Fossil SCM. This API concerns itself only with the components of
** fossil which do not need user interaction or the display of UI
** components (including HTML and CLI output). It is intended only to
** model the core internals of fossil, off of which user-level
** applications could be built.
**
** This code is 100% hypothetical/potential, and does not represent
** any Official Version 2.0. All Fossil users are encouraged to
** participate in its development, but if you are reading this then
** you probably already knew that :). Rather than think of this as v2,
** i would prefer for people to think of it as a refactoring of v1, as
** the intention is for it to be completely compatible with v1
** repositories, just providing other means of accessing them.
**
** Conventions:
**
** - API docs (as you have probably already noticed), follow Fossil's
** comment style (see the '**' at the start of each line? That's what
** i mean) EXCEPT that each block MUST start with two or more
** asterisks, or '*!', or doxygen apparently doesn't understand it
** (http://www.stack.nl/~dimitri/doxygen/manual/docblocks.html). When
** adding code snippets and whatnot to docs, please use doxygen
** conventions if it is not too much of an inconvenience. All public
** APIs must be documented with a useful amount of detail. If you hate
** documenting, let me know and i'll document it (it's what i do for
** fun).
**
** - API members have a fsl_ or FSL_ prefix (fossil_ seems too long?)
**
** - Structs and functions use lower_underscore_style()
**
** - Overall style should follow Fossil v1.x.
**
** - Structs and enums all get the optional typedef so that they do
** not need to be qualified with 'struct' resp. 'enum' when used.
**
** - Structs intended to be created on the stack are accompanied by a
** const instance named fsl_STRUCT_NAME_empty, and possibly by a macro
** named fsl_STRUCT_NAME_empty_m, both of which are
** "default-initialized" instances of that struct. This is superiour
** to using memset() for struct initialization because we can set
** arbitrary default values this way and all clients who
** copy-construct them are unaffected by many types of changes to the
** struct's signature (though they may need a recompile).
**
** - Function typedefs are named fsl_XXX_f. Implementations of such
** typedefs/interfaces are typically named fsl_XXX_f_SUFFIX(), where
** SUFFIX describes the implementation's specialization.
**
** - Typedefs for non-struct types tend to be named fsl_XXX_t and
** structs do not have a _t extensions.
**
** Notes about "my style" (this===stephan)... i tend to add a lot of
** little things which most people consider frivilous, mysterious,
** overkill, or YAGNI, e.g. the various fsl_XXX_empty_m macros. They
** are there because my experience has been that they're really
** useful. They are of course open to discussion (as is everything in
** here - none of this is holy!).
**
** Happy Hacking!
**
** ----- stephan@wanderinghorse.net / sgbeal@googlemail.com
*/

#include <stdarg.h> /* va_list */

#if defined(__cplusplus)
extern "C" {
#endif

  typedef struct fsl_outputer fsl_outputer;
  typedef struct fsl_cx fsl_cx;
  typedef struct fsl_allocator fsl_allocator;
  typedef struct fsl_db fsl_db;
  typedef struct fsl_stmt fsl_stmt;
  typedef struct fsl_buffer fsl_buffer;
  typedef struct fsl_error fsl_error;
  typedef struct fsl_state fsl_state;
  typedef struct fsl_cx_config fsl_cx_config;

  /**
   ** @struct fsl_cx
   **
   ** The main Fossil "context" type. This is the first argument to
   ** many Fossil library API routines, and holds all state related
   ** to a checkout and/or repository database.
   **
   ** This type will likely eventually be made opaque to client code -
   ** do not depend on any of its members/contents. Having it
   ** non-opaque also has advantages, though. We'll see. Binary
   ** compatibility concerns might force us to make it opaque.  But for
   ** now having it public simplifies testing and debugging.
   **
   ** An instance's lifetime looks like:
   **
   ** @code
   ** int rc;
   ** fsl_cx * f = NULL;
   ** rc = fsl_cx_init( &f, NULL );
   ** assert(!rc);
   ** rc = fsl_repo_open_db( f, "myrepo.fsl" );
   ** ...
   ** fsl_cx_finalize(f);
   ** @endcode
   */
  
  
  /**
   ** Most funcs return error codes from the fsl_rc_t enum.  None of
   ** these entries are (currently) guaranteed to have a specific value
   ** across Fossil versions except for FSL_RC_OK, which is guaranteed
   ** to always be 0.
   **
   ** The only reasons numbers are hard-coded to the values (or some of
   ** them) is to simplify debugging during development.
   */
  enum fsl_rc_t {
  /**
   ** The quintessential not-an-error value.
   */
  FSL_RC_OK = 0,
  /**
   ** Generic/unknown error.
   */
  FSL_RC_ERROR = 100,
  /**
   ** A placeholder return value for "not yet implemented" functions.
   */
  FSL_RC_NYI = 101,
  /**
   ** Out of memory. Indicates that a resource allocation request
   ** failed.
   */
  FSL_RC_OOM = 102,
  /*
  ** API misuse (invalid args)
  */
  FSL_RC_MISUSE = 103,
  /**
   ** Some range was violated (function argument, UTF character, etc.).
   */
  FSL_RC_RANGE = 104,
  /**
   ** Indicates that access to or locking of a resource was denied
   ** by some security mechanism or other.
   */
  FSL_RC_ACCESS = 105,
  /**
   ** Indicates an I/O error. Whether it was reading or writing is
   ** context-dependent.
   */
  FSL_RC_IO = 106,
  /**
   ** requested resource not found
   */
  FSL_RC_NOT_FOUND = 107,
  /**
   ** Immutable resource already exists
   */
  FSL_RC_ALREADY_EXISTS = 108,
  /**
   ** Data consistency problem
   */
  FSL_RC_CONSISTENCY = 109,

  /**
   ** Indicates that the requested repo needs to be rebuilt.
   */
  FSL_RC_REPO_NEEDS_REBUILD = 110,

  /**
   ** Indicates that the requested repo is not, in fact, a repo. Also
   ** used by some APIs to indicate that no repo has been opened yet.
   */
  FSL_RC_NOT_A_REPO = 111,
  /**
   ** Tried to load a too-old or too-new repo
   */
  FSL_RC_REPO_VERSION = 112,
  /**
   ** db-level error (e.g. statement prep failed)
   */
  FSL_RC_DB = 113,
  /**
   ** Used by some iteration routines to indicate that iteration should
   ** stop prematurely without an error.
   */
  FSL_RC_BREAK = 114,

  /**
   ** Indicates that a row has been fetched and the cursor may be used
   ** to access the current row state.
   */
  FSL_RC_STEP_ROW = 115,

  /**
   ** Indicates that the end of the result set has been reached and
   ** that there is no row data to process. This is also the result for
   ** non-fetching queries (INSERT and friends).
   */
  FSL_RC_STEP_DONE = 116,

  /**
   ** Indicates that a db-level error occurred during step() iteration.
   */
  FSL_RC_STEP_ERROR = 117,

  /**
   ** Indicates that some data type is incorrect.
   */
  FSL_RC_TYPE = 118,

  FSL_RC_NOT_A_CHECKOUT,

  /* ...more to come... */
  FSL_RC_TRAILING_COMMA_KLUDGE /* don't ask. hint: emacs macros */
  };
  typedef enum fsl_rc_t fsl_rc_t;

  /**
   ** Returns a "standard" string form for a fsl_rc_t code.  The string
   ** is primarily intended for debugging purposes.  The returned bytes
   ** are guaranteed to be static and NUL-terminated. They are not
   ** guaranteed to contain anything useful for any purposes other than
   ** debugging and tracking down problems.
   */
  char const * fsl_rc_cstr(int);

  /**
   ** Returns the value of FSL_LIBRARY_VERSION used to compile the
   ** library. If this value differs from the value the caller was
   ** compiled with, Chaos might ensue.
   **
   ** The API does not yet have any mechanism for determining
   ** compatibility between repository versions, but it also currently
   ** does no explicit checking to disallow incompatible versions.
   */
  char const * fsl_library_version();

  /**
   ** Returns true (non-0) if yourLibVersion compares lexically
   ** equal to FSL_LIBRARY_VERSION, else it returns false (0).
   */
  char fsl_library_version_matches(char const * yourLibVersion);
  
  /**
   ** Generic interface for streaming out data. Implementations must
   ** write n bytes from s to their destination channel and return 0 on
   ** success, non-0 on error (assumed to be a value from the fsl_rc_t
   ** enum). The state parameter is the implementation-specified
   ** output channel.
   */
  typedef int (*fsl_output_f)( void * state,
                               void const * src, fsl_size_t n );

  /**
   ** Generic interface for streaming in data. Implementations must
   ** read (at most) *n bytes from their input, copy it to dest, assign
   ** *n to the number of bytes actually read, return 0 on success, and
   ** return non-0 on error (assumed to be a value from the fsl_rc_t
   ** enum). When called, *n is the max length to read. On return, *n
   ** is the actual amount read. The state parameter is the
   ** implementation-specified input file/buffer/whatever channel.
   */
  typedef int (*fsl_input_f)( void * state, void * dest, fsl_size_t * n );

  /**
   ** A fsl_input_f() implementation which requires that state be
   ** a readable (FILE*) handle.
   */
  int fsl_input_FILE( void * state, void * dest, fsl_size_t * n );
  
  /**
   ** Generic interface for finalizing/freeing memory. Intended
   ** primarily for use as a destructor/finalizer for high-level
   ** structs. Implementations must semantically behave like free(mem),
   ** regardless of whether or not they actually free the memory. At
   ** the very least, they generally should clean up any memory owned by
   ** mem (e.g. db resources or buffers), even if they do not free() mem.
   ** some implementations assume that mem is stack-allocated
   ** and they only clean up resources owned by mem.
   **
   ** The state parameter is any state needed by the finalizer
   ** (e.g. a memory allocation context) and mem is the memory which is
   ** being finalized. 
   **
   ** The exact interpretaion of the state and mem are of course
   ** implementation-specific.
   */
  typedef void (*fsl_finalizer_f)( void * state, void * mem );

  /**
   ** Generic interface for memory finalizers.
   */
  struct fsl_finalizer {
    /**
     ** State to be passed as the first argument to f().
     */
    void * state;
    /**
     ** Finalizer function. Should be called like this->f( this->state, ... ).
     */
    fsl_finalizer_f f;
  };
  typedef struct fsl_finalizer fsl_finalizer;
  /** Empty-initialized fsl_finalizer instance. */
#define fsl_finalizer_empty_m {NULL,NULL}

  /**
   ** Generic list container type.
   **
   ** It is up to the APIs using this type to manage the entry count
   ** member and use fsl_list_reserve() to manage the "alloced"
   ** member.
   **
   ** @see fsl_list_reserve()
   **  @see fsl_list_append()
   */
  struct fsl_list {
    /**
     ** Array of entries. It contains this->alloced entries,
     ** this->count of which are "valid" (in use).
     */
    void ** list;
    /**
     ** Number of "used" entries in the list.
     */
    fsl_size_t count;
    /**
     ** Number of slots allocated in this->list. Use fsl_list_reserve()
     ** to modify this. Doing so might move the this->list pointer but
     ** the values it points to will stay stable.
     */
    fsl_size_t alloced;
  };
  typedef struct fsl_list fsl_list;
  /**
   ** Empty-initialized fsl_list object.
   */
#define fsl_list_empty_m { NULL, 0, 0 }
  /**
   ** Empty-initialized fsl_list object.
   */
  extern const fsl_list fsl_list_empty;

  
  /** Generic state-with-finalizer holder */
  struct fsl_state {
    /**
     ** Arbitrary context-dependent state.
     */
    void * state;
    /**
     ** Finalizer for this->state. If used, it should be called like:
     **
     ** @code
     ** this->finalize.f( this->finalize.state, this->state );
     ** @endcode
     **
     ** After which this->state must be treated as if it has been
     ** free(3)'d.
     */
    fsl_finalizer finalize;
  };
  /** Empty-initialized fsl_state instance. */
#define fsl_state_empty_m {NULL,fsl_finalizer_empty_m}

  /**
   ** Generic interface for flushing arbitrary output streams.  Must
   ** return 0 on success, non-0 on error, but the result code "should"
   ** (to avoid downstream confusion) be one of the fsl_rc_t
   ** values. When in doubt, return FSL_RC_IO on error.
   */
  typedef int (*fsl_flush_f)(void * state);

  /**
   ** A fsl_flush_f() impl which expects _FILE to be-a (FILE*), which
   ** this function passes the call on to fflush(). If fflush() returns
   ** 0, so does this function, else it returns FSL_RC_IO.
   */
  int fsl_flush_f_FILE(void * _FILE);

  /**
   ** A fsl_finalizer_f() impl which requires that mem be-a (FILE*).
   ** If mem is not (stdout, stderr) then this function fclose()es
   ** it, else it is a no-op. The state parameter is ignored.
   */
  void fsl_finalizer_f_FILE( void * state, void * mem );

  /**
   ** A fsl_output_f() impl which requires state to be-a (FILE*), which
   ** this function passes the call on to fwrite(). Returns 0 on
   ** success, FSL_RC_IO on error.
   */
  int fsl_output_f_FILE( void * state, void const * src, fsl_size_t n );

  /**
   ** A fsl_output_f() impl which requires state to be-a (fsl_buffer*),
   ** which this function passes to fsl_buffer_append(). Returns 0 on
   ** success, FSL_RC_OOM (probably) on error.
   */
  int fsl_output_f_buffer( void * state, void const * src, fsl_size_t n );

  /**
   ** fsl_finalizer_f() impl which requires that mem be-a
   ** (fsl_buffer*).  This function frees all memory associated with
   ** that buffer and zeroes out the structure, but does not free mem
   ** (because it is rare that fsl_buffers are created on the
   ** heap). The state parameter is ignored.
   */
  int fsl_finalizer_f_buffer( void * state, void * mem );

  /**
   ** An interface which encapsulates data for managing an output
   ** destination, primarily intended for use with fsl_output(). Why
   ** abstract it to this level? So that we can do interesting things
   ** like output to buffers, files, sockets, etc., using the core
   ** output mechanism. e.g. so script bindings can send their output
   ** to the same channel used by the library and other library
   ** clients.
   */
  struct fsl_outputer {
    /**
     ** Output channel.
     */
    fsl_output_f out;
    /**
     ** flush() implementation.
     */
    fsl_flush_f flush;
    /**
     ** State to be used when calling this->out(), namely:
     ** this->out( this->state.state, ... ).
     */
    fsl_state state;
  };
  /** Empty-initialized fsl_outputer instance. */
#define fsl_outputer_empty_m {NULL,NULL,fsl_state_empty_m}

  /**
   ** A fsl_outputer instance which is initialized to output to a
   ** (FILE*). To use it, this value then set the copy's state.state
   ** member to an opened-for-write (FILE*) handle. By default it will
   ** use stdout. Its finalizer (if called!) will fclose(3)
   ** self.state.state if self.state.state is not one of (stdout,
   ** stderr). To disable the closing behaviour (and not close the
   ** file), set self.state.finalize.f to NULL (but then be sure that
   ** the file handle outlives this object and to fclose(3) it when
   ** finished with it).
   */
  extern const fsl_outputer fsl_outputer_FILE;

  /**
   ** fsl_flush_f() implementation which requires state to be
   ** a writeable (FILE*) handle.
   */
  int fsl_flush_f_FILE(void * state);

  /**
   ** fsl_output_f() implementation which requires state to be
   ** a writeable (FILE*) handle.
   */
  int fsl_output_f_FILE( void * state, void const * src, fsl_size_t n );

  /**
   ** fsl_outputer initializer which uses fsl_flush_f_FILE(),
   ** fsl_output_f_FILE(), and fsl_finalizer_f_FILE().
   */
#define fsl_outputer_FILE_m {                   \
    fsl_output_f_FILE,                          \
      fsl_flush_f_FILE,                         \
      {/*state*/                                \
        NULL,                                   \
        {NULL,fsl_finalizer_f_FILE}             \
      }                                         \
  }
    
  /**
   **
   ** A general-purpose buffer buffer, analog to Fossil v1's Blob
   ** class. It is not called fsl_blob to avoid confusion with DB-side
   ** Blobs. Buffers are used extensively in fossil to do everything
   ** from reading files to compressing artifacts to creating
   ** dynamically-formatted strings. Because they are such a pervasive
   ** low-level type, and have such a simple structure, their members
   ** (unlike most other structs in this API) may be considered public
   ** and used directly by client code (as long as they do not mangle
   ** their state, e.g. by setting this->capacity smaller than
   ** this->used!).
   **
   ** @see fsl_buffer_reserve()
   ** @see fsl_buffer_append()
   ** @see fsl_buffer_appendf()
   */
  struct fsl_buffer {
    /**
     ** The raw memory owned by this buffer. It is this->capacity bytes
     ** long, of which this->used are considered "used" by the client.
     ** The difference beween (this->capacity - this->used) represents
     ** space the buffer has available for use before it will require
     ** another expansion/reallocation.
     */
    unsigned char * mem;
    /**
     ** Number of bytes allocated for this buffer.
     */
    fsl_size_t capacity;
    /**
     ** Number of "used" bytes in the buffer. This is generally
     ** interpreted as the virtual EOF (the one-past-the-end) position
     ** of this->mem.
     **
     ** Library routines which manipulate buffers must ensure that
     ** (this->used<=this->capacity) is always true, expanding the
     ** buffer if necessary. Much of the API assumes that precondition
     ** is always met, and any violation of it opens the code to
     ** undefined behaviour (which is okay, just don't ever break that
     ** precondition).
     */
    fsl_size_t used;
  };
  /** Empty-initialized fsl_buffer instance. */
#define fsl_buffer_empty_m {NULL,0U,0U}
  /** Empty-initialized fsl_buffer instance. */
  extern const fsl_buffer fsl_buffer_empty;
    
  /**
   ** A container for storing generic error state.
   */
  struct fsl_error {
    /**
     ** Error message text is stored in this->msg.mem.  The usable text
     ** part is this->msg.used bytes long.
     */
    fsl_buffer msg;
    /**
     ** Error code, generally assumed to be a fsl_rc_t value.
     */
    int code;
  };
  /** Empty-initialized fsl_error instance. */
#define fsl_error_empty_m {fsl_buffer_empty_m,0}
  /** Empty-initialized fsl_error instance. */
  extern const fsl_error fsl_error_empty;

  /**
   ** Populates err with the given code and formatted string, replacing
   ** any existing state. If fmt==NULL then fsl_rc_cstr(rc) is used to
   ** get the error string.
   **
   ** Returns code on success, some other non-0 code on error.
   **
   ** As a special case, if 0==code then fmt is ignored and the error
   ** state is cleared. This will not free any memory held by err but
   ** will re-set its string to start with a NUL byte, read for re-use
   ** later on.
   **
   ** As a special case, if code==FSL_RC_OOM then fmt is ignored
   ** to avoid a memory allocation (which would presumably fail).
   **
   ** @see fsl_error_get()
   ** @see fsl_error_clean()
   ** @see fsl_error_move()
   */
  int fsl_error_set( fsl_error * err, int code, char const * fmt,
                     ... );

  /** va_list counterpart to fsl_cx_err_set(). */
  int fsl_error_setv( fsl_error * err, int code, char const * fmt,
                      va_list args );

  /**
   ** Fetches the error state from err. If !err it returns
   ** FSL_RC_MISUSE without side-effects, else it returns err's current
   ** error code.
   **
   ** If str is not NULL then *str will point to the raw
   ** (NUL-terminated) error string (which might be empty or even
   ** NULL). The memory for the string is owned by err and may be
   ** invalidated by any calls which take err as a non-const parameter
   ** OR which might modify it indirectly through its container, so the
   ** client is required to copy it if it is needed for later on.
   **
   ** If len is not NULL then *len will hold the length of the string
   ** (in bytes).
   **
   ** @see fsl_error_set()
   ** @see fsl_error_clean()
   ** @see fsl_error_move()
   */
  int fsl_error_get( fsl_error * err, char const ** str, fsl_size_t * len );

  /**
   ** Frees up any resources owned by err and sets its error code to 0,
   ** but does not free err. This is harmless no-op if !err or if err
   ** holds no dynamically allocated no memory.
   **
   ** @see fsl_error_set()
   ** @see fsl_error_get()
   ** @see fsl_error_move()
   */
  void fsl_error_clean( fsl_error * err );

  /**
   ** Swaps the error state of the two given error objects and then
   ** sets lower->code to 0 and lower->msg.used = 0, effectively
   ** clearing the error state but not immediately deallocating the
   ** memory.
   **
   ** This is intended for "uplifting" an error from one context
   ** to a higher one.
   **
   ** Results are undefined if either parameter is NULL or either is
   ** not properly initialized. i.e. neither may refer to uninitialized
   ** memory. Copying fsl_error_empty at declaration-time is a simple
   ** way to ensure that instances are cleanly initialized.
   */
  void fsl_error_move( fsl_error * lower, fsl_error * higher );

  /**
   ** This code replaces the v1 concept of g.zMainDbType, and provides
   ** a type ID tag which can be applied to fsl_db instances so that
   ** the library can figure out which DB is which. This is primarily
   ** important for certain queries, which need to know whether they
   ** are accessing the repo or config db, for example.
   **
   ** All that said, i'm not yet fully convinced that a straight port
   ** of the v1 model is the best option for how we internally manage
   ** DBs, so this is subject to eventual change or removal.
   **
   */
  enum fsl_db_role_t {
  /**
   ** Sentinel "no role" value.
   */
  FSL_DB_ROLE_NONE = 0,
  /**
   ** Analog to v1's "configdb".
   */
  FSL_DB_ROLE_CONFIG = 0x01,
  /**
   ** Analog to v1's "repository".
   */
  FSL_DB_ROLE_REPO = 0x02,
  /**
   ** Analog to v1's "localdb".
   */
  FSL_DB_ROLE_CHECKOUT = 0x04,
  /**
   ** Analog to v1's "main", which is basically an alias for the
   ** first checkout db opened.
   */
  FSL_DB_ROLE_MAIN = 0x08
  };
  typedef enum fsl_db_role_t fsl_db_role_t;

  /**
   ** Placeholder for sqlite3/4 type. We currently use v3 but will
   ** almost certainly switch to v4 at some point. Before we can do
   ** that we need an upgrade/migration path.
   */
  typedef struct sqlite3 sqlite3;

  /**
   ** A level of indirection to hide the actual db driver
   ** implementation from the public API. Whether or not the API
   ** uses/will use sqlite3 or 4 is undecided at this point.  We
   ** currently use 3 because (A) it bootstraps development and
   ** testing by letting us use existing fossil repos for testing and
   ** (B) it reduces the number of potential problems when porting
   ** SQL-heavy code from the v1 tree.
   */
  typedef sqlite3 fsl_dbh_t;

  /**
   ** Db handle wrapper/helper.
   */
  struct fsl_db {
    /**
     ** Fossil Context on whose behalf this instance is operating.
     */
    fsl_cx * f;
    /**
     ** Underlying db driver handle.
     */
    fsl_dbh_t * dbh;

    /**
     ** Holds error state from the underlying driver.  fsl_db and
     ** fsl_stmt operations which fail at the driver level "should"
     ** update this state to include error info from the driver.
     ** fsl_cx APIs which fail at the DB level then uplift this (using
     ** fsl_error_move()) so that they can pass it on to the caller.
     */
    fsl_error error;

    /**
     ** Holds the file name used when opening this db.
     */
    fsl_buffer filename;

    /**
     ** Holds the database name for use in creating queries.
     ** Might or might not be set/needed, depending on
     ** the context.
     */
    fsl_buffer name;

    
    /**
     ** Describes what role this db connection plays in
     ** fossil (if any). We may or may not still need this.
     */
    int role;
    
    /**
     ** Debugging/test counter. Closing a db with opened statements
     ** might assert() or trigger debug output when the db is closed.
     */
    int openStatementCount;

    /**
     ** A marker which tells fsl_db_close() whether or not this
     ** API allocated this instance (in which case fsl_db_close()
     ** will fsl_free() it) or not (in which case it does not free()
     ** it).
     */
    void const * allocStamp;
  };
  /** Empty-initialized fsl_db instance. */
#define fsl_db_empty_m {                        \
    NULL/*f*/,                                  \
      NULL/*dbh*/,                              \
      fsl_error_empty_m /*error*/,              \
      fsl_buffer_empty_m/*filename*/,           \
      fsl_buffer_empty_m/*name*/,               \
      FSL_DB_ROLE_NONE,                         \
      0/*openStatementCount*/,                  \
      NULL/*allocStamp*/                        \
      }

  /** Empty-initialized fsl_db instance. */
  extern const fsl_db fsl_db_empty;

  /**
   ** If db is not NULL then this function returns its name (the one
   ** used to open it). The bytes are valid until the db connection is
   ** closed. If len is not NULL then *len is (on success) assigned to
   ** the length of the returned string, in bytes.  The string is
   ** NUL-terminated, so fetching the length (by passing a non-NULL 2nd
   ** parameter) is optional.
   **
   ** Returns NULL if !f or f has no checkout opened.
   */
  char const * fsl_db_filename(fsl_db const * db, fsl_size_t * len);


  /**
   ** Generic memory alloc/free/realloc interface().
   **
   ** Implementations must behave as follows:
   **
   ** - If 0==n then semantically behave like free(3) and return
   ** NULL.
   **
   ** - If 0!=n and !mem then semantically behave like malloc(3).
   **
   ** - If 0!=n and NULL!=mem then semantically behave like
   ** realloc(3). Note that realloc specifies: "If n was equal to 0,
   ** either NULL or a pointer suitable to be passed to free() is
   ** returned." Which is kind of useless, and thus implementations
   ** MUST return NULL when n==0.
   */
  typedef void *(*fsl_realloc_f)(void * state, void * mem, fsl_size_t n);

  /**
   ** Holds an allocator function and its related state.
   */
  struct fsl_allocator {
    /**
     ** Base allocator function. It must be passed this->state
     ** as its first parameter.
     */
    fsl_realloc_f f;
    /**
     ** State intended to be passed as the first parameter to
     ** this->f().
     */
    void * state;
  };

  /** Empty-initialized fsl_allocator instance. */
#define fsl_allocator_empty_m {NULL,NULL}


  /**
   ** A fsl_realloc_f() implementation which uses the standard
   ** malloc()/free()/realloc(). The state parameter is ignored.
   */
  void * fsl_realloc_f_stdalloc(void * state, void * mem, fsl_size_t n);

  /**
   ** Library-wide allocator. If modified by the client then it must be
   ** changed before the library allocates any resources. The default
   ** uses the C-standard de/re/allocators.
   */
  extern fsl_allocator fsl_memory_allocator;
  /**
   ** Placeholder for external sqlite3_stmt.
   */
  typedef struct sqlite3_stmt sqlite3_stmt;
  typedef sqlite3_stmt fsl_stmt_t;
  /**
   ** Represents a prepared statement handle.
   ** Intended usage:
   **
   ** @code
   ** fsl_stmt st = fsl_stmt_empty;
   ** int rc = fsl_stmt_prepare( f, &st, "..." );
   ** if(rc){
   **   assert(!st.stmt);
   **   // Error! Use fsl_cx_err_get() to find out if
   **   // the db driver told us something helpful.
   ** }else{
   **   // ...use st and eventually finalize it:
   **   fsl_stmt_finalize( &st );
   ** }
   ** @endcode
   */
  struct fsl_stmt {
    /**
     ** The db which prepared this statement.
     */
    fsl_db * db;
    /**
     ** Underlying db driver-level statement handle.
     */
    fsl_stmt_t * stmt;
    /**
     ** SQL used for preparing this statement.
     */
    fsl_buffer sql;
    /**
     ** Number of result columns in this statement.
     */
    int colCount;
    /**
     ** Number of bound parameter indexes in this statement.
     */
    int paramCount;

    /**
     ** A marker which tells fsl_stmt_finalize() whether or not this
     ** API allocated this instance (in which case fsl_stmt_finalize()
     ** will fsl_free() it) or not (in which case it does not free()
     ** it).
     */
    void const * allocStamp;
  };
  /**
   ** Empty-initialized fsl_stmt instance, intended for
   ** copy-constructing.
   */
  extern const fsl_stmt fsl_stmt_empty;

  /**
   ** Prepares an SQL statement for execution. On success it returns 0,
   ** populates tgt with the statement's state, and the caller is
   ** obligated to eventually pass tgt to fsl_stmt_finalize().
   **
   ** On error non-0 is returned and tgt is not modified. If
   ** preparation of the statement fails at the db level then FSL_RC_DB
   ** is returned f's error state (fsl_cx_err_get()) will contain more
   ** details about the problem.
   **
   ** sql and the following arguments are applied as printf-style formatting,
   ** and any formatting options supported by fsl_appendf() may be used
   ** here. 
   ** 
   */
  int fsl_stmt_prepare( fsl_db *db, fsl_stmt * tgt, char const * sql, ... );

  /**
   ** va_list counterpart of fsl_stmt_prepare().
   */
  int fsl_stmt_preparev( fsl_db *db, fsl_stmt * tgt, char const * sql, va_list args );

  /**
   ** Frees memory associated with stmt but does not free stmt unless
   ** it was allocated by fsl_stmt_malloc(). These objects are normally
   ** stack-allocated. Returns FSL_RC_MISUSE if !stmt or it has already
   ** been finalized (but was not freed).
   */
  int fsl_stmt_finalize( fsl_stmt * stmt );

  /**
   ** "Steps" the given SQL cursor one time and returns one of the
   ** following: FSL_RC_STEP_ROW, FSL_RC_STEP_DONE, FSL_RC_STEP_ERROR.
   ** On a db error this will update the underlying the underlying db's
   ** error state.
   **
   ** Returns FSL_RC_MISUSE if !stmt or stmt has not been prepared.
   */
  int fsl_stmt_step( fsl_stmt * stmt );

  /**
   ** A callback for use with fsl_stmt_each(). It will be called one
   ** time for each row fetched, passed the statement object and the
   ** state parameter passed as the 3rd parameter to fsl_stmt_each().
   ** If it returns non-0 then iteration stops and that code is
   ** returned UNLESS it returns FSL_RC_BREAK, in which case
   ** fsl_stmt_each() stops iteration and returns 0.
   **
   ** It is strictly illegal for a callback to step() the statement.
   ** It must only read the current column data (or similar metatdata,
   ** e.g. column names) from the statement.
   */
  typedef int (*fsl_stmt_each_f)( void * state, fsl_stmt * stmt );

  /**
   ** Calls the given callback one time for each result row in the
   ** given statement. It applies no meaning to the callbackState
   ** parameter - that is passed as-is to the callback. See
   ** fsl_stmt_each_f() for the semantics of the callback.
   **
   ** Returns 0 on success. Returns FSL_RC_MISUSE if !stmt or
   ** !callback.
   */
  int fsl_stmt_each( fsl_stmt * stmt, fsl_stmt_each_f callback,
                     void * callbackState );

  /**
   ** Resets the given statement, analog to sqlite3_reset(). Should be
   ** called one time between step() iterations when running multiple
   ** INSERTS, UPDATES, etc. via the same statement.
   **
   ** Returns 0 on success.
   */
  int fsl_stmt_reset( fsl_stmt * stmt );

  /**
   ** Returns the name of the given 0-based result column index, or
   ** NULL if !stmt, stmt is not prepared, or index is out out of
   ** range. The returned bytes are owned by the statement object and
   ** may be invalidated shortly after this is called, so the caller
   ** must copy the returned value if it needs to have any useful
   ** lifetime guarantees. It's a bit more complicated than this, but
   ** assume that any API calls involving the statement handle might
   ** invalidate the colum name bytes.
   **
   ** The API guarantees that the returned value is either NULL or
   ** NUL-terminated.
   */
  char const * fsl_stmt_col_name(fsl_stmt * stmt, int index);
  
  /**
   ** Returns the result column count for the given statement, or -1 if
   ** !stmt or it has not been prepared. Note that this value is cached
   ** when the statement is created. Note that non-fetching queries
   ** (e.g. INSERT and UPDATE) have a column count of 0. Some non-SELECT
   ** constructs, e.g. PRAGMA table_info(tname), behave like SELECT
   ** and have a positive column count.
   */
  int fsl_stmt_col_count( fsl_stmt const * stmt );

  /**
   ** Returns the bound parameter count for the given statement, or -1
   ** if !stmt or it has not been prepared. Note that this value is
   ** cached when the statement is created.
   */
  int fsl_stmt_param_count( fsl_stmt const * stmt );

  /**
   ** Binds NULL to the given 1-based parameter index.  Returns 0 on
   ** succcess. Sets the DB's error state on error.
   */
  int fsl_stmt_bind_null( fsl_stmt * stmt, int index );

  /**
   ** Binds v to the given 1-based parameter index.  Returns 0 on
   ** succcess. Sets the DB's error state on error.
   */
  int fsl_stmt_bind_int32( fsl_stmt * stmt, int index, fsl_int32_t v );

  /**
   ** Binds v to the given 1-based parameter index.  Returns 0 on
   ** succcess. Sets the DB's error state on error.
   */
  int fsl_stmt_bind_int64( fsl_stmt * stmt, int index, fsl_int64_t v );

  /**
   ** Binds v to the given 1-based parameter index.  Returns 0 on
   ** succcess. Sets the Fossil context's error state on error.
   */
  int fsl_stmt_bind_double( fsl_stmt * stmt, int index, fsl_double_t v );

  /**
   ** Binds the first n bytes of v as text to the given 1-based bound
   ** parameter column in the given statement. If makeCopy is true then
   ** the binding makes an copy of the data. Set makeCopy to false ONLY
   ** if you KNOW that the bytes will outlive the binding.
   **
   ** Returns 0 on success. On error stmt's underlying db's error state
   ** is updated, hopefully with a useful error message.
   */
  int fsl_stmt_bind_text( fsl_stmt * stmt, int index,
                          char const * v, fsl_int_t n,
                          char makeCopy );
  /**
   ** Binds the first n bytes of v as a blob to the given 1-based bound
   ** parameter column in the given statement. See fsl_stmt_bind_text()
   ** for the semantics of the makeCopy parameter and return value.
   */
  int fsl_stmt_bind_blob( fsl_stmt * stmt, int index,
                          void const * v, fsl_int_t len,
                          char makeCopy );

  /**
   ** Gets an integer value from the given 0-based result set column,
   ** assigns *v to that value, and returns 0 on success.
   **
   ** Returns FSL_RC_RANGE if index is out of range for stmt.
   */
  int fsl_stmt_get_int32( fsl_stmt * stmt, int index, fsl_int32_t * v );

  /**
   ** Gets an integer value from the given 0-based result set column,
   ** assigns *v to that value, and returns 0 on success.
   **
   ** Returns FSL_RC_RANGE if index is out of range for stmt.
   */
  int fsl_stmt_get_int64( fsl_stmt * stmt, int index, fsl_int64_t * v );

  /**
   ** Gets double value from the given 0-based result set column,
   ** assigns *v to that value, and returns 0 on success.
   **
   ** Returns FSL_RC_RANGE if index is out of range for stmt.
   */
  int fsl_stmt_get_double( fsl_stmt * stmt, int index, fsl_double_t * v );

  /**
   ** Gets a string value from the given 0-based result set column,
   ** assigns *out (if out is not NULL) to that value, assigns *outLen
   ** (if outLen is not NULL) to *out's length, and returns 0 on
   ** success. Ownership of the string memory is passed to the caller,
   ** who must eventually pass it to fsl_free() to free it.
   **
   ** Returns FSL_RC_RANGE if index is out of range for stmt.
   */
  int fsl_stmt_get_text( fsl_stmt * stmt, int index, char const **out, fsl_int_t * outLen );

  /**
   ** The Blob counterpart of fsl_stmt_get_text(). Identical to that
   ** function except that its output result (3rd paramter) type
   ** differs, and it fetches the data as a raw blob, without any sort
   ** of string interpretation.
   **
   ** Returns FSL_RC_RANGE if index is out of range for stmt.
   */
  int fsl_stmt_get_blob( fsl_stmt * stmt, int index, void const **out, fsl_int_t * outLen );

  /**
   ** Executes multiple SQL statements, ignoring any results they might
   ** collect. Returns 0 on success, non-0 on error.  On error
   ** db->error might be updated to report the problem.
   */
  int fsl_db_exec_multi( fsl_db * db, const char * sql, ...);

  /**
   ** va_list counterpart of db_exec_multi().
   */
  int fsl_db_exec_multiv( fsl_db * db, const char * sql, va_list args);

  /**
   ** Executes a single SQL statement, skipping over any results
   ** it may have. Returns 0 on success. On error db's error state
   ** may be updated.
   */
  int fsl_db_exec( fsl_db * db, char const * sql, ... );

  /**
   ** va_list counterpart of fs_db_exec().
   */
  int fsl_db_execv( fsl_db * db, char const * sql, va_list args );

  /**
   ** UNTESTED.
   **
   ** Runs a fetch-style SQL query against DB and returns the first
   ** column of the first result row via *rv. If the query returns no
   ** rows, *rv is not modified. The intention is that the caller sets
   ** *rv to his preferred default (or sentinel) value before calling
   ** this.
   **
   ** The format string (the sql parameter) accepts all formatting
   ** options supported by fsl_appendf().
   **
   ** Returns 0 on success. On error db's error state is updated and
   ** *rv is not modified.
   **
   ** Returns FSL_RC_MISUSE without side effects if !db, !rv, !sql,
   ** or !*sql.
   */
  int fsl_db_get_int32( fsl_db * db, fsl_int32_t * rv,
                        char const * sql, ... );
  /**
   ** va_list counterpart of fsl_db_get_int32().
   */
  int fsl_db_get_int32v( fsl_db * db, fsl_int32_t * rv,
                         char const * sql, va_list args);

  /**
   ** UNTESTED.
   **
   ** The int64 counterpart of fsl_db_get_int32().
   */
  int fsl_db_get_int64( fsl_db * db, fsl_int64_t * rv,
                        char const * sql, ... );

  /**
   ** va_list counterpart of fsl_db_get_int64().
   */
  int fsl_db_get_int64v( fsl_db * db, fsl_int64_t * rv,
                         char const * sql, va_list args);

  /**
   ** UNTESTED.
   **
   ** The double counterpart of fsl_db_get_int32().
   */
  int fsl_db_get_double( fsl_db * db, fsl_double_t * rv,
                         char const * sql, ... );

  /**
   ** va_list counterpart of fsl_db_get_double().
   */
  int fsl_db_get_doublev( fsl_db * db, fsl_double_t * rv,
                          char const * sql, va_list args);
  
  /**
   ** UNTESTED.
   **
   ** The String counterpart of fsl_db_get_int32(). On success *rv will
   ** be set to a dynamically allocated string copied from the first
   ** column of the first result row. If rvLen is not NULL then *rvLen
   ** will be assigned the byte length of that string. If no row is
   ** found, *rv is not modified.
   */
  int fsl_db_get_text( fsl_db * db, char ** rv, fsl_size_t * rvLen,
                       char const * sql, ... );

  /**
   ** va_list counterpart of fsl_db_get_text().
   */
  int fsl_db_get_textv( fsl_db * db, char ** rv, fsl_size_t * rvLen,
                        char const * sql, va_list args );

  /**
   ** UNTESTED.
   **
   ** The Blob counterpart of fsl_db_get_text(). Identical to that
   ** function except that its output result (2nd paramter) type
   ** differs, and it fetches the data as a raw blob, without any sort
   ** of string interpretation.
   */
  int fsl_db_get_blob( fsl_db * db, void ** rv, fsl_size_t * stmtLen,
                       char const * sql, ... );

  /**
   ** va_list counterpart of fsl_db_get_blob().
   */
  int fsl_db_get_blobv( fsl_db * db, void ** rv, fsl_size_t * stmtLen,
                        char const * sql, va_list args );

  /**
   ** UNTESTED.
   **
   ** Similar to fsl_db_get_text() and fsl_db_get_blob(), but writes
   ** its result to tgt, overwriting any existing memory it might hold.
   **
   ** If asBlob is true then the underlying BLOB API is used to
   ** populate the buffer, else the underlying STRING/TEXT API is used.
   */
  int fsl_db_get_buffer( fsl_db * db, fsl_buffer * tgt,
                         char asBlob,
                         char const * sql, ... );

  /**
   ** va_list counterpart of fsl_db_get_buffer().
   */
  int fsl_db_get_bufferv( fsl_db * db, fsl_buffer * tgt,
                          char asBlob,
                          char const * sql, va_list args );

  /**
   ** Expects sql to be a SELECT-style query which (potentially)
   ** returns a result set. For each row in the set callback() is
   ** called, as described for fsl_stmt_each(). Returns 0 on success.
   **
   ** Returns FSL_RC_MISUSE if !db, db is not opened, !callback,
   ** !sql, or !*sql.
   */
  int fsl_db_each( fsl_db * db, fsl_stmt_each_f callback,
                   void * callbackState, char const * sql, ... );

  /**
   ** va_list counterpart to fsl_db_each().
   */
  int fsl_db_eachv( fsl_db * db, fsl_stmt_each_f callback,
                    void * callbackState, char const * sql, va_list args );

  /**
   ** A part of the configuration used by fsl_cx_init() and friends.
   **
   */
  struct fsl_cx_config {
    /**
     ** If true, all SQL which goes through the fossil engine
     ** will be traced to the fsl_output()-configured channel.
     */
    char traceSql;
    /**
     ** If true, the print() SQL function will output its output to the
     ** fsl_output()-configured channel, else it is a no-op.
     */
    char sqlPrint;
  };
  /**
   ** fsl_cx_config instance initialized with useful defaults.
   */
#define fsl_cx_config_empty_m {                 \
    0/*traceSql*/,                              \
      0/*sqlPrint*/                             \
      }
  extern const fsl_cx_config fsl_cx_config_empty;
  /**
     Parameters for fsl_cx_init().
  */
  struct fsl_init_param {
    /**
       The output channel for the Fossil instance.
    */
    fsl_outputer output;
    /** ... what else? Config db file name? Default repo file to open? 
        We have a chicken/egg scenario with some bits,
        e.g. fsl_buffer_reserve() requires a fsl_cx, so we can't use
        buffers to create file name strings until after the ctx is
        initialized. Or we need extra buffer APIs which take a
        fsl_allocator instead of a fsl_cx parameter. Or we need to set
        the allocator as part of the buffer class. That would not be
        bad but would be memory-expensive - buffers are showing up
        everywhere.
    */
    fsl_cx_config config;
  };
  typedef struct fsl_init_param fsl_init_param;

  /** Empty-initialized fsl_init_param instance. */
#define fsl_init_param_empty_m {fsl_outputer_empty_m, fsl_cx_config_empty_m}
  /**
   ** fsl_init_param instance initialized to use stdout for output and
   ** the standard system memory allocator.
   */
#define fsl_init_param_default_m {fsl_outputer_FILE_m, fsl_cx_config_empty_m}

  /** Empty-initialized fsl_init_param instance. */
  extern const fsl_init_param fsl_init_param_empty;

  /**
   ** fsl_init_param instance initialized to use stdout for output and
   ** the standard system memory allocator. Used as the default when
   ** fsl_cx_init() is passed a NULL value for this parameter.
   */
  extern const fsl_init_param fsl_init_param_default;

  /**
   ** Initializes a fsl_cx instance. tgt must be a pointer to NULL,
   ** e.g.:
   **
   ** @code
   ** fsl_cxt * f = NULL;
   ** int rc = fsl_cx_init( &f, NULL );
   ** @endcode
   **
   ** If the second parameter is NULL then default implementations
   ** are used for the context's output and allocation routines.  If
   ** it is not NULL then param->allocator and param->output must be
   ** initialized properly before calling this function. The contents
   ** of param are bitwise copied by this function and ownership is
   ** transfered to *tgt in all cases except one:
   **
   ** If this function cannot allocate a new instance it immediately
   ** returns FSL_RC_OOM and does not modify *tgt. In this case,
   ** ownership of param's contents is not changed. On any other
   ** error, ownership of param's contents are transfered to *tgt and
   ** the client is responsible for passing *tgt ot
   ** fsl_cxt_finalize() when he is done with it. Note that (like in
   ** sqlite3), *tgt may be valid memory even if this function fails,
   ** and the caller must pass it to fsl_cx_finalize() whether or
   ** not this function succeeds unless it fails at the initial OOM
   ** (which the client can check by seeing if (*tgt) is NULL, but
   ** only if he set it to NULL before calling this).
   **
   ** Returns 0 on success, FSL_RC_OOM on an allocation error,
   ** FSL_RC_MISUSE if (!tgt).
   */
  int fsl_cx_init( fsl_cx ** tgt, fsl_init_param * param );

  /**
   ** Frees all memory associated with f, which must have been
   ** initialized using fsl_cx_init() (or equivalent).
   **
   ** Returns FSL_RC_MISUSE if !f, else 0.
   */
  int fsl_cx_finalize( fsl_cx * f );

  /**
   ** Sets the Fossil error state to the given error code and
   ** fsl_appendf()-style format string/arguments. On success it
   ** returns the code parameter. It does not return 0 unless code is
   ** 0, and if it returns a value other than code then something went
   ** seriously wrong (e.g. allocation error: FSL_RC_OOM) or the
   ** arguments were invalid: !f results in FSL_RC_MISUSE.
   **
   ** If !fmt then fsl_rc_cstr(code) is used to create the
   ** error string.
   **
   ** As a special case, if code is FSL_RC_OOM, no error string is
   ** allocated (because it would likely fail, assuming the OOM
   ** is real).
   **
   ** As a special case, if code is 0 (the non-error value) then fmt is
   ** ignored and any error state is cleared.
   */
  int fsl_cx_err_set( fsl_cx * f, int code, char const * fmt, ... );

  /**
   ** va_list counterpart to fsl_cx_err_set().
   */
  int fsl_cx_err_setv( fsl_cx * f, int code, char const * fmt,
                       va_list args );

  /**
   ** Fetches the error state from f. See fsl_error_get() for the semantics
   ** of the parameters and return value.
   */
  int fsl_cx_err_get( fsl_cx * f, char const ** str, fsl_size_t * len );

  /**
   ** Roles equate to permissions in Fossil v1. Here we implement them
   ** as a bitmask and hope we never need more than 31 of them.
   */
  enum fsl_roles_t {
  FSL_ROLE_GUEST = 0,
  FSL_ROLE_ANONYMOUS = 1,
  FSL_ROLE_ADMIN = 1 << 1,
  FSL_ROLE_SETUP  = 1 << 2,
  FSL_ROLE_READ = 1 << 3,
  FSL_ROLE_COMMIT = 1 << 4,
  FSL_ROLE_ALL = 0x7FFFFFFF
  /* unsigned 32-bit+ enums are not portable :/ */
  };
  typedef enum fsl_roles_t fsl_roles_t;

  /**
   ** Holds type ID tags for the db-level types which have a
   ** fsl_db_record-derived class.
   */
  enum fsl_db_type_t {
  FSL_TYPE_INVALID = 0,
  FSL_TYPE_USER = 1,
  FSL_TYPE_TAG = 2
  /* ... */
  };
  typedef enum fsl_db_type_t fsl_db_type_t;

  /**
   ** Base type for db record classes. Each db record subclass must
   ** have a fsl_db_record instance as its first struct member (for
   ** C-level casting reasons).
   */
  struct fsl_db_record {
    fsl_db_type_t typeId; /* const? */
    fsl_id_t dbId;
    /* maybe put mtime field here b/c it's used by several classes */

    /**
     ** For creating linked lists of records, for algorithms which
     ** want to return multiple records. Its concrete type is
     ** determined by this->typeId.
     */
    void * next;
  };
  typedef struct fsl_db_record fsl_db_record;
  extern const fsl_db_record fsl_db_record_empty;

  struct fsl_user {
    fsl_db_record base;
    fsl_buffer name;
    fsl_int32_t roles; /* bitmask of fsl_roles_t values */
    fsl_time_t mtime; /* ??? */
  };
  typedef struct fsl_user fsl_user;
  extern const fsl_user fsl_user_empty;
    
  struct fsl_tag {
    fsl_db_record base;
    fsl_buffer key;
    fsl_buffer value;
  };
  typedef struct fsl_tag fsl_tag;
  extern const fsl_tag fsl_tag_empty;

  /**
   ** Represents a db blob, not fossil's Blob class.
   */
  struct fsl_blob {
    fsl_db_record base;
    fsl_time_t mtime;
#if 0
    /* "raw" SHA1 digest */
    unsigned char digest[20]; 
    /* OR... */
#else
    /**
     ** 40-byte SHA1 plus terminating NUL.
     */
    char sha1[41];
#endif
    /* the latter is probably more useful/easier */
  };
  typedef struct fsl_blob fsl_blob;
#if 0
  /**
   ** Elided: abstractions   suitable for  adding an ORM-like  layer.
   ** That would   be taking it  too far,  i  think. If,  however, we
   ** decide   to   abstract away  the    DB  completely then  a CRUD
   ** abstraction API would   indeed make sense.  Except  that fossil
   ** hasn't much  need for  the  'D'  in CRUD,   so  it'd be  a  CRU
   ** abstraction API.
   */
#endif


  /**
   ** Semantically behaves like malloc(3), but may introduce instrumentation,
   ** error checking, or similar.
   */
  void * fsl_malloc( fsl_size_t n );

  /**
   ** Semantically behaves like free(3), but may introduce instrumentation,
   ** error checking, or similar.
   */
  void fsl_free( void * mem );

  /**
   ** Behaves like realloc(3). Clarifications on the behaviour (because
   ** the standard has one case of unfortunate wording involving what
   ** it returns when n==0):
   **
   ** - If passed (NULL, n>0) then it semantically behaves like
   ** fsl_malloc(f, n).
   **
   ** - If 0==n then it semantically behaves like free(2) and returns
   ** NULL (clarifying the aforementioned wording problem).
   **
   ** - If passed (non-NULL, n) then it semantically behaves like
   ** realloc(mem,n).
   **
   ** Returns NULL if !f.
   ** 
   */
  void * fsl_realloc( void * mem, fsl_size_t n );

  /**
   ** Reserves at least n bytes of capacity in buf. Returns 0 on
   ** success, FSL_RC_OOM if allocation fails, FSL_RC_MISUSE if !buf.
   **
   ** This does not change buf->used, nor will it shrink the buffer
   ** (reduce buf->capacity) unless n is 0, in which case it
   ** immediately frees buf->mem and sets buf->capacity and buf->used
   ** to 0.
   */
  int fsl_buffer_reserve( fsl_buffer * buf, fsl_size_t n );

  /**
   ** Resets buf->used to 0 and sets buf->mem[0] (if buf->mem is not
   ** NULL) to 0. Does not (de)allocate memory, only changes the
   ** logical "used" size of the buffer. Returns 0 on success,
   ** FSL_RC_MISUSE if !buf.
   **
   ** Achtung for v1 porters: this function's semantics are much
   ** different from the v1 blob_reset(). To get those semantics,
   ** use fsl_buffer_reserve(buf, 0).
   */
  int fsl_buffer_reset( fsl_buffer * buf );

  /**
   ** Similar to fsl_buffer_reserve() except that...
   **
   ** - It does not free all memory when n==0. Instead it essentially
   ** makes the memory a length-0, NUL-terminated string.
   **
   ** - It will try to shrink (realloc) buf's memory if (n<buf->capacity).
   **
   ** - It sets buf->capacity to (n+1) and buf->used to n. This routine
   ** allocates one extra byte to ensure that buf is always
   ** NUL-terminated.
   **
   ** - On success it always NUL-terminates the buffer at
   ** offset buf->used.
   **
   ** Returns 0 on success, FSL_RC_MISUSE if !buf, FSL_RC_OOM if
   ** (re)allocation fails.
   */
  int fsl_buffer_resize( fsl_buffer * buf, fsl_size_t n );

  /**
   ** Swaps the contents of the left and right arguments. Results are
   ** undefined if either argument is NULL or points to uninitialized
   ** memory.
   */
  void fsl_buffer_swap( fsl_buffer * left, fsl_buffer * right );

  /**
   ** Similar fsl_buffer_swap() but it also optionally frees one of
   ** the buffer's memories after swapping them. If clearWhich is
   ** negative then the left buffer (1st arg) is cleared _after_
   ** swapping (i.e., the NEW left hand side gets cleared). If
   ** clearWhich is greater than 0 then the right buffer (2nd arg) is
   ** cleared _after_ swapping (i.e. the NEW right hand side gets
   ** cleared). If clearWhich is 0, this function behaves identically
   ** to fsl_buffer_swap().
   */
  void fsl_buffer_swap_free( fsl_buffer * left, fsl_buffer * right, char clearWhich );  
  /**
   **
   ** Appends the first n bytes of src to b, expanding b as
   ** necessary. If n is less than 0 then the equivalent of
   ** fsl_strlen((char const*)src) is used to calculate the length.
   **
   ** Returns 0 on success, FSL_RC_MISUSE if !f, !b, or !src,
   ** FSL_RC_OOM if allocation of memory fails. It returns 0 without
   ** side-effects if 0==n or if ((n<0) and !*src).
   **
   ** If this function appends anything, it guarantees that it
   ** NUL-terminates the buffer (but that the NUL terminator is not
   ** counted in b->used).
   */
  int fsl_buffer_append( fsl_buffer * b,
                         void const * src, fsl_int_t n );

  /**
   ** Uses fsl_appendf() to append formatted output to the given buffer.
   ** Returns 0 on success, FSL_RC_MISUSE if !f or !dest,
   */
  int fsl_buffer_appendf( fsl_buffer * dest,
                          char const * fmt, ... );

  /** va_list counterpart to fsl_buffer_appendfv(). */
  int fsl_buffer_appendfv( fsl_buffer * dest,
                           char const * fmt, va_list args );

  /**
   ** Compresses the first pIn->used bytes of pIn to pOut. It is ok for
   ** pIn and pOut to be the same blob.
   **
   ** pOut must either be the same as pIn or else cleanly
   ** initialized/empty.
   **
   ** Results are undefined if any argument is NULL.
   **
   ** Returns 0 on success, FSL_RC_OOM on allocation error, and FSL_RC_ERROR
   ** if the lower-level compression routines fail.
   **
   ** TODO: add a streaming variant which takes the input from a
   ** fsl_input_f() and pushes the output to a fsl_output_f(). The code
   ** exists in the libwhio source tree already.
   **
   ** TODO: if pOut!=pIn1 then re-use pOut's memory, if it has any.
   */
  int fsl_buffer_compress(fsl_buffer const *pIn, fsl_buffer *pOut);

  /**
   ** Compress the concatenation of a blobs pIn1 and pIn2 into pOut.
   **
   ** pOut must be either uninitialized or must be the same as either pIn1 or
   ** pIn2.
   **
   ** Results are undefined if any argument is NULL.
   **
   ** Returns 0 on success, FSL_RC_OOM on allocation error, and FSL_RC_ERROR
   ** if the lower-level compression routines fail.
   **
   ** TODO: if pOut!=(pIn1 or pIn2) then re-use its memory, if it has any.
   */
  int fsl_buffer_compress2(fsl_buffer *pIn1,
                           fsl_buffer *pIn2, fsl_buffer *pOut);

  /**
   ** Uncompress buffer pIn and store the result in pOut. It is ok for
   ** pIn and pOut to be the same buffer. Returns 0 on success. On
   ** error pOut is not modified.
   **
   ** pOut must be either cleanly initialized/empty or the same as pIn.
   **
   ** Results are undefined if any argument is NULL.
   **
   ** Returns 0 on success, FSL_RC_OOM on allocation error, and
   ** FSL_RC_ERROR if the lower-level decompression routines fail.
   **
   ** TODO: add a streaming variant which takes the input from a
   ** fsl_input_f() and pushes the output to a fsl_output_f(). The code
   ** exists in the libwhio source tree already.
   **
   ** TODO: if pOut!=(pIn1 or pIn2) then re-use its memory, if it has any.
   */
  int fsl_buffer_uncompress(fsl_buffer const *pIn, fsl_buffer *pOut);

  /**
   ** Returns true if this function believes that mem (which must be
   ** at least len bytes of valid memory long) appears to have been
   ** compressed by fsl_buffer_compress() or equivalent. This is not
   ** a 100% reliable check - it could have false positives on certain
   ** inputs, but it is thought to be unlikely.
   **
   ** Returns 0 if mem is NULL.
   */
  char fsl_data_is_compressed(unsigned char const * mem, fsl_size_t len);

  /**
   ** Equivalent to fsl_data_is_compressed(buf->mem, buf->used).
   */
  char fsl_buffer_is_compressed(fsl_buffer const * buf);

  /**
   ** Equivalent to ((char const *)b->mem), but returns NULL if !b. The
   ** returned memory is effectively b->used bytes long unless the user
   ** decides to apply his own conventions.
   */
  char const * fsl_buffer_cstr(fsl_buffer const *b);

  /**
   ** If buf is not NULL and has any memory allocated to it, that
   ** memory is returned. If both b and len are not NULL then *len is
   ** set to b->used. If b has no dynamic memory then NULL is returned
   ** and *len (if len is not NULL) is set to 0.
   **/
  char const * fsl_buffer_cstr2(fsl_buffer const *b, fsl_size_t * len);

  /**
   ** Equivalent to ((char *)b->mem), but returns NULL if !b. The
   ** returned memory is effectively b->used bytes long unless the user
   ** decides to apply his own conventions.
   */
  char * fsl_buffer_str(fsl_buffer const *b);

  /*
  ** Returns the "used" size of b, or 0 if !b.
  */
  fsl_size_t fsl_buffer_size(fsl_buffer const * b);
  /*
  ** Returns the current capacity of b, or 0 if !b.
  */
  fsl_size_t fsl_buffer_capacity(fsl_buffer const * b);
  
  /**
   ** Compares the contents of buffers lhs and rhs using memcmp(3)
   ** semantics. Return negative, zero, or positive if the first
   ** buffer is less then, equal to, or greater than the second.
   ** Results are undefined if either argument is NULL.
   **
   ** When buffers of different length match on the first N bytes,
   ** where N is the shorter of the two buffers' lengths, it treats the
   ** shorter buffer as being "less than" the longer one.
   */
  int fsl_buffer_compare(fsl_buffer const * lhs, fsl_buffer const * rhs);

  /**
   ** Compare two buffers in constant (a.k.a. O(1)) time and return
   ** zero if they are equal.  Constant time comparison only applies
   ** for buffers of the same length.  If lengths are different,
   ** immediately returns 1.
   */
  int fsl_buffer_compare_O1(fsl_buffer const * lhs, fsl_buffer const * rhs);


  /**
   ** Uses a fsl_input_f() function to buffer input into a fsl_buffer.
   **
   ** dest must be a non-NULL, initialized (though possibly empty)
   ** fsl_buffer object. Its contents, if any, will be overwritten by
   ** this function, and any memory it holds might be re-used.
   **
   ** The src function is called, and passed the state parameter, to
   ** fetch the input. If it returns non-0, this function returns that
   ** error code. src() is called, possibly repeatedly, until it
   ** reports that there is no more data.
   **
   ** Whether or not this function succeeds, dest still owns any memory
   ** pointed to by dest->mem, and the client must eventually free it
   ** by calling fsl_buffer_reserve(dest,0).
   **
   ** dest->mem might (and possibly will) be (re)allocated by this
   ** function, so any pointers to it held from before this call might
   ** be invalidated by this call.
   **
   ** On error non-0 is returned and dest has almost certainly been
   ** modified but its state must be considered incomplete.
   **
   ** Errors include:
   **
   ** dest or src are NULL (FSL_RC_MISUSE)
   **
   ** Allocation error (FSL_RC_OOM)
   **
   ** src() returns an error code
   **
   ** Whether or not the state parameter may be NULL depends on the src
   ** implementation requirements.
   **
   ** On success dest will contain the contents read from the input
   ** source. dest->used will be the length of the read-in data, and
   ** dest->mem will point to the memory. dest->mem is automatically
   ** NUL-terminated if this function succeeds, but dest->used does not
   ** count that terminator. On error the state of dest->mem must be
   ** considered incomplete, and is not guaranteed to be
   ** NUL-terminated.
   **
   ** Example usage:
   **
   ** @code
   ** fsl_buffer buf = fsl_buffer_empty;
   ** int rc = fsl_buffer_fill_from( &buf,
   **                                fsl_input_FILE,
   **                                stdin );
   ** if( rc ){
   **   fprintf(stderr,"Error %d (%s) while filling buffer.\n",
   **   rc, fsl_rc_cstr(rc));
   **   fsl_buffer_reserve( &buf, 0 );
   **   return ...;
   ** }
   ** ... use the buf->mem ...
   ** ... clean up the buffer ...
   ** fsl_buffer_reserve( &buf, 0 );
   ** @endcode
   **
   ** To take over ownership of the buffer's memory, do:
   **
   ** @code
   ** void * mem = buf.mem;
   ** buf = fsl_buffer_empty;
   ** @endcode
   **
   **
   ** In which case the memory must eventually be passed to fsl_free()
   ** to free it.
   */
  int fsl_buffer_fill_from( fsl_buffer * dest, fsl_input_f src, void * state );

  /**
     A fsl_buffer_fill_from() proxy which overwrite's dest->mem
     with the contents of the given FILE handler (which must be
     opened for read access).  Returns 0 on success, after which
     dest->mem contains dest->used bytes of content from the input
     source. On error dest may be partially filled.
  */
  int fsl_buffer_fill_from_FILE( fsl_buffer * dest, FILE * src );

  /**
     Wrapper for fsl_buffer_fill_from_FILE() which gets its input
     from the given file name. As a special case it interprets the
     name "-" as stdin.
  */
  int fsl_buffer_fill_from_filename( fsl_buffer * dest, char const * filename );    

  
  /**
   ** Outputs the first n bytes of src to f's configured output
   ** channel. Returns 0 on success, FSL_RC_MISUSE if (!f || !src),
   ** 0 (without side effects) if !n, else it returns the result of
   ** the underlying output call. This is a harmless no-op if f is
   ** configured with no output channel.
   */
  int fsl_output( fsl_cx * f, void const * src, fsl_size_t n );

  /**
   ** Uses fsl_appendf() to append formatted output to the channel
   ** configured for use with fsl_output().
   */
  int fsl_outputf( fsl_cx * f, char const * fmt, ... );

  /** va_list counterpart to fsl_outputf(). */
  int fsl_outputfv( fsl_cx * f, char const * fmt, va_list args );

  /**
   ** Uses fsl_appendf() to create a dynamically-allocated string.
   ** On success the new string is returned to the caller, who must
   ** eventually pass it to fsl_free() or fsl_realloc() to free it.
   */
  char * fsl_mprintf( char const * fmt, ... );

  /** Equivalent to fsl_mprintfv(). */
  char * fsl_mprintfv( char const * fmt, va_list args );

  /**
   ** Equivalent to strdup(3) but returns NULL if !src.  The returned
   ** memory must eventually be passed to fsl_free().
   */
  char * fsl_strdup( char const * src );
  
  /**
   ** Equivalent to strlen(3) but returns 0 if src is NULL.
   ** Note that it counts bytes, not UTF characters.
   */
  fsl_size_t fsl_strlen( char const * src );

  /**
   ** Like strcmp() except that it accepts NULL pointers.  NULL sorts
   ** before all non-NULL string pointers.  Also, this strcmp() is a
   ** binary comparison that does not consider locale.
   */
  int fsl_strcmp( char const * lhs, char const * rhs );

  /**
   ** Case-insensitive form of fsl_strcmp().
   */
  int fsl_stricmp(const char *zA, const char *zB);

  /**
   ** fsl_strcmp() variant which compares at most nByte bytes
   ** of the given strings, case-insensitively.
   */
  int fsl_strnicmp(const char *zA, const char *zB, int nByte);

  /**
   ** fsl_strcmp() variant which compares at most nByte bytes
   ** of the given strings, case-sensitively.
   */
  int fsl_strncmp(const char *zA, const char *zB, int nByte);

  /**
   ** Flags for use with fsl_db_open() and friends.
   */
  enum fsl_open_flags {
  /**
   ** The "no flags" value.
   */
  FSL_OPEN_F_NONE = 0,
  /**
   ** Flag for fsl_db_open() specifying that the db should be opened
   ** in read-only mode.
   */
  FSL_OPEN_F_RO = 0x01,
  /**
   ** Flag for fsl_db_open() specifying that the db should be opened
   ** in read-write mode, but should not create the db if it does
   ** not already exist.
   */
  FSL_OPEN_F_RW = 0x02,
  /**
   ** Flag for fsl_db_open() specifying that the db should be opened in
   ** read-write mode, creating the db if it does not already exist.
   */
  FSL_OPEN_F_CREATE = 0x04,
  /**
   ** Shorthand for RW+CREATE flags.
   */
  FSL_OPEN_F_RWC = FSL_OPEN_F_RW | FSL_OPEN_F_CREATE,
  /**
   ** Indicates that a routine should not fail if the given file
   ** does not yet exist. It should create it in this case (if possible
   ** for the given routine). Not all routines honor this flag.
   */
  FSL_OPEN_F_NOT_FOUND_OK = 0x10,
  /**
   ** Tells fsl_cx_repo_open_xxx() to confirm that the db
   ** is a repository.
   */
  FSL_OPEN_F_SCHEMA_VALIDATE = 0x20
  };
  
 
  /**
   ** Quivalent to fopen(3) but expects name to be UTF8-encoded.
   */
  FILE * fsl_fopen(char const * name, char const *mode);

  /**
   ** Opens the given db file and populates db with its handle.  db
   ** must have been cleanly initialized by copy-constructing it from
   ** fsl_db_empty or allocating it using fsl_db_malloc(). Failure to
   ** do so will lead to undefined behaviour.
   **
   ** openFlags may be a mask of FSL_OPEN_F_xxx values. If
   ** FSL_OPEN_F_NOT_FOUND_OK is _not_ set in openFlags and dbFile
   ** does not exist, it will return FSL_RC_NOT_FOUND. The existence
   ** of FSL_OPEN_F_CREATE in the flags trumps FSL_OPEN_F_NOT_FOUND_OK,
   ** so a not-found error is not reported if openMode contains has the
   ** FSL_OPEN_F_CREATE bit set.
   **
   ** Returns FSL_RC_MISUSE if !db, !dbFile, !*dbFile, or
   ** if db->dbh is not NULL.
   **
   ** On error db->dbh will not be set, but db->dbh.error might contain
   ** error details.
   **
   ** Regardless of success or failure, db should be passed to
   ** fsl_db_close() to free up all memory associated with it. It is
   ** not closed automatically by this function because doing so cleans
   ** up the error state, which the caller will presumably want to
   ** have.
   **
   ** If db->f is not NULL then it is assumed that db should be plugged
   ** in to the repository system, and the following additions things
   ** happen:
   **
   ** - A number of SQL functions are registered with the db.
   **
   ** - If db->FSL_OPEN_F_SCHEMA_VALIDATE is set in openFlags then the
   ** db is validated to see if it has a fossil schema.  If that
   ** validation fails, FSL_RC_REPO_NEEDS_REBUILD or FSL_RC_NOT_A_REPO
   ** will be returned and db's error state will be updated.
   **
   **
   ** Note that this is a lower level operation than the fossil
   ** binary's 'open' command, and simply initializes f's db-related
   ** resources, and does not check out any files.
   */
  int fsl_db_open( fsl_db * db, char const * dbFile, int openFlags );

  /**
   ** Closes the given db handle and frees any resources owned by
   ** db. Returns 0 on success.
   **
   ** If db was allocated using fsl_db_alloc() (as determined by
   ** examining db->allocStamp) then this routine also fsl_free()s it,
   ** otherwise it is assumed to either be on the stack or part of a
   ** larger struct and is not freed.
   */
  int fsl_db_close( fsl_db * db );

  /**
   ** Allocates a new fsl_db instance(). Returns NULL on allocation
   ** error. Note that fsl_db instances can often be used from the
   ** stack - allocating them dynamically is an uncommon case necessary
   ** for script bindings.
   **
   ** Achtung: the returned value's allocStamp member is used for
   ** determining if fsl_db_close() should free the value or not.  Thus
   ** if clients copy over this value without adjusting allocStamp back
   ** to its original value, the library will likely leak the instance.
   ** Been there, done that.
   */
  fsl_db * fsl_db_malloc();

  /**
   ** The fsl_stmt counterpart of fsl_db_malloc(). See that function
   ** for when you might want to use this and a caveat involving the
   ** allocStamp member of the returned value. fsl_stmt_finalize() will
   ** free statements created with this function.
   */
  fsl_stmt * fsl_stmt_malloc();
  
  /**
   ** Opens the given db file name as f's repository. Returns 0 on
   ** success. On error it sets f's error state and returns that code
   ** unless the error was FSL_RC_MISUSE (which indicates invalid
   ** arguments and it does not set the error state).
   **
   ** Fails with FSL_RC_MISUSE if !f, !repoDbFile, !*repoDbFile. Returns
   ** FSL_RC_ACCESS if f already has an opened repo db.
   **
   ** Returns FSL_RC_NOT_FOUND if repoDbFile is not found, as this
   ** routine cannot create a new repository db.
   **
   ** openFlags is a bitmask of FSL_OPEN_F_xxx. If it is 0 then this
   ** default is used: (FSL_OPEN_F_RW | FSL_OPEN_F_SCHEMA_VALIDATE).
   **
   ** fsl_db_open() for the meaning of the openFlags parameter
   ** and various other details.
   */
  int fsl_cx_repo_open_db( fsl_cx * f, char const * repoDbFile, int openFlags );

  /**
   **
   ** Tries to open a checked-out fossil repository db in the given
   ** directory. It looks for files named (_FOSSIL_, .fslckout), in
   ** that order in the given directory. If neither is found then it
   ** moves up the path one directory and tries again, until it
   ** hits the root of the dirPath (see below for a note/caveat).
   **
   ** If dirName is NULL then it behaves as if it has been passed the
   ** absolute path of the current directory (as determined by
   ** fsl_getcwd()).
   **
   ** dirName is not NULL and dirNameLen is <0 then fsl_strlen() is
   ** used to calculate dirName's len.
   **
   ** Achtung: if dirName is relative, this routine might not find a
   ** checkout where it would find one if given an absolute path
   ** (because it traverses the path string given it instead of its
   ** canonical form). Wether or not this is a bug or a feature is not
   ** yet clear. When in doubt, use fsl_file_canonical_name() to
   ** normalize the directory name before passing it in here. If it
   ** turns out that we always want that behaviour, this routine
   ** will/should be modified to canonicalize the name.
   **
   ** If this routine finds/opens a checkout, it also tries to open
   ** the repository database from which the checkout derives.
   **
   ** Returns 0 on success. If there is an error opening or validating
   ** the checkout or its repository db, f's error state will be
   ** updated. Error codes/conditions include:
   **
   ** - FSL_RC_MISUSE if f is NULL.
   **
   ** - FSL_RC_ACCESS if f has already opened a checkout as
   ** its main database (it can only handle one at a time).
   **
   ** - FSL_RC_OOM if an allocation fails.
   **
   ** - FSL_RC_RANGE if dirname is not NULL but has a length of 0,
   ** either because 0 was passed in for dirNameLen or because
   ** dirNameLen was negative and *dirName is a NUL byte.
   **
   ** - Various codes from fsl_getcwd() (if dirName is NULL).
   **
   **
   ** TODOs:
   **
   ** - automatically open repo db based on checkout's repo. Awaiting
   ** porting of some db-level utility code.
   **
   ** - If a repo db has already been opened, ensure that it belongs
   ** to the checkout being opened, else return FSL_RC_MISUSE or
   ** FSL_RC_CONSISTENCY, or maybe a new code.
   ** 
   */
  int fsl_cx_checkout_open( fsl_cx * f, char const * dirName, fsl_int_t dirNameLen );

  /**
   ** If fsl_cx_checkout_open() has been used to open a checkout db,
   ** this call closes that db and returns 0. Returns FSL_RC_MISUSE if
   ** !f, FSL_RC_NOT_A_CHECKOUT if f has not opened a checkout as its
   ** primary DB.
   **
   ** If alsoCloseRepo is true and a repository DB is opened then
   ** it is also closed.
   **
   ** TODO: also close repo db here?
   */
  int fsl_cx_checkout_close( fsl_cx * f, char alsoCloseRepo );
  
  /**
   ** If f is not NULL and has a checkout db opened then this function
   ** returns its name. The bytes are valid until that checkout db
   ** connection is closed. If len is not NULL then *len is (on
   ** success) assigned to the length of the returned string, in
   ** bytes. The string is NUL-terminated, so fetching the length (by
   ** passing a non-NULL 2nd parameter) is optional.
   **
   ** Returns NULL if !f or f has no checkout opened.
   **
   ** @see fsl_cx_checkout_open()
   ** @see fsl_cx_checkout_dir_name()
   */
  char const * fsl_cx_checkout_db_file(fsl_cx const * f,
                                       fsl_size_t * len);


  /**
   ** Equivalent to fsl_cx_checkout_db_file() except that
   ** it applies to the name of the opened repository db,
   ** if any.
   */
  char const * fsl_cx_repo_db_file(fsl_cx const * f,
                                   fsl_size_t * len);

  /**
   ** Equivalent to fsl_cx_checkout_db_file() except that
   ** it applies to the name of the opened config db,
   ** if any.
   */
  char const * fsl_cx_config_db_file(fsl_cx const * f,
                                     fsl_size_t * len);

  /**
   ** Equivalent to fsl_cx_checkout_db_file() except that
   ** it applies to db file implied by the specified role
   ** (2nd parameter). If no such role is opened, or the
   ** role is invalid, NULL is returned.
   **
   ** FIXME: the 1st parameter "should" be const - it is not modified
   ** here - but it currently cannot be without violating an internal
   ** constness guaranty which can be fixed with a little code
   ** duplication.
   */
  char const * fsl_cx_db_file_for_role(fsl_cx * f,
                                       fsl_db_role_t r,
                                       fsl_size_t * len);

  /**
   ** If f has an opened checkout db (from fsl_cx_checkout_open())
   ** then this function returns the directory part of the path
   ** for the checkout. The returned bytes are valid until that db
   ** connection is closed. If len is not NULL then *len is (on
   ** success) assigned to the length of the returned string, in bytes.
   ** The string is NUL-terminated, so fetching the length (by passing
   ** a non-NULL 2nd parameter) is optional.
   **
   ** Returns NULL if !f or f has no checkout opened.
   **
   ** @see fsl_cx_checkout_open()
   ** @see fsl_cx_checkout_db_name()
   */
  char const * fsl_cx_checkout_dir_name(fsl_cx const * f,
                                        fsl_size_t * len);


  /**
   ** Returns a handle to f's main db, or NULL if !f.
   **
   ** The current architecture sets up an in-memory DB
   ** as the main db and ATTACHes all others. Whether or not
   ** this is a simpler/better approach than managing
   ** multiple DB connections is as yet unclear.
   **/
  fsl_db * fsl_cx_db( fsl_cx * f );

  /**
   ** If f is not NULL and has had its repo opened via
   ** fsl_cx_repo_open_db() or similar, this returns a pointer to that
   ** database, else it returns NULL.
   */
  fsl_db * fsl_cx_db_repo( fsl_cx * f );

  /**
   ** If f is not NULL and has had a checkout opened via
   ** fsl_cx_checkout_open() or similar, this returns a pointer to that
   ** database, else it returns NULL.
   */
  fsl_db * fsl_cx_db_checkout( fsl_cx * f );

  /**
   ** IN PROGRESS/INCOMPLETE
   **
   ** Opens the given database file as f's configuration database. If f
   ** already has a config database opened, it is closed before opening
   ** the new one. The database is created and populated with an
   ** initial schema if needed.
   **
   ** If dbName is NULL or empty then it uses a default db name,
   ** "probably" under the user's home directory. To get the name of
   ** the database after it has been opened/attached, use
   ** fsl_cx_config_db_file().
   **
   **
   ** TODO: strongly consider supporting non-attached use of
   ** the config db. Comments in v1 suggest that it is possible
   ** to lock the config db for other apps when it is attached
   ** to a long-running op by a fossil process.
   **
   ** These notes do not apply, but it may be (re)added later:
   **
   ** If useAttach is 0 (the most common case), the db is opened in
   ** its own connection, otherwise it is ATTACH'd to the currently
   ** opened db. The latter case is unusual, but allows one to create
   ** queries which join against multiple databases. When in doubt,
   ** pass 0 here.
   **
   */
  int fsl_cx_config_open( fsl_cx * f, char const * dbName );

  /**
   ** Closes/detaches the database connection opened by
   ** fsl_cx_config_open().   
   */
  int fsl_cx_config_close( fsl_cx * f );
  
  /*
  ** If f has an opened configuration db then its handle is returned.
  ** It will return NULL if the config db was opened via "attaching"
  ** it. See fsl_cx_config_open().
  */
  fsl_db * fsl_cx_db_config( fsl_cx * f );
  
#if 0
  /**
   ** TODO.
   **
   ** Should create a new fossil repo db. Do we need some sort of progress
   ** callback here? Creation is fast, so probably not.
   **
   */
  int fsl_cx_repo_create_db( fsl_cx * f, char const * repoDbFile, int flags /**???*/ );
#endif

  /**
   ** If fsl_cx_repo_open_xxx() has been used to open a respository db,
   ** this call closes that db and returns 0. Returns FSL_RC_MISUSE if
   ** !f.
   **
   ** FSL_RC_NOT_A_REPO if f has not opened a repository.
   **
   ** TODO: also close checkout db here?
   */
  int fsl_cx_repo_close( fsl_cx * f );

  /**
   ** Convenience form of fsl_stmt_prepare() which uses f's db.
   ** Returns 0 on success, FSL_RC_MISUSE if !f or !sql, FSL_RC_RANGE
   ** if !*sql.
   */
  int fsl_cx_prepare( fsl_cx *f, fsl_stmt * tgt, char const * sql, ... );

  /**
   ** va_list counterpart of fsl_cx_prepare().
   */
  int fsl_cx_preparev( fsl_cx *f, fsl_stmt * tgt, char const * sql, va_list args );

  /**
   ** @typedef long (*fsl_appendf_f)( void * arg, char const * data, long n )
   **
   ** The fsl_appendf_f typedef is used to provide fsl_appendfv() with
   ** a flexible output routine, so that it can be easily send its
   ** output to arbitrary targets.
   **
   ** The policies which implementations need to follow are:
   **
   ** - arg is an implementation-specific pointer (may be 0) which is
   ** passed to vappendf. fsl_appendfv() doesn't know what this
   ** argument is but passes it to its fsl_appendf_f. Typically it
   ** will be an object or resource handle to which string data is
   ** pushed or output.
   **
   ** - The 'data' parameter is the data to append. If it contains
   ** embedded nulls, this function will stop at the first one. Thus
   ** it is not binary-safe.
   **
   ** - n is the number of bytes to read from data. If n<0 then
   ** strlen(data) should be used.
   **
   ** - Returns, on success, the number of bytes appended (may be 0).
   **
   ** - Returns, on error, an implementation-specified negative
   ** number.  Returning a negative error code will cause
   ** fsl_appendfv() to stop the processing of that string. Note that
   ** 0 is a success value (some printf format specifiers do not add
   ** anything to the output).
   */
  typedef long (*fsl_appendf_f)( void * arg,
                                 char const * data,
                                 long n );

  /**
   ** This function works similarly to classical printf
   ** implementations, but instead of outputing somewhere specific, it
   ** uses a callback function to push its output somewhere. This
   ** allows it to be used for arbitrary external representations. It
   ** can be used, for example, to output to an external string, a UI
   ** widget, or file handle (it can also emulate printf by outputing
   ** to stdout this way).
   **
   ** INPUTS:
   **
   ** pfAppend: The is a fsl_appendf_f function which is responsible
   ** for accumulating the output. If pfAppend returns a negative
   ** integer then processing stops immediately.
   **
   ** pfAppendArg: is ignored by this function but passed as the first
   ** argument to pfAppend. pfAppend will presumably use it as a data
   ** store for accumulating its string.
   **
   ** fmt: This is the format string, as in the usual printf().
   **
   ** ap: This is a pointer to a list of arguments.  Same as in
   ** vprintf() and friends.
   **
   **
   ** OUTPUTS:
   **
   ** The return value is the total number of characters sent to the
   ** function "func", or a negative number on a pre-output error. If
   ** this function returns an integer greater than 1 it is in general
   ** impossible to know if all of the elements were output. As such
   ** failure can only happen if the callback function returns an
   ** error, and this type of error is very rare in a printf-like
   ** context, this is not considered to be a significant problem. (The
   ** same is true for any classical printf implementations.) Clients
   ** may use their own state objects which can propagate errors from
   ** their own internals back to the caller, but generically speaking
   ** it is difficult to trace errors back through this routine.  Then
   ** again, it only breaks when using using a broken output routine or
   ** bad output state.
   **
   ** CURRENT (documented) PRINTF EXTENSIONS:
   **
   ** %%z works like %%s, but takes a non-const (char *) and vappendf
   ** deletes the string (using fsl_free()) after appending it to the
   ** output.
   **
   ** %%h (HTML) works like $%s but converts certain characters (namely
   ** '<' and '&') to their HTML escaped equivalents.
   **
   ** %%t (URL encode) works like %%s but converts certain characters
   ** into a representation suitable for use in an HTTP URL. (e.g. ' ' 
   ** gets converted to %%20)
   **
   ** %%T (URL decode) does the opposite of %t - it decodes URL-encoded
   ** strings.
   **
   ** %%r requires an int and renders it in "ordinal form". That is,
   ** the number 1 converts to "1st" and 398 converts to "398th".
   **
   ** %%q quotes a string as required for SQL. That is, '\'' characters
   ** get doubled.
   **
   ** %%Q as %%q, but includes the outer '\'' characters and null
   ** pointers replaced by SQL NULL.
   **
   ** %%/: requires a C-string parameter. Normalizes path-like strings
   ** by replacing backslashes with the One True Slash.
   **
   ** %%b: works like %%s but takes its input from a (fsl_buffer*)
   ** argument.
   **
   ** %%B: works like %%Q but takes its input from a (fsl_buffer*)
   ** argument.
   **
   ** These extensions may be disabled by setting certain macros when
   ** compiling fsl_appendf.c (see that file for details).
   **
   **
   ** FIXME? fsl_appendf_f() is an artifact of older code from which
   ** this implementation derives. The first parameter should arguably
   ** be replaced with fsl_output_f(), which does the same thing _but_
   ** has different return semantics (more reliable, because the
   ** current semantics report partial success as success in some
   ** cases). Doing this would require us to change the return
   ** semantics of this function, but that wouldn't necessarily be a
   ** bad thing (we don't rely on sprintf()-like return semantics all
   ** that much, AFAIK?). Or we just add a proxy which forwards to a
   ** fsl_output_f(). Oh, hey, that's what fsl_outputf() does.
   **
   ** TODO?: replace 'long' with either an int (using fsl_output_f()
   ** semantics) or an int using sprintf() semantics (as it is now).
   */
  long fsl_appendfv(fsl_appendf_f pfAppend, void * pfAppendArg,
                    const char *fmt, va_list ap );

  /**
   **
   ** Identical to fsl_appendfv() but takes a (...) ellipses list
   ** instead of a va_list.
   */
  long fsl_appendf(fsl_appendf_f pfAppend,
                   void * pfAppendArg,
                   const char *fmt,
                   ... );

  /**
   ** Emulates fprintf() using fsl_appendf(). Returns the result of
   ** passing the data through fsl_appendf() to the given file handle.
   */
  long fsl_appendf_FILE( FILE * fp, char const * fmt, ... );


  /**
   ** Works like fsl_appendfv(), but appends all output to a
   ** dynamically-allocated string, expanding the string as necessary
   ** to collect all formatted data. The returned NUL-terminated string
   ** is owned by the caller and it must be cleaned up using
   ** fsl_free(...). If !fmt, NULL is returned. It is conceivable that
   ** it returns NULL on a zero-length formatted string, e.g.  (%.*s)
   ** with (0,"...") as arguments, but it will only do that if the
   ** whole format string resolves to empty.
   */
  char * fsl_mprintf( char const * fmt, ... );

  /**
   ** va_list counterpart to fsl_mprintf().
   */
  char * fsl_mprintfv(char const * fmt, va_list vargs );

  /**
   ** Possibly reallocates self->list, changing its size. This function
   ** ensures that self->list has at least n entries. If n is 0 then
   ** the list is deallocated (but the self object is not), BUT THIS
   ** DOES NOT DO ANY TYPE-SPECIFIC CLEANUP of the items. If n is less
   ** than or equal to self->alloced then there are no side effects. If
   ** n is greater than self->alloced, self->list is reallocated and
   ** self->alloced is adjusted to be at least n (it might be bigger -
   ** this function may pre-allocate a larger value).
   **
   ** Passing an n of 0 when self->alloced is 0 is a no-op.
   **
   ** Newly-allocated slots will be initialized with NUL bytes.
   **
   ** Returns the total number of items allocated for self->list.  On
   ** success, the value will be equal to or greater than n (in the
   ** special case of n==0, 0 is returned). Thus a return value smaller
   ** than n is an error. Note that if n is 0 or self is NULL then 0 is
   ** returned.
   **
   ** The return value should be used like this:
   **
   ** @code
   ** fsl_size_t const n = number of bytes to allocate;
   ** if( n > fsl_list_reserve( myList, n ) ) { ... error ... }
   ** // Or the other way around:
   ** if( fsl_list_reserve( myList, n ) < n ) { ... error ... }
   ** @endcode
   */
  fsl_size_t fsl_list_reserve( fsl_list * self, fsl_size_t n );

  /**
   ** Appends a bitwise copy of cp to self->list, expanding the list as
   ** necessary and adjusting self->count.
   **
   ** Ownership of cp is unchanged by this call. cp may not be NULL.
   **
   ** Returns 0 on success, FSL_RC_MISUSE if any argument is NULL, or
   ** FSL_RC_OOM on allocation error.
   */
  int fsl_list_append( fsl_list * self, void * cp );

  /** @typedef typedef int (*fsl_list_visitor_f)(void * p, void * visitorState )
   **
   ** Generic visitor interface for fsl_list lists.  Used by
   ** fsl_list_visit(). p is the pointer held by that list entry and
   ** visitorState is the 4th argument passed to fsl_list_visit().
   **
   ** Implementations must return 0 on success. Any other value causes
   ** looping to stop and that value to be returned, but interpration
   ** of the value is up to the caller (it might or might not be an
   ** error, depending on the context). Note that client code may use
   ** custom values, and is not restricted to FSL_RC_xxx values.
   */
  typedef int (*fsl_list_visitor_f)(void * obj, void * visitorState );

  /**
   ** For each item in self->list, visitor(item,visitorState) is
   ** called.  The item is owned by self. The visitor function MUST
   ** NOT free the item, but may manipulate its contents if
   ** application rules do not specify otherwise.
   **
   **
   ** If order is 0 or greater then the list is traversed from start
   ** to finish, else it is traverse from end to begin.
   **
   **
   ** Returns 0 on success, non-0 on error.
   **
   ** If visitor() returns non-0 then looping stops and that code is
   ** returned.
   */
  int fsl_list_visit( fsl_list * self, char order,
                      fsl_list_visitor_f visitor, void * visitorState );

  /**
   **
   **
   ** Works similarly to the visit operation without the _p suffix
   ** except that the pointer the visitor function gets is a (**)
   ** pointing back to the entry within this list. That means that
   ** callers can assign the entry in the list to another value during
   ** the traversal process (e.g. set it to 0). If shiftIfNulled is
   ** true then if the callback sets the list's value to 0 then it is
   ** removed from the list and self->count is adjusted (self->alloced
   ** is not changed).
   */
  int fsl_list_visit_p( fsl_list * self, char order, char shiftIfNulled,
                        fsl_list_visitor_f visitor, void * visitorState );


  /**
   ** Returns 0 if the given file is readable. Flags may be any values
   ** accepted by the accept(2) resp. _waccept() system calls.
   */
  int fsl_file_access(const char *zFilename, int flags);

  /**
   ** Compute a canonical pathname for a file or directory.
   ** Make the name absolute if it is relative.
   ** Remove redundant / characters.
   ** Remove all /./ path elements.
   ** Convert /A/../ to just /.
   ** If the slash parameter is non-zero, the trailing slash, if any,
   ** is retained.
   **
   ** Returns 0 on success, FSL_RC_MISUSE if !zOrigName or !pOut,
   ** FSL_RC_OOM if an allocation fails.
   **
   ** pOut is _appended_ to, so be sure to set pOut->used=0 (or pass it
   ** to fsl_buffer_reset()) before calling this if you want to start
   ** writing at the beginning.
   */
  int fsl_file_canonical_name(const char *zOrigName,
                              fsl_buffer *pOut, char slash);

  /**
   ** Writes the absolute path name of the current directory to zBuf,
   ** which must be at least nBuf bytes long (nBuf includes the space
   ** for a trailing NUL terminator).
   **
   ** Returns FSL_RC_RANGE if the name would be too long for nBuf,
   ** FSL_RC_IO if it cannot determine the current directory (e.g. a
   ** side effect of having removed the directory at runtime or similar
   ** things), and 0 on success.
   **
   ** On success, if outLen is not NULL then the length of the string
   ** written to zBuf is assigned to *outLen The output string is
   ** always NUL-terminated.
   **
   ** On Windows, the name is converted from unicode to UTF8 and all '\\'
   ** characters are converted to '/'.  No conversions are needed on
   ** Unix.
   */
  int fsl_getcwd(char *zBuf, fsl_size_t nBuf, fsl_size_t * outLen);

  /**
   ** Return non-zero if string z matches glob pattern zGlob and zero
   ** if the pattern does not match. Always returns 0 if either
   ** argument is NULL.
   **
   ** Globbing rules:
   **
   **      '*'       Matches any sequence of zero or more characters.
   **
   **      '?'       Matches exactly one character.
   **
   **     [...]      Matches one character from the enclosed list of
   **                characters.
   **
   **     [^...]     Matches one character not in the enclosed list.
   */
  char fsl_str_glob(const char *zGlob, const char *z);

  /**
   ** Return the size of a file in bytes.  Return -1 if the file does not
   ** exist or is not stat()able.
   */
  fsl_int64_t fsl_file_size(const char *zFilename);

  /**
   ** Same as fsl_file_size(), but takes into account symlinks.
   ** (What does that mean, anyway?)
   */
  fsl_int64_t fsl_file_wd_size(const char *zFilename);

  /**
   ** Return the modification time for a file.  Return -1 if the file
   ** does not exist.
   */
  fsl_time_t fsl_file_mtime(const char *zFilename);

  /**
   ** Same as fsl_file_mtime(), but takes into account symlinks.
   */
  fsl_time_t fsl_file_wd_mtime(const char *zFilename);

  /**
   ** Return TRUE if the named file is an ordinary file or symlink
   ** and symlinks are allowed.
   ** Return false for directories, devices, fifos, etc.
   */
  int fsl_file_wd_isfile_or_link(const char *zFilename);

  /**
   ** Return TRUE if the named file is an ordinary file.  Return false
   ** for directories, devices, fifos, symlinks, etc.
   */
  int fsl_file_isfile(const char *zFilename);

  /**
   ** Same as fsl_file_isfile(), but takes into account symlinks.
   */
  int fsl_file_wd_isfile(const char *zFilename);
  /**
   ** Returns true if the given path appears to be absolute, else
   ** false. On Unix a path is absolute if it starts with a '/'.  On
   ** Windows a path is also absolute if it starts with a letter, a
   ** colon, and a backslash.
   */
  char fsl_file_is_absolute_path(const char *zPath);
  
  /**
   ** Returns true, else false if the given letter is an ASCII alphabet
   ** character.
   */
  char fsl_isalpha(int ch);
  char fsl_islower(int ch);
  char fsl_isspace(int c);
  char fsl_islower(int c);
  char fsl_isupper(int c);
  char fsl_isdigit(int c);
  char fsl_tolower(int c);
  char fsl_toupper(int c);
  char fsl_isalpha(int c);
  char fsl_isalnum(int c);

  typedef struct fsl_sha1_cx fsl_sha1_cx;

  /**
   ** Holds state for SHA1 calculations. They are to be used like this:
   **
   ** @code
   **  unsigned char digest[20]
   **  char hex[41];
   **  fsl_sha1_cx cx;
   **  fsl_sha1_init(&cx);
   **  ...call fsl_sha1_update(&cx,...) any number of times to
   **  ...incrementally calculate the hash.
   **  fsl_sha1_final(&cx, digest); // ends the calculation
   **  fsl_sha1_digest_to_base16(&cx, hex);
   **  // digest now contains the raw 20-byte SHA1 digest.
   **  // hex now contains the 40-byte SHA1 + a trailing NUL
   ** @endcode
   */
  struct fsl_sha1_cx {
    unsigned int state[5];
    unsigned int count[2];
    unsigned char buffer[64];
  };

  /**
   ** Initializes the given context with the initial SHA1 state.  This
   ** must be the first routine called on an SHA1 context, and passing
   ** this context to other SHA1 routines without first having passed
   ** it to this will lead to undefined results.
   */
  void fsl_sha1_init(fsl_sha1_cx *context);

  /**
   ** Updates the given context to include the hash of the first len bytes
   ** of the given data.
   */
  void fsl_sha1_update( fsl_sha1_cx *context, const unsigned char *data, unsigned int len);

  /**
   ** Add padding and finalizes the message digest. If digest is not
   ** NULL then it writes 20 bytes of digest to the 2nd parameter.
   */
  void fsl_sha1_final(fsl_sha1_cx *context, unsigned char * digest);

  /**
   ** Convert a digest into base-16.  digest must be at least 20
   ** bytes long (the SHA1 digest is stored in the first 20 bytes).
   ** zBuf must be at least 41 bytes long, for 40 characters of SHA1
   ** hash and 1 NUL byte.
   */
  void fsl_sha1_digest_to_base16(unsigned char *digest, char *zBuf);

  /**
   ** Compute the SHA1 checksum of pIn and stores the resulting
   ** checksum in the buffer pCksum.  pCksum's memory is re-used if is
   ** has any allocated to it. pCksum may == pIn, in which case this is
   ** a destructive operation (replacing the data to hash with its
   ** hash code).
   **
   ** Return 0 on success, FSL_RC_OOM if (re)allocating pCksum fails.
   */
  int fsl_sha1sum_buffer(fsl_buffer const *pIn, fsl_buffer *pCksum);

  /**
   ** Computes the SHA1 checksum of the first len bytes of the given
   ** string.  If len is negative then zInt must be NUL-terminated and
   ** fsl_strlen() is used to find its length..  The result is a
   ** length-40 string (+NUL byte) returned in memory obtained from
   ** fsl_malloc(), so it must be passed to fsl_free() to free it. If
   ** NULL==zIn or !len then NULL is returned.
   */
  char *fsl_sha1sum_cstr(const char *zIn, int len);

  /**
   ** NYI: missing some permissions bits from v1.
   **
   ** Compute the SHA1 checksum of a file on disk.  Store the resulting
   ** checksum in the buffer pCksum.
   **
   ** Returns 0 on success.
   */
  int fsl_sha1sum_file(const char *zFilename, fsl_buffer *pCksum);
  
  
#if defined(__cplusplus)
} /*extern "C"*/
#endif

#endif
/* NET_FOSSIL_SCM_FOSSIL2_H_INCLUDED */