/* -*- 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_CORE_H_INCLUDED) #define NET_FOSSIL_SCM_FSL_CORE_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/ ** ********************************************************************* ** This file declares the core SCM-related public APIs. */ #include "fossil-scm/fossil-util.h" /* MUST come first b/c of config macros */ #include /* struct tm, time_t */ #if defined(__cplusplus) extern "C" { #endif /** ** @struct fsl_cx ** ** The main Fossil "context" type. This is the first argument to ** many Fossil library API routines, and holds all state related ** to a checkout and/or repository and/or global fossil configuration ** database(s). ** ** An instance's lifetime looks something like this: ** ** @code ** int rc; ** fsl_cx * f = NULL; // ALWAYS initialize to NULL or results are undefined ** rc = fsl_cx_init( &f, NULL ); ** assert(!rc); ** rc = fsl_repo_open( f, "myrepo.fsl" ); ** ...use the context, and clean up when done... ** fsl_cx_finalize(f); ** @endcode ** ** The contents of an fsl_cx instance are strictly private, for use ** only by APIs in this library. Any client-side dependencies on ** them will lead to undefined behaviour at some point. ** ** Design note: this type is currently opaque to client ** code. Having it non-opaque also has advantages, though, and i'd ** generally prefer that (to allow client-side allocation and ** embedding in other structs). Binary compatibility concerns might ** force us to keep it opaque. ** */ typedef struct fsl_cx fsl_cx; typedef struct fsl_cx_config fsl_cx_config; typedef struct fsl_db fsl_db; typedef struct fsl_cx_init_opt fsl_cx_init_opt; typedef struct fsl_stmt fsl_stmt; /** ** This enum defines type ID tags with which the API tags fsl_db ** instances so that the library can figure out which DB is ** which. This is primarily important for certain queries, which ** need to know whether they are accessing the repo or config db, ** for example. ** ** All that said, i'm not yet fully convinced that a straight port ** of the v1 model is the best option for how we internally manage ** DBs, so this is subject to eventual change or removal. */ enum fsl_db_role_t { /** ** Sentinel "no role" value. */ FSL_DB_ROLE_NONE = 0, /** ** Analog to v1's "configdb". */ FSL_DB_ROLE_CONFIG = 0x01, /** ** Analog to v1's "repository". */ FSL_DB_ROLE_REPO = 0x02, /** ** Analog to v1's "localdb". */ FSL_DB_ROLE_CHECKOUT = 0x04, /** ** Analog to v1's "main", which is basically an alias for the first ** db opened. */ FSL_DB_ROLE_MAIN = 0x08 }; typedef enum fsl_db_role_t fsl_db_role_t; /** ** Roles equate to permissions in Fossil v1. Here we implement them ** as a bitmask and hope we never need more than 31 of them. ** ** Actually... all of this app-level stuff. The library doesn't ** really care about users (and therefore access rights) at all. ** Nonetheless, the library should provide some base functionality ** for it, based on the v1 model. Clients are of course not ** prohibited from adding their own security models/policies. */ enum fsl_user_role_t { FSL_UROLE_DEFAULT = 0, FSL_UROLE_GUEST = FSL_UROLE_DEFAULT, FSL_UROLE_ANONYMOUS = 1, FSL_UROLE_ADMIN = 1 << 1, FSL_UROLE_SETUP = 1 << 2, FSL_UROLE_READ = 1 << 3, FSL_UROLE_COMMIT = 1 << 4, FSL_UROLE_DELETE = 1 << 5, FSL_UROLE_PASSWORD = 1 << 6, FSL_UROLE_QUERY = 1 << 7, FSL_UROLE_WRITE = 1 << 8, FSL_UROLE_HYPERLINK = 1 << 9, FSL_UROLE_CLONE = 1 << 10, FSL_UROLE_WIKI_READ = 1 << 11, FSL_UROLE_WIKI_CREATE = 1 << 12, FSL_UROLE_WIKI_APPEND = 1 << 13, FSL_UROLE_WIKI_EDIT = 1 << 14, FSL_UROLE_WIKI_MODERATE = 1 << 15, FSL_UROLE_TKT_READ = 1 << 16, FSL_UROLE_TKT_NEW = 1 << 17, FSL_UROLE_TKT_APPEND = 1 << 18, FSL_UROLE_TKT_WRITE = 1 << 19, FSL_UROLE_TKT_MODERATE = 1 << 20, FSL_UROLE_TKT_RPT_FORMAT = 1 << 21, FSL_UROLE_ATTACH = 1 << 22, FSL_UROLE_READ_ADDR = 1 << 23, FSL_UROLE_ZIP = 1 << 24, FSL_UROLE_PRIVATE = 1 << 25, FSL_UROLE_ALL = 0x7FFFFFFF /* unsigned 32-bit+ enums are not portable :/ */ }; typedef enum fsl_user_role_t fsl_user_role_t; /** ** Bitmask values specifying "configuration sets." The values in ** this enum come directly from fossil(1), but they are not part of ** the db structure, so may be changed over time. */ enum fsl_configset_t { /** Sentinel value. */ FSL_CONFSET_NONE = 0x000000, /** Style sheet only */ FSL_CONFIGSET_CSS = 0x000001, /** WWW interface appearance */ FSL_CONFIGSET_SKIN = 0x000002, /** Ticket configuration */ FSL_CONFIGSET_TKT = 0x000004, /** Project name */ FSL_CONFIGSET_PROJ = 0x000008, /** Shun settings */ FSL_CONFIGSET_SHUN = 0x000010, /** The USER table */ FSL_CONFIGSET_USER = 0x000020, /** The CONCEALED table */ FSL_CONFIGSET_ADDR = 0x000040, /** Transfer configuration */ FSL_CONFIGSET_XFER = 0x000080, /** Everything */ FSL_CONFIGSET_ALL = 0x0000ff, /** Causes overwrite instead of merge */ FSL_CONFIGSET_OVERWRITE = 0x100000, /** Use the legacy format */ FSL_CONFIGSET_OLDFORMAT = 0x200000 }; typedef enum fsl_configset_t fsl_configset_t; /** ** Runtime-configurable flags for a fsl_cx instance. */ enum fsl_cx_flag_t { FSL_CX_F_NONE = 0, /** ** DO NOT USE THIS - it will be removed. ** ** Indicates that when "crosslinking" a CONTROL manifest, timeline ** event entries should _not_ be created for T cards (tags). The ** default, for historical reasons, is to add 'g' events. ** ** Note that the event table is generated locally for each copy of ** a repository, based on input from the manifests. Thus this only ** applies to the current copy of the repo. When the artifacts are ** synced into other repos (or somehow back into this repo, e.g. ** via a rebuild) then the timeline entry(ies) elided due to this ** flag will appear. The timeline is largely an artifact of ** fossil(1), not this library, and it is not clear if this library ** should maintain the timeline in its current form. ** ** Please help us find a better name for this flag. */ FSL_CX_F_MF_TAGS_NO_EVENT = 0x01, /** ** Don't use this - it is almost certainly not useful at the ** library level. ** ** Used by fsl_cx_localtime() to figure out whether to convert times ** to GMT or not. Note that this conversion is different from UTC ** in some cases! ** ** This has no effect on the core operations of libfossil, nor on ** data which comes from artifacts (e.g. the D-card is always left ** as-is), but may change time strings for some output routines. */ FSL_CX_F_LOCALTIME_GMT = 0x02, /** ** Tells us whether or not we want to calculate R-cards by default. ** Historically they were initially required but eventually made ** optional due largely to their memory costs. */ FSL_CX_F_CALC_R_CARD = 0x04, /** ** Default flags for all fsl_cx instances. */ FSL_CX_F_DEFAULTS = FSL_CX_F_CALC_R_CARD }; typedef enum fsl_cx_flag_t fsl_cx_flag_t; /** ** Most functions in this API which return an int type return error ** codes from the fsl_rc_t enum. None of these entries are ** (currently) guaranteed to have a specific value across Fossil ** versions except for FSL_RC_OK, which is guaranteed to always be ** 0 (and the API guarantees that no other code shall have a value ** of zero). ** ** The only reasons numbers are hard-coded to the values (or some of ** them) is to simplify debugging during development. Clients may use ** fsl_rc_cstr() to get some human-readable (or programmer-readable) ** form for any given value in this enum. ** ** Maintenance reminder: as entries are added/changed, update ** fsl_rc_cstr(). */ enum fsl_rc_t { /** ** The quintessential not-an-error value. */ FSL_RC_OK = 0, /** ** Generic/unknown error. */ FSL_RC_ERROR = 100, /** ** A placeholder return value for "not yet implemented" functions. */ FSL_RC_NYI = 101, /** ** Out of memory. Indicates that a resource allocation request ** failed. */ FSL_RC_OOM = 102, /* ** API misuse (invalid args) */ FSL_RC_MISUSE = 103, /** ** Some range was violated (function argument, UTF character, etc.). */ FSL_RC_RANGE = 104, /** ** Indicates that access to or locking of a resource was denied ** by some security mechanism or other. */ FSL_RC_ACCESS = 105, /** ** Indicates an I/O error. Whether it was reading or writing is ** context-dependent. */ FSL_RC_IO = 106, /** ** requested resource not found */ FSL_RC_NOT_FOUND = 107, /** ** Indicates that a to-be-created resource already exists. */ FSL_RC_ALREADY_EXISTS = 108, /** ** Data consistency problem */ FSL_RC_CONSISTENCY = 109, /** ** Indicates that the requested repo needs to be rebuilt. */ FSL_RC_REPO_NEEDS_REBUILD = 110, /** ** Indicates that the requested repo is not, in fact, a repo. Also ** used by some APIs to indicate that they require a repository db ** but none has been opened. */ FSL_RC_NOT_A_REPO = 111, /** ** Indicates an attempt to open a too-old or too-new repository db. */ FSL_RC_REPO_VERSION = 112, /** ** Indicates db-level error (e.g. statement prep failed). In such ** cases, the error state of the related db handle (fsl_db) or ** Fossilc context (fsl_cx) will be updated to contain more ** information directly from the db driver. */ FSL_RC_DB = 113, /** ** Used by some iteration routines to indicate that iteration should ** stop prematurely without an error. */ FSL_RC_BREAK = 114, /** ** Indicates that fsl_stmt_step() has fetched a row and the cursor ** may be used to access the current row state (e.g. using ** fsl_stmt_get_int32() and friends). It is strictly illegal to use ** the fsl_stmt_get_xxx() APIs unless fsl_stmt_step() has returned ** this code. */ FSL_RC_STEP_ROW = 115, /** ** Indicates that fsl_stmt_step() has reached the end of the result ** set and that there is no row data to process. This is also the ** result for non-fetching queries (INSERT and friends). It is strictly ** illegal to use the fsl_stmt_get_xxx() APIs after fsl_stmt_step() has ** returned this code. */ FSL_RC_STEP_DONE = 116, /** ** Indicates that a db-level error occurred during a ** fsl_stmt_step() iteration. */ FSL_RC_STEP_ERROR = 117, /** ** Indicates that some data type or logical type is incorrect ** (e.g. an invalid card type in conjunction with a given ** fsl_deck). */ FSL_RC_TYPE = 118, /** ** Indicates that an operation which requires a checkout does not ** have a checkout to work on. */ FSL_RC_NOT_A_CHECKOUT = 119, /** ** Not yet used. Indicates that a repo and checkout do not belong ** together. The public API currently does not allow that to ** happen. */ FSL_RC_REPO_MISMATCH = 120, /** ** Indicates that a checksum comparison failed, possibly indicating ** that corrupted or unexpected data was just read. */ FSL_RC_CHECKSUM_MISMATCH = 121, /** ** Indicates that a size comparison check failed. ** ** TODO: remove this if it is not used. */ FSL_RC_SIZE_MISMATCH, /** ** Indicates that an invalid separator was encountered while ** parsing a delta. */ FSL_RC_DELTA_INVALID_SEPARATOR, /** ** Indicates that an invalid size value was encountered while ** parsing a delta. */ FSL_RC_DELTA_INVALID_SIZE, /** ** Indicates that an invalid operator was encountered while parsing ** a delta. */ FSL_RC_DELTA_INVALID_OPERATOR, /** ** Indicates that an invalid terminator was encountered while ** parsing a delta. */ FSL_RC_DELTA_INVALID_TERMINATOR, /** ** Indicates a generic syntax error in a control artifact. Some ** types of manifest-releated errors are reported with more ** specific error codes, e.g. FSL_RC_RANGE if a given Card type ** appears too often. */ FSL_RC_CA_SYNTAX, /** ** Indicates that some value or expression is ambiguous. Typically ** caused by trying to resolve ambiguous symbolic names or partial ** UUIDs to their full UUIDs. */ FSL_RC_AMBIGUOUS }; typedef enum fsl_rc_t fsl_rc_t; /** ** Filesystem-level permissions flags supported by fossil ** Manifests. Their numeric values are a hard-coded part of the ** Fossil architecture and must not be changed. Note that these ** refer to manifest-level permissions and not filesystem-level ** permissions (though they translate to/from filesystem-level ** meanings at some point). */ enum fsl_fs_perm_t { /** Indicates a regular, writable file. */ FSL_FS_PERM_REGULAR = 0, /** Indicates a regular file with the executable bit set. */ FSL_FS_PERM_EXE = 0x1, /** Indicates a symlink. Note that symlinks do not have the ** executable bit set separately on Unix systems. Also note ** that libfossil does NOT YET IMPLEMENT symlink support ** like fossil(1) does - it currently treats symlinks as ** Unix treats symlinks. */ FSL_FS_PERM_LINK = 0x2 }; typedef enum fsl_fs_perm_t fsl_fs_perm_t; /** ** Returns a "standard" string form for a fsl_rc_t code. The string ** is primarily intended for debugging purposes. The returned bytes ** are guaranteed to be static and NUL-terminated. They are not ** guaranteed to contain anything useful for any purposes other than ** debugging and tracking down problems. */ char const * fsl_rc_cstr(int); /** ** Returns the value of FSL_LIBRARY_VERSION used to compile the ** library. If this value differs from the value the caller was ** compiled with, Chaos might ensue. ** ** The API does not yet have any mechanism for determining ** compatibility between repository versions and it also currently ** does no explicit checking to disallow incompatible versions. */ char const * fsl_library_version(); /** ** Returns true (non-0) if yourLibVersion compares lexically ** equal to FSL_LIBRARY_VERSION, else it returns false (0). */ char fsl_library_version_matches(char const * yourLibVersion); /** ** This type, accessible to clients via the ::fsl_lib_configurable ** global, contains configuration-related data for the library ** which can be swapped out by clients. */ struct fsl_lib_configurable_t { /** ** Library-wide allocator. It may be replaced by the client IFF ** it is replaced before the library allocates any memory. The ** default implementation uses the C-standard ** de/re/allocators. Modifying this member while any memory ** allocated through it is still "live" leads to undefined ** results. There is an exception: a "read-only" middleman proxy ** which does not change how the memory is allocated or ** intepreted can safely be swapped in or out at any time ** provided the underlying allocator stays the same and the ** client can ensure that there are no thread-related race ** conditions. e.g. it is legal to swap this out with a proxy ** which logs allocation requests and then forwards the call on ** to the original implementation, and it is legal to do so at ** essentially any time. The important thing this that all of the ** library-allocated memory goes through a single underlying ** (de)allocator for the lifetime of the application. */ fsl_allocator allocator; }; typedef struct fsl_lib_configurable_t fsl_lib_configurable_t; extern fsl_lib_configurable_t fsl_lib_configurable; /** ** A part of the configuration used by fsl_cx_init() and friends. ** */ struct fsl_cx_config { /** ** If true, all SQL which goes through the fossil engine ** will be traced to the fsl_output()-configured channel. */ char traceSql; /** ** If true, the print() SQL function will output its output to the ** fsl_output()-configured channel, else it is a no-op. */ char sqlPrint; }; /** ** fsl_cx_config instance initialized with defaults, intended for ** in-struct initialization. */ #define fsl_cx_config_empty_m { \ 0/*traceSql*/, \ 0/*sqlPrint*/ \ } /** ** fsl_cx_config instance initialized with defaults, intended for ** copy-initialization. */ extern const fsl_cx_config fsl_cx_config_empty; /** ** Parameters for fsl_cx_init(). */ struct fsl_cx_init_opt { /** ** The output channel for the Fossil instance. */ fsl_outputer output; /** ** Basic configuration parameters. */ fsl_cx_config config; }; /** Empty-initialized fsl_cx_init_opt instance. */ #define fsl_cx_init_opt_empty_m {fsl_outputer_empty_m, fsl_cx_config_empty_m} /** ** fsl_cx_init_opt instance initialized to use stdout for output and ** the standard system memory allocator. */ #define fsl_cx_init_opt_default_m {fsl_outputer_FILE_m, fsl_cx_config_empty_m} /** Empty-initialized fsl_cx_init_opt instance. */ extern const fsl_cx_init_opt fsl_cx_init_opt_empty; /** ** fsl_cx_init_opt instance initialized to use stdout for output and ** the standard system memory allocator. Used as the default when ** fsl_cx_init() is passed a NULL value for this parameter. */ extern const fsl_cx_init_opt fsl_cx_init_opt_default; /** ** Allocates a new fsl_cx instance, which must eventually ** be passed to fsl_cx_finalize() to clean it up. ** Normally clients do not need this - they can simply pass ** a pointer to NULL as the first argument to fsl_cx_init() ** to let it allocate an instance for them. */ fsl_cx * fsl_cx_malloc(); /** ** Initializes a fsl_cx instance. tgt must be a pointer to NULL, ** e.g.: ** ** @code ** fsl_cxt * f = NULL; // NULL is important - see below ** int rc = fsl_cx_init( &f, NULL ); ** @endcode ** ** It is very important that f be initialized to NULL _or_ to an ** instance which has been properly allocated and empty-initialized ** (e.g. via fsl_cx_malloc()). If *tgt is NULL, this routine ** allocates the context, else it assumes the caller did. If f ** points to unitialized memory then results are undefined. ** ** If the second parameter is NULL then default implementations are ** used for the context's output routine and other options. If it ** is not NULL then param->allocator and param->output must be ** initialized properly before calling this function. The contents ** of param are bitwise copied by this function and ownership of ** the returned value is transfered to *tgt in all cases except ** one: ** ** If this function cannot allocate a new instance it ** returns FSL_RC_OOM and does not modify *tgt. In this case, ** ownership of param's contents is not changed. On any other ** error, ownership of param's contents are transfered to *tgt and ** the client is responsible for passing *tgt ot ** fsl_cxt_finalize() when he is done with it. Note that (like in ** sqlite3), *tgt may be valid memory even if this function fails, ** and the caller must pass it to fsl_cx_finalize() whether or ** not this function succeeds unless it fails at the initial OOM ** (which the client can check by seeing if (*tgt) is NULL, but ** only if he set it to NULL before calling this). ** ** Returns 0 on success, FSL_RC_OOM on an allocation error, ** FSL_RC_MISUSE if (!tgt). ** ** @see fsl_cx_finalize() ** @see fsl_cx_reset() */ int fsl_cx_init( fsl_cx ** tgt, fsl_cx_init_opt const * param ); /** ** Clears (most) dynamic state in f, but does not free f and does ** not free "static" state (that set up by the init process). If ** closeDatabases is true then any databases managed by f are ** closed, else they are kept open. ** ** Client code will not normally need this - it is intended for a ** particular potential memory optimization case. If (and only if) ** closeDatabases is true then after calling this, f may be legally ** re-used as a target for fsl_cx_init(). ** ** This function does not trigger any finializers set for f's ** client state or output channel. It _does_ clear any user name ** set fsl_cx_user_set(). ** ** This is a no-op if !f. */ void fsl_cx_reset( fsl_cx * f, char closeDatabases ); /** ** Frees all memory associated with f, which must have been ** allocated/initialized using fsl_cx_malloc(), fsl_cx_init(), or ** equivalent, or created on the stack and properly initialized ** (via fsl_cx_init() or copy-constructed from fsl_cx_empty). ** ** This function triggers any finializers set for f's client state ** or output channel. ** ** This is a no-op if !f and is effectively a no-op if f has no ** state to destruct. */ void fsl_cx_finalize( fsl_cx * f ); /** ** Sets or unsets one or more option flags on the given fossil ** context. flags is the flag or a bitmask of flags to set (from ** the fsl_cx_flag_t enum). If enable is true the flag(s) is (are) ** set, else it (they) is (are) unset. Returns the new set of ** flags, or -1 if !f. */ int fsl_cx_flag_set( fsl_cx * f, int flags, char enable ); /** ** Returns f's flags, or -1 if !f. */ int fsl_cx_flags_get( fsl_cx * f ); /** ** Sets the Fossil error state to the given error code and ** fsl_appendf()-style format string/arguments. On success it ** returns the code parameter. It does not return 0 unless code is ** 0, and if it returns a value other than code then something went ** seriously wrong (e.g. allocation error: FSL_RC_OOM) or the ** arguments were invalid: !f results in FSL_RC_MISUSE. ** ** If !fmt then fsl_rc_cstr(code) is used to create the ** error string. ** ** As a special case, if code is FSL_RC_OOM, no error string is ** allocated (because it would likely fail, assuming the OOM ** is real). ** ** As a special case, if code is 0 (the non-error value) then fmt is ** ignored and any error state is cleared. */ int fsl_cx_err_set( fsl_cx * f, int code, char const * fmt, ... ); /** ** va_list counterpart to fsl_cx_err_set(). */ int fsl_cx_err_setv( fsl_cx * f, int code, char const * fmt, va_list args ); /** ** Fetches the error state from f. See fsl_error_get() for the semantics ** of the parameters and return value. */ int fsl_cx_err_get( fsl_cx * f, char const ** str, fsl_size_t * len ); /** ** Resets's f's error state, basically equivalent to ** fsl_cx_err_set(f,0,NULL). Is a no-op if f is NULL. This may be ** necessary for apps if they rely on looking at fsl_cx_err_get() ** at the end of their app/routine, because error state survives ** until it is cleared, even if the error held there was caught and ** recovered. This function might keep error string memory around ** for re-use later on. */ void fsl_cx_err_reset(fsl_cx * f); /** ** Replaces f's error state with the contents of err, taking over ** any memory owned by err (but not err itself). Returns the new ** error state code (the value of err->code before this call) on ** success. The only error case is if !f (FSL_RC_MISUSE). If err is ** NULL then f's error state is cleared and 0 is returned. err's ** error state is cleared by this call. */ int fsl_cx_err_set_e( fsl_cx * f, fsl_error * err ); /** ** If f has error state then it outputs its error state to its ** output channel and returns the result of fsl_output(). Returns ** FSL_RC_MISUSE if !f, 0 if f has no error state our output of the ** state succeeds. If addNewline is true then it adds a trailing ** newline to the output, else it does not. ** ** This is intended for testing and debugging only, and not as an ** error reporting mechanism for a full-fledged application. */ int fsl_cx_err_report( fsl_cx * f, char addNewline ); /** ** Moves db->error's state into f. If db is NULL then f's primary ** db connection is used. Returns FSL_RC_MISUSE if !f or (!db && ** f-is-not-opened). On success it returns f's new error code. ** ** The main purpose of this function is to propagate db-level ** errors up to higher-level code which deals directly with the f ** object but not the underlying db(s). */ int fsl_cx_uplift_db_error( fsl_cx * f, fsl_db * db ); /** ** Outputs the first n bytes of src to f's configured output ** channel. Returns 0 on success, FSL_RC_MISUSE if (!f || !src), ** 0 (without side effects) if !n, else it returns the result of ** the underlying output call. This is a harmless no-op if f is ** configured with no output channel. ** ** @see fsl_outputf() ** @see fsl_flush() */ int fsl_output( fsl_cx * f, void const * src, fsl_size_t n ); /** ** Flushes f's output channel. Returns 0 on success, FSL_RC_MISUSE ** if !f. If the flush routine is NULL then this is a harmless ** no-op. ** ** @see fsl_outputf() ** @see fsl_output() */ int fsl_flush( fsl_cx * f ); /** ** Uses fsl_appendf() to append formatted output to the channel ** configured for use with fsl_output(). Returns 0 on success, ** FSL_RC_MISUSE if !f or !fmt, FSL_RC_RANGE if !*fmt, and ** FSL_RC_IO if the underlying fsl_appendf() operation fails. ** ** Note, however, that due to the printf()-style return semantics ** of fsl_appendf(), it is not generically possible to distinguish ** a partially-successful (i.e. failed in the middle) write from ** success. e.g. if fmt contains a format specifier which performs ** memory allocation and that allocation fails, it is unlikely that ** this function will be able to be aware of that error. The only ** way to fix that is to change the return semantics of ** fsl_appendf() (and adjust any existing code which relies on ** them). ** ** @see fsl_output() ** @see fsl_flush() */ int fsl_outputf( fsl_cx * f, char const * fmt, ... ); /** ** va_list counterpart to fsl_outputf(). */ int fsl_outputfv( fsl_cx * f, char const * fmt, va_list args ); /** ** Opens the given db file name as f's repository. Returns 0 on ** success. On error it sets f's error state and returns that code ** unless the error was FSL_RC_MISUSE (which indicates invalid ** arguments and it does not set the error state). ** ** Fails with FSL_RC_MISUSE if !f, !repoDbFile, !*repoDbFile. Returns ** FSL_RC_ACCESS if f already has an opened repo db. ** ** Returns FSL_RC_NOT_FOUND if repoDbFile is not found, as this ** routine cannot create a new repository db. ** ** When a repository is opened, the fossil-level user name ** associated with f (if any) is overwritten with the default user ** from the repo's login table (the one with uid=1). Thus ** fsl_cx_user_get() may return a value even if the client has not ** called fsl_cx_user_set(). ** ** It would be nice to have a parameter specifying that the repo ** should be opened read-only. That's not as straightforward as it ** sounds because of how the various dbs are internally managed ** (via one db handle). Until then, the permissions of the ** underlying repo file will determine how it is opened. i.e. a ** read-only repo will be opened read-only. ** ** @see fsl_repo_create() ** @see fsl_repo_close() */ int fsl_repo_open( fsl_cx * f, char const * repoDbFile/*, char readOnlyCurrentlyIgnored*/ ); /** ** If fsl_repo_open_xxx() or fsl_checkout_open_dir() has been ** used to open a respository db, this call closes that db and ** returns 0. Returns FSL_RC_MISUSE if !f. FSL_RC_NOT_FOUND if f ** has not opened a repository. ** ** If the repo is the "main" db, this also closes any associated ** checkout and config dbs. ** ** If a repository is opened "indirectly" via ** fsl_checkout_open_dir() then clients must not close it using ** this function; they should allow it to be closed implicitly when ** the checkout db is closed. ** ** @see fsl_repo_open() ** @see fsl_repo_create() */ int fsl_repo_close( fsl_cx * f ); /** ** Sets or clears (if userName is NULL) the default repository user ** name for operations which require one. ** ** Returns 0 on success, FSL_RC_MISUSE if f is NULL, ** FSL_RC_OOM if copying of the userName fails. ** ** Example usage: ** @code ** char * u = fsl_guess_user_name(); ** int rc = fsl_cx_user_set(f, u); ** fsl_free(u); ** @endcode ** ** (Sorry about the extra string copy there, but adding a function ** which passes ownership of the name string seems like overkill.) */ int fsl_cx_user_set( fsl_cx * f, char const * userName ); /** ** Returns the name set by fsl_cx_user_set(), or NULL if f has no ** default user name set. The returned bytes are owned by f and may ** be invalidated by any call to fsl_cx_user_set(). */ char const * fsl_cx_user_get( fsl_cx const * f ); /** ** Configuration parameters for fsl_repo_create(). Always ** copy-construct these from fsl_repo_create_opt_empty ** resp. fsl_repo_create_opt_empty_m in order to ensure proper ** behaviour vis-a-vis default values. ** ** TODOs: ** ** - Add project name/description, and possibly other ** configuration bits. ** ** - Allow client to set password for default user (currently set ** randomly, as fossil(1) does). */ struct fsl_repo_create_opt { /** ** The file name for the new repository. */ char const * filename; /** ** Fossil user name for the admin user in the new repo. If NULL, ** defaults to the Fossil context's user (see ** fsl_cx_user_get()). If that is NULL, it defaults to ** "root" for historical reasons. */ char const * username; /** ** The comment text used for the initial commit. If NULL or empty ** (starts with a NUL byte) then no initial check is ** created. fossil(1) is largely untested with that scenario (but ** it seems to work), so for compatibility it is not recommended ** that this be set to NULL. ** ** The default value (when copy-initialized) is "egg". There's a ** story behind the use of "egg" as the initial checkin comment, ** and it all started with a typo: "initial chicken" */ char const * commitMessage; /** ** If not NULL and not empty, fsl_repo_create() will use this ** repository database to copy the configuration, copying over ** the following settings: ** ** - The reportfmt table, overwriting any existing entries. ** ** - The user table fields (cap, info, mtime, photo) are copied ** for the "system users". The system users are: anonymous, ** nobody, developer, reader. ** ** - The vast majority of the config table is copied, arguably ** more than it should (e.g. the 'manifest' setting). */ char const * configRepo; /** ** If false, fsl_repo_create() will fail if this->filename ** already exists. */ char allowOverwrite; }; typedef struct fsl_repo_create_opt fsl_repo_create_opt; /** Initialized-with-defaults fsl_repo_create_opt struct, intended for in-struct initialization. */ #define fsl_repo_create_opt_empty_m {\ NULL/*filename*/, \ NULL/*username*/, \ "egg"/*commitMessage*/, \ NULL/*configRepo*/, \ 0/*allowOverwrite*/ \ } /** Initialized-with-defaults fsl_repo_create_opt struct, intended for copy-initialization. */ extern const fsl_repo_create_opt fsl_repo_create_opt_empty; /** ** Creates a new repository database using the options provided in ** the second argument. If f is not NULL, it must be a valid ** context instance, though it need not have an opened ** checkout/repository (if it does, it/they will be closed by this ** operation). If f is NULL, a temporary context is used for ** creating the repository, in which case the caller will not have ** access to detailed error information (only the result code) if ** this operation fails. The opt argument may not be NULL. ** ** If opt->allowOverwrite is false (0) and the file exists, it ** fails with FSL_RC_ALREADY_EXISTS, otherwise is ** creates/overwrites the file. This is a destructive operation if ** opt->allowOverwrite is true (non-0), so be careful. ** ** This operation installs the various "static" repository schemas ** into the db, sets up some default settings, and installs a ** default user. ** ** This operation always closes any repository/checkout opened by f ** because setting up the new db requires wiring it to f to set up ** some of the db-side infrastructure. The one exception is if ** argument validation fails, in which case f's ** repo/checkout-related state are not modified. ** ** See the fsl_repo_create_opt docs for more details regarding the ** creation options. ** ** On success, 0 is returned and f (if not NULL) is left with the ** new repository opened and ready for use. On error, f's error ** state is updated and any number of the FSL_RC_xxx codes may be ** returned - there are no less than 30 different _potential_ error ** conditions on the way to creating a new repository. ** ** Example usage: ** ** @code ** fsl_repo_create_opt opt = fsl_repo_create_opt_empty; ** int rc; ** opt.filename = "my.fossil"; ** // ... any other opt.xxx you want to set, e.g.: ** // opt.user = "fred"; ** // Assume fsl is a valid fsl_cx instance: ** rc = fsl_repo_create(fsl, &opt ); ** if(rc) { ...error... } ** else { ** fsl_db * db = fsl_cx_db_repo(f); ** assert(db); // == the new repo db ** ... ** } ** @endcode ** ** @see fsl_repo_open() ** @see fsl_repo_close() */ int fsl_repo_create(fsl_cx * f, fsl_repo_create_opt const * opt ); /** ** UNTESTED. ** ** Returns true if f has an opened repository database which is ** opened in read-only mode, else returns false. */ char fsl_repo_is_readonly(fsl_cx const * f); /** ** Tries to open a checked-out fossil repository db in the given ** directory. It looks for files named one of (_FOSSIL_, ** .fslckout), in that order, in the given directory. If neither is ** found then it moves up the path one directory and tries again, ** until it hits the root of the dirPath (see below for a ** note/caveat). ** ** If dirName is NULL then it behaves as if it had been passed the ** absolute path of the current directory (as determined by ** fsl_getcwd()). ** ** If dirName is not NULL and dirNameLen is <0 then fsl_strlen() is ** used to calculate dirName's len. ** ** Achtung: if dirName is relative, this routine might not find a ** checkout where it would find one if given an absolute path ** (because it traverses the path string given it instead of its ** canonical form). Wether this is a bug or a feature is not yet ** clear. When in doubt, use fsl_file_canonical_name() to normalize ** the directory name before passing it in here. If it turns out ** that we always want that behaviour, this routine will/should be ** modified to canonicalize the name. ** ** If this routine finds/opens a checkout, it also tries to open ** the repository database from which the checkout derives (and ** fails if it cannot). ** ** Returns 0 on success. If there is an error opening or validating ** the checkout or its repository db, f's error state will be ** updated. Error codes/conditions include: ** ** - FSL_RC_MISUSE if f is NULL. ** ** - FSL_RC_ACCESS if f already has and opened checkout. ** ** - FSL_RC_OOM if an allocation fails. ** ** - FSL_RC_NOT_FOUND if no checkout is foud or if a checkout's ** repository is not found. ** ** - FSL_RC_RANGE if dirname is not NULL but has a length of 0, ** either because 0 was passed in for dirNameLen or because ** dirNameLen was negative and *dirName is a NUL byte. ** ** - Various codes from fsl_getcwd() (if dirName is NULL). ** ** - Various codes if opening the associated repository DB fails. ** ** TODO: there's really nothing in the architecture which restricts ** a checkout db to being in the same directory as the checkout, ** except for some historical bits which "could" be refactored. It ** "might be interesting" to eventually provide a variant which ** opens a checkout db file directly. We have the infrastructure, ** just need some refactoring. We would need to add the working ** directory path to the checkout db's config, but should otherwise ** require no trickery or incompatibilities with fossil(1). */ int fsl_checkout_open_dir( fsl_cx * f, char const * dirName, fsl_int_t dirNameLen ); /** ** If fsl_checkout_open_dir() has been used to open a checkout db, ** this call closes that db and returns 0. Returns FSL_RC_MISUSE if ** !f, FSL_RC_NOT_FOUND if f has not opened a checkout. ** ** This also closes the repository implicitly opened for the ** checkout. ** ** If the repo is the "main" db, this also closes any associated ** config db. */ int fsl_checkout_close( fsl_cx * f ); /** ** Returs version information for the current checkout. ** ** If f is not NULL and has an opened checkout then... ** ** If uuid is not NULL then *uuid is set to the UUID of the opened ** checkout. If rid is not NULL, *rid is set to the record ID of ** that checkout. The returned uuid bytes and rid are valid until ** the library closes the checkout db or updates its state to a ** newer checkout version. When in doubt about lifetime issues, ** copy the UUID immediately after calling this. ** ** If f is NULL or has no checkout then *uuid will be set to NULL ** and *rid will be set to 0. */ void fsl_checkout_version_info(fsl_cx *f, fsl_uuid_cstr * uuid, fsl_id_t * rid ); /** ** If f is not NULL and has a checkout db opened then this function ** returns its name. The bytes are valid until that checkout db ** connection is closed. If len is not NULL then *len is (on ** success) assigned to the length of the returned string, in ** bytes. The string is NUL-terminated, so fetching the length (by ** passing a non-NULL 2nd parameter) is optional. ** ** Returns NULL if !f or f has no checkout opened. ** ** @see fsl_checkout_open_dir() ** @see fsl_cx_dir_name_checkout() ** @see fsl_cx_db_file_config() ** @see fsl_cx_db_file_repo() */ char const * fsl_cx_db_file_checkout(fsl_cx const * f, fsl_size_t * len); /** ** Equivalent to fsl_checkout_db_file() except that ** it applies to the name of the opened repository db, ** if any. ** ** @see fsl_cx_db_file_checkout() ** @see fsl_cx_db_file_config() */ char const * fsl_cx_db_file_repo(fsl_cx const * f, fsl_size_t * len); /** ** Equivalent to fsl_checkout_db_file() except that ** it applies to the name of the opened config db, ** if any. ** ** @see fsl_cx_db_file_checkout() ** @see fsl_cx_db_file_repo() */ char const * fsl_cx_db_file_config(fsl_cx const * f, fsl_size_t * len); /** ** Similar to fsl_cx_db_file_checkout() and friends except that it ** applies to db file implied by the specified role (2nd ** parameter). If no such role is opened, or the role is invalid, ** NULL is returned. */ char const * fsl_cx_db_file_for_role(fsl_cx const * f, fsl_db_role_t r, fsl_size_t * len); /** ** Returns a db name string for the given fsl_db_role value. The ** string is static, guaranteed to live as long as the app. It ** returns NULL (or asserts in debug builds) if passed ** FSL_DB_ROLE_NONE or some value out of range for the enum. */ const char * fsl_db_role_label(enum fsl_db_role_t r); /** ** If f has an opened checkout db (from fsl_checkout_open_dir()) ** then this function returns the directory part of the path ** for the checkout. The returned bytes are valid until that db ** connection is closed. If len is not NULL then *len is (on ** success) assigned to the length of the returned string, in bytes. ** The string is NUL-terminated, so fetching the length (by passing ** a non-NULL 2nd parameter) is optional. ** ** Returns NULL if !f or f has no checkout opened. ** ** @see fsl_checkout_open_dir() ** @see fsl_checkout_db_file() */ char const * fsl_cx_dir_name_checkout(fsl_cx const * f, fsl_size_t * len); /** ** Returns a handle to f's main db, or NULL if !f. The returned ** handle is valid as long as that db remains open. As a rule, ** it is invalidated by fsl_checkout_close() and ** fsl_repo_close(). The object is owned by f and the client MUST NOT ** do any of the following: ** ** - Close the db handle. ** ** - Use transactions without using fsl_db_transaction_begin() ** and friends. ** ** - Fiddle with the handle's internals. Doing so might confuse its ** owning context. ** ** Clients MAY add new user-defined functions, use the handle with ** fsl_db_prepare(), and other "mundane" db-related tasks. ** ** Design notes: ** ** The current architecture designates the first db opened for a ** context as its "main" db, and the other databases (if opened) ** get attached to that one. As long as there are no table name ** collisions across databases, this does not affect how queries ** are formulated. It does, however, pose problems when ** constructing full-qualified db table names. ** ** @see fsl_cx_db_repo() ** @see fsl_cx_db_checkout() */ fsl_db * fsl_cx_db( fsl_cx * f ); /** ** If f is not NULL and has had its repo opened via ** fsl_repo_open(), fsl_checkout_open_dir(), or similar, this ** returns a pointer to that database, else it returns NULL. ** ** @see fsl_cx_db() */ fsl_db * fsl_cx_db_repo( fsl_cx * f ); /** ** If f is not NULL and has had a checkout opened via ** fsl_checkout_open_dir() or similar, this returns a pointer to that ** database, else it returns NULL. ** ** @see fsl_cx_db() */ fsl_db * fsl_cx_db_checkout( fsl_cx * f ); /** ** A helper which fetches f's repository db. If f has no repo db ** then it sets f's error state to FSL_RC_NOT_A_REPO with a message ** describing the requirement, then returns NULL. Returns NULL if ** !f. */ fsl_db * fsl_needs_repo(fsl_cx * f); /** ** The checkout-db counterpart of fsl_needs_repo(). */ fsl_db * fsl_needs_checkout(fsl_cx * f); /** ** Opens the given database file as f's configuration database. If f ** already has a config database opened, it is closed before opening ** the new one. The database is created and populated with an ** initial schema if needed. ** ** If dbName is NULL or empty then it uses a default db name, ** "probably" under the user's home directory. To get the name of ** the database after it has been opened/attached, use ** fsl_cx_db_file_config(). ** ** TODO: strongly consider supporting non-attached use of ** the config db. Comments in v1 suggest that it is possible ** to lock the config db for other apps when it is attached ** to a long-running op by a fossil process. ** ** The following notes no longer apply, but it may be (re)added ** later: ** ** If useAttach is 0 (the most common case), the db is opened in ** its own connection, otherwise it is ATTACH'd to the currently ** opened db. The latter case is unusual, but allows one to create ** queries which join against multiple databases. When in doubt, ** pass 0 here. ** */ int fsl_config_open( fsl_cx * f, char const * dbName ); /** ** Closes/detaches the database connection opened by ** fsl_config_open(). Returns 0 on succes, FSL_RC_MISUSE if !f, ** FSL_RC_NOT_FOUND if no config db connection is opened/attached. */ int fsl_config_close( fsl_cx * f ); /** ** If f has an opened/attached configuration db then its handle is ** returned. See fsl_config_open(). */ fsl_db * fsl_cx_db_config( fsl_cx * f ); /** ** Convenience form of fsl_db_prepare() which uses f's main db. ** Returns 0 on success, FSL_RC_MISUSE if !f or !sql, FSL_RC_RANGE ** if !*sql. */ int fsl_cx_prepare( fsl_cx *f, fsl_stmt * tgt, char const * sql, ... ); /** ** va_list counterpart of fsl_cx_prepare(). */ int fsl_cx_preparev( fsl_cx *f, fsl_stmt * tgt, char const * sql, va_list args ); /** ** Wrapper around fsl_db_last_insert_id() which uses f's main ** database. Returns -1 if !f or f has no opened db. ** ** @see fsl_cx_db() */ fsl_id_t fsl_cx_last_insert_id(fsl_cx *f); /** ** Returns the raw SQL code for a Fossil global config database. */ char const * fsl_schema_config(); /** ** Returns the raw SQL code for the "static" parts of a Fossil ** repository database. These are the parts which are immutable ** (for the most part) between Fossil versions. They change _very_ ** rarely. */ char const * fsl_schema_repo1(); /** ** Returns the raw SQL code for the "transient" parts of a Fossil ** repository database - any parts which can be calculated via data ** held in the primary "static" schemas. These parts are ** occassionally recreated, e.g. via a 'rebuild' of a repository. */ char const * fsl_schema_repo2(); /** ** Returns the raw SQL code for a Fossil checkout database. */ char const * fsl_schema_checkout(); /** ** Returns the raw SQL code for a Fossil checkout db's ** _default_ core ticket-related tables. ** ** @see fsl_cx_schema_ticket() */ char const * fsl_schema_ticket(); /** ** If f's opened repository has a config non-empty entry named ** 'ticket-table', this returns its text via appending it to ** pOut. If no entry is found, fsl_schema_ticket() is appended to ** pOut. ** ** Returns 0 on success. On error the contents of pOut must not be ** considered valid but pOut might be partially populated. */ int fsl_cx_schema_ticket(fsl_cx * f, fsl_buffer * pOut); /** ** Returns the raw SQL code for Fossil ticket reports schemas. ** This gets installed as needed into repository databases. */ char const * fsl_schema_ticket_reports(); /** ** Works similarly to fsl_stat(), except that zName must refer to a ** path under f's current checkout directory. Note that this stats ** local files, not repository-level content. ** ** If relativeToCwd is true (non-0) then the filename is ** resolved/canonicalized based on the current working directory ** (see fsl_getcwd()), otherwise f's current checkout directory is ** used as the virtual root. This makes a subtle yet important ** difference in how the name is resolved. Applications taking ** input from users (e.g. CLI apps) will normally want to resolve ** from the current working dir (assuming the filenames were passed ** in from the CLI). In a GUI environment, where the current ** directory is likely not the checkout root, resolving based on ** the checkout root (i.e. relativeToCwd=0) is probably saner. ** ** Returns 0 on success. Errors include, but are not limited to: ** ** - FSL_RC_MISUSE if !f or !zName. ** ** - FSL_RC_NOT_A_CHECKOUT if f has no opened checkout. ** ** - If fsl_is_simple_pathname(zName) returns false then ** fsl_checkout_filename_check() is used o normalize the name. If ** that fails, its failure core is returned. ** ** - As for fsl_stat(). ** ** See fsl_stat() for more details regarding the tgt parameter. ** ** TODO: fossil-specific symlink support. Currently it does not ** distinguish between symlinks and non-links. ** ** @see fsl_cx_stat2() */ int fsl_cx_stat( fsl_cx * f, char relativeToCwd, char const * zName, fsl_fstat * tgt ); /** ** This works identically to fsl_cx_stat(), but provides more ** information. ** ** If nameOut is not NULL then the resolved/normalized path to to ** that file is appended to nameOut. If fullPath is true then an ** absolute path is written to nameOut, otherwise a ** checkout-relative path is written. ** ** Returns 0 on success. On stat() error, nameOut is not updated, ** but after stat()'ing, allocation of memory for nameOut's buffer ** may fail. ** ** @TODO clarify whether or not the result gets a trailing slash, ** or add a parameter which says whether or not to keep the slash ** (as with do in a few other functions). ** ** @see fsl_cx_stat() */ int fsl_cx_stat2( fsl_cx * f, char relativeToCwd, char const * zName, fsl_fstat * tgt, fsl_buffer * nameOut, char fullPath); /** ** Sets the case-sensitivity flag for f to the given value. */ void fsl_cx_case_sensitive_set(fsl_cx * f, char caseSensitive); /** ** Returns true (non-0) if f is set for case-sensitive filename ** handling, else 0. Returns 0 if !f. */ char fsl_cx_is_case_sensitive(fsl_cx const * f); /** ** If f is set to use case-sensitive filename handling, ** returns a pointer to an empty string, otherwise a pointer ** to the string "COLLATE nocase" is returned. ** Results are undefined if f is NULL. The returned bytes ** are static. */ char const * fsl_cx_filename_collation(fsl_cx const * f); /** ** Don't use this - the "selected files" mechanism is still ** up for re-thinking. ** ** Adds the given file f's list of "selected" files. zName ** must be a NUL-terminated string and its bytes are copied. ** Returns 0 on success, FSL_RC_MISUSE if either pointer is NULL, ** *zName is NUL, or on allocation error. */ int fsl_cx_selected_files_add(fsl_cx * f, char const * zName); /** ** Clears f's internal list of "selected" files. If freeListMemory ** is true then all underlying memory is freed immediately. If it ** is false, the strings are cleared but the list memory is ** available for re-use via fsl_cx_selected_files_add(). ** */ void fsl_cx_selected_files_clear(fsl_cx * f, char freeListMemory); /** ** Holds the list of "selected" files added by ** fsl_cx_selected_files_add(). The list is owned by f, and each ** entry in the list is a (char const *) owned by f. The list may ** be modified by the client if he knows what he's doing. Returns ** NULL if !f. */ fsl_list * fsl_cx_selected_files(fsl_cx *f); /** ** Const-correct form of fsl_cx_selected_files(). */ fsl_list const * fsl_cx_selected_files_c(fsl_cx const *f); /** ** An enumeration of the types of control artifacts used by ** Fossil. Their numeric values (with the exception of ** FSL_TYPE_CATYPE_INVALID) are a hard-coded part of the Fossil db ** architecture and must never 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_CHECKIN = 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 an "attachment" artifact (used in the ticketing ** subsystem). */ FSL_CATYPE_ATTACHMENT = 6, /** ** Indicates an "event" artifact (kind of like a blog entry). */ 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); /** ** For a given artifact type, it returns the key string used in the ** event.type db table. Returns NULL if passed an unknown value or ** a type which is not used in the event table, otherwise the ** returned bytes are static and NUL-terminated. ** ** The returned strings for a given type are as follows: ** ** - FSL_CATYPE_ANY returns "*" ** - FSL_CATYPE_CHECKIN returns "ci" ** - FSL_CATYPE_WIKI returns "w" ** - FSL_CATYPE_TAG returns "g" ** - FSL_CATYPE_TICKET returns "t" ** - FSL_CATYPE_EVENT returns "e" ** ** The other control artifact types to not have representations ** in the event table, and NULL is returned for them. ** ** All of the returned values can be used in comparison clauses in ** queries on the event table's 'type' field (but use GLOB instead ** of '=' so that the "*" returned by FSL_ATYPE_ANY can match!). ** For example, to get the comments from the most recent 5 commits: ** ** @code ** SELECT datetime(mtime), comment FROM event WHERE type='ci' ** ORDER BY mtime DESC LIMIT 5; ** @endcode ** ** Where 'ci' in the SQL should be a non-NULL return value from ** this function. */ char const * fsl_catype_event_cstr(fsl_catype_t t); /** ** 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_sym_to_rid( fsl_cx * f, char const * sym, fsl_catype_t type, fsl_id_t * rv ); /** ** Similar to fsl_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_sym_to_uuid( fsl_cx * f, char const * sym, fsl_catype_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 one of several unspecified negative values is ** returned. If no uuid match is found 0 is returned. ** ** Error cases include: either argument is NULL, uuid does not ** appear to be a full or partial UUID (or is too long), ** uuid is ambiguous (try providing a longer one) ** ** This implementation is more efficient when given a full, ** valid UUID (one for which fsl_is_uuid() returns true). */ fsl_id_t fsl_uuid_to_rid( fsl_cx * f, char const * uuid ); /** ** The opposite of fsl_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. If no record is ** found, f's error state is updated with an explanation of the ** problem. */ fsl_uuid_str fsl_rid_to_uuid(fsl_cx * f, fsl_id_t rid); #if 0 /** ** DO NOT USE - not yet tested and ready. ** ** Returns the result of either localtime(clock) or gmtime(clock), ** depending on f: ** ** - If f is NULL, returns localtime(clock). ** ** - If f has had its FSL_CX_F_LOCALTIME_GMT flag set (see ** fsl_cx_flag_set()) then returns gmtime(clock), else ** localtime(clock). ** ** If clock is NULL, NULL is returned. ** ** Note that fsl_cx instances default to using UTC for everything, ** which is the opposite of fossil(1). */ struct tm * fsl_cx_localtime( fsl_cx const * f, const time_t * clock ); /** ** Equivalent to fsl_cx_localtime(NULL, clock). */ struct tm * fsl_localtime( const time_t * clock ); /** ** DO NOT USE - not yet tested and ready. ** ** This function passes (f, clock) to fsl_cx_localtime(), ** then returns the result of mktime(3) on it. So... ** it adjusts a UTC Unix timestamp to either the same UTC ** local timestamp or to the local time. */ time_t fsl_cx_time_adj(fsl_cx const * f, time_t clock); #endif #if defined(__cplusplus) } /*extern "C"*/ #endif #endif /* NET_FOSSIL_SCM_FSL_CORE_H_INCLUDED */