/* -*- 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_CHECKOUT_H_INCLUDED)
#define NET_FOSSIL_SCM_FSL_CHECKOUT_H_INCLUDED
/*
  Copyright 2013-2021 The Libfossil Authors, see LICENSES/BSD-2-Clause.txt

  SPDX-License-Identifier: BSD-2-Clause-FreeBSD
  SPDX-FileCopyrightText: 2021 The Libfossil Authors
  SPDX-ArtifactOfProjectName: Libfossil
  SPDX-FileType: Code

  Heavily indebted to the Fossil SCM project (https://fossil-scm.org).

  ******************************************************************************
  This file declares public APIs for working with checkout-side fossil
  content.
*/

#include "fossil-db.h" /* MUST come first b/c of config macros */
#include "fossil-repo.h"

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


/**
   Returns 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 they will be
   needed later.

   Corner case: a new repo with no checkins has an RID of 0
   and a UUID of NULL.

   If f is NULL or has no checkout then *uuid will be set to NULL
   and *rid will be set to 0.
*/
FSL_EXPORT void fsl_checkout_version_info(fsl_cx *f, fsl_id_t * rid,
                                          fsl_uuid_cstr * uuid );

/**
   Given a fsl_cx with an opened checkout, and a filename, this
   function canonicalizes zOrigName to a form suitable for use as
   an in-repo filename, _appending_ the results to pOut. If pOut is
   NULL, it performs its normal checking but does not write a
   result, other than to return 0 for success.

   As a special case, if zOrigName refers to the top-level checkout
   directory, it resolves to either "." or "./", depending on whether
   zOrigName contains a trailing slash.

   If relativeToCwd is true then the filename is canonicalized
   based on the current working directory (see fsl_getcwd()),
   otherwise f's current checkout directory is used as the virtual
   root.

   If the input name contains a trailing slash, it is retained in
   the output sent to pOut except in the top-dir case mentioned
   above.

   Returns 0 on success, meaning that the value appended to pOut
   (if not NULL) is a syntactically valid checkout-relative path.

   Returns FSL_RC_RANGE if zOrigName points to a path outside
   of f's current checkout root.

   Returns FSL_RC_NOT_A_CHECKOUT if f has no checkout opened.

   Returns FSL_RC_MISUSE if !f, !zOrigName, FSL_RC_OOM on an
   allocation error.

   This function does not validate whether or not the file actually
   exists, only that its name is potentially valid as a filename
   for use in a checkout (though other, downstream rules might prohibit that, e.g.
   the filename "..../...." is not valid but is not seen as invalid by
   this function). (Reminder to self: we could run the end result through
   fsl_is_simple_pathname() to catch that?)
*/
FSL_EXPORT int fsl_checkout_filename_check( fsl_cx * f, char relativeToCwd,
                                            char const * zOrigName, fsl_buffer * pOut );


/**
   Adds the given filename to the current checkout vfile list of
   files as a to-be-added file, or updates an existing record if
   one exists.

   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. CLI apps which take file
   names from the user will generally want to set relativeToCwd to
   true. GUI apps, OTOH, will possibly need it to be false,
   depending on how they resolve and pass on the filenames.

   This function ensures that zFilename gets canonicalized and can
   be found under the checkout directory, and fails if no such file
   exists (checking against the canonicalized name).

   Returns 0 on success, non-0 on error.

   Note that unlike fsl_checkout_file_rm(), this routine cannot
   recursively add files from a directory name. Fixing that is on
   the TODO list.

   @see fsl_checkout_file_rm()
*/
FSL_EXPORT int fsl_checkout_file_add( fsl_cx * f, char relativeToCwd, char const * zFilename );

/**
   The converse of fsl_checkout_file_add(), this queues a file for
   removal from the current checkout. The arguments have identical
   meanings as for fsl_checkout_file_add() except that this routine
   does not ensure that the resolved filename actually exists - it
   only normalizes zFilename into its repository-friendly form.

   If recurseDirs is true then if zFilename refers to a directory
   then this operation queues all files under that directory
   (recursively) for removal. In this case, it is irrelevant
   whether or not zFilename ends in a trailing slash or not.

   Returns 0 on success, any of a number of non-0 codes on error.
   Returns FSL_RC_MISUSE if !f, !zFilename, or !*zFilename.
   Returns FSL_RC_NOT_A_CHECKOUT if f has no opened checkout.

   @see fsl_checkout_file_add()
*/
FSL_EXPORT int fsl_checkout_file_rm( fsl_cx * f, char relativeToCwd, char const * zFilename,
                          char recurseDirs );

