Login
Artifact [fcab0d5938]
Login

Artifact fcab0d5938d8225a122942e6529f4009f8acabf1:


/* -*- 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_FSL_CONTENT_H_INCLUDED)
#define NET_FOSSIL_SCM_FSL_CONTENT_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 "fossil-db.h" /* MUST come first b/c of config macros */

#if defined(__cplusplus)
extern "C" {
#endif
  typedef struct fsl_card_F fsl_card_F;
  typedef struct fsl_card_J fsl_card_J;
  typedef struct fsl_card_Q fsl_card_Q;
  typedef struct fsl_card_T fsl_card_T;
  typedef struct fsl_deck fsl_deck;


  /**
   ** The types of control artifacts used by Fossil. Their numeric
   ** values are a hard-coded part of the Fossil architecture and must
   ** not be changed.
   */
  enum fsl_catype_t {
  /**
   ** Sentinel value used for some error reporting.
   */
  FSL_CATYPE_INVALID = -1,
  /**
   ** Sentinel value used to mark a deck as being "any" type. This is
   ** a placeholder on a deck's way to completion.
   */
  FSL_CATYPE_ANY = 0,
  /**
   ** Indicates a "manifest" artifact (a checkin record).
   */
  FSL_CATYPE_MANIFEST = 1,
  /**
   ** Indicates a "cluster" artifact. These are used during synchronization.
   */
  FSL_CATYPE_CLUSTER = 2,
  /**
   ** Indicates a "control" artifact (a tag change).
   */
  FSL_CATYPE_CONTROL = 3,
  /**
   ** Indicates a "wiki" artifact.
   */
   FSL_CATYPE_WIKI = 4,
  /**
   ** Indicates a "ticket" artifact.
   */
   FSL_CATYPE_TICKET = 5,
  /**
   ** Indicates a "manifest" artifact (a checkin record).
   */
   FSL_CATYPE_ATTACHMENT = 6,
  /**
   ** Indicates a "manifest" artifact (a checkin record).
   */
   FSL_CATYPE_EVENT = 7
  };
  typedef enum fsl_catype_t fsl_catype_t;

  /**
   ** Returns some arbitrary but distinct string for the given
   ** fsl_catype_t. The returned bytes are static and
   ** NUL-terminated. Intended primarily for debugging and informative
   ** purposes, not actual user output.
   */
  char const * fsl_catype_cstr(fsl_catype_t t);

  /**
   ** Categories of artifacts Fossil internally supports.
   **
   ** The numeric values come from the closely-related fsl_catype_t,
   ** but are not part of the internal Fossil architecture in
   ** this particular context (they are in a fsl_catype_t context,
   ** however).
   **
   ** TODO: we can consolidate this with fsl_catype_t, which covers
   ** these, if a bit more cryptically.
   */
  enum fsl_atype_t {
  /**
   ** Sentinel value indicating "any artifact type."
   */
  FSL_ATYPE_ANY = FSL_CATYPE_ANY,
  /**
   ** Indicates a "checkin" artifact or timeline event.
   */
  FSL_ATYPE_CHECKIN = FSL_CATYPE_MANIFEST,
  /**
   ** Indicates an "event" artifact or timeline event.
   */
  FSL_ATYPE_EVENT = FSL_CATYPE_EVENT,
  /**
   ** Indicates a "tag" artifact or timeline event.
   */
  FSL_ATYPE_TAG = FSL_CATYPE_CONTROL,
  /**
   ** Indicates a "ticket" artifact or timeline event.
   */
  FSL_ATYPE_TICKET = FSL_CATYPE_TICKET,
  /**
   ** Indicates a "wiki" artifact or timeline event.
   */
  FSL_ATYPE_WIKI = FSL_CATYPE_WIKI
  };
  typedef enum fsl_atype_t fsl_atype_t;

  /**
   ** For a given artifact type, it returns the key string used in the
   ** event.type db table. Returns NULL if passed an unknown value,
   ** otherwise the returned bytes are static and NUL-terminated. The
   ** type FSL_ATYPE_ANY returns "*", which can be used in GLOB
   ** clauses in queries.
   */
  char const * fsl_atype_cstr(fsl_atype_t t);  

  /**
   ** This function is a programmatic interpretation of
   ** this table:
   **
   ** http://fossil-scm.org/index.html/doc/trunk/www/fileformat.wiki#summary
   **
   ** For a given control artifact type and a card name in the form of
   ** the card name's letter (e.g. 'A', 'W', ...), this function
   ** returns 0 (false) if that card type is not permitted in this
   ** control artifact type, a negative value if the card is optional
   ** for this artifact type, and a positive value if the card type is
   ** required for this artifact type.
   **
   ** As a special case, if t==FSL_CATYPE_ANY then this function
   ** always returns a negative value as long as card is a valid card
   ** letter.
   **/
  char fsl_card_is_legal( fsl_catype_t t, char card );
  
  /**
   ** Permissions flags supported by Manifests. Their numeric values
   ** are a hard-coded part of the Fossil architecture and must not be
   ** changed.
   */
  enum fsl_mf_perm_t {
  /** Indicates a regular, writable file. */
  FSL_MF_PERM_REGULAR = 0,
  /** Indicates a regular file with the executable bit set. */
  FSL_MF_PERM_EXE = 0x1,
  /** Indicates a symlink. Note that symlinks do not have the
      executable bit set separately on Unix systems.
  */
  FSL_MF_PERM_LINK = 0x2
  };
  typedef enum fsl_mf_perm_t fsl_mf_perm_t;

  /**
   ** Artifact tag types used by the Fossil framework. Their values
   ** are a hard-coded part of the Fossil format, and not subject to
   ** change (only extension, possibly).
   **/
  enum fsl_tag_type {
  /**
   ** Sentinel value for use with constructors/initializers.
   */
  FSL_TAGTYPE_INVALID = -1,
  /**
   ** The "cancel tag" indiciator, a.k.a. an anti-tag.
   */
  FSL_TAGTYPE_CANCEL = 0,
  /**
   ** The "add tag" indicator, a.k.a. a singleton tag.
   */
  FSL_TAGTYPE_ADD = 1,
  /**
   ** The "propagating tag" indicator.
   */
  FSL_TAGTYPE_PROPAGATING = 2
  };
  typedef enum fsl_tag_type fsl_tag_type;

  /**
   ** Hard-coded IDs used by the 'tag' table of repository DBs. These
   ** values get installed as part of the base Fossil db schema in new
   ** repos, and they must never change.
   */
  enum fsl_tag_ids {
  /**
   ** DB string tagname='bgcolor'.
   */
  FSL_TAGID_BGCOLOR = 1,
  /**
   ** DB: tag.tagname='comment'.
   */
  FSL_TAGID_COMMENT = 2,
  /**
   ** DB: tag.tagname='user'.
   */
  FSL_TAGID_USER = 3,
  /**
   ** DB: tag.tagname='date'.
   */
  FSL_TAGID_DATE = 4,
  /**
   ** DB: tag.tagname='hidden'.
   */
  FSL_TAGID_HIDDEN = 5,
  /**
   ** DB: tag.tagname='private'.
   */
  FSL_TAGID_PRIVATE = 6,
  /**
   ** DB: tag.tagname='cluster'.
   */
  FSL_TAGID_CLUSTER = 7,
  /**
   ** DB: tag.tagname='branch'.
   */
  FSL_TAGID_BRANCH = 8,
  /**
   ** DB: tag.tagname='closed'.
   */
  FSL_TAGID_CLOSED = 9,
  /**
   ** DB: tag.tagname='parent'.
   */
  FSL_TAGID_PARENT = 10,

  /**
   ** Largest tag ID reserved for internal use.
   */
  FSL_TAGID_MAX_INTERNAL = 16
  };
  
  /**
   ** A "deck" stores (predictably enough) a collection of "cards."
   ** Cards are constructs embedded within Fossil's Control Artifacts
   ** to denote various sorts of changes in a Fossil repository, and a
   ** Deck encapsulates the cards for a single Control Artifact of an
   ** arbitrary type, e.g. Manifest or Cluster. A card is basically a
   ** command with a single-letter name and a well-defined signature
   ** for its arguments. Each card is represented by a member of this
   ** struct whose name is the same as the card type. Not all cards
   ** are valid in all Control Artifact types. See the list of valid
   ** card/construct combinations here:
   **
   ** http://fossil-scm.org/index.html/doc/trunk/www/fileformat.wiki#summary
   **
   ** fsl_card_is_legal() can be used determine if a given card type
   ** is legal (per the above chart) with a given Control Artifiact
   ** type (as stored in the fsl_deck::type member).
   **
   ** The type member is used by some algorithms to determine which
   ** operations are legal on a given Control Artifact type, so that
   ** they can fail long before the user gets a chance to add a
   ** malformed Control Artifact to the database. Clients who bypass
   ** the Deck APIs and manipulate the deck's members "by hand" (so to
   ** say) effectively invoke undefined behaviour.
   **
   ** The various routines to add/set cards in the deck are named
   ** fsl_deck_CARDNAME_add() resp. fsl_deck_CARDNAME_set(). The "add"
   ** functions represent cards which may appear multiple times
   ** (e.g. the 'F' card) or have multiple values (the 'P' card), and
   ** those named "set" represent unique or optional cards. The R-card
   ** is the outlier, with fsl_deck_R_calc().
   **
   ** Note that the 'Z' card is not in this structure because it is a
   ** hash of the other inputs and is calculated incrementally and
   ** appended automatically by fsl_deck_output(). Adding the Z card
   ** to this class would require that fsl_deck_output() and friends
   ** take a non-const deck object (because Z is calculated
   ** incrementally during output of the CA), which just seems
   ** philosophically wrong for an output operation.  It might be
   ** useful to expand fsl_deck_output() to write the Z card's result
   ** to an optional output parameter.
   **
   ** Maintenance reminder: please keep the card members alpha sorted to
   ** simplify eyeball-searching through their docs.
   **
   ** @see fsl_deck_init()
   ** @see fsl_deck_parse()
   ** @see fsl_deck_load_rid()
   ** @see fsl_deck_finalize()
   ** @see fsl_deck_malloc()
   ** @see fsl_deck_clean()
   ** @see fsl_deck_save()
   */
  struct fsl_deck {
    /**
     ** Specifies the the type (or eventual type) of this
     ** artifact. The function fsl_card_is_legal() can be used to
     ** determined if a given card type is legal for a given value of
     ** this member. APIs which add/set cards use that to determine if
     ** the operation requested by the client is semantically legal.
     */
    fsl_catype_t type;

    /**
     ** DB repo.blob.rid value. Normally set by fsl_deck_parse().
     */
    fsl_id_t rid;

    /**
     ** Gets set by fsl_deck_parse() to the hash/UUID of the
     ** manifest it parsed. Normally set by fsl_deck_parse().
     */
    fsl_uuid_str uuid;

    /**
     ** The Fossil context responsible for this deck. We store
     ** this so that some API routines to not require the caller
     ** to explicitly pass around the context.
     */
    fsl_cx * f;
    
    /**
     ** The 'A' (attachment) card. Only used by FSL_CATYPE_ATTACHMENT
     ** decks. The spec currently specifies only 1 A card per
     ** manifest, but conceptually this could/should be a list.
     */
    struct {
      /**
       ** Filename of the A card.
       */
      fsl_buffer name;

      /**
       ** Name of event or UUID of ticket or wiki page to which the
       ** attachment applies. For tickets/events, the "name" is its
       ** UUID.
       */
      char * tgt;

      /**
       ** UUID of the file being attached via the A card.
       */
      fsl_uuid_str src;
    } A;

    struct {
      /**
       ** The 'B' (baseline) card holds the UUID of baseline manifest.
       ** This is empty for baseline manifests and holds the UUID of
       ** the parent for delta manifests.
       */
      fsl_uuid_str uuid;

      /**
       ** Baseline manifest corresponding to this->B. It is loaded on
       ** demand. The parent/child relationship in Fossil is the
       ** reverse of conventional - children own their parents, not
       ** the other way around. i.e. this->baseline will get cleaned
       ** up (recursively) when this instance is cleaned up (when the
       ** containing deck is cleaned up).
       */
      fsl_deck * baseline;
    } B;
    /**
     ** The 'C' (comment) card.
     */
    fsl_buffer C;

    /**
     ** The 'D' (date) card, in Julian format.
     */
    fsl_double_t D;

    /**
     ** The 'E' (event) card.
     */
    struct {
      /**
       ** The 'E' card's date in Julian Day format.
       */
      fsl_double_t julian;

      /**
       ** The 'E' card's UUID.
       */
      fsl_uuid_str uuid;
    } E;

    /**
     ** The 'F' (file) card container.
     */
    struct {
      /**
       ** A list of 'F' (file) cards. Contains (fsl_card_F*)
       ** entries.
       */
      fsl_list list;
      /**
       ** An internal cursor into this->list used for certain
       ** operations.
       */
      fsl_int_t cursor;
    } F;

    /**
     ** The 'J' card specifies changes to "value" of "fields" in
     ** tickets (FSL_CATYPE_TICKET).
     **
     ** Holds (fsl_card_J*) entries.
     */
    fsl_list J;

    /**
     ** The 'L' (wiki name/title) card.
     */
    fsl_buffer L;

    /**
     ** UUID for the 'K' (ticket) card.
     */
    fsl_uuid_str K;

    /**
     ** List of UUIDs (char*) of ref'd objects in a cluster ('M' cards).
     */
    fsl_list M;

    /**
     ** The 'N' (content mime type) card.
     */
    fsl_buffer N;

    /**
     ** List of UUIDs of parents ('P' cards). Entries are of type
     ** (fsl_uuid_str*).
     */
    fsl_list P;

    /**
     ** 'Q' (cherry pick) cards. Holds (fsl_card_J*) entries.
     */
    fsl_list Q;

    /**
     ** The R card holds a hash which is calculated based on the
     ** names, sizes, and contents of the files included in a
     ** manifest.
     */
    fsl_uuid_str R;
    
    /**
     ** List of 'T' (tag) cards. Holds (fsl_card_T*) instances.
     */
    fsl_list T;

    /**
     ** The U (user) card.
     */
    fsl_buffer U;

    /**
     ** The W (wiki content) card.
     */
    fsl_buffer W;

    /**
     ** For propagating error state through certain parts of the API.
     */
    fsl_error error;

    /**
     ** Porting artifact - original content blob. Quite possibly not
     ** needed at this level of API abstraction.
     */
    fsl_buffer content;

    /**
     ** To be used for a manifest cache.
     */
    fsl_deck * next;
    
    /**
     ** A marker which tells fsl_deck_finalize() whether or not
     ** fsl_deck_malloc() allocated this instance (in which case
     ** fsl_deck_finalize() will fsl_free() it) or not (in which case
     ** it does not free() it).
     */
    void const * allocStamp;

  };

  /**
   ** Empty-initialized fsl_deck structure.
   */
  extern const fsl_deck fsl_deck_empty;

  /**
   ** Empty-initialized fsl_deck structure.
   */
#define fsl_deck_empty_m {                      \
    FSL_CATYPE_ANY /*type*/,                    \
    -1/*rid*/,\
    NULL/*uuid*/,\
    NULL/*f*/,\
    {/*A*/ fsl_buffer_empty_m /* name */,       \
           NULL /* tgt */,           \
           NULL /* src */},          \
    {/*B*/ NULL /*uuid*/,                        \
           NULL /*baseline*/},                      \
     fsl_buffer_empty_m /* C */,               \
     0.0 /*D*/,                        \
     {/*E*/ 0.0 /* julian */,                    \
            NULL /* uuid */},      \
     {/*F*/ fsl_list_empty_m /*list*/,0/*cursor*/},    \
     fsl_list_empty_m /* J */,                 \
     fsl_buffer_empty_m /* L */,               \
     NULL /* K */,               \
     fsl_list_empty_m /* M */,                 \
     fsl_buffer_empty_m /* N */,               \
     fsl_list_empty_m /* P */,                 \
     fsl_list_empty_m /* Q */,                 \
     NULL /* R */,                           \
     fsl_list_empty_m /* T */,                 \
     fsl_buffer_empty_m /* U */,               \
     fsl_buffer_empty_m /* W */,               \
     fsl_error_empty_m /* error */,            \
     fsl_buffer_empty_m/*content*/,             \
     NULL/*next*/,\
     NULL/*allocStamp*/ \
  }


  /**
   ** Allocates a new fsl_deck instance. Returns NULL on allocation
   ** error. The returned value must eventually be passed to
   ** fsl_deck_finalize() to free its resources.
   **
   ** @see fsl_deck_finalize()
   **/
  fsl_deck * fsl_deck_malloc();

  /**
   ** Frees all resources belonging to the given deck's members
   ** (including its parents, recursively), and wipes deck clean, but
   ** does not free() deck. Is a no-op if deck is NULL.
   **
   ** @see fsl_deck_finalize()
   */
  void fsl_deck_clean(fsl_deck *deck);
  
  /**
   ** Frees all memory owned by deck (see fsl_deck_clean()).  If deck
   ** was allocated using fsl_deck_malloc() then this function
   ** fsl_free()'s it, otherwise it does not free it.
   **
   ** @see fsl_deck_malloc()
   ** @see fsl_deck_clean()
   */
  void fsl_deck_finalize(fsl_deck *deck);
  
  /**
   ** Sets the 'A' card for an Attachment (FSL_CATYPE_ATTACHMENT)
   ** deck. Returns 0 on success.
   **
   ** Returns FSL_RC_MISUSE if any of (mf, filename, target) are NULL,
   ** FSL_RC_RANGE if !*filename or if uuidSrc is not NULL and
   ** fsl_is_uuid(uuidSrc) returns false.
   **
   ** Returns FSL_RC_TYPE if mf is not (as determined by its mf->type
   ** member) of a deck type capable of holding 'A' cards. (Only decks
   ** of type FSL_CATYPE_ATTACHMENT may hold an 'A' card.) If uuidSrc
   ** is NULL or starts with a NUL byte then it is ignored, otherwise
   ** the same restrictions apply to it as to target.
   **
   ** The target parameter represents the "name" of the
   ** wiki/ticket/event record to which the attachment applies. For
   ** wiki pages this is their normal name (e.g. "MyWikiPage"). For
   ** events and tickets it is their full 40-byte UUID.
   **
   ** uuidSrc is the UUID of the attachment blob itself. If it is NULL
   ** or empty then this card indicates that the attachment will be
   ** "deleted" (insofar as anything is ever deleted in Fossil).
   */
  int fsl_deck_A_set( fsl_deck * mf, char const * filename,
                      char const * target, fsl_uuid_cstr uuidSrc);
  /**
   ** Sets or unsets (if uuidBaseline is NULL or empty) the B card for
   ** the given manifest. Returns 0 on success, FSL_RC_MISUSE if !mf,
   ** FSL_RC_OOM on allocation error.
   **
   ** Returns FSL_RC_RANGE if uuidBaseline is not NULL or exactly
   ** FSL_UUID_STRLEN bytes. If it is NULL the current value is
   ** freed.
   **
   ** Returns FSL_RC_TYPE if mf is not syntactically allowed to have
   ** this card card (as determined by
   ** fsl_card_is_legal(mf->type,...)) or if the value is not a
   ** syntactically valid UUID.
   **/
  int fsl_deck_B_set( fsl_deck * mf, fsl_uuid_cstr uuidBaseline);

  /**
   ** Semantically identical fsl_deck_B_set() but sets the C card and
   ** does not place a practical limit on the comment's length.
   ** comment must be the comment text for the change being applied.
   */
  int fsl_deck_C_set( fsl_deck * mf, char const * comment, fsl_int_t cardLen);

  /**
   ** Sets mf's D card as a Julian Date value. Returns FSL_RC_MISUSE
   ** if !mf, FSL_RC_RANGE if date is negative, else 0. Has no
   ** side-effects on error.
   **
   */
  int fsl_deck_D_set( fsl_deck * mf, fsl_double_t date);

  /**
   ** Sets the E card in the given deck. date may not be negative - use
   ** fsl_db_julian_now() or similar to get a default time if needed.
   ** Retursn FSL_RC_MISUSE if !mf or !uuid, FSL_RC_RANGE if date is
   ** not positive, FSL_RC_RANGE if uuid is not a valid UUID string.
   **
   ** Note that the UUID for an event, unlike most other UUIDs, need
   ** not be calculated - it may be a random hex string, but it must
   ** pass the fsl_is_uuid() test. Use fsl_db_random_hex() to generate
   ** random UUIDs. When editing events, e.g. using the HTML UI, only
   ** the most recent event with the same UUID is shown. So when
   ** updating events, be sure to apply the same UUID to the edited
   ** copies before saving them.
   */
  int fsl_deck_E_set( fsl_deck * mf, fsl_double_t date, fsl_uuid_cstr uuid);

  /**
   ** Adds a new F card to the given deck. The uuid argument is
   ** required to pass the fsl_is_uuid() test. The name must be a
   ** "simplified path name" (as determined by
   ** fsl_is_simple_pathname()), or FSL_RC_RANGE is returned.
   **
   ** perms should be one of the fsl_mf_perm_t values (0 is the usual
   ** case).
   **
   ** oldName must only be non-NULL when renaming a file, and it must
   ** follow the same naming rules as the name parameter.
   **
   ** Returns 0 on success.
   **/
  int fsl_deck_F_add( fsl_deck * mf, char const * name,
                      fsl_uuid_cstr uuid,
                      fsl_mf_perm_t perms, 
                      char const * oldName);

  /**
   ** Adds the given file instance to the given deck.  Returns 0 on
   ** success, FSL_RC_MISUSE if either argument is NULL, FSL_RC_OOM if
   ** appending the file to the list fails.
   **
   ** On success ownership of t is passed to mf. On error ownership is
   ** not modified.
   */
  int fsl_deck_F_add2( fsl_deck * mf, fsl_card_F * t);

  /**
   ** Callback type for use with fsl_deck_F_foreach() and
   ** friends. Implementations must return 0 on success, FSL_RC_BREAK
   ** to abort looping without an error, and any other value on error.
   */
  typedef int (*fsl_card_F_visitor_f)(fsl_card_F const * fc,
                                      void * state);
  
  /**
   ** For each F-card in d, cb(card,visitorState) is called. Returns
   ** the result of that loop. If cb returns FSL_RC_BREAK, the
   ** visitation loop stops immediately and this function returns
   ** 0. If cb returns any other non-0 code, looping stops and that
   ** code is returned immediately.
   **
   ** If includeBaseline is false or d has no baseline then this
   ** function behaves identically to fsl_deck_F_foreach_own(),
   ** otherwise it iterates through the F-cards such that d's copy of
   ** a given card takes precedence, if it is set.
   **
   ** If includeBaseline is true and d appears to have a baseline, but
   ** it is not loaded, this function loads it.
   **
   ** The F-cards will be visited in the order they are declared in
   ** d. For loaded manifests this is always lexical order (consistent
   ** across the delta and baseline for delta manifests). For
   ** hand-created decks which have not been fsl_deck_unshuffle()'d,
   ** the order is unspecified.
   */
  int fsl_deck_F_foreach( fsl_deck * d, char includeBaseline,
                          fsl_card_F_visitor_f cb, void * visitorState );

  /**
   ** Works similarly to fsl_deck_F_foreach() except that it only
   ** loops over d's own F-cards (which allows d to remain const),
   ** ignoring any F-cards from its baseline manifest (if any).
   */
  int fsl_deck_F_foreach_own( fsl_deck const * d, fsl_card_F_visitor_f cb,
                              void * visitorState );
  
  /**
   ** Fetches the next F-card entry from d. fsl_deck_F_rewind() must
   ** have be successfully executed one time before calling this,
   ** as that routine ensures that the baseline is loaded (if needed),
   ** which is needed for proper iteration.
   **
   ** On success 0 is returned and *f is assigned to the next F-card.
   ** If *f is NULL when returning 0 then the end of the list has been
   ** reached (fsl_deck_F_rewind() can be used to re-set it).
   **
   ** Example usage:
   **
   ** @code
   ** int rc;
   ** fsl_card_F const * fc = NULL;
   ** rc = fsl_deck_F_rewind(d);
   ** if(!rc) while( !(rc=fsl_deck_F_next(d, &fc)) && fc) {...}
   ** @endcode
   **
   */
  int fsl_deck_F_next( fsl_deck * d, fsl_card_F const **f );

  /**
   ** Rewinds d's F-card traversal iterator and loads d's baseline
   ** manifest, if it has one and it is not loaded already. Returns 0
   ** on success.  The only error condition is if loading of the
   ** a baseline manifest fails.
  */
  int fsl_deck_F_rewind( fsl_deck * d );
  
  /**
   ** Adds a J card to the given deck, setting/updating the given ticket
   ** property key to the given value. The key is required but the value
   ** is optional (may be NULL). If isAppend then the value is appended
   ** to any existing value, otherwise it replaces any existing value.
   **
   ** It is currently unclear whether it is legal to include multiple
   ** J cards for the same key in the same control artifact, in
   ** particular if their isAppend values differ.
   **
   ** Returns 0 on success, FSL_RC_MISUSE if !mf or !key, FSL_RC_RANGE
   ** if !*field, FSL_RC_TYPE if mf is of a type for which J cards are
   ** not legal (see fsl_card_is_legal()), FSL_RC_OOM on allocation
   ** error.
   */
  int fsl_deck_J_add( fsl_deck * mf, char isAppend,
                      char const * key, char const * value );

  /**
   ** Semantically identical fsl_deck_B_set() but sets the K card.  uuid
   ** must be the UUID of the ticket this change is being applied to.
   */
  int fsl_deck_K_set( fsl_deck * mf, fsl_uuid_cstr uuid);

  /**
   ** Semantically identical fsl_deck_B_set() but sets the L card.
   ** title must be the wiki page title text of the wiki page this
   ** change is being applied to.
   */
  int fsl_deck_L_set( fsl_deck * mf, char const *title, fsl_int_t len);

  /**
   ** Adds the given UUID as an M-card entry. Returns 0 on success, or:
   **
   ** FSL_RC_MISUSE if !mf or !uuid
   **
   ** FSL_RC_TYPE if fsl_deck_check_type(mf,'M') returns false.
   **
   ** FSL_RC_RANGE if !fsl_is_uuid(uuid).
   **
   ** FSL_RC_OOM if memory allocation fails while adding the entry.
   */
  int fsl_deck_M_add( fsl_deck * mf, fsl_uuid_cstr uuid );

  /**
   ** Semantically identical fsl_deck_B_set() but sets the N card.
   ** mimeType must be the content mime type for COMMENT text of the
   ** change being applied.
   */
  int fsl_deck_N_set( fsl_deck * mf, char const *mimeType, fsl_int_t len);

  /**
   ** Adds the given UUID as a parent of the mf change record. If len
   ** is less than 0 then fsl_strlen(parentUuid) is used to determine
   ** its length. Returns FSL_RC_MISUE if !mf, !parentUuid, or
   ** !*parentUuid. Returns FSL_RC_RANGE if parentUuid is not 40
   ** bytes long.
   **
   ** The first P card added to a deck MUST be the UUID of its primary
   ** parent (one which was not involved in a merge operation). All others
   ** are considered "non-primary."
   **
   ***/
  int fsl_deck_P_add( fsl_deck * mf, fsl_uuid_cstr parentUuid);

  /**
   ** If d contains a P card with the given index, this returns the
   ** RID corresponding to the UUID at that index. Returns a negative
   ** value on error, 0 if there is no for that index or the index
   ** is out of bounds.
   */
  fsl_id_t fsl_deck_P_get_id(fsl_deck * d, int index);
  
  /**
   ** Adds a Q card record to the given deck. type must be negative
   ** for a backed-out change, positive for a cherrypicked change.
   ** target must be a valid UUID string. If baseline is not NULL then
   ** it also must be a valid UUID.
   **
   ** Returns 0 on success, non-0 on error. FSL_RC_MISUSE if !mf
   ** or !target, FSL_RC_RANGE if target/baseline are not valid
   ** UUID strings (baseline may be NULL).
   */
  int fsl_deck_Q_add( fsl_deck * mf, char type,
                      fsl_uuid_cstr target,
                      fsl_uuid_cstr baseline );

  /**
   ** Functionally identical to fsl_deck_B_set() except that it sets
   ** the R card. Returns 0 on succes, FSL_RC_RANGE if md5 is not NULL
   ** or exactly FSL_MD5_STRLEN bytes long (not including trailing
   ** NUL). If md5==NULL the current R value is cleared.
   **
   ** Reminder: calculating/verifying the proper R hash value is
   ** currently (20130814) beyond the capabilities of the library -
   ** there is still work to do here.
   */
  int fsl_deck_R_set( fsl_deck * mf, char const *md5);

  /**
   ** Adds a new T card entry to the given deck.
   **
   ** If uuid is not NULL and fsl_is_uuid(uuid) returns false then
   ** this function returns NULL. If it is NULL then it is assumed
   ** to be the UUID of the currently-being-constructed manifest in which
   ** the tag is contained.
   **
   ** Returns 0 on success. Returns FSL_RC_MISUE if !mf or
   ** !name. Returns FSL_RC_TYPE (and update's mf's error state with a
   ** message) if the T card is not legal for mf (see
   ** fsl_card_is_legal()).  Returns FSL_RC_RANGE if !*name, tagType
   ** is invalid, or if uuid is not NULL and fsl_is_uuid(uuid)
   ** return false. Returns FSL_RC_OOM if an allocation fails.
   **/
  int fsl_deck_T_add( fsl_deck * mf, fsl_tag_type tagType,
                      fsl_uuid_cstr uuid, char const * name,
                      char const * value);

  
  /**
   ** Adds the given tag instance to the given manifest.
   ** Returns 0 on success, FSL_RC_MISUSE if either argument
   ** is NULL, FSL_RC_OOM if appending the tag to the list
   ** fails.
   **
   ** On success ownership of t is passed to mf. On error ownership is
   ** not modified.
   **
   */
  int fsl_deck_T_add2( fsl_deck * mf, fsl_card_T * t);

  
  /**
   ** Calculates the value of d's R-card based on its F-cards and
   ** updates d->R. It may also, as a side-effect, sort d->F.list
   ** lexically (a requirement of a R-card calculation). Returns 0 on
   ** success. This requires an opened repository db but not a
   ** checkout.
   **
   ** Note that this calculation is exceedingly memory-hungry.
   ** While Fossil originally required R cards, the cost of
   ** calculation eventually caused the R-card to be made
   ** optional. This API currently requires the card if F-cards used
   ** but will at some point offer a flag to disable its generation.
   **
   ** This requires that d->f have an opened repository.
   */
  int fsl_deck_R_calc(fsl_deck * d);
  
  /**
   ** Semantically identical fsl_deck_B_set() but sets the U card.
   ** userName must be the user who's name should be recorded for
   ** this change.
   */
  int fsl_deck_U_set( fsl_deck * mf, char const *userName, fsl_int_t len);

  /**
   ** Semantically identical fsl_deck_B_set() but sets the W card.
   ** content must be the page content of the wiki page this change is
   ** being applied to.
   */
  int fsl_deck_W_set( fsl_deck * mf, char const *content, fsl_int_t len);

  /**
   ** Must be called to initialize a newly-created/allocated deck
   ** instance. This function clears out all contents of the d
   ** parameter except for its (f, type, allocStamp) members, sets its
   ** (f, type) members, and leaves d->allocStamp intact.
   */
  void fsl_deck_init( fsl_cx * cx, fsl_deck * d, fsl_catype_t type );

  /**
   ** Returns true (non-0) if d contains data for all _required_
   ** cards, as determined by the value of d->type, else returns false
   ** (0). It returns 0 if d->type==FSL_CATYPE_ANY, as that is a
   ** placeholder value intended to be re-set by the deck's user.
   */
  char fsl_deck_has_required_cards( fsl_deck const * d );

  /**
   ** Prepares the given deck for output by ensuring that cards
   ** which need to be sorted are sorted, and it may run some
   ** last-minute validation checks.
   **
   ** The cards which get sorted are: F, J, M, Q, T. The P-card list
   ** is _not_ sorted - the client is responsible for ensuring that
   ** the primary parent is added to that list first, and after that
   ** the ordering is largely irrelevant.
   **
   ** If calculateRCard is true and fsl_card_is_legal(d,'R') then this
   ** function calculates the R-card for the deck if it has
   ** F-cards. The R-card calculation is _extremely_ memory-hungry but
   ** adds another level of integrity checking to fossil.
   **
   ** The R card, if used, must be calculated before
   ** fsl_deck_output()ing a deck containing F cards. Clients may
   ** alternately call fsl_deck_R_calc() to calculate the R card
   ** separately, but there is little reason to do so. Historically
   ** speaking the R-card was required when F-cards were used, but it
   ** was eventually made optional because (A) the memory cost and (B)
   ** it's part of a 3rd or 4th level of integrity-related checks, and
   ** is somewhat superfluous.
   */
  int fsl_deck_unshuffle( fsl_deck * d, char calculateRCard );
  
  /**
   ** Renders the given control artifact's contents to the given
   ** output function and calculates any cards which cannot be
   ** calculated until the contents are complete (namely the R and Z
   ** cards).
   **
   ** fsl_deck_unshuffle() must have been called on the deck first to
   ** finalize any pending values to be calculated for the deck.
   **
   ** Returns 0 on success, FSL_RC_MISUSE if !mf or !f. If
   ** f() returns non-0, that code is returned. outputState is passed
   ** as the first argument to f(). f() may be called an arbitrary
   ** number of times by this routine.
   **
   ** The cx argument is the fossil context for which the manifest is
   ** being created. It must have an open checkout database, or
   ** FSL_RC_MISUSE is returned. It is required because generating
   ** parts of the manifest require access to the underlying database
   ** API.
   **
   ** The exact structure of the ouput depends on the value of
   ** mf->type, and FSL_RC_TYPE is returned if this function cannot
   ** figure out what to do with the given cardset's type.
   **
   ** Returns FSL_RC_CA_SYNTAX if fsl_deck_has_required_cards(mf)
   ** returns false.
   **
   ** If the calls to out() fail then its result code is returned
   ** to the caller of this function.
   **
   ** In most non-trivial error cases f's error state will be updated
   ** with an explaination of the problem.
   **
   ** @see fsl_deck_unshuffle().
   **
   **/
  int fsl_deck_output( fsl_cx * f, fsl_deck const * mf,
                       fsl_output_f out, void * outputState );


  /**
   ** Saves the given deck into f's repository database as new control
   ** artifact content. If isPrivate is true then the content is
   ** marked as private, otherwise it is not. Note that the isPrivate
   ** is a suggestion and might be trumped by existing state within f
   ** or its repository, and such a trumping is not treated as an
   ** error. e.g. tags are automatically private when they tag private
   ** content.
   **
   ** Before saving, the deck is passed through fsl_deck_unshuffle()
   ** and fsl_deck_output(), which will fail for a variety of
   ** easy-to-make errors such as the deck missing required cards.
   ** For unshuffle purposes, the R-card currently gets calculated if
   ** the deck has any F-cards, but the plan is to make that a
   ** flag/option.
   **
   ** Returns 0 on success, the usual non-0 suspects on error.
   **
   ** If d->rid and d->uuid are set when this is called, it is assumed
   ** that we are saving existing or phantom content, and that case:
   **
   ** - An existing phantom is populated with the new content.
   **
   ** - If an existing record is found with a non-0 size then it is
   ** not modified but this is currently not treated as an error (for
   ** historical reasons, though one could argue that it should result
   ** in FSL_RC_ALREADY_EXISTS).
   **
   ** ACHTUNG: the pre-existing blob case is as yet untested!
   **
   ** If d->rid and d->uuid are not set when this is called then... on
   ** success, d->rid and d->uuid will contain the values held by
   ** their counterparts in the blob table. They will only be set on
   ** success because they would otherwise refer to db records which
   ** get destroyed when the transaction rolls back.
   **
   ** After saving, the deck gets crosslinked (fsl_deck_crosslink())
   ** to update any relationships described by the deck.
   **
   ** The save operation happens within a transaction, of course, and
   ** on any sort of error, db-side changes are rolled back. Note that
   ** is _is_ legal to start the transaction before calling this,
   ** which effectively makes this operation part of that transaction.
   **
   ** Maintenance reminder: this function also does a small bit of
   ** artifact-type-specific processing.
   **
   ** @see fsl_deck_output()
   ** @see fsl_content_put_ex()
   */
  int fsl_deck_save( fsl_deck * d, char isPrivate );
  
  /**
   ** Subject to change.
   **
   ** Runs postprocessing on the manifest represented by d. d->rid
   ** must be set and valid and d's contents must accurately represent
   ** the stored manifest for the given rid. This is normally run just
   ** after the insertion of a new manifest, but will (eventually)
   ** also be run as part of a rebuild.
   **
   ** Returns FSL_RC_MISUSE if !f or !d, FSL_RC_RANGE if d->rid<=0,
   ** FSL_RC_MISUSE (with more error info in f) if d does not
   ** contain all required cards for its d->type value.
   **
   ** Parts which are currently missing:
   **
   ** - Tickets
   **
   ** TODO: d "should" be const but some internals (d->F.cursor and
   ** delayed baseline loading) currently prohibit it.
   */
  int fsl_deck_crosslink( fsl_cx * f, fsl_deck /* const */ * d );

  /**
   ** Parses src as Control Artifact content and populates d with it.
   **
   ** d will be cleaned up by this function if it has any contents.
   **
   ** Pass 0 for the rid parameter for the time being. It is not yet clear
   ** whether we need that parameter here or not. A negative value will
   ** result in a FSL_RC_RANGE error.
   **
   ** The artifact content in the source blob is modified by this
   ** function because (A) that simplifies tokenization greatly, (B)
   ** saves us having to make another copy to work on, (C) the
   ** original implementation did it and way and (D) because in
   ** historical use the source is normally thrown away after parsing,
   ** anyway.
   **
   ** The fsl_cx argument must (in the current implementation) have
   ** opened at least one database handle because we use db functionality
   ** during parsing (unfortunately).
   **
   ** On success it returns 0 and d will be updated with the state
   ** from the input manifest. (Ideally, outputing d via
   ** fsl_deck_output() will produce a lossless copy of the original.) 
   ** If the manifest has a counterpart in the database (determined
   ** via an SHA1 match) then d->rid is set to a positive value upon
   ** return. d->uuid will be set to the SHA1 of the input artifact,
   ** ignoring any surrounding PGP signature for hashing purposes.
   **
   ** On error f's error state might be updated with more info
   ** (depends on the type of error, but anything non-trivial will be
   ** noted there). d might be partially populated on error. src is
   ** modified during parsing, and will be modified if the error
   ** happens after basic argument validation and validation of the
   ** Z-card (if any) takes place.
   **
   ** Error result codes include:
   **
   ** - FSL_RC_MISUSE if any pointer argument is NULL.
   **
   ** - FSL_RC_CA_SYNTAX on syntax errors.
   **
   ** - FSL_RC_CONSISTENCY if validation of a Z-card fails.
   **
   ** - Any number of errors coming from the allocator, database, or
   ** fsl_deck APIs used here.
   **
   **
   ** Design notes/reminders:
   **
   ** - The rid argument doesn't seem to be necessary here. It is left
   ** in for the time being because the internal logic (ported in)
   ** implies that there are cases where the rid is expected to be 0
   ** vs. positive.
   **
   ** - We only need the fsl_cx argument for a database handle and
   ** only need that for the string-to-Julian conversion. But since we
   ** have it, this function also (on success) sets d->rid and
   ** d->uuid.
   */
  int fsl_deck_parse(fsl_cx * f, fsl_id_t rid,
                     fsl_deck * d, fsl_buffer * src);

  /**
   ** Loads the content from given rid and tries to parse it as a
   ** manifest. If type==FSL_CATYPE_ANY then it will allow any type of
   ** control artifact, else it returns FSL_RC_TYPE if the loaded
   ** manifest is of the wrong type.
   **
   ** Returns 0 on success.
   **
   ** d may be partially populated on error, and the caller must
   ** eventually pass it to fsl_deck_finalize() resp. fsl_deck_clean()
   ** regardless of success or error. This function "could" clean it
   ** up on error, but leaving it partially populated makes debugging
   ** easier. If the error was an artifact type mismatch then d will
   ** be properly populated but will not hold the type of artifact
   ** requested (but should otherwise be well-formed because parsing
   ** errors occur before the type check can happen).
   **
   ** f's error state may be updated on error.
   */
  int fsl_deck_load_rid( fsl_cx * f, fsl_id_t rid, fsl_deck * d, 
                         fsl_catype_t type );

  /**
   ** Loads the baseline manifest specified in d->B.uuid. Returns 0 on
   ** success, if d->B.baseline is already set, or d->B.uuid is NULL
   ** (in which case there is no baseline).
   **
   ** Neither argument may be NULL and d must be a fully-populated
   ** object, complete with a proper d->rid, before calling this.
   **
   ** On success 0 is returned. If d->B.baseline is NULL then
   ** it means that d has no baseline manifest (and d->B.uuid will be NULL
   ** in that case). If d->B.baseline is not NULL then it is owned by
   ** d and will be cleaned up when d is cleaned/finalized.
   **
   ** Error codes include, but are not limited to:
   **
   ** - FSL_RC_MISUSE if !d or !d->f.
   **
   ** - FSL_RC_NOT_A_REPO if f has no opened repo db.
   **
   ** - FSL_RC_RANGE if d->rid<=0, but that might propagate up from
   ** a lower-level call as well.
   **
   ** On non-trivial errors f's error state will be updated to hold
   ** a description of the problem.
   **
   ** Some misuses trigger assertions in debug builds.
   **
   */
  int fsl_deck_baseline_fetch( fsl_deck * d );

  /**
   ** Not yet implemented: a callback interface for manifest crosslinking,
   ** so that we can farm out the updating of the event table. That would
   ** allow, e.g., native-language updates to the timeline.
   */
  typedef int (*fsl_deck_xlink_f)(fsl_cx * f, fsl_deck const * d, void * state);

  /**
   ** Adds the given function as a "crosslink callback" for the given
   ** Fossil context. The callback is called at the end of a
   ** successfull fsl_deck_crosslink() operation and provides a way
   ** for the client to perform their own work based on the app having
   ** crosslinked an artifact. Crosslinking happens when artifacts are
   ** saved or upon a rebuild operation.
   **
   ** Crosslink callbacks are called in an unspecified order and the
   ** library may register its own before the client gets a chance to.
   **
   ** If _any_ crosslinking callback fails (returns non-0) then the
   ** _whole_ crosslinking fails and is rolled back (which may very
   ** well include pending tags/commits/whatever getting rolled back).
   **
   ** The state parameter has no meaning for this function, but is
   ** passed on as the final argument to cb(). If not NULL, cbState
   ** must outlive f, as there is currently no API to remove
   ** registered crosslink listeners.
   **
   ** The name parameter is for future use, to allow clients to
   ** replace built-in implementations and remove crosslink listeners
   ** using published symbolic names. The name must be
   ** non-NULL/empty. If a listener is registered with a duplicate
   ** name then the first one is replaced. This function does not copy
   ** the name bytes - they are assumed to be static or otherwise to
   ** live at least as long as f. It is recommended that clients
   ** choose a namespace/prefix to apply to the names they
   ** register. The library reserves the prefix "fsl-" for its own
   ** use. The name string need not be stable across appication
   ** sessions and maybe be a randomly-generated string.
   **
   ** TODO: publish the name(s) of overrideable crosslinkers
   ** once we have them in place.
   */
  int fsl_xlink_listener( fsl_cx * f, char const * name,
                          fsl_deck_xlink_f cb, void * cbState );

  
  /**
   ** For the given blob.rid value, returns the blob.size value of
   ** that record via *rv. Returns 0 or higher on success, -1 if a
   ** phantom record is found, -2 if no entry is found, or a smaller
   ** negative value on error (dig around the sources to decode them -
   ** this is not expects to fail unless your system is undergoing a
   ** catastrophe).
   **
   ** @see fsl_content_blob()
   ** @see fsl_content_get()
   **/
  fsl_int_t fsl_content_size( fsl_cx * f, fsl_id_t blobRid );

  /**
   ** For the given blob.rid value, fetches the content field of that
   ** record and overwrites tgt's contents with it (reusing tgt's
   ** memory if it has any and if it can). The blob's contents are
   ** uncompressed if they were stored in compressed form. This
   ** extracts a raw blob and does not apply any deltas - use
   ** fsl_content_get() to fully expand a delta-stored blob.
   **
   ** Returns 0 on success. On error tgt might be partially updated,
   ** e.g. it might be populated with compressed data instead of
   ** uncompressed. On error tgt's contents should be recycled
   ** (e.g. fsl_buffer_reset()) or discarded (e.g. fsl_buffer_clear())
   ** by the client.
   **
   ** @see fsl_content_get()
   ** @see fsl_content_size()
   */
  int fsl_content_blob( fsl_cx * f, fsl_id_t blobRid, fsl_buffer * tgt );

  /**
   ** Functionally similar to fsl_content_blob() but does a lot of
   ** work to ensure that the returned blob is expanded from its
   ** deltas, if any. The tgt buffer's memory, if any, will be replaced/reused
   ** if it has any. Returns 0 on success. There are no less than 50
   ** potental different errors, so we won't bother to list them all.
   ** The basic error cases are:
   **
   ** - FSL_RC_MISUSE if !tgt or !f.
   **
   ** - FSL_RC_RANGE if rid<=0 or if an infinite loop is discovered in
   ** the repo delta table links (that is a consistency check to avoid
   ** an infinite loop - that condition "cannot happen" because the
   ** verify-before-commit logic catches that error case).
   **
   ** - FSL_RC_NOT_A_REPO if f has no repo db opened.
   **
   ** - FSL_RC_NOT_FOUND if the given rid is not in the repo db.
   **
   ** - FSL_RC_OOM if an allocation fails.
   ** 
   **
   ** @see fsl_content_blob()
   ** @see fsl_content_size()
   */
  int fsl_content_get( fsl_cx * f, fsl_id_t blobRid, fsl_buffer * tgt );

  /**
   ** Returns true if the given rid is marked as PRIVATE in f's current
   ** repository. Returns false (0) on error or if the content is not
   ** marked as private.
   */
  char fsl_content_is_private(fsl_cx * f, fsl_id_t rid);

  /**
   ** Marks the given rid public, if it was previously marked as
   ** private. Returns 0 on success, non-0 on error.
   **
   ** Note that it is not possible to make public content private.
   */
  int fsl_content_make_public(fsl_cx * f, fsl_id_t rid);
  
  
  /**
   ** If the given blob ID refers to deltified repo content, this routine
   ** undeltifies it and replaces its content with its expanded
   ** form.
   **
   ** Returns 0 on success, FSL_RC_MISUSE if !f, FSL_RC_NOT_A_REPO if
   ** f has no opened repository, FSL_RC_RANGE if rid is not positive,
   ** and any number of other potential errors during the db and
   ** content operations. This function treats already unexpanded
   ** content as success.
   **
   ** @see fsl_content_deltify()
   */
  int fsl_content_undelta(fsl_cx * f, fsl_id_t rid);


  /**
   ** The converse of fsl_content_undelta(), this replaces the storage
   ** of the given blob record so that it is a delta of srcid.
   **
   ** If rid is already a delta from some other place then no
   ** conversion occurs and this is a no-op unless force is true.
   **
   ** It never generates a delta that carries a private artifact into
   ** a public artifact. Otherwise, when we go to send the public
   ** artifact on a sync operation, the other end of the sync will
   ** never be able to receive the source of the delta.  It is OK to
   ** delta private->private and public->private and public->public.
   ** Just no private->public delta. For such cases this function
   ** returns 0, as opposed to FSL_RC_ACCESS or some similar code, and
   ** leaves the content untouched.
   **
   ** If srcid is a delta that depends on rid, then srcid is
   ** converted to undelta'd text.
   **
   ** If either rid or srcid contain less than 50 bytes, or if the
   ** resulting delta does not achieve a compression of at least 25% 
   ** the rid is left untouched.
   **
   ** Return 0 if a delta is successfully made or none needs to be
   ** made, non-0 on error.
   **
   ** @see fsl_content_undelta()
   */
  int fsl_content_deltify(fsl_cx * f, fsl_id_t rid,
                          fsl_id_t srcid, char force);

  
  /**
   ** Creates a new phantom blob with the given UUID and return its
   ** artifact ID via *newId. Returns 0 on success, FSL_RC_MISUSE if
   ** !f or !uuid, FSL_RC_RANGE if uuid is not FSL_UUID_STRLEN bytes
   ** long or syntactically invalid, FSL_RC_NOT_A_REPO if f has no
   ** repository opened, FSL_RC_ACCESS if the given uuid has been
   ** shunned, and about 20 other potential error codes from the
   ** underlying db calls. If isPrivate is true _or_ f has been flag
   ** as being in "private mode" then the new content is flagged as
   ** private. newId may be NULL but if it is then the caller will
   ** have to find the record id himself by looking for the uuid
   ** in the "phantom" table.
   */
  int fsl_content_new( fsl_cx * f, fsl_uuid_cstr uuid, char isPrivate,
                            fsl_id_t * newId );

  /**
   ** Experimental generic callback interface for visiting decks. The
   ** interface does not generically require that d survive after this
   ** call returns.
   */
  typedef int (*fsl_deck_cb_f)( fsl_cx * f, fsl_deck const * d,
                                void * state );

  /**
   ** For each unique wiki page name in f's repostory, this calls
   ** cb(), passing it the manifest of the most recent version of that
   ** page. The callback should return 0 on success, FSL_RC_BREAK to
   ** stop looping without an error, or any other non-0 code
   ** (preferably a value from fsl_rc_t) on error.
   **
   ** The 3rd parameter has no meaning for this function but it is
   ** passed on as-is to the callback.
   **
   ** ACHTUNG: the deck passed to the callback is transient and will
   ** be cleaned up after the callback has returned, so the callback
   ** must not hold a pointer to it or its contents.
   **/
  int fsl_wiki_foreach_page( fsl_cx * f, fsl_deck_cb_f cb, void * state );

  /**
   ** Fetches the most recent RID for the given wiki page name and
   ** assigns *newId (if it is not NULL) to that value. Returns 0 on
   ** success, FSL_RC_MISUSE if !f or !pageName, FSL_RC_RANGE if
   ** !*pageName, and a host of other potential db-side errors
   ** indicating more serious problems. If no such page is found,n
   ** newRid is not modified and this function returns 0 (as opposed
   ** to FSL_RC_NOT_FOUND) because that simplifies usage (so far).
   **
   ** On error *newRid is not modified.
   */
  int fsl_wiki_latest_rid( fsl_cx * f, char const * pageName, fsl_id_t * newRid );
  
  /**
   ** Loads the artifact for the most recent version of the given wiki page,
   ** populating d with its contents.
   **
   ** Returns 0 on success. On error d might be partially populated,
   ** so it needs to be passed to fsl_deck_finalize() regardless of
   ** whether this function succeeds or fails.
   **
   ** Returns FSL_RC_NOT_FOUND if no page with that name is found.
   */
  int fsl_wiki_load_latest( fsl_cx * f, char const * pageName, fsl_deck * d );

  /**
   ** Returns true (non-0) if f's repo database contains a page with the
   ** given name, else false.
   */
  char fsl_wiki_page_exists(fsl_cx * f, char const * pageName);
  
  /**
   ** Under development - do not use.
   **
   ** Saves wiki content to f's repository db.
   **
   ** pageName is the name of the page to update or create.
   **
   ** b contains the content for the page.
   **
   ** userName specifies the user name to apply to the change. If NULL
   ** or empty then fsl_guess_user_name() is used to determine the name.
   **
   ** mimeType specifies the mime type for the content (may be NULL).
   ** Mime type names supported directly by fossil(1) include (as of
   ** this writing): text/x-fossil-wiki, text/x-markdown,
   ** text/plain
   **
   ** Whether or not this function is allowed to create a new page
   ** or not is determined by isNew. If isNew is true then then this
   ** will fail with FSL_RC_ALREADY_EXISTS if a page with the given
   ** name already exists. If it is false and the page does _not_
   ** exist, FSL_RC_NOT_FOUND is returned.
   **
   ** TODO: find better semantics for isNew, so clients don't have to
   ** check if it exists first. e.g. a policy enum which specifies
   ** whether to allow creation of a new page.
   **
   ** @see fsl_wiki_page_exists()
   */
  int fsl_wiki_save(fsl_cx * f, char const * pageName,
                    fsl_buffer const * b,
                    char const * userName,
                    char const * mimeType,
                    char isNew );

  /**
   ** Fetches the list of all wiki page names in f's current repo db
   ** and appends them as new (char *) strings to tgt. On error tgt
   ** might be partially populated (but this will only happen on an
   ** OOM).
   **
   ** It is up to the caller free the entries added to the list. Some
   ** of the many possibilities include:
   **
   ** @code
   ** fsl_list_visit( list, 0, fsl_list_v_fsl_free, NULL );
   ** fsl_list_reserve(list,0);
   ** // Or:
   ** fsl_list_clear(list, fsl_list_v_fsl_free, NULL);
   ** // Or simply:
   ** fsl_list_visit_free( list, 1 );
   ** @endcode
   **
   */
  int fsl_wiki_names_get( fsl_cx * f, fsl_list * tgt );

  /**
   ** Returns n bytes of random lower-case hexidecimal characters
   ** using the given db as its data source. The returned memory must
   ** eventually be freed using fsl_free(). Returns NULL if !db, !n,
   ** or on a db-level error.
   */
  char * fsl_db_random_hex(fsl_db * db, fsl_size_t n);

  /**
   ** Represents one file entry in a Manifest/Control Artifact.
   */
  struct fsl_card_F {
    /**
     ** Name of the file.
     */
    char * name;
    /**
     ** UUID of the underlying blob record for the file. NULL for
     ** removed entries.
     */
    fsl_uuid_str uuid;
    /**
     ** Previous name, if the file was renamed.
     */
    char * priorName;
    /**
     ** File permissions.
     **
     ** TODO: rename to perm (singular), as fossil only supports
     ** permissions letter.
     **
     ** @see fsl_mf_perm_t
     */
    fsl_mf_perm_t perms;
  };

  /**
   ** Empty-initialized fsl_card_F structure, intended for use in
   ** initialization when embedding fsl_card_F in another struct or
   ** copy-initializing a const struct.
   */
