/* -*- 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 */