/**
   Change-type flags for use with fsl_checkout_changes_visit() and
   friends.
*/
enum fsl_checkout_change_e {
/**
   Sentinel placeholder value.
*/
FSL_CKOUT_CHANGE_NONE = 0,
/**
   Indicates that a file was modified in some unspecified way.
*/
FSL_CKOUT_CHANGE_MOD,
/**
   Indicates that a file was modified as the result of a merge.
*/
FSL_CKOUT_CHANGE_MERGE_MOD,
/**
   Indicates that a file was added as the result of a merge.
*/
FSL_CKOUT_CHANGE_MERGE_ADD,
/**
   Indicates that a file was modified as the result of an
   integrate-merge.
*/
FSL_CKOUT_CHANGE_INTEGRATE_MOD,
/**
   Indicates that a file was added as the result of an
   integrate-merge.
*/
FSL_CKOUT_CHANGE_INTEGRATE_ADD,
/**
   Indicates that a file was added.
*/
FSL_CKOUT_CHANGE_ADDED,
/**
   Indicates that a file was removed.
*/
FSL_CKOUT_CHANGE_REMOVED,
/**
   Indicates that a file is missing from the local checkout.
*/
FSL_CKOUT_CHANGE_MISSING,
/**
   Indicates that a file was renamed.
*/
FSL_CKOUT_CHANGE_RENAMED,
/**
   NOT YET USED.

   Indicates that a file contains conflict markers.
*/
FSL_CKOUT_CHANGE_CONFLICT,
/**
   NOT YET USED.

   Indicates that a file in the changes table references
   a non-file on disk.
*/
FSL_CKOUT_CHANGE_NOT_A_FILE,
/**
   NOT YET USED.

   Indicates that a file is part of a cherrypick merge.
*/
FSL_CKOUT_CHANGE_CHERRYPICK,
/**
   NOT YET USED.

   Indicates that a file is part of a backout.
*/
FSL_CKOUT_CHANGE_BACKOUT
};

typedef enum fsl_checkout_change_e fsl_checkout_change_e;

/**
   Sets up the vfile table in f's opened checkout db and scans the
   checkout root directory's contents for changes compared to the
   pristine checkout state. It records any changes in the vfile
   table.

   Returns 0 on success, non-0 on error. Results are undefined if f is
   not valid.

   For compatibility with fossil(1), this routine clears the vfile
   table of any entries not related to the current checkout.

   @see fsl_checkout_changes_visit()
*/
FSL_EXPORT int fsl_checkout_changes_scan(fsl_cx * f);

/**
   A typedef for visitors of checkout status information via
   fsl_checkout_changes_visit(). Implementions will receive the
   last argument passed to fsl_checkout_changes_visit() as their
   first argument. The second argument indicates the type of change
   and the third holds the repository-relative name of the file.

   If changes is FSL_CKOUT_CHANGE_RENAMED then origName will hold
   the original name, else it will be NULL.

   Implementations must return 0 on success, non-zero on error. On
   error any looping performed by fsl_checkout_changes_visit() will
   stop and this function's result code will be returned.

   @see fsl_checkout_changes_visit()
*/
typedef int (*fsl_checkout_changes_f)(void * state, fsl_checkout_change_e change,
                                      char const * filename,
                                      char const * origName);

/**
   Compares the changes of f's local checkout against repository
   version vid (checkout version if vid is negative). For each
   change detected it calls visitor(state,...) to report the
   change.  If visitor() returns non-0, that code is returned from
   this function. If doChangeScan is true then
   fsl_checkout_changes_scan() is called by this function before
   iterating, otherwise it is assumed that the caller has called
   that or has otherwise ensured that the checkout db's vfile table
   has been populated.

   Returns 0 on success.

   @see fsl_checkout_changes_scan()
*/
FSL_EXPORT int fsl_checkout_changes_visit( fsl_cx * f, fsl_id_t vid,
                                           char doChangeScan,
                                           fsl_checkout_changes_f visitor,
                                           void * state );
/**
   A bitmask of flags for fsl_vfile_changes_scan().
*/
enum fsl_ckout_sig_t {
/**
   The empty flags set.
*/
FSL_VFILE_CKSIG_NONE = 0,

/**
   Non-file FS objects throw an error. Not yet implemented.
*/
FSL_VFILE_CKSIG_ENOTFILE = 0x001,
/**
   Verify file content using sha1sum, regardless of whether or not
   file timestamps differ.

   FIXME: rename to SHA and use the current hash for that artifact or
   the repo's preferred hash.
*/
FSL_VFILE_CKSIG_HASH = 0x002,
/**
   For unchanged or changed-by-merge files, set the mtime to last
   check-out time, as determined by fsl_mtime_of_manifest_file().
*/
FSL_VFILE_CKSIG_SETMTIME = 0x004,
/**
   Don't use this - introducing this feature may cause breakage
   with fossil.

   Indicates that when populating the vfile table, it should be
   cleared of entries for other checkins. This is primarily for
   compatibility with fossil(1), which generally assumes only a
   single checkin's worth of state is in vfile and can get confused
   if that is not the case.
*/
FSL_VFILE_CKSIG_CLEAR_VFILE = 0x008
};

/**
    This function clears and populates (if needed) the vfile table of
    f's checkout db for the given checkin version ID then compares
    files listed in it against files in the checkout directory,
    updating vfile's status for the current checkout version id as its
    goes.  If vid is negative then the current checkout's RID is used
    in its place (note that 0 is the RID of an initial empty
    repository!). cksigFlags must be a bitmask of fsl_ckout_sig_t
    values.

    Returns 0 on success, non-0 on error.

    BUG: this does not properly catch one particular corner-case
    change, where a file has been replaced by a same-named non-file
    (symlink or directory).
*/
FSL_EXPORT int fsl_vfile_changes_scan(fsl_cx * f, fsl_id_t vid, int cksigFlags);

/**
   If f has an opened checkout which has local changes noted in its
   checkout db state, returns true, else returns false. Note that this
   function does not do the filesystem scan to check for changes, but
   checks only the db state. Use fsl_vfile_changes_scan() to perform
   the actual scan (noting that library-side APIs which update that
   state may also record individual changes or automatically run a
   scan).
*/
FSL_EXPORT bool fsl_checkout_has_changes(fsl_cx *f);

/**
   Adds the given file f's list of "selected" files - the list of
   filenames which should be included in the next commit
   (see fsl_checkin_commit()).

   Warning: if this function is not called before
   fsl_checkin_commit(), then fsl_checkin_commit() will select all
   modified, added, removed, or renamed files by default.

   zName must be a non-empty NUL-terminated string and its bytes are
   copied. The filename is canonicalized via
   fsl_checkout_filename_check() - see that function for the meaning
   of the relativeToCwd parameter.

   The resolved name must refer to either a single vfile.pathname
   value in the current vfile table (i.e. in the current checkout,
   though possibly newly-added and not necessarily committed), or it
   must refer to a directory, under which all modified, added,
   deleted, or renamed files are queued up for the next commit.

   If given a single file name it returns FSL_RC_NOT_FOUND if the
   file is not in the current checkout. In this case f's error state
   is updated with a description of the problem.

   If given a directory name, it does not validate that any changes
   are actually detected for queuing up (that detection comes at the
   final commit stage).

   The change-state of the file(s) is not actually checked by this
   function, other than to confirm that the file is indeed listed in
   the current checkout. That means that the file may still be
   modified by the client before the commit takes place, and the
   changes on disk at the point of the fsl_checkin_commit() are the
   ones which get saved (or not).

   Returns 0 on success, FSL_RC_MISUSE if either pointer is NULL,
   or *zName is NUL. Returns FSL_RC_OOM on allocation error.

   On error f's error state might (depending on the nature of the
   problem) contain more details.

   Returns 0 and has no side-effects if zName is already in the
   checkin queue. This function honors the
   fsl_cx_is_case_sensitive() setting when comparing names but the
   check for the repo-level file is case-sensitive! That's arguably
   a bug.

   @see fsl_checkin_file_is_enqueued()
   @see fsl_checkin_file_dequeue()
   @see fsl_checkin_discard()
   @see fsl_checkin_commit()
*/
FSL_EXPORT int fsl_checkin_file_enqueue(fsl_cx * f, char const * zName,
                             char relativeToCwd);

/**
   The opposite of fsl_checkin_file_enqueue(), then removes the
   given file or directory name from f's checkin queue. Returns 0 on
   succes. Unlike fsl_checkin_file_enqueue(), this function does
   little validation on the input and simply asks the internals to
   clean up. Specifically, it does not return an error if this
   operation finds no entries to unqueue. If zName is empty or NULL
   then ALL files are unqueued from the pending checkin.

   If relativeToCwd is true (non-0) then zName is resolved based on
   the current directory, otherwise it is resolved based on the
   checkout's root directory.


   @see fsl_checkin_file_enqueue()
   @see fsl_checkin_file_is_enqueued()
   @see fsl_checkin_discard()
   @see fsl_checkin_commit()
*/
FSL_EXPORT int fsl_checkin_file_dequeue(fsl_cx * f, char const * zName,
                             char relativeToCwd);

/**
   Returns true (non-0) if the file named by zName is in f's current
   file checkin queue.  If NO files are in the current selection
   queue then this routine assumes that ALL files are implicitely
   selected. As long as at least once file is enqueud (via
   fsl_checkin_file_enqueue()) then this function only returns true
   for files which have been explicitly enqueued.

   If relativeToCwd then zName is resolved based on the current
   directory, otherwise it is resolved based on the checkout's
   root directory.

   This function returning true does not necessarily indicate that
   the file _will_ be checked in at the next commit. If the file has
   not been modified at commit-time then it will not be part of the
   commit.

   This function honors the fsl_cx_is_case_sensitive() setting
   when comparing names.

   Achtung: this does not resolve directory names like
   fsl_checkin_file_enqueue() and fsl_checkin_file_dequeue() do. It
   only works with file names.

   @see fsl_checkin_file_enqueue()
   @see fsl_checkin_file_dequeue()
   @see fsl_checkin_discard()
   @see fsl_checkin_commit()
*/
FSL_EXPORT bool fsl_checkin_file_is_enqueued(fsl_cx * f, char const * zName,
                                             int relativeToCwd);

/**
   Discards any state accumulated for a pending checking,
   including any files queued via fsl_checkin_file_enqueue()
   and tags added via fsl_checkin_T_add().

   @see fsl_checkin_file_enqueue()
   @see fsl_checkin_file_dequeue()
   @see fsl_checkin_file_is_enqueued()
   @see fsl_checkin_commit()
   @see fsl_checkin_T_add()
*/
FSL_EXPORT void fsl_checkin_discard(fsl_cx * f);

/**
   Parameters for fsl_checkin_commit().

   Checkins are created in a multi-step process:

   - fsl_checkin_file_enqueue() queues up a file or directory for
   commit at the next commit.

   - fsl_checkin_file_dequeue() removes an entry, allowing
   UIs to toggle files in and out of a checkin before
   committing it.

   - fsl_checkin_file_is_enqueued() can be used to determine whether
   a given name is already enqueued or not.

   - fsl_checkin_T_add() can be used to T-cards (tags) to a
   deck. Branch tags are intended to be applied via the
   fsl_checkin_opt::branch member.

   - fsl_checkin_discard() can be used to cancel any pending file
   enqueuings, effectively cancelling a commit (which can be
   re-started by enqueuing another file).

   - fsl_checkin_commit() creates a checkin for the list of enqueued
   files (defaulting to all modified files in the checkout!). It
   takes an object of this type to specify a variety of parameters
   for the check.

   Note that this API uses the terms "enqueue" and "unqueue" rather
   than "add" and "remove" because those both have very specific
   (and much different) meanings in the overall SCM scheme.
*/
struct fsl_checkin_opt {
  /**
     The commit message. May not be empty - the library
     forbids empty checkin messages.
  */
  char const * message;

  /**
     The optional mime type for the message. Only set
     this if you know what you're doing.
  */
  char const * messageMimeType;

  /**
     The user name for the checkin. If NULL or empty, it defaults to
     fsl_cx_user_get(). If that is NULL, a FSL_RC_RANGE error is
     triggered.
  */
  char const * user;

  /**
     If not NULL, makes the checkin the start of a new branch with
     this name.
  */
  char const * branch;

  /**
     If this->branch is not NULL, this is applied as its "bgcolor"
     propagating property. If this->branch is NULL then this is
     applied as a one-time color tag to the checkin.

     It must be NULL, empty, or in a form usable by HTML/CSS,
     preferably \#RRGGBB form. Length-0 values are ignored (as if
     they were NULL).
  */
  char const * bgColor;