#define fsl_card_F_empty_m {NULL, NULL, NULL, 0}

  /**
   ** Empty-initialized fsl_card_F instance, intended for use in
   ** copy-constructing.
   */
  extern const fsl_card_F fsl_card_F_empty;


  /**
   ** Represents a J card in a Ticket Control Artifact.
   */
  struct fsl_card_J {
    /**
     ** If true, the new value should be appended to any existing one
     ** with the same key, else it will replace any old one.
     */
    char isAppend;
    /**
    ** The ticket field to update.
    */
    char const * field;
    /**
    ** The value for the field.
    */
    char const * value;
    /**
     ** Memory storage for the string properties.
     */
    fsl_buffer storage;
  };
  /** Empty-initialized fsl_card_J struct. */
#define fsl_card_J_empty_m {0,NULL, NULL, fsl_buffer_empty_m}
  /** Empty-initialized fsl_card_J struct. */
  extern const fsl_card_J fsl_card_J_empty;

  
  /**
   ** Represents a tag in a Manifest or Control Artifact.
   */
  struct fsl_card_T {
    /**
     ** The type of tag.
     */
    fsl_tag_type type;
    /**
    ** UUID of the artifact this tag is tagging. When applying a tag
    ** to a new checkin, this value is left empty and gets replaced by
    ** a '*' in the resulting control artifact.
    */
    fsl_uuid_str uuid;
    /**
     ** The tag's name.
     */
    fsl_buffer name;
    /**
     ** The tag's value. May be empty.
     */
    fsl_buffer value;
  };
  /** Defaults-initialized fsl_card_T instance. */
#define fsl_card_T_empty_m {FSL_TAGTYPE_INVALID, NULL, fsl_buffer_empty_m,fsl_buffer_empty_m}
  /** Defaults-initialized fsl_card_T instance. */
  extern const fsl_card_T fsl_card_T_empty;

  /**
   ** Represents a Q card in a Manifest or Control Artifact.
   */
  struct fsl_card_Q {
    /** 0==invalid, negative==backed out, positive=cherrypicked. */
    char type;
    /**
    ** UUID of the target of the cherrypick.
    */
    fsl_uuid_cstr target;
    /**
    ** UUID of the baseline for the cherrypick.
    */
    fsl_uuid_cstr baseline;
    /**
     ** Memory storage for the target and baseline properties.
     */
    fsl_buffer storage;
  };
  /** Empty-initialized fsl_card_Q struct. */
#define fsl_card_Q_empty_m {-1, NULL, NULL, fsl_buffer_empty_m}
  /** Empty-initialized fsl_card_Q struct. */
  extern const fsl_card_Q fsl_card_Q_empty;

  /**
   ** Allocates a new J-card record instance
   **
   ** On success it returns a new record which must eventually be
   ** passed to fsl_card_J_free() to free its resources. On
   ** error (invalid arguments or allocation error) it returns NULL.
   ** field may not be NULL or empty but value may be either.
   **
   ** These records are immutable - the API provides no way to change
   ** them one they are instantiated.
   */
  fsl_card_J * fsl_card_J_malloc(char isAppend,
                                     char const * field,
                                     char const * value);
  /**
   ** Frees a J-card record created by fsl_card_J_malloc().
   ** Is a no-op if cp is NULL.
   */
  void fsl_card_J_free( fsl_card_J * cp );
 

  /**
   ** Allocates a new fsl_card_F instance for use with
   ** fsl_deck_F_add2(). Returns NULL for any of these error cases:
   **
   ** - name is NULL
   ** - uuid is not NULL and fsl_is_uuid(uuid) returns false.
   ** - allocation error
   **
   ** On success it returns a new object which must eventually be
   ** passed to fsl_card_F_free() to free it.
   **
   ** @see fsl_card_F_free()
   */
  fsl_card_F * fsl_card_F_malloc(char const * name,
                               fsl_uuid_cstr uuid,
                               int perms,
                               char const * oldName);

  /**
   ** Frees up any memory owned by t and clears out t's state,
   ** but does not free t.
   **
   ** @see fsl_card_F_free()
   */
  void fsl_card_F_clean(fsl_card_F *t);

  /**
   ** Calls fsl_card_F_clean(t) and then passes t to
   ** fsl_free().
   **
   ** @see fsl_card_F_clean()
   */
  void fsl_card_F_free(fsl_card_F * f);
  
  /**
   ** Allocates a new fsl_card_T instance. If any of the pointer
   ** parameters are non-NULL, their values are assumed to be
   ** NUL-terminated strings, which this function copies.  Returns
   ** NULL on allocation error.  The returned value must eventually be
   ** passed to fsl_card_T_finalize() to free its resources.
   **
   ** If uuid is not NULL and fsl_is_uuid(uuid) returns false then
   ** this function returns NULL. If it is NULL and gets assigned
   ** later, it must conform to fsl_is_uuid()'s rules or downstream
   ** results are undefined.
   **
   ** @see fsl_card_T_free()
   **/
  fsl_card_T * fsl_card_T_malloc(fsl_tag_type tagType,
                                 fsl_uuid_cstr uuid,
                                 char const * name,
                                 char const * value);
  /**
   ** Calls fsl_card_T_clean(t) and then passes t to
   ** fsl_free().
   **
   ** @see fsl_card_T_clean()
   */
  void fsl_card_T_free(fsl_card_T *t);

  /**
   ** Frees up any memory owned by t and clears out t's state,
   ** but does not free t.
   **
   ** @see fsl_card_T_free()
   */
  void fsl_card_T_clean(fsl_card_T *t);

  
  /**
   ** Allocates a new cherrypick record instance. The type argument
   ** must be negative for a backed-out change, positive for a
   ** cherrypicked change.  target must be a valid UUID string. If
   ** baseline is not NULL then it also must be a valid UUID.
   **
   ** On success it returns a new record which must eventually be
   ** passed to fsl_card_Q_free() to free its resources. On
   ** error (invalid arguments or allocation error) it returns NULL.
   **
   ** These records are immutable - the API provides no way to change
   ** them once they are instantiated.
   */
  fsl_card_Q * fsl_card_Q_malloc(char type,
                                 fsl_uuid_cstr target,
                                 fsl_uuid_cstr baseline);
  /**
   ** Frees a cherrypick record created by fsl_card_Q_malloc().
   ** Is a no-op if cp is NULL.
   */
  void fsl_card_Q_free( fsl_card_Q * cp );

  /**
   ** Resolves client-provided symbol as an artifact's db record ID.
   ** f must have an opened repository db, and some symbols can only
   ** be looked up if it has an opened checkout (see the list below).
   **
   ** Returns 0 and sets *rv to the id if it finds an unambiguous
   ** match.
   **
   ** Returns FSL_RC_MISUSE if !f, !sym, !*sym, or !rv.
   **
   ** Returns FSL_RC_NOT_A_REPO if f has no opened repository.
   **
   ** Returns FSL_RC_AMBIGUOUS if sym is a partial UUID which matches
   ** multiple full UUIDs.
   **
   ** Returns FSL_RC_NOT_FOUND if it cannot find anything.
   **
   ** Symbols supported by this function:
   **
   ** - SHA1 hash
   ** - SHA1 hash prefix of at least 4 characters
   ** - Symbolic Name
   ** - "tag:" + symbolic name
   ** - Date or date-time 
   ** - "date:" + Date or date-time
   ** - symbolic-name ":" date-time
   ** - "tip"
   ** - "root:" resolves to the root manifest of the given checkin. In
   ** the trunk this will always resolve to the first "empty checkin"
   ** manifest.
   **
   ** The following additional forms are available in local checkouts:
   **
   ** - "current"
   ** - "prev" or "previous"
   ** - "next"
   **
   */
  int fsl_repo_sym_to_rid( fsl_cx * f, char const * sym, fsl_atype_t type,
                           fsl_id_t * rv );

  /**
   ** Similar to fsl_repo_sym_to_rid() but on success if returns a UUID
   ** string by assigning it to *rv. If rid is not NULL then on
   ** success the db record ID corresponding to the returned UUID is
   ** assigned to *rid. The caller must eventually free the returned
   ** string memory by passing it to fsl_free().
   **/
  int fsl_repo_sym_to_uuid( fsl_cx * f, char const * sym,
                            fsl_atype_t type, fsl_uuid_str * rv,
                            fsl_id_t * rid );

  /**
   ** Searches f's repo database for the a blob with the given uuid
   ** (any unique UUID prefix). On success a positive record ID is
   ** returned. On error a negative value is returned. If no uuid
   ** match is found 0 is returned.
   */
  fsl_id_t fsl_repo_uuid_to_rid( fsl_cx * f, char const * uuid );

  /**
   ** The opposite of fsl_repo_uuid_to_rid(), this returns the UUID
   ** string of the given blob record ID. Ownership of the string is
   ** passed to the caller and it must eventually be freed using
   ** fsl_free(). Returns NULL on error (invalid arguments or f has no
   ** repo opened) or if no blob record is found.
   */
  fsl_uuid_str fsl_repo_rid_to_uuid(fsl_cx * f, fsl_id_t rid);
  
  /**
   ** Convenience wrapper around fsl_db_g_int32() which returns the
   ** value of a property from f's repo db's config table. Returns
   ** dflt if !f, f has no opened repo db, no entry is found, or on
   ** db-level errors.
   */
  fsl_int32_t fsl_repo_g_int32( fsl_cx * f, fsl_int32_t dflt, char const * key );

  /**
   ** fsl_in64_t counterpart of fsl_repo_g_int32().
   */
  fsl_int64_t fsl_repo_g_int64( fsl_cx * f, fsl_int64_t dflt, char const * key );

  /**
   ** fsl_double_t counterpart of fsl_repo_g_int32().
   */
  fsl_double_t fsl_repo_g_double( fsl_cx * f, fsl_double_t dflt, char const * key );

  /**
   ** fsl_id_t counterpart of fsl_repo_g_int32().
   */
  fsl_id_t fsl_repo_g_id( fsl_cx * f, fsl_id_t dflt, char const * key );

  /**
   ** The boolean counterpart of fsl_repo_g_int32(). A boolean value
   ** is any for which fsl_str_bool() returns a true value. If the
   ** given config entry is not found, or on any error, dflt is returned.
   */
  char fsl_repo_g_bool( fsl_cx * f, char dflt, char const * key );

  /**
   ** String counterpart of fsl_repo_g_int32(). The returned memory
   ** must eventually be freed using fsl_free(). If len is not NULL
   ** then it is set to the length of the returned string. Returns NULL
   ** for any sort of error.
   */
  char * fsl_repo_g_text( fsl_cx * f, char const * key, fsl_size_t * len);


  /**
   ** Sets a configuration variable in f's checkout database. Returns
   ** 0 on success.  val may be NULL. Returns FSL_RC_MISUSE if !f, f
   ** has no opened checkout, or !key, FSL_RC_RANGE if !key.
   */
  int fsl_repo_set_text( fsl_cx * f, char const * key, char const * val );

  /**
   ** Int32 counterpart of fsl_repo_set_text().
   */
  int fsl_repo_set_int32( fsl_cx * f, char const * key, fsl_int32_t val );

  /**
   ** Int64 counterpart of fsl_repo_set_text().
   */
  int fsl_repo_set_int64( fsl_cx * f, char const * key, fsl_int64_t val );

  /**
   ** Double counterpart of fsl_repo_set_text().
   */
  int fsl_repo_set_double( fsl_cx * f, char const * key, fsl_double_t val );
  
  /**
   ** Convenience wrapper around fsl_db_g_int32() which returns the
   ** value of a property from f's checkout db's vvar table. Returns
   ** dflt if !f, f has no checkout, no entry is found, or on db-level
   ** errors.
   */
  fsl_int32_t fsl_local_g_int32( fsl_cx * f, fsl_int32_t dflt, char const * key );

  /**
   ** fsl_in64_t counterpart of fsl_local_g_int32().
   */
  fsl_int64_t fsl_local_g_int64( fsl_cx * f, fsl_int64_t dflt, char const * key );

  /**
   ** fsl_double_t counterpart of fsl_local_g_int32().
   */
  fsl_double_t fsl_local_g_double( fsl_cx * f, fsl_double_t dflt, char const * key );

  /**
   ** fsl_id_t counterpart of fsl_local_g_int32().
   */
  fsl_id_t fsl_local_g_id( fsl_cx * f, fsl_id_t dflt, char const * key );

  /**
   ** The "checkout" db counterpart of fsl_repo_g_bool()
   */
  char fsl_local_g_bool( fsl_cx * f, char dflt, char const * key );

  /**
   ** String counterpart of fsl_local_g_int32(). The returned memory
   ** must eventually be freed using fsl_free(). If len is not NULL
   ** then it is set to the length of the returned string. Returns NULL
   ** for any sort of error.
   */
  char * fsl_local_g_text( fsl_cx * f, char const * key, fsl_size_t * len);


  /**
   ** Sets a configuration variable in f's checkout database. Returns
   ** 0 on success.  val may be NULL. Returns FSL_RC_MISUSE if !f, f
   ** has no opened checkout, or !key, FSL_RC_RANGE if !key.
   */
  int fsl_local_set_text( fsl_cx * f, char const * key, char const * val );

  /**
   ** Int32 counterpart of fsl_local_set_text().
   */
  int fsl_local_set_int32( fsl_cx * f, char const * key, fsl_int32_t val );

  /**
   ** Int64 counterpart of fsl_local_set_text().
   */
  int fsl_local_set_int64( fsl_cx * f, char const * key, fsl_int64_t val );

  /**
   ** Double counterpart of fsl_local_set_text().
   */
  int fsl_local_set_double( fsl_cx * f, char const * key, fsl_double_t val );

  /** TODO */
  int fsl_local_set_bool( fsl_cx * f, char const * key, char val );
  
  /**
   ** Incomplete/experimental, subject to much change. But it seems to
   ** work.
   **
   ** Adds a control record to f's repositoriy that either creates or
   ** cancels a tag.
   **
   ** symToTag is a symbolic name (as per fsl_repo_sym_to_rid()) of the
   ** artifact to tag.
   **
   ** tagType is the type (add, cancel, or propagate) of tag.
   **
   ** tagName is the name of the tag. Must not be NULL/empty.
   **
   ** tagValue is the optional value for the tag. May be NULL.
   **
   ** userName is the user's name to apply to the artifact. May not be
   ** empty/NULL. Use fsl_guess_user_name() to try to figure out
   ** a proper user name based on the environment.
   **
   ** mtime is the timestamp for the new artifact. Pass a value <=0 to
   ** use the current time.
   **
   ** If newId is not NULL then on success the rid of the new tag control
   ** artifact is assigned to *newId.
   **
   ** Returns 0 on success and has about a million and thirteen
   ** possible error conditions.
   **
   ** If the artifact being tagged is private, the new tag is also
   ** marked as private.
   **
   */
  int fsl_repo_tag_sym( fsl_cx * f,
                        fsl_tag_type tagType,
                        char const * symToTag,
                        char const * tagName,
                        char const * tagValue,
                        char const * userName,
                        fsl_double_t mtime,
                        fsl_id_t * newId );

  /**
   ** Equivalent to fsl_repo_tag_sym() except that it takes an RID
   ** instead of a symbolic name as the artifact-to-tag argument (its
   ** 3rd arg).
   */
  int fsl_repo_tag_rid( fsl_cx * f, fsl_tag_type tagType,
                        fsl_id_t artifactRidToTag, char const * tagName,
                        char const * tagValue, char const * userName,
                        fsl_double_t mtime, fsl_id_t * newId );

  /**
   ** Returns non-0 (true) if the checkin with the given rid is a
   ** leaf, 0 (false) if not. Returns 0 if !f, f has no repo db
   ** opened, the query fails (likely indicating that it is not a
   ** repository db), or just about any other conceivable non-success
   ** case.
   **
   ** A leaf is a commit which has no children in the same branch.
   */
  char fsl_repo_id_is_leaf(fsl_cx * f, fsl_id_t rid);

  /**
   ** Counts the number of primary non-branch children for the given
   ** check-in.
   **
   ** A primary child is one where the parent is the primary parent, not
   ** a merge parent.  A "leaf" is a node that has zero children of any
   ** kind.  This routine counts only primary children.
   **
   ** A non-branch child is one which is on the same branch as the parent.
   **
   ** Returns a negative value on error.
   */
  fsl_int_t fsl_repo_count_nonbranch_children(fsl_cx * f, fsl_id_t rid);

  /**
   ** Looks for the delta table record where rid==deltaRid, and
   ** returns that record's srcid via *rv. Returns 0 on success, non-0
   ** on error. *rv is set to 0 before running the query, and will have
   ** that value if no record is found.
   **/
  int fsl_repo_delta_src_id( fsl_cx * f, fsl_id_t deltaRid, fsl_id_t * rv );


  /**
   ** Return true if the given artifact ID should is listed in he shun
   ** table, else false.
   */
  char fsl_repo_uuid_is_shunned(fsl_cx * f, const char *zUuid);
  


#if defined(__cplusplus)
} /*extern "C"*/
#endif
#endif
/* NET_FOSSIL_SCM_FSL_CONTENT_H_INCLUDED */