  /**
     If true, the checkin will be marked as private, otherwise it
     will be marked as private or public, depending on whether or
     not it inherits private content.
  */
  bool isPrivate;

  /**
     Whether or not to calculate an R-card. Doing so is very
     expensive (memory and I/O) but it adds another layer of
     consistency checking to manifest files. In practice, the R-card
     is somewhat superfluous and the cost of calculating it has
     proven painful on very large repositories. fossil(1) creates an
     R-card for all checkins but does not require that one be set
     when it reads a manifest.
  */
  bool calcRCard;

  /**
     Whether to allow (or try to force) a delta manifest or not. 0
     means no deltas allowed - it will generate a baseline
     manifest. Greater than 0 forces generation of a delta if
     possible (if one can be readily found) even if doing so would not
     save a notable amount of space. Less than 0 means to
     decide via some heuristics.

     A "readily available" baseline means either the current
     checkout is a baseline or has a baseline. In either case, we
     can use that as a baseline for a delta. i.e. a baseline
     "should" basically available except on the initial checkin,
     which has neither a parent checkin nor a baseline.

     The current behaviour for "auto-detect" mode is: it will generate
     a delta if a baseline is "readily available." Once it calculates
     a delta form, it calculates whether that form saves any
     appreciable space/overhead compared to whether a baseline
     manifest was generated. If so, it discards the delta and
     re-generates the manifest as a baseline. The "force" behaviour
     (deltaPolicy>0) bypasses the "is it too big?" test, and is only
     intended for testing, not real-life use.

     Caveat: if the repository has the "forbid-delta-manifests" set to
     a true value, this option is ignored: that setting takes
     priority.
  */
  int deltaPolicy;

  /**
     Tells the checkin to close merged-in branches (merge type of
     0). INTEGRATE merges (type=-4) are always closed by a
     checkin. This does not apply to CHERRYPICK (type=-1) and
     BACKOUT (type=-2) merges.
  */
  bool integrate;

  /**
     If true, allow a file to be checked in if it contains
     fossil-style merge conflict markers, else fail if an attempt
     is made to commit any files with such markers.
  */
  bool allowMergeConflict;

  
  /**
     Time of the checkin. If 0 or less, the current time
     is used.
  */
  double julianTime;

  /**
     If this is not NULL then the committed manifest will include a
     tag which closes the branch. The value of this string will be
     the value of the "closed" tag, and the value may be an empty
     string. The intention is that this gets set to a comment about
     why the branch is closed, but it is in no way mandatory.
  */
  char const * closeBranch;

  /**
     Tells fsl_checkin_commit() to dump the generated manifest to
     this file. Intended only for debugging and testing. Checking in
     will fail if this file cannot be opened for writing.
  */
  char const * dumpManifestFile;
  /*
    fossil(1) has many more options. We might want to wrap some of
    it up in the "incremental" state (f->ckin.mf).

    TODOs:

    A callback mechanism which supports the user cancelling
    the checkin. It is (potentially) needed for ops like
    confirming the commit of CRNL-only changes.
  */
};

/**
   Empty-initialized fsl_checkin_opt instance, intended for use in
   const-copy constructing.
*/
#define fsl_checkin_opt_empty_m {               \
    NULL/*message*/,                            \
      NULL/*messageMimeType*/,                  \
      NULL/*user*/,                             \
      NULL/*branch*/,                           \
      NULL/*bgColor*/,                          \
      false/*isPrivate*/,                           \
      true/*calcRCard*/,                           \
      -1/*deltaPolicy*/,                        \
      false/*integrate*/,                           \
      false/*allowMergeConflict*/,\
      0.0/*julianTime*/,                        \
      NULL/*closeBranch*/,                      \
      NULL/*dumpManifestFile*/                  \
      }

/**
   Empty-initialized fsl_checkin_opt instance, intended for use in
   copy-constructing. It is important that clients copy this value
   (or fsl_checkin_opt_empty_m) to cleanly initialize their
   fsl_checkin_opt instances, as this may set default values which
   (e.g.) a memset() would not.
*/
FSL_EXPORT const fsl_checkin_opt fsl_checkin_opt_empty;

/**
   This creates and saves a "checkin manifest" for the current
   checkout.

   Its primary inputs is a list of files to commit. This list is
   provided by the client by calling fsl_checkin_file_enqueue() one or
   more times.  If no files are explicitely selected (enqueued) then
   it calculates which local files have changed vs the current
   checkout and selects all of those.

   Non-file inputs are provided via the opt parameter.

   On success, it returns 0 and...

   - If newRid is not NULL, it is assigned the new checkin's RID
   value.

   - If newUuid is not NULL, it is assigned the new checkin's UUID
   value. Ownership of the bytes is passed to the caller, who must
   eventually pass them to fsl_free() to free them.

   Note that the new RID and UUID can also be fetched afterwards by
   calling fsl_checkout_version_info().

   On error non-0 is returned and f's error state may (depending on
   the nature of the problem) contain details about the problem.
   Note, however, that any error codes returned here may have arrived
   from several layers down in the internals, and may not have a
   single specific interpretation here. When possible/practical, f's
   error state gets updated with a human-readable description of the
   problem.

   ACHTUNG: all pending checking state is cleaned if this function
   fails for any reason other than basic argument validation. This
   means any queued files or tags need to be re-applied if the client
   wants to try again. That is somewhat of a bummer, but this
   behaviour is the only way we can ensure that then the pending
   checkin state does not get garbled on a second use. When in doubt
   about the state, the client should call fsl_checkin_discard() to
   clear it before try to re-commit. (Potential TODO: add a
   success/fail state flag to the checkin state and only clean up on
   success? OTOH, since something in the state likely caused the
   problem, we might not want to do that.)

   This operation does all of its db-related work in a transaction, so
   it rolls back any db changes if it fails. To implement a "dry-run"
   mode, simply wrap this call in a transaction started on the
   fsl_cx_db_checkout() db handle (passing it to
   fsl_db_transaction_begin()), then, after this call, either cal;
   fsl_db_transaction_rollback() (to implement dry-run mode) or
   fsl_db_transaction_commit() (for "wet-run" mode). If this function
   returns non-0 due to anything more serious than basic argument
   validation, such a transaction will be in a roll-back state.

   Some of the more notable, potentially not obvious, error
   conditions:

   - Trying to commit against a closed leaf: FSL_RC_ACCESS. Doing so
   is not permitted by fossil(1), so we disallow it here.

   - An empty/NULL user name or commit message, or no files were
   selected which actually changed: FSL_RC_MISSING_INFO. In these
   cases f's error state describes the problem.

   - Some resource is not found (e.g. an expected RID/UUID could not
   be resolved): FSL_RC_NOT_FOUND. This would generally indicate
   some sort of data consistency problem. i.e. it's quite possibly
   very bad if this is returned.

   - If the checkin would result in no file-level changes vis-a-vis
   the current checkout, FSL_RC_NOOP is returned.

   BUGS:

   - It cannot currently properly distinguish a "no-op" commit, one in
   which no files were modified or only their permissions were
   modifed.

   @see fsl_checkin_file_enqueue()
   @see fsl_checkin_file_dequeue()
   @see fsl_checkin_discard()
   @see fsl_checkin_T_add()
*/
FSL_EXPORT int fsl_checkin_commit(fsl_cx * f, fsl_checkin_opt const * opt,
                                  fsl_id_t * newRid, fsl_uuid_str * newUuid);

/**
   Works like fsl_deck_T_add(), adding the given tag information to
   the pending checkin state. Returns 0 on success, non-0 on
   error. A checkin may, in principal, have any number of tags, and
   this may be called any number of times to add new tags to the
   pending commit. This list of tags gets cleared by a successful
   fsl_checkin_commit() or by fsl_checkin_discard().

   @see fsl_checkin_file_enqueue()
   @see fsl_checkin_file_dequeue()
   @see fsl_checkin_commit()
   @see fsl_checkin_discard()
*/
FSL_EXPORT int fsl_checkin_T_add( fsl_cx * f, fsl_tagtype_e tagType,
                       fsl_uuid_cstr uuid, char const * name,
                       char const * value);


/**
   Clears all contents from f's checkout database, including the vfile
   table, vmerge table, and some of the vvar table. The tables are
   left intact. Returns 0 on success, non-0 if f has no checkout or for
   a database error.
 */
FSL_EXPORT int fsl_checkout_clear_db(fsl_cx *f);

/**
   Returns the base name of the current platform's checkout database
   file. That is "_FOSSIL_" on Windows and ".fslckout" everywhere
   else. The returned bytes are static.

   TODO: an API which takes a dir name and looks for either name
*/
FSL_EXPORT char const *fsl_preferred_checkout_db_name();  

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