/* -*- 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_UTIL_H_INCLUDED) #define NET_FOSSIL_SCM_FSL_UTIL_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-config.h" /* MUST come first b/c of config macros */ #include /* FILE type */ #include /* va_list */ #if defined(__cplusplus) extern "C" { #endif typedef struct fsl_allocator fsl_allocator; typedef struct fsl_buffer fsl_buffer; typedef struct fsl_error fsl_error; typedef struct fsl_finalizer fsl_finalizer; typedef struct fsl_fstat fsl_fstat; typedef struct fsl_list fsl_list; typedef struct fsl_outputer fsl_outputer; typedef struct fsl_state fsl_state; /** ** fsl_uuid_str and fsl_uuid_cstr are "for documentation and ** readability purposes" typedefs used to denote strings which the ** API requires to be in the form of Fossil UUID strings. Such ** strings are exactly FSL_UUID_STRLEN bytes long plus a ** terminating NUL byte and contain only lower-case hexadecimal ** bytes. Where this typedef is used, the library requires, ** enforces, and/or assumes (at different times) that fsl_is_uuid() ** returns true for such strings (if they are not NULL, though not ** all contexts allow a NULL UUID). These typedef are _not_ used to ** denote arguments which may refer to partial UUIDs or symbolic ** names, only 100% bonafide Fossil UUIDs (which are different from ** RFC4122 UUIDs). ** ** The API guarantees that this typedef will always be (char *) and ** that fsl_uuid_cstr will always ben (char const *), and thus it ** is safe/portable to use those type instead of thse. These ** typedefs serve only to improve the readability of certain APIs ** by implying (through the use of this typedef) the preconditions ** defined for UUID strings. ** ** @see fsl_is_uuid() */ typedef char * fsl_uuid_str; /** ** The const counterpart of fsl_uuid_str. ** ** @see fsl_is_uuid() */ typedef char const * fsl_uuid_cstr; /** ** Returns true (non-0) if str is not NULL, is exactly ** FSL_UUID_STRLEN bytes long, and contains only lower-case ** hexadecimal characters, else returns false (0). ** ** Note that Fossil UUIDs are not RFC4122 UUIDs, but are SHA1 ** hash strings. Don't let that disturb you. As Tim Berners-Lee ** writes: ** ** 'The assertion that the space of URIs is a universal space ** sometimes encounters opposition from those who feel there should ** not be one universal space. These people need not oppose the ** concept because it is not of a single universal space: Indeed, ** the fact that URIs form universal space does not prevent anyone ** else from forming their own universal space, which of course by ** definition would be able to envelop within it as a subset the ** universal URI space. Therefore the web meets the "independent ** design" test, that if a similar system had been concurrently and ** independently invented elsewhere, in such a way that the ** arbitrary design decisions were made differently, when they met ** later, the two systems could be made to interoperate.' ** ** Source: http://www.w3.org/DesignIssues/Axioms.html ** ** (Just mentally translate URI as UUID.) */ char fsl_is_uuid(char const * str); /** ** Expects str to be a string containing an unsigned decimal ** value. Returns its decoded value, or -1 on error. */ fsl_size_t fsl_str_to_size(char const * str); /** ** Expects str to be a string containing a decimal value, ** optionally with a leading sign. Returns its decoded value, or ** dflt if !str or on error. */ fsl_int_t fsl_str_to_int(char const * str, fsl_int_t dflt); /** ** Generic list container type. This is used heavily by the Fossil ** API for storing arrays of dynamically-allocated objects. It is ** not useful as a non-pointer-array replacement. ** ** It is up to the APIs using this type to manage the entry count ** member and use fsl_list_reserve() to manage the "capacity" ** member. ** ** @see fsl_list_reserve() ** @see fsl_list_append() ** @see fsl_list_visit() */ struct fsl_list { /** ** Array of entries. It contains this->capacity entries, ** this->count of which are "valid" (in use). */ void ** list; /** ** Number of "used" entries in the list. */ fsl_size_t used; /** ** Number of slots allocated in this->list. Use fsl_list_reserve() ** to modify this. Doing so might move the this->list pointer but ** the values it points to will stay stable. */ fsl_size_t capacity; }; /** ** Empty-initialized fsl_list structure, intended for const-copy ** initialization. */ #define fsl_list_empty_m { NULL, 0, 0 } /** ** Empty-initialized fsl_list structure, intended for copy ** initialization. */ extern const fsl_list fsl_list_empty; /** ** Generic interface for finalizing/freeing memory. Intended ** primarily for use as a destructor/finalizer for high-level ** structs. Implementations must semantically behave like free(mem), ** regardless of whether or not they actually free the memory. At ** the very least, they generally should clean up any memory owned by ** mem (e.g. db resources or buffers), even if they do not free() mem. ** some implementations assume that mem is stack-allocated ** and they only clean up resources owned by mem. ** ** The state parameter is any state needed by the finalizer ** (e.g. a memory allocation context) and mem is the memory which is ** being finalized. ** ** The exact interpretaion of the state and mem are of course ** implementation-specific. */ typedef void (*fsl_finalizer_f)( void * state, void * mem ); /** ** Generic interface for memory finalizers. */ struct fsl_finalizer { /** ** State to be passed as the first argument to f(). */ void * state; /** ** Finalizer function. Should be called like this->f( this->state, ... ). */ fsl_finalizer_f f; }; /** Empty-initialized fsl_finalizer struct. */ #define fsl_finalizer_empty_m {NULL,NULL} /** ** fsl_finalizer_f() impl which requires that mem be-a ** (fsl_buffer*). This function frees all memory associated with ** that buffer and zeroes out the structure, but does not free mem ** (because it is rare that fsl_buffers are created on the ** heap). The state parameter is ignored. */ int fsl_finalizer_f_buffer( void * state, void * mem ); /** ** Generic state-with-finalizer holder. Used for binding ** client-specified state to another other object, such that a ** client-specified finalizer is called with the other object is ** cleaned up. */ struct fsl_state { /** ** Arbitrary context-dependent state. */ void * state; /** ** Finalizer for this->state. If used, it should be called like: ** ** @code ** this->finalize.f( this->finalize.state, this->state ); ** @endcode ** ** After which this->state must be treated as if it has been ** free(3)'d. */ fsl_finalizer finalize; }; /** Empty-initialized fsl_state struct. */ #define fsl_state_empty_m {NULL,fsl_finalizer_empty_m} /** ** Empty-initialized fsl_state struct, intended for ** copy-initializing. */ extern const fsl_state fsl_state_empty; /** ** Generic interface for streaming out data. Implementations must ** write n bytes from s to their destination channel and return 0 on ** success, non-0 on error (assumed to be a value from the fsl_rc_t ** enum). The state parameter is the implementation-specified ** output channel. */ typedef int (*fsl_output_f)( void * state, void const * src, fsl_size_t n ); /** ** Generic interface for flushing arbitrary output streams. Must ** return 0 on success, non-0 on error, but the result code "should" ** (to avoid downstream confusion) be one of the fsl_rc_t ** values. When in doubt, return FSL_RC_IO on error. */ typedef int (*fsl_flush_f)(void * state); /** ** Generic interface for streaming in data. Implementations must ** read (at most) *n bytes from their input, copy it to dest, assign ** *n to the number of bytes actually read, return 0 on success, and ** return non-0 on error (assumed to be a value from the fsl_rc_t ** enum). When called, *n is the max length to read. On return, *n ** is the actual amount read. The state parameter is the ** implementation-specified input file/buffer/whatever channel. */ typedef int (*fsl_input_f)( void * state, void * dest, fsl_size_t * n ); /** ** fsl_output_f() implementation which requires state to be ** a writeable (FILE*) handle. */ int fsl_output_f_FILE( void * state, void const * src, fsl_size_t n ); /** ** An interface which encapsulates data for managing an output ** destination, primarily intended for use with fsl_output(). Why ** abstract it to this level? So that we can do interesting things ** like output to buffers, files, sockets, etc., using the core ** output mechanism. e.g. so script bindings can send their output ** to the same channel used by the library and other library ** clients. */ struct fsl_outputer { /** ** Output channel. */ fsl_output_f out; /** ** flush() implementation. */ fsl_flush_f flush; /** ** State to be used when calling this->out(), namely: ** this->out( this->state.state, ... ). */ fsl_state state; }; /** Empty-initialized fsl_outputer instance. */ #define fsl_outputer_empty_m {NULL,NULL,fsl_state_empty_m} /** Empty-initialized fsl_outputer instance, intended for copy-initializing. */ extern const fsl_outputer fsl_outputer_empty; /** ** A fsl_outputer instance which is initialized to output to a ** (FILE*). To use it, this value then set the copy's state.state ** member to an opened-for-write (FILE*) handle. By default it will ** use stdout. Its finalizer (if called!) will fclose(3) ** self.state.state if self.state.state is not one of (stdout, ** stderr). To disable the closing behaviour (and not close the ** file), set self.state.finalize.f to NULL (but then be sure that ** the file handle outlives this object and to fclose(3) it when ** finished with it). */ extern const fsl_outputer fsl_outputer_FILE; /** ** fsl_outputer initializer which uses fsl_flush_f_FILE(), ** fsl_output_f_FILE(), and fsl_finalizer_f_FILE(). */ #define fsl_outputer_FILE_m { \ fsl_output_f_FILE, \ fsl_flush_f_FILE, \ {/*state*/ \ NULL, \ {NULL,fsl_finalizer_f_FILE} \ } \ } /** ** Generic stateful alloc/free/realloc() interface. ** ** Implementations must behave as follows: ** ** - If 0==n then semantically behave like free(3) and return ** NULL. ** ** - If 0!=n and !mem then semantically behave like malloc(3), returning ** newly-allocated memory on success and NULL on error. ** ** - If 0!=n and NULL!=mem then semantically behave like ** realloc(3). Note that realloc specifies: "If n was equal to 0, ** either NULL or a pointer suitable to be passed to free() is ** returned." Which is kind of useless, and thus implementations ** MUST return NULL when n==0. */ typedef void *(*fsl_realloc_f)(void * state, void * mem, fsl_size_t n); /** ** Holds an allocator function and its related state. */ struct fsl_allocator { /** ** Base allocator function. It must be passed this->state ** as its first parameter. */ fsl_realloc_f f; /** ** State intended to be passed as the first parameter to ** this->f(). */ void * state; }; /** Empty-initialized fsl_allocator instance. */ #define fsl_allocator_empty_m {NULL,NULL} /** ** A fsl_realloc_f() implementation which uses the standard ** malloc()/free()/realloc(). The state parameter is ignored. */ void * fsl_realloc_f_stdalloc(void * state, void * mem, fsl_size_t n); /** ** A fsl_flush_f() impl which expects _FILE to be-a (FILE*) opened ** for writing, which this function passes the call on to ** fflush(). If fflush() returns 0, so does this function, else it ** returns non-0. */ int fsl_flush_f_FILE(void * _FILE); /** ** A fsl_finalizer_f() impl which requires that mem be-a (FILE*). ** This function passes that FILE to fsl_fclose(). The state ** parameter is ignored. */ void fsl_finalizer_f_FILE( void * state, void * mem ); /** ** A fsl_output_f() impl which requires state to be-a (FILE*), which ** this function passes the call on to fwrite(). Returns 0 on ** success, FSL_RC_IO on error. */ int fsl_output_f_FILE( void * state, void const * src, fsl_size_t n ); /** ** A fsl_output_f() impl which requires state to be-a (fsl_buffer*), ** which this function passes to fsl_buffer_append(). Returns 0 on ** success, FSL_RC_OOM (probably) on error. */ int fsl_output_f_buffer( void * state, void const * src, fsl_size_t n ); /** ** A fsl_input_f() implementation which requires that state be ** a readable (FILE*) handle. */ int fsl_input_f_FILE( void * state, void * dest, fsl_size_t * n ); /** ** A generic streaming routine which copies data from an ** fsl_input_f() to an fsl_outpuf_f(). ** ** Reads all data from inF() in chunks of an unspecified size and ** passes them on to outF(). It reads until inF() returns fewer ** bytes than requested. Returns the result of the last call to ** outF() or (only if reading fails) inF(). Returns FSL_RC_MISUSE ** if inF or ouF are NULL. ** ** Here is an example which basically does the same thing as the ** cat(1) command on Unix systems: ** ** @code ** fsl_stream( fsl_input_f_FILE, stdin, fsl_output_f_FILE, stdout ); ** @endcode ** ** Or copy a FILE to a buffer: ** ** @code ** fsl_buffer myBuf = fsl_buffer_empty; ** rc = fsl_stream( fsl_input_f_FILE, stdin, fsl_output_f_buffer, &myBuf ); ** // Note that on error myBuf might be partially populated. ** // Eventually clean up the buffer: ** fsl_buffer_clear(&myBuf); ** @endcode ** */ int fsl_stream( fsl_input_f inF, void * inState, fsl_output_f outF, void * outState ); /** ** ** A general-purpose buffer class, analog to Fossil v1's Blob ** class. It is not called fsl_blob to avoid confusion with DB-side ** Blobs. Buffers are used extensively in fossil to do everything ** from reading files to compressing artifacts to creating ** dynamically-formatted strings. Because they are such a pervasive ** low-level type, and have such a simple structure, their members ** (unlike most other structs in this API) may be considered public ** and used directly by client code (as long as they do not mangle ** their state, e.g. by setting this->capacity smaller than ** this->used!). ** ** @see fsl_buffer_reserve() ** @see fsl_buffer_append() ** @see fsl_buffer_appendf() ** @see fsl_buffer_cstr() ** @see fsl_buffer_size() ** @see fsl_buffer_capacity() ** @see fsl_buffer_clear() */ struct fsl_buffer { /** ** The raw memory owned by this buffer. It is this->capacity bytes ** long, of which this->used are considered "used" by the client. ** The difference beween (this->capacity - this->used) represents ** space the buffer has available for use before it will require ** another expansion/reallocation. */ unsigned char * mem; /** ** Number of bytes allocated for this buffer. */ fsl_size_t capacity; /** ** Number of "used" bytes in the buffer. This is generally ** interpreted as the string length of this->mem, and the buffer ** APIs which add data to a buffer always ensure that ** this->capacity is large enough to account for a trailing NUL ** byte in this->mem. ** ** Library routines which manipulate buffers must ensure that ** (this->used<=this->capacity) is always true, expanding the ** buffer if necessary. Much of the API assumes that precondition ** is always met, and any violation of it opens the code to ** undefined behaviour (which is okay, just don't ever break that ** precondition). Most APIs ensure that (usedmsg.mem. The usable text ** part is this->msg.used bytes long. */ fsl_buffer msg; /** ** Error code, generally assumed to be a fsl_rc_t value. ** ** Potential todo: change this to fsl_rc_t to help ensure that we ** don't get cross-API result code polution (e.g. from sqlite)? */ int code; }; /** Empty-initialized fsl_error instance. */ #define fsl_error_empty_m {fsl_buffer_empty_m,0} /** Empty-initialized fsl_error instance. */ extern const fsl_error fsl_error_empty; /** ** Populates err with the given code and formatted string, replacing ** any existing state. If fmt==NULL then fsl_rc_cstr(rc) is used to ** get the error string. ** ** Returns code on success, some other non-0 code on error. ** ** As a special case, if 0==code then fmt is ignored and the error ** state is cleared. This will not free any memory held by err but ** will re-set its string to start with a NUL byte, ready for ** re-use later on. ** ** As a special case, if code==FSL_RC_OOM then fmt is ignored ** to avoid a memory allocation (which would presumably fail). ** ** @see fsl_error_get() ** @see fsl_error_clear() ** @see fsl_error_move() */ int fsl_error_set( fsl_error * err, int code, char const * fmt, ... ); /** ** va_list counterpart to fsl_error_set(). */ int fsl_error_setv( fsl_error * err, int code, char const * fmt, va_list args ); /** ** Fetches the error state from err. If !err it returns ** FSL_RC_MISUSE without side-effects, else it returns err's current ** error code. ** ** If str is not NULL then *str will be assigned to the raw ** (NUL-terminated) error string (which might be empty or even ** NULL). The memory for the string is owned by err and may be ** invalidated by any calls which take err as a non-const parameter ** OR which might modify it indirectly through its container, so ** the client is required to copy it if it is needed for later on. ** ** If len is not NULL then *len will be assigned to the length of ** the returned string (in bytes). ** ** @see fsl_error_set() ** @see fsl_error_clear() ** @see fsl_error_move() */ int fsl_error_get( fsl_error const * err, char const ** str, fsl_size_t * len ); /** ** Frees up any resources owned by err and sets its error code to 0, ** but does not free err. This is harmless no-op if !err or if err ** holds no dynamically allocated no memory. ** ** @see fsl_error_set() ** @see fsl_error_get() ** @see fsl_error_move() */ void fsl_error_clear( fsl_error * err ); /** ** Swaps the error state of the two given error objects. ** ** This "uplifts" an error from the 'from' object to the 'to' ** object. After this returns 'to' will contain the prior error ** state of 'from' and 'from' will contain the old error message ** memory of 'to' but will be re-set to the non-error state (we ** keep the buffer memory intact for later reuse, though). ** ** Results are undefined if either parameter is NULL or either is ** not properly initialized. i.e. neither may refer to uninitialized ** memory. Copying fsl_error_empty at declaration-time is a simple ** way to ensure that instances are cleanly initialized. */ void fsl_error_move( fsl_error * from, fsl_error * to ); /** ** Returns the given Unix Epoch timestamp value as its approximate ** Julian Day value. Note that the calculation does not account for ** leap seconds. */ fsl_double_t fsl_unix_to_julian( fsl_time_t unixEpoch ); /** ** Returns the current Unix Epoch time converted to its approximate ** Julian form. Equivalent to fsl_unix_to_julian( time(0) ); */ fsl_double_t fsl_julian_now(); /** ** Returns the given Unix Epoch time value formatted as an ISO8601 ** string. Returns NULL on allocation error, else a string 19 ** bytes long plus a terminating NUL ** (e.g. "2013-08-19T20:35:49"). The returned memory must ** eventually be freed using fsl_free(). */ char * fsl_unix_to_iso8601( fsl_time_t j ); /** ** Returns non-0 (true) if the first 10 digits of z _appear_ to ** form the start of an ISO date string (YYYY-MM-DD). Whether or ** not the string is really a valid date is left for downstream ** code to determine. Returns 0 (false) in all other cases, ** including if z is NULL. */ char fsl_str_is_date(const char *z); /** ** Reserves at least n bytes of capacity in buf. Returns 0 on ** success, FSL_RC_OOM if allocation fails, FSL_RC_MISUSE if !buf. ** ** This does not change buf->used, nor will it shrink the buffer ** (reduce buf->capacity) unless n is 0, in which case it ** immediately frees buf->mem and sets buf->capacity and buf->used ** to 0. ** ** @see fsl_buffer_resize() ** @see fsl_buffer_clear() */ int fsl_buffer_reserve( fsl_buffer * buf, fsl_size_t n ); /** ** Convenience equivalent of fsl_buffer_reserve(buf,0). ** This a no-op if buf==NULL. */ void fsl_buffer_clear( fsl_buffer * buf ); /** ** Resets buf->used to 0 and sets buf->mem[0] (if buf->mem is not ** NULL) to 0. Does not (de)allocate memory, only changes the ** logical "used" size of the buffer. Returns 0 on success, ** FSL_RC_MISUSE if !buf. ** ** Achtung for v1 porters: this function's semantics are much ** different from the v1 blob_reset(). To get those semantics, use ** fsl_buffer_reserve(buf, 0) or its convenience form ** fsl_buffer_clear(). */ int fsl_buffer_reset( fsl_buffer * buf ); /** ** Similar to fsl_buffer_reserve() except that... ** ** - It does not free all memory when n==0. Instead it essentially ** makes the memory a length-0, NUL-terminated string. ** ** - It will try to shrink (realloc) buf's memory if (ncapacity). ** ** - It sets buf->capacity to (n+1) and buf->used to n. This routine ** allocates one extra byte to ensure that buf is always ** NUL-terminated. ** ** - On success it always NUL-terminates the buffer at ** offset buf->used. ** ** Returns 0 on success, FSL_RC_MISUSE if !buf, FSL_RC_OOM if ** (re)allocation fails. ** ** @see fsl_buffer_reserve() ** @see fsl_buffer_clear() */ int fsl_buffer_resize( fsl_buffer * buf, fsl_size_t n ); /** ** Swaps the contents of the left and right arguments. Results are ** undefined if either argument is NULL or points to uninitialized ** memory. */ void fsl_buffer_swap( fsl_buffer * left, fsl_buffer * right ); /** ** Similar fsl_buffer_swap() but it also optionally frees one of ** the buffer's memories after swapping them. If clearWhich is ** negative then the left buffer (1st arg) is cleared _after_ ** swapping (i.e., the NEW left hand side gets cleared). If ** clearWhich is greater than 0 then the right buffer (2nd arg) is ** cleared _after_ swapping (i.e. the NEW right hand side gets ** cleared). If clearWhich is 0, this function behaves identically ** to fsl_buffer_swap(). */ void fsl_buffer_swap_free( fsl_buffer * left, fsl_buffer * right, char clearWhich ); /** ** ** Appends the first n bytes of src, plus a NUL byte, to b, ** expanding b as necessary and incrementing b->used by n. If n is ** less than 0 then the equivalent of fsl_strlen((char const*)src) ** is used to calculate the length. ** ** If n is 0 (or negative and !*src), this function ensures that ** b->mem is at least 1 byte long and sets the first byte to 0 ** (note that (b->used+n == b->used), so its effective length does ** not change in that case). ** ** src may only be NULL if n==0. If passed (src==NULL, n!=0) then ** FSL_RC_RANGE is returned. ** ** Returns 0 on success, FSL_RC_MISUSE if !f, !b, or !src, ** FSL_RC_OOM if allocation of memory fails. ** ** If this function succeeds, it guarantees that it NUL-terminates ** the buffer (but that the NUL terminator is not counted in ** b->used). */ int fsl_buffer_append( fsl_buffer * b, void const * src, fsl_int_t n ); /** ** Uses fsl_appendf() to append formatted output to the given buffer. ** Returns 0 on success, FSL_RC_MISUSE if !f or !dest, */ int fsl_buffer_appendf( fsl_buffer * dest, char const * fmt, ... ); /** va_list counterpart to fsl_buffer_appendfv(). */ int fsl_buffer_appendfv( fsl_buffer * dest, char const * fmt, va_list args ); /** ** Compresses the first pIn->used bytes of pIn to pOut. It is ok for ** pIn and pOut to be the same blob. ** ** pOut must either be the same as pIn or else cleanly ** initialized/empty. ** ** Results are undefined if any argument is NULL. ** ** Returns 0 on success, FSL_RC_OOM on allocation error, and FSL_RC_ERROR ** if the lower-level compression routines fail. ** ** TODO: add a streaming variant which takes the input from a ** fsl_input_f() and pushes the output to a fsl_output_f(). The code ** exists in the libwhio source tree already. ** ** TODO: if pOut!=pIn1 then re-use pOut's memory, if it has any. */ int fsl_buffer_compress(fsl_buffer const *pIn, fsl_buffer *pOut); /** ** Compress the concatenation of a blobs pIn1 and pIn2 into pOut. ** ** pOut must be either uninitialized or must be the same as either pIn1 or ** pIn2. ** ** Results are undefined if any argument is NULL. ** ** Returns 0 on success, FSL_RC_OOM on allocation error, and FSL_RC_ERROR ** if the lower-level compression routines fail. ** ** TODO: if pOut!=(pIn1 or pIn2) then re-use its memory, if it has any. */ int fsl_buffer_compress2(fsl_buffer const *pIn1, fsl_buffer const *pIn2, fsl_buffer *pOut); /** ** Uncompress buffer pIn and store the result in pOut. It is ok for ** pIn and pOut to be the same buffer. Returns 0 on success. On ** error pOut is not modified. ** ** pOut must be either cleanly initialized/empty or the same as pIn. ** ** Results are undefined if any argument is NULL. ** ** Returns 0 on success, FSL_RC_OOM on allocation error, and ** FSL_RC_ERROR if the lower-level decompression routines fail. ** ** TODO: add a streaming variant which takes the input from a ** fsl_input_f() and pushes the output to a fsl_output_f(). The code ** exists in the libwhio source tree already. ** ** TODO: if pOut!=(pIn1 or pIn2) then re-use its memory, if it has any. */ int fsl_buffer_uncompress(fsl_buffer const *pIn, fsl_buffer *pOut); /** ** Returns true if this function believes that mem (which must be ** at least len bytes of valid memory long) appears to have been ** compressed by fsl_buffer_compress() or equivalent. This is not a ** 100% reliable check - it could potentially have false positives ** on certain inputs, but that is thought to be unlikely (at least ** for text data). ** ** Returns 0 if mem is NULL. */ char fsl_data_is_compressed(unsigned char const * mem, fsl_size_t len); /** ** Equivalent to fsl_data_is_compressed(buf->mem, buf->used). */ char fsl_buffer_is_compressed(fsl_buffer const * buf); /** ** If fsl_data_is_compressed(mem,len) returns true then this function ** returns the uncompressed size of the data, else it returns a negative ** value. */ fsl_int_t fsl_data_uncompressed_size(unsigned char const *mem, fsl_size_t len); /** ** The fsl_buffer counterpart of fsl_data_uncompressed_size(). */ fsl_int_t fsl_buffer_uncompressed_size(fsl_buffer const * b); /** ** Equivalent to ((char const *)b->mem), but returns NULL if !b. The ** returned memory is effectively b->used bytes long unless the user ** decides to apply his own conventions. ** ** @see fsl_buffer_str() ** @see fsl_buffer_cstr2() */ char const * fsl_buffer_cstr(fsl_buffer const *b); /** ** If buf is not NULL and has any memory allocated to it, that ** memory is returned. If both b and len are not NULL then *len is ** set to b->used. If b has no dynamic memory then NULL is returned ** and *len (if len is not NULL) is set to 0. ** ** @see fsl_buffer_str() ** @see fsl_buffer_cstr() **/ char const * fsl_buffer_cstr2(fsl_buffer const *b, fsl_size_t * len); /** ** Equivalent to ((char *)b->mem), but returns NULL if !b. The ** returned memory is effectively b->used bytes long unless the user ** decides to apply his own conventions. */ char * fsl_buffer_str(fsl_buffer const *b); /** ** Returns the "used" size of b, or 0 if !b. */ fsl_size_t fsl_buffer_size(fsl_buffer const * b); /** ** Returns the current capacity of b, or 0 if !b. */ fsl_size_t fsl_buffer_capacity(fsl_buffer const * b); /** ** Compares the contents of buffers lhs and rhs using memcmp(3) ** semantics. Return negative, zero, or positive if the first ** buffer is less then, equal to, or greater than the second. ** Results are undefined if either argument is NULL. ** ** When buffers of different length match on the first N bytes, ** where N is the shorter of the two buffers' lengths, it treats the ** shorter buffer as being "less than" the longer one. */ int fsl_buffer_compare(fsl_buffer const * lhs, fsl_buffer const * rhs); /** ** Compare two buffers in constant (a.k.a. O(1)) time and return ** zero if they are equal. Constant time comparison only applies ** for buffers of the same length. If lengths are different, ** immediately returns 1. */ int fsl_buffer_compare_O1(fsl_buffer const * lhs, fsl_buffer const * rhs); /** ** Overwrites dest's contents with those of src (reusing dest's memory ** if it has any). Results are undefined if either pointer is NULL ** or invalid. Returns 0 on success, FSL_RC_OOM on allocation error. */ int fsl_buffer_copy( fsl_buffer const * src, fsl_buffer * dest ); /** ** Apply the delta in pDelta to the original content pOriginal to ** generate the target content pTarget. All three pointers must point ** to properly initialized memory. ** ** If pTarget==pOriginal then this is a destructive operation, ** replacing the original's content with its new form. ** ** Return 0 on success. ** ** @see fsl_buffer_delta_apply() ** @see fsl_delta_apply() ** @see fsl_delta_apply2() */ int fsl_buffer_delta_apply( fsl_buffer const * pOriginal, fsl_buffer const * pDelta, fsl_buffer * pTarget); /** ** Identical to fsl_buffer_delta_apply() except that if ** delta application fails then any error messages/codes ** are written to pErr if it is not NULL. ** ** @see fsl_buffer_delta_apply() ** @see fsl_delta_apply() ** @see fsl_delta_apply2() */ int fsl_buffer_delta_apply2( fsl_buffer const * pOriginal, fsl_buffer const * pDelta, fsl_buffer * pTarget, fsl_error * pErr); /** ** Uses a fsl_input_f() function to buffer input into a fsl_buffer. ** ** dest must be a non-NULL, initialized (though possibly empty) ** fsl_buffer object. Its contents, if any, will be overwritten by ** this function, and any memory it holds might be re-used. ** ** The src function is called, and passed the state parameter, to ** fetch the input. If it returns non-0, this function returns that ** error code. src() is called, possibly repeatedly, until it ** reports that there is no more data. ** ** Whether or not this function succeeds, dest still owns any memory ** pointed to by dest->mem, and the client must eventually free it ** by calling fsl_buffer_reserve(dest,0). ** ** dest->mem might (and possibly will) be (re)allocated by this ** function, so any pointers to it held from before this call might ** be invalidated by this call. ** ** On error non-0 is returned and dest has almost certainly been ** modified but its state must be considered incomplete. ** ** Errors include: ** ** dest or src are NULL (FSL_RC_MISUSE) ** ** Allocation error (FSL_RC_OOM) ** ** src() returns an error code ** ** Whether or not the state parameter may be NULL depends on the src ** implementation requirements. ** ** On success dest will contain the contents read from the input ** source. dest->used will be the length of the read-in data, and ** dest->mem will point to the memory. dest->mem is automatically ** NUL-terminated if this function succeeds, but dest->used does not ** count that terminator. On error the state of dest->mem must be ** considered incomplete, and is not guaranteed to be ** NUL-terminated. ** ** Example usage: ** ** @code ** fsl_buffer buf = fsl_buffer_empty; ** int rc = fsl_buffer_fill_from( &buf, ** fsl_input_f_FILE, ** stdin ); ** if( rc ){ ** fprintf(stderr,"Error %d (%s) while filling buffer.\n", ** rc, fsl_rc_cstr(rc)); ** fsl_buffer_reserve( &buf, 0 ); ** return ...; ** } ** ... use the buf->mem ... ** ... clean up the buffer ... ** fsl_buffer_reserve( &buf, 0 ); ** @endcode ** ** To take over ownership of the buffer's memory, do: ** ** @code ** void * mem = buf.mem; ** buf = fsl_buffer_empty; ** @endcode ** ** In which case the memory must eventually be passed to fsl_free() ** to free it. */ int fsl_buffer_fill_from( fsl_buffer * dest, fsl_input_f src, void * state ); /** ** A fsl_buffer_fill_from() proxy which overwrite's dest->mem with ** the contents of the given FILE handler (which must be opened for ** read access). Returns 0 on success, after which dest->mem ** contains dest->used bytes of content from the input source. On ** error dest may be partially filled. */ int fsl_buffer_fill_from_FILE( fsl_buffer * dest, FILE * src ); /** ** Wrapper for fsl_buffer_fill_from_FILE() which gets its input ** from the given file name. ** ** Uses fsl_fopen() to open the file, so it supports the name '-' ** as an alias for stdin. */ int fsl_buffer_fill_from_filename( fsl_buffer * dest, char const * filename ); /** ** Writes the given buffer to the given filename. Returns 0 on success, ** FSL_RC_MISUSE if !b or !fname, FSL_RC_IO if opening or writing fails. ** ** Uses fsl_fopen() to open the file, so it supports the name '-' ** as an alias for stdout. */ int fsl_buffer_to_filename( fsl_buffer * b, char const * fname ); /** ** Works like fsl_appendfv(), but appends all output to a ** dynamically-allocated string, expanding the string as necessary ** to collect all formatted data. The returned NUL-terminated string ** is owned by the caller and it must be cleaned up using ** fsl_free(...). If !fmt, NULL is returned. It is conceivable that ** it returns NULL on a zero-length formatted string, e.g. (%.*s) ** with (0,"...") as arguments, but it will only do that if the ** whole format string resolves to empty. */ char * fsl_mprintf( char const * fmt, ... ); /** ** va_list counterpart to fsl_mprintf(). */ char * fsl_mprintfv(char const * fmt, va_list vargs ); /** ** An sprintf(3) clone which uses fsl_appendf() for the formatting. ** Outputs at most n bytes to dest and returns the number of bytes ** output. Returns a negative value if !dest or !fmt. Returns 0 ** without side-effects if !n or !*fmt. ** ** If the destination buffer is long enough (this function returns ** a non-negative value less than n), this function NUL-terminates it. ** If it returns n then there was no space for the terminator. ** **/ fsl_int_t fsl_snprintf( char * dest, fsl_size_t n, char const * fmt, ... ); /** va_list counterpart to fsl_snprintf() */ fsl_int_t fsl_snprintfv( char * dest, fsl_size_t n, char const * fmt, va_list args ); /** ** Equivalent to fsl_strndup(src,-1). */ char * fsl_strdup( char const * src ); /** ** Similar to strndup(3) but returns NULL if !src. The returned ** memory must eventually be passed to fsl_free(). Returns NULL on ** allocation error. If len is less than 0 and src is not NULL then ** fsl_strlen() is used to calculate its length. */ char * fsl_strndup( char const * src, fsl_int_t len ); /** ** Equivalent to strlen(3) but returns 0 if src is NULL. ** Note that it counts bytes, not UTF characters. */ fsl_size_t fsl_strlen( char const * src ); /** ** Like strcmp(3) except that it accepts NULL pointers. NULL sorts ** before all non-NULL string pointers. Also, this routine ** performs a binary comparison that does not consider locale. */ int fsl_strcmp( char const * lhs, char const * rhs ); /** ** Case-insensitive form of fsl_strcmp(). */ int fsl_stricmp(const char *zA, const char *zB); /** ** fsl_strcmp() variant which compares at most nByte bytes of the ** given strings, case-insensitively. If nByte is less than 0 then ** fsl_strlen(zB) is used to obtain the length for comparision ** purposes. */ int fsl_strnicmp(const char *zA, const char *zB, fsl_int_t nByte); /** ** fsl_strcmp() variant which compares at most nByte bytes of the ** given strings, case-sensitively. Returns 0 if nByte is 0. */ int fsl_strncmp(const char *zA, const char *zB, fsl_size_t nByte); /** ** Equivalent to fsl_strncmp(lhs, rhs, FSL_UUID_STRLEN). */ int fsl_uuidcmp( fsl_uuid_cstr lhs, fsl_uuid_cstr rhs ); /** ** Returns false if s is NULL or starts with any of (0 (NUL), '0' ** (ASCII zero), 'f', 'n', "off"), case-insensitively, else it ** returns true. */ char fsl_str_bool( char const * s ); /** ** Flags for use with fsl_db_open() and friends. */ enum fsl_open_flags { /** ** The "no flags" value. */ FSL_OPEN_F_NONE = 0, /** ** Flag for fsl_db_open() specifying that the db should be opened ** in read-only mode. */ FSL_OPEN_F_RO = 0x01, /** ** Flag for fsl_db_open() specifying that the db should be opened ** in read-write mode, but should not create the db if it does ** not already exist. */ FSL_OPEN_F_RW = 0x02, /** ** Flag for fsl_db_open() specifying that the db should be opened in ** read-write mode, creating the db if it does not already exist. */ FSL_OPEN_F_CREATE = 0x04, /** ** Shorthand for RW+CREATE flags. */ FSL_OPEN_F_RWC = FSL_OPEN_F_RW | FSL_OPEN_F_CREATE, /** ** Tells fsl_repo_open_xxx() to confirm that the db ** is a repository. */ FSL_OPEN_F_SCHEMA_VALIDATE = 0x20 }; /** ** _Almost_ equivalent to fopen(3) but: ** ** - expects name to be UTF8-encoded. ** ** - If name=="-", it returns one of stdin or stdout, depending on ** the mode string: stdout is returned if 'w' or '+' appear, ** otherwise stdin. ** ** If at all possible, use fsl_close() to close these handles, as it ** has logic to skip closing the standard streams. ** ** ** Potential TODOs: ** ** - extend mode string to support 'x', meaning "exclusive", analog ** to open(2)'s O_EXCL flag. Barring race conditions, we have ** enough infrastructure to implement that. (It turns out that ** glibc's fopen() supports an 'x' with exactly this meaning.) ** ** - extend mode to support a 't', meaning "temporary". The idea ** would be that we delete the file from the FS right after ** opening, except that Windows can't do that. */ FILE * fsl_fopen(char const * name, char const *mode); /** ** Passes f to fclose(3) unless f is NULL or one of (stdin, stdout, ** stderr). */ void fsl_fclose(FILE * f); /** ** @typedef fsl_int_t (*fsl_appendf_f)( void * arg, char const * data, fsl_int_t n ) ** ** The fsl_appendf_f typedef is used to provide fsl_appendfv() with ** a flexible output routine, so that it can be easily send its ** output to arbitrary targets. ** ** The policies which implementations need to follow are: ** ** - arg is an implementation-specific pointer (may be 0) which is ** passed to fsl_appendf(). fsl_appendfv() doesn't know what this ** argument is but passes it to its fsl_appendf_f ** argument. Typically this pointer will be an object or resource ** handle to which string data is pushed. ** ** - The 'data' parameter is the data to append. The API does not ** currently guaranty that data containing embeded NULs will ** survive the ride through fsl_appendf() and its delegates friends ** (but it "should work"). ** ** - n is the number of bytes to read from data. The fact that n is ** of a signed type is historical. It can be treated as an unsigned ** type for purposes of fsl_appendf(). ** ** - Returns, on success, the number of bytes appended (may be 0). ** ** - Returns, on error, an implementation-specified negative ** number. Returning a negative error code will cause ** fsl_appendfv() to stop processing and return. Note that 0 is a ** success value (some printf format specifiers do not add anything ** to the output). */ typedef fsl_int_t (*fsl_appendf_f)( void * arg, char const * data, fsl_int_t n ); /** ** This function works similarly to classical printf ** implementations, but instead of outputing somewhere specific, it ** uses a callback function to push its output somewhere. This ** allows it to be used for arbitrary external representations. It ** can be used, for example, to output to an external string, a UI ** widget, or file handle (it can also emulate printf by outputing ** to stdout this way). ** ** INPUTS: ** ** pfAppend: The is a fsl_appendf_f function which is responsible ** for accumulating the output. If pfAppend returns a negative ** value then processing stops immediately. ** ** pfAppendArg: is ignored by this function but passed as the first ** argument to pfAppend. pfAppend will presumably use it as a data ** store for accumulating its string. ** ** fmt: This is the format string, as in the usual printf(3), except ** that it supports more options (detailed below). ** ** ap: This is a pointer to a list of arguments. Same as in ** vprintf() and friends. ** ** ** OUTPUTS: ** ** The return value is the total number of characters sent to the ** function "func", or a negative number on a pre-output error. If ** this function returns an integer greater than 1 it is in general ** impossible to know if all of the elements were output. As such ** failure can only happen if the callback function returns an ** error, and this type of error is very rare in a printf-like ** context, this is not considered to be a significant problem. (The ** same is true for any classical printf implementations.) Clients ** may use their own state objects which can propagate errors from ** their own internals back to the caller, but generically speaking ** it is difficult to trace errors back through this routine. Then ** again, it only breaks when using using a broken output routine or ** bad output state. ** ** Most printf-style specifiers work as they do in standard printf() ** implementations. There might be some very minor differences, but ** the more common format specifiers work as most developers expect ** them to. In addition... ** ** Current (documented) printf extensions: ** ** (If you are NOT reading this via doxygen-processed sources: the ** percent signs below are doubled for the sake of doxygen, and ** each pair refers to only a single percent sign in the format ** string.) ** ** %%z works like %%s, but takes a non-const (char *) and deletes ** the string (using fsl_free()) after appending it to the output. ** ** %%h (HTML) works like $%s but converts certain characters (namely ** '<' and '&') to their HTML escaped equivalents. ** ** %%t (URL encode) works like %%s but converts certain characters ** into a representation suitable for use in an HTTP URL. (e.g. ' ' ** gets converted to %%20) ** ** %%T (URL decode) does the opposite of %t - it decodes URL-encoded ** strings and outputs their decoded form. ** ** %%r requires an int and renders it in "ordinal form". That is, ** the number 1 converts to "1st" and 398 converts to "398th". ** ** %%q quotes a string as required for SQL. That is, '\'' ** characters get doubled. It does NOT included the outer quotes ** and NULL values get replaced by the string "(NULL) (without ** quotes). See %%Q... ** ** %%Q works like %%q, but includes the outer '\'' characters and ** NULL pointers get output as the string literal "NULL" (without ** quotes), i.e. an SQL NULL. ** ** %%/: works like %%s but normalizes path-like strings by ** replacing backslashes with the One True Slash. ** ** %%b: works like %%s but takes its input from a (fsl_buffer*) ** argument. ** ** %%B: works like %%Q but takes its input from a (fsl_buffer*) ** argument. ** ** %%F: works like %%s but runs the output through ** fsl_bytes_fossilize(). This requires dynamic memory allocation, ** so is less efficient than re-using a client-provided buffer with ** fsl_bytes_fossilize() if the client needs to fossilize more than ** one element. ** ** These extensions may be disabled by setting certain macros when ** compiling fsl_appendf.c (see that file for details). ** ** ** FIXME? fsl_appendf_f() is an artifact of older code from which ** this implementation derives. The first parameter should arguably ** be replaced with fsl_output_f(), which does the same thing _but_ ** has different return semantics (more reliable, because the ** current semantics report partial success as success in some ** cases). Doing this would require us to change the return ** semantics of this function, but that wouldn't necessarily be a ** bad thing (we don't rely on sprintf()-like return semantics all ** that much, AFAIK?). Or we just add a proxy which forwards to a ** fsl_output_f(). Oh, hey, that's what fsl_outputf() does. */ fsl_int_t fsl_appendfv(fsl_appendf_f pfAppend, void * pfAppendArg, const char *fmt, va_list ap ); /** ** Identical to fsl_appendfv() but takes a (...) ellipses list ** instead of a va_list. */ fsl_int_t fsl_appendf(fsl_appendf_f pfAppend, void * pfAppendArg, const char *fmt, ... ); /** ** A fsl_appendf_f() impl which requires that state be an opened, ** writable (FILE*) handle. */ fsl_int_t fsl_appendf_f_FILE( void * state, char const * s, fsl_int_t n ); /** ** Emulates fprintf() using fsl_appendf(). Returns the result of ** passing the data through fsl_appendf() to the given file handle. */ fsl_int_t fsl_fprintf( FILE * fp, char const * fmt, ... ); /** ** The va_list counterpart of fsl_fprintf(). */ fsl_int_t fsl_fprintfv( FILE * fp, char const * fmt, va_list args ); /** ** Possibly reallocates self->list, changing its size. This function ** ensures that self->list has at least n entries. If n is 0 then ** the list is deallocated (but the self object is not), BUT THIS ** DOES NOT DO ANY TYPE-SPECIFIC CLEANUP of the items. If n is less ** than or equal to self->capacity then there are no side effects. If ** n is greater than self->capacity, self->list is reallocated and ** self->capacity is adjusted to be at least n (it might be bigger - ** this function may pre-allocate a larger value). ** ** Passing an n of 0 when self->capacity is 0 is a no-op. ** ** Newly-allocated slots will be initialized with NUL bytes. ** ** Returns 0 on success, FSL_RC_MISUSE if !self, FSL_RC_OOM if ** reservation of new elements fails. ** ** The return value should be used like this: ** ** @code ** fsl_size_t const n = number of bytes to allocate; ** int const rc = fsl_list_reserve( myList, n ); ** if( rc ) { ... error ... } ** @endcode */ int fsl_list_reserve( fsl_list * self, fsl_size_t n ); /** ** Appends a bitwise copy of cp to self->list, expanding the list as ** necessary and adjusting self->used. ** ** Ownership of cp is unchanged by this call. cp may not be NULL. ** ** Returns 0 on success, FSL_RC_MISUSE if any argument is NULL, or ** FSL_RC_OOM on allocation error. */ int fsl_list_append( fsl_list * self, void * cp ); /** @typedef typedef int (*fsl_list_visitor_f)(void * p, void * visitorState ) ** ** Generic visitor interface for fsl_list lists. Used by ** fsl_list_visit(). p is the pointer held by that list entry and ** visitorState is the 4th argument passed to fsl_list_visit(). ** ** Implementations must return 0 on success. Any other value causes ** looping to stop and that value to be returned, but interpration ** of the value is up to the caller (it might or might not be an ** error, depending on the context). Note that client code may use ** custom values, and is not restricted to FSL_RC_xxx values. ** */ typedef int (*fsl_list_visitor_f)(void * obj, void * visitorState ); /** ** A fsl_list_visitor_f() implementation which requires that obj be ** arbitrary memory which can legally be passed to fsl_free() ** (which this function does). The visitorState parameter is ** ignored. */ int fsl_list_v_fsl_free(void * obj, void * visitorState ); /** ** For each item in self->list, visitor(item,visitorState) is ** called. The item is owned by self. The visitor function MUST ** NOT free the item (unless the visitor is a finalizer!), but may ** manipulate its contents if application rules do not specify ** otherwise. ** ** If order is 0 or greater then the list is traversed from start ** to finish, else it is traverse from end to begin. ** ** Returns 0 on success, non-0 on error. ** ** If visitor() returns non-0 then looping stops and that code is ** returned. */ int fsl_list_visit( fsl_list const * self, char order, fsl_list_visitor_f visitor, void * visitorState ); /** ** A list clean-up routine which takes a callback to clean up its ** contents. ** ** Passes each element in the given list to ** childFinalizer(item,finalizerState). If that returns non-0, ** processing stops and that value is returned, otherwise ** fsl_list_reserve(list,0) is called and 0 is returned. ** ** @see fsl_list_visit_free() **/ int fsl_list_clear( fsl_list * list, fsl_list_visitor_f childFinalizer, void * finalizerState ); /** ** Similar to fsl_list_clear(list, fsl_list_v_fsl_free, NULL), but ** only clears the list itself if the second argument is true, ** otherwise it sets the list's length to 0 but keeps its memory ** intact for later use. ** ** Be sure only to use this on lists of types for which fsl_free() ** is legal. i.e. don't use it on a list of fsl_deck objects or ** other types which have their own finalizers. ** ** Results are undefined if list is NULL. ** ** @see fsl_list_clear() */ void fsl_list_visit_free( fsl_list * list, char freeListMem ); /** ** ** ** Works similarly to the visit operation without the _p suffix ** except that the pointer the visitor function gets is a (**) ** pointing back to the entry within this list. That means that ** callers can assign the entry in the list to another value during ** the traversal process (e.g. set it to 0). If shiftIfNulled is ** true then if the callback sets the list's value to 0 then it is ** removed from the list and self->used is adjusted (self->capacity ** is not changed). */ int fsl_list_visit_p( fsl_list * self, char order, char shiftIfNulled, fsl_list_visitor_f visitor, void * visitorState ); /** ** Sorts the given list using the given comparison function. Neither ** argument may be NULL. The arugments passed to the comparison function ** will be pointers to pointers to the original entries, and may (depending ** on how the list is used) point to NULL. */ void fsl_list_sort( fsl_list * li, int (*cmp)( void const * lhs, void const * rhs )); /** ** Returns 0 if the given file is readable. Flags may be any values ** accepted by the accept(2) resp. _waccept() system calls. */ int fsl_file_access(const char *zFilename, int flags); /** ** Compute a canonical pathname for a file or directory. ** Make the name absolute if it is relative. ** Remove redundant / characters. ** Remove all /./ path elements. ** Convert /A/../ to just /. ** If the slash parameter is non-zero, the trailing slash, if any, ** is retained. ** ** Returns 0 on success, FSL_RC_MISUSE if !zOrigName or !pOut, ** FSL_RC_OOM if an allocation fails. ** ** pOut is _appended_ to, so be sure to set pOut->used=0 (or pass it ** to fsl_buffer_reset()) before calling this if you want to start ** writing at the beginning. */ int fsl_file_canonical_name(const char *zOrigName, fsl_buffer *pOut, char slash); /** ** Writes the absolute path name of the current directory to zBuf, ** which must be at least nBuf bytes long (nBuf includes the space ** for a trailing NUL terminator). ** ** Returns FSL_RC_RANGE if the name would be too long for nBuf, ** FSL_RC_IO if it cannot determine the current directory (e.g. a ** side effect of having removed the directory at runtime or similar ** things), and 0 on success. ** ** On success, if outLen is not NULL then the length of the string ** written to zBuf is assigned to *outLen. The output string is ** always NUL-terminated. ** ** On Windows, the name is converted from unicode to UTF8 and all '\\' ** characters are converted to '/'. No conversions are needed on ** Unix. */ int fsl_getcwd(char *zBuf, fsl_size_t nBuf, fsl_size_t * outLen); /** ** Return true if the filename given is a valid filename for ** a file in a repository. Valid filenames follow all of the ** following rules: ** ** * Does not begin with "/" ** * Does not contain any path element named "." or ".." ** * Does not contain any of these characters in the path: "\" ** * Does not end with "/". ** * Does not contain two or more "/" characters in a row. ** * Contains at least one character ** ** Invalid UTF8 characters result in a false return if bStrictUtf8 is ** true. If bStrictUtf8 is false, invalid UTF8 characters are silently ** ignored. See http://en.wikipedia.org/wiki/UTF-8#Invalid_byte_sequences ** and http://en.wikipedia.org/wiki/Unicode (for the noncharacters). ** ** Fossil compatibility note: the bStrictUtf8 flag must be true ** when parsing new manifests but is false when parsing legacy ** manifests, for backwards compatibility. ** ** z must be NUL terminated. Results are undefined if !z. */ char fsl_is_simple_pathname(const char *z, char bStrictUtf8); /** ** Return the size of a file in bytes. Returns -1 if the file does ** not exist or is not stat(2)able. */ fsl_size_t fsl_file_size(const char *zFilename); /** ** Return the modification time for a file. Return -1 if the file ** does not exist or is not stat(2)able. */ fsl_time_t fsl_file_mtime(const char *zFilename); /** ** Don't use this. The wd (working directory) family of functions ** might or might-not be necessary and in any case they require ** a fsl_cx context argument because they require repo-specific ** "allow-symlinks" setting. ** Return TRUE if the named file is an ordinary file or symlink ** and symlinks are allowed. ** ** Return false for directories, devices, fifos, etc. */ int fsl_file_wd_isfile_or_link(const char *zFilename); /** ** Return TRUE if the named file is an ordinary file. Return false ** for directories, devices, fifos, symlinks, etc. */ int fsl_file_isfile(const char *zFilename); /** ** Returns true if the given path appears to be absolute, else ** false. On Unix a path is absolute if it starts with a '/'. On ** Windows a path is also absolute if it starts with a letter, a ** colon, and a backslash. */ char fsl_file_is_absolute_path(const char *zPath); /** ** Simplify a filename by ** ** * Convert all \ into / on windows and cygwin ** * removing any trailing and duplicate / ** * removing /./ ** * removing /A/../ ** ** Changes are made in-place. Return the new name length. If the ** slash parameter is non-zero, the trailing slash, if any, is ** retained. If n is <0 then fsl_strlen(z) is used to calculate the ** length. */ fsl_size_t fsl_file_simplify_name(char *z, fsl_int_t n_, char slash); /** ** Return non-zero if string z matches glob pattern zGlob and zero ** if the pattern does not match. Always returns 0 if either ** argument is NULL. ** ** Globbing rules: ** ** '*' Matches any sequence of zero or more characters. ** ** '?' Matches exactly one character. ** ** [...] Matches one character from the enclosed list of ** characters. ** ** [^...] Matches one character not in the enclosed list. */ char fsl_str_glob(const char *zGlob, const char *z); /** ** Returns true, else false if the given letter is an ASCII alphabet ** character. */ char fsl_isalpha(int c); char fsl_islower(int c); char fsl_isspace(int c); char fsl_islower(int c); char fsl_isupper(int c); char fsl_isdigit(int c); char fsl_tolower(int c); char fsl_toupper(int c); char fsl_isalpha(int c); char fsl_isalnum(int c); #ifdef _WIN32 /** ** Translate MBCS to UTF-8. Return a pointer to the translated ** text. ACHTUNG: Call fsl_mbcs_free() (not fsl_free()) to ** deallocate any memory used to store the returned pointer when ** done. */ char * fsl_mbcs_to_utf8(char const * mbcs); /** ** Frees a string allocated from fsl_mbcs_to_utf8(). Results are undefined ** if mbcs was allocated using any other mechanism. */ void fsl_mbcs_free(char * mbcs); #endif /* _WIN32 */ /** ** Deallocates the given memory, which must have been allocated ** from fsl_unicode_to_utf8(), fsl_utf8_to_unicode(), or any ** function which explicitly documents this function as being the ** proper finalizer for its returned memory. */ void fsl_unicode_free(void *); /** ** Translate UTF-8 to Unicode for use in system calls. Returns a ** pointer to the translated text. The returned value must ** eventually be passed to fsl_unicode_free() to deallocate any ** memory used to store the returned pointer when done. ** ** This function exists only for Windows. On other platforms ** it behaves like fsl_strdup(). ** ** The returned type is (wchar_t*) on Windows and (char*) ** everywhere else. */ void *fsl_utf8_to_unicode(const char *zUtf8); /** ** Translates Unicode text into UTF-8. Return a pointer to the ** translated text. Call fsl_unicode_free() to deallocate any ** memory used to store the returned pointer when done. ** ** This function exists only for Windows. On other platforms it ** behaves like fsl_strdup(). */ char *fsl_unicode_to_utf8(const void *zUnicode); /** ** Translate text from the OS's character set into UTF-8. Return a ** pointer to the translated text. Call fsl_filename_free() to ** deallocate any memory used to store the returned pointer when ** done. ** ** This function must not convert '\' to '/' on Windows/Cygwin, as ** it is used in places where we are not sure it's really filenames ** we are handling, e.g. fsl_getenv() or handling the argv ** arguments from main(). ** ** On Windows, translate some characters in the in the range ** U+F001 - U+F07F (private use area) to ASCII. Cygwin sometimes ** generates such filenames. See: ** */ char *fsl_filename_to_utf8(const void *zFilename); /** ** Translate text from UTF-8 to the OS's filename character set. ** Return a pointer to the translated text. Call ** fsl_filename_free() to deallocate any memory used to store the ** returned pointer when done. ** ** On Windows, characters in the range U+0001 to U+0031 and the ** characters '"', '*', ':', '<', '>', '?' and '|' are invalid in ** filenames. Therefore, translate those to characters in the in the ** range U+F001 - U+F07F (private use area), so those characters ** never arrive in any Windows API. The filenames might look ** strange in Windows explorer, but in the cygwin shell everything ** looks as expected. ** ** See: ** ** The returned type is (wchar_t*) on Windows and (char*) ** everywhere else. */ void *fsl_utf8_to_filename(const char *zUtf8); /** ** Deallocate pOld, which must have been allocated by ** fsl_filename_to_utf8(), fsl_utf8_to_filename(), fsl_getenv(), or ** another routine which explicitly documents this function as ** being the proper finalizer for its returned memory. */ void fsl_filename_free(void *pOld); /** ** Returns a (possible) copy of the environment variable with the ** given key, or NULL if no entry is found. The returned value must ** be passed to fsl_filename_free() to free it. ACHTUNG: DO NOT ** MODIFY the returned value - on Unix systems it is _not_ a ** copy. That interal API inconsistency "should" be resolved ** (==return a copy from here, but that means doing it everywhere) ** to avoid memory ownership problems later on. ** ** Why return a copy? Because native strings from at least one of ** the more widespread OSes often have to be converted to something ** portable and this requires allocation on such platforms, but ** not on Unix. For API transparency, that means all platforms get ** the copy(-like) behaviour. **/ char *fsl_getenv(const char *zName); /** ** Returns a positive value if zFilename is a directory, 0 if ** zFilename does not exist, or a negative value if zFilename ** exists but is something other than a directory. Results are ** undefined if zFilename is NULL. */ char fsl_dir_check(const char *zFilename); /** ** Deletes the given file from the filesystem. Returns 0 on ** success. */ int fsl_file_unlink(const char *zFilename); /** ** Create the directory with the given name if it does not already ** exist. If forceFlag is true, delete any prior non-directory ** object with the same name. ** ** If the directory already exists, 0 is returned, not an error. ** ** Return 0 on success, non-0 on error. */ int fsl_mkdir(const char *zName, char forceFlag); /** ** Uses fsl_getenv() to look for the environment variables ** (FOSSIL_USER, (Windows: USERNAME), (Unix: USER, LOGNAME)). If ** it finds one it returns a copy of that value, which must ** eventually be passed to fsl_free() to free it (NOT ** fsl_filename_free(), though fsl_getenv() requires that one). If ** it finds no match, or if copying the entry fails, it returns ** NULL. */ char * fsl_guess_user_name(); /** ** Tries to find the user's home directory. If found, 0 is ** returned, tgt's memory is _overwritten_ (not appended) with the ** path, and tgt->used is set to the path's string length. (Design ** note: the overwrite behaviour is inconsistent with must of the ** API, but the implementation currently requires this.) ** ** If requireWriteAccess is true then the directory is checked for ** write access, and FSL_RC_ACCESS is returned if that check ** fails. For historical (possibly techinical?) reasons, this check ** is only performed on Unix platforms. On others this argument is ** ignored. When writing code on Windows, it may be necessary to ** assume that write access is necessary on non-Windows platform, ** and to pass 1 for the second argument even though it is ignored ** on Windows. ** ** On error non-0 is returned and tgt is updated with an error ** string OR (if the error was an allocation error while appending ** to the path or allocating MBCS strings for Windows), it returns ** FSL_RC_OOM and tgt "might" be updated with a partial path (up to ** the allocation error), and "might" be empty (if the allocation ** error happens early on). ** ** This routine does not canonicalize/transform the home directory ** path provided by the environment, other than to convert the ** string byte encoding on some platforms. i.e. if the environment ** says that the home directory is "../" then this function will ** return that value, possibly to the eventual disappointment of ** the caller. ** ** Result codes include: ** ** - FSL_RC_OK (0) means a home directory was found and tgt is ** populated with its path. ** ** - FSL_RC_NOT_FOUND means the home directory (platform-specific) ** could not be found. ** ** - FSL_RC_ACCESS if the home directory is not writable and ** requireWriteAccess is true. Unix platforms only - ** requireWriteAccess is ignored on others. ** ** - FSL_RC_TYPE if the home (as determined via inspection of the ** environment) is not a directory. ** ** - FSL_RC_OOM if a memory (re)allocation fails. */ int fsl_find_home_dir( fsl_buffer * tgt, char requireWriteAccess ); /** ** Values for use with the fsl_fstat::mode field. */ enum fsl_fstat_type_t { FSL_FSTAT_TYPE_UNKNOWN = 0, /** Indicates a directory filesystem entry. */ FSL_FSTAT_TYPE_DIR, /** Indicates a non-directory, non-symlink filesystem entry. */ FSL_FSTAT_TYPE_FILE, /** Indicates a symlink filesystem entry. */ FSL_FSTAT_TYPE_LINK }; typedef enum fsl_fstat_type_t fsl_fstat_type_t; /** ** Bitmask values for use with the fsl_fstat::perms field. */ enum fsl_fstat_perm_t { /** ** Sentinel value. */ FSL_FSTAT_PERM_UNKNOWN = 0, /** ** The executable bit, as understood by Fossil. Fossil does not ** differentiate between different +x values for user/group/other. */ FSL_FSTAT_PERM_EXE = 0x01 }; typedef enum fsl_fstat_perm_t fsl_fstat_perm_t; /** ** A simple wrapper around the stat(2) structure resp. _stat/_wstat ** (on Windows). It exposes only the aspects of stat(2) info which ** Fossil works with, and not any platform-/filesystem-specific ** details except the executable bit for the permissions mode. **/ struct fsl_fstat { /** ** Indicates the type of filesystem object. */ fsl_fstat_type_t type; /** ** The creation time stat'd file, in... well, the man pages ** (neither for Linux nor Windows) do not specify exactly what ** unit this is. Let's assume seconds since the start of the Unix ** Epoch. */ fsl_time_t ctime; /** ** Last modification time. */ fsl_time_t mtime; /** ** The size of the stat'd file, in bytes. */ fsl_size_t size; /** ** Not yet used. ** ** TODO: decide whether we want to expose all OS/FS-level ** permissions or just the executable bit (as v1 does). ** fsl_fstat is intended to be used in more generic contexts than ** v1's fossil_stat(), so it "might" make sense to expose those ** here, even though fossil will only track the exec permission. */ int perms; }; /** Empty-initialized fsl_fstat structure. */ #define fsl_fstat_empty_m {FSL_FSTAT_TYPE_UNKNOWN,0,0,0,0} /** Empty-initialize fsl_fstat instance, intended for copy construction. */ extern const fsl_fstat fsl_fstat_empty; /** ** Runs the OS's stat(2) equivalent to populate fst with ** information about the given file. ** ** Returns 0 on success, FSL_RC_MISUSE if zFilename is NULL or ** starts with a NUL byte, or if fst is NULL. Returns ** FSL_RC_NOT_FOUND if no filesystem entry is found for the given ** name. Returns FSL_RC_IO if the underlying stat() (or equivalent) ** fails for other reasons (because MS apparently doesn't document ** the errno values which can be set by _wstati64()). ** ** The derefSymlinks argument is ignored on non-Unix platforms. On ** Unix platforms, if derefSymlinks is non-0 then stat(2) is used, ** else lstat(2) (if available on the platform) is used. For most ** cases clients should pass non-0. They should only pass 0 if they ** need to differentiate between symlinks and files. ** ** The fsl_fstat_type_t family of flags can be used to determine ** the type of the filesystem object being stat()'d (file, ** directory, or symlink). It does apply any special logic for ** platform-specific oddities other than symlinks (e.g. character ** devices and such). **/ int fsl_stat(const char *zFilename, fsl_fstat * fst, char derefSymlinks ); /** ** Create a new delta between the memory zIn and zOut. ** ** The delta is written into a preallocated buffer, zDelta, which ** must be at least 60 bytes longer than the target memory, zOut. ** The delta string will be NUL-terminated, but it might also ** contain embedded NUL characters if either the zSrc or zOut files ** are binary. ** ** On success this function returns 0 and the length of the delta ** string, in bytes, excluding the final NUL terminator character, ** is written to *deltaSize. ** ** Returns FSL_RC_MISUSE if any of the pointer arguments are NULL ** and FSL_RC_OOM if memory allocation fails during generation of ** the delta. Returns FSL_RC_RANGE if lenSrc or lenOut are "too ** big" (if they cause an overflow in the math). ** ** Output Format: ** ** The delta begins with a base64 number followed by a newline. ** This number is the number of bytes in the TARGET file. Thus, ** given a delta file z, a program can compute the size of the ** output file simply by reading the first line and decoding the ** base-64 number found there. The fsl_delta_applied_size() ** routine does exactly this. ** ** After the initial size number, the delta consists of a series of ** literal text segments and commands to copy from the SOURCE file. ** A copy command looks like this: ** ** (Achtung: extra backslashes are for Doxygen's benefit - not ** visible in the processsed docs.) ** ** NNN\@MMM, ** ** where NNN is the number of bytes to be copied and MMM is the ** offset into the source file of the first byte (both base-64). ** If NNN is 0 it means copy the rest of the input file. Literal ** text is like this: ** ** NNN:TTTTT ** ** where NNN is the number of bytes of text (base-64) and TTTTT is ** the text. ** ** The last term is of the form ** ** NNN; ** ** In this case, NNN is a 32-bit bigendian checksum of the output ** file that can be used to verify that the delta applied ** correctly. All numbers are in base-64. ** ** Pure text files generate a pure text delta. Binary files ** generate a delta that may contain some binary data. ** ** Algorithm: ** ** The encoder first builds a hash table to help it find matching ** patterns in the source file. 16-byte chunks of the source file ** sampled at evenly spaced intervals are used to populate the hash ** table. ** ** Next we begin scanning the target file using a sliding 16-byte ** window. The hash of the 16-byte window in the target is used to ** search for a matching section in the source file. When a match ** is found, a copy command is added to the delta. An effort is ** made to extend the matching section to regions that come before ** and after the 16-byte hash window. A copy command is only ** issued if the result would use less space that just quoting the ** text literally. Literal text is added to the delta for sections ** that do not match or which can not be encoded efficiently using ** copy commands. ** ** @see fsl_delta_applied_size() ** @see fsl_delta_apply() */ int fsl_delta_create( unsigned char const *zSrc, fsl_size_t lenSrc, unsigned char const *zOut, fsl_size_t lenOut, unsigned char *zDelta, fsl_size_t * deltaSize); /** ** Works identically to fsl_delta_create() but sends its output to ** the given output function. out(outState,...) may be called any ** number of times to emit delta output. Each time it is called it ** should append the new bytes to its output channel. ** ** The semantics of the return value and the first four arguments ** are identical tofsl_delta_create(), with these ammendments ** regarding the return: ** ** - Returns FSL_RC_MISUSE if any of (zSrc, zOut, out) are NULL. ** ** - If out() returns non-0 at any time, delta generation is ** aborted and that code is returned. ** ** Example usage: ** ** @code ** int rc = fsl_delta_create( v1, v1len, v2, v2len, ** fsl_output_f_FILE, stdout); ** @endcode */ int fsl_delta_create2( unsigned char const *zSrc, fsl_size_t lenSrc, unsigned char const *zOut, fsl_size_t lenOut, fsl_output_f out, void * outState); /** ** A fsl_delta_create() wrapper which uses the first two arguments ** as the original and "new" content versions to delta, and outputs ** the delta to the 3rd argument (overwriting any existing contents ** and re-using any memory it had allocated). ** ** Returns 0 on success. */ int fsl_buffer_delta_create( fsl_buffer const * src, fsl_buffer const * newVers, fsl_buffer * delta); /** ** Apply a delta created using fsl_delta_create(). ** ** The output buffer must be big enough to hold the whole output ** file and a NUL terminator at the end. The ** fsl_delta_applied_size() routine can be used to determine that ** size. ** ** zSrc represents the original sources to apply the delta to. ** It must be at least lenSrc bytes of valid memory. ** ** zDelta holds the delta (created using fsl_delta_create()), ** and it must be lenDelta bytes long. ** ** On success this function returns 0 and writes the applied delta ** to zOut. ** ** Returns FSL_RC_MISUSE if any pointer argument is NULL. Returns ** FSL_RC_RANGE if lenSrc or lenDelta are "too big" (if they cause ** an overflow in the math). Invalid delta input can cause any of ** FSL_RC_RANGE, FSL_RC_DELTA_INVALID_TERMINATOR, ** FSL_RC_CHECKSUM_MISMATCH, FSL_RC_SIZE_MISMATCH, or ** FSL_RC_DELTA_INVALID_OPERATOR to be returned. ** ** Refer to the fsl_delta_create() documentation above for a ** description of the delta file format. ** ** @see fsl_delta_applied_size() ** @see fsl_delta_create() ** @see fsl_delta_apply2() */ int fsl_delta_apply( unsigned char const *zSrc, fsl_size_t lenSrc, unsigned char const *zDelta, fsl_size_t lenDelta, unsigned char *zOut ); /** ** Functionally identical to fsl_delta_apply() but any errors generated ** during application of the delta are described in more detail ** in pErr. If pErr is NULL this behaves exactly as documented for ** fsl_delta_apply(). */ int fsl_delta_apply2( unsigned char const *zSrc, fsl_size_t lenSrc, unsigned char const *zDelta, fsl_size_t lenDelta, unsigned char *zOut, fsl_error * pErr); /* ** Calculates the size (in bytes) of the output from applying a the ** given delta. On success 0 is returned and *appliedSize will be ** updated with the amount of memory required for applying the ** delta. zDelta must point to lenDelta bytes of memory in the ** format emitted by fsl_delta_create(). It is legal for appliedSize ** to point to the same memory as the 2nd argument. ** ** Returns FSL_RC_MISUSE if any pointer argument is NULL. Returns ** FSL_RC_RANGE if lenDelta is too short to be a delta. Returns ** FSL_RC_DELTA_INVALID_TERMINATOR if the delta's encoded length ** is not properly terminated. ** ** This routine is provided so that an procedure that is able to ** call fsl_delta_apply() can learn how much space is required for ** the output and hence allocate nor more space that is really ** needed. ** ** TODO?: consolidate 2nd and 3rd parameters into one i/o parameter? ** ** @see fsl_delta_apply() ** @see fsl_delta_create() */ int fsl_delta_applied_size(unsigned char const *zDelta, fsl_size_t lenDelta, fsl_size_t * appliedSize); /** ** "Fossilizes" the first len bytes of the given input string. If ** (len<0) then fsl_strlen(inp) is used to calculate its length. ** The output is appended to out, which is expanded as needed and ** out->used is updated accordingly. Returns 0 on success, ** FSL_RC_MISUSE if !inp or !out. Returns 0 without side-effects if ** 0==len or (!*inp && len<0). Returns FSL_RC_OOM if reservation of ** the output buffer fails (it is expanded, at most, one time by ** this function). ** ** Fossilization replaces the following bytes/sequences with the ** listed replacements: ** ** (Achtung: usage of doubled backslashes here it just to please ** doxygen - they will show up as single slashes in the processed ** output.) ** ** - Backslashes are doubled. ** ** - (\\n, \\r, \\v, \\t, \\f) are replaced with \\\\X, where X is the ** conventional encoding letter for that escape sequence. ** ** - Spaces are replaced with \\s. ** ** - Embedded NULs are replaced by \\0 (numeric 0, not character ** '0'). */ int fsl_bytes_fossilize( unsigned char const * inp, fsl_int_t len, fsl_buffer * out ); /** ** "Defossilizes" bytes encoded by fsl_bytes_fossilize() in-place. ** inp must be a string encoded by fsl_bytes_fossilize(), and the ** decoding processes stops at the first unescaped NUL terminator. ** It has no error conditions except for !inp or if inp is not ** NUL-terminated, both of which invoke in undefined behaviour. ** ** If resultLen is not NULL then *resultLen is set to the resulting string ** length. ** */ void fsl_bytes_defossilize( unsigned char * inp, fsl_size_t * resultLen ); /** ** Defossilizes the contents of b. Equivalent to: ** fsl_bytes_defossilize( b->mem, &b->used ); */ void fsl_buffer_defossilize( fsl_buffer * b ); /** ** Return true (non-0) if the input string contains only valid base-16 ** digits. If any invalid characters appear in the string, return ** 0 (false). */ char fsl_validate16(const char *zIn, fsl_size_t nIn); /** ** The input string is a base16 value. Convert it into its canonical ** form. This means that digits are all lower case and that conversions ** like "l"->"1" and "O"->"0" occur. */ void fsl_canonical16(char *z, fsl_size_t n); /** ** Decode a N-character base-16 number into base-256. N must be a ** multiple of 2. The output buffer must be at least N/2 characters ** in length. Returns 0 on success. */ int fsl_decode16(const unsigned char *zIn, unsigned char *pOut, fsl_size_t N); /** ** Encode a N-digit base-256 in base-16. N is the byte length of pIn ** and zOut must be at least (N*2+1) bytes long (the extra is for a ** terminating NUL). Returns zero on success, FSL_RC_MISUSE if !pIn ** or !zOut. */ int fsl_encode16(const unsigned char *pIn, unsigned char *zOut, fsl_size_t N); /** ** Tries to convert the value of errNo, which is assumed to come ** from the global errno, to a fsl_rc_t code. If it can, it returns ** something approximating the errno value, else it returns dflt. ** ** Example usage: ** ** @code ** FILE * f = fsl_fopen("...", "..."); ** int rc = f ? 0 : fsl_errno_to_rc(errno, FSL_RC_IO); ** ... ** @endcode ** ** Why require the caller to pass in errno, instead of accessing it ** directly from this function? To avoid the the off-chance that ** something changes errno between the call and the conversion ** (whether or not that's possible is as yet undetermined). It can ** also be used by clients to map to explicit errno values to ** fsl_rc_t values, e.g. fsl_errno_to_rc(EROFS,-1) returns ** FSL_RC_ACCESS. */ int fsl_errno_to_rc(int errNo, int dflt); /** ** Make the given string safe for HTML by converting every "<" into ** "<", every ">" into ">", every "&" into "&", and ** encode " as " so that it can appear as an argument to ** markup. ** ** The escaped output is send to out(oState,...). ** ** Returns 0 on success or if there is nothing to do (input has a ** length of 0). Returns FSL_RC_MISUSE if !out or !zIn. If out() ** returns a non-0 code then that value is returned to the caller. ** ** If n is negative, fsl_strlen() is used to calculate zIn's length. */ int fsl_htmlize(fsl_output_f out, void * oState, const char *zIn, fsl_int_t n); /** ** Functionally equivalent to fsl_htmlize() but optimized to perform ** only a single allocation. ** ** Returns 0 on success or if there is nothing to do (input has a ** length of 0). Returns FSL_RC_MISUSE if !p or !zIn, and ** FSL_RC_OOM on allocation error. ** ** If n is negative, fsl_strlen() is used to calculate zIn's length. */ int fsl_htmlize_to_buffer(fsl_buffer *p, const char *zIn, fsl_int_t n); /** ** Equivalent to fsl_htmlize_to_buffer() but returns the result as a ** new string which must eventually be fsl_free()d by the caller. ** ** Returns NULL for invalidate arguments or allocation error. */ char *fsl_htmlize_str(const char *zIn, fsl_int_t n); /** ** If c is a character Fossil likes to HTML-escape, assigns *xlate ** to its transformed form, else set it to NULL. Returns 1 for ** untransformed characters and the strlen of *xlate for others. ** Bytes returned via xlate are static and immutable. ** ** Results are undefined if xlate is NULL. */ fsl_size_t fsl_htmlize_xlate(int c, char const ** xlate); /** ** Flags for use with text-diff generation APIs, ** e.g. fsl_diff_text(). ** ** Maintenance reminder: these values are holy and must not be ** changed without also changing the corresponding code in ** fsl_diff.c. */ enum fsl_diff_flag_t { /** Inline (not side-by-side) diff */ FSL_DIFF_INLINE = 0x00, /** Ignore end-of-line whitespace */ FSL_DIFF_IGNORE_EOLWS = 0x01, /** Generate a side-by-side diff */ FSL_DIFF_SIDEBYSIDE = 0x02, /** Missing shown as empty files */ FSL_DIFF_VERBOSE = 0x04, /** Show filenames only */ FSL_DIFF_BRIEF = 0x08, /** Render for HTML. */ FSL_DIFF_HTML = 0x10, /** Show line numbers. */ FSL_DIFF_LINENO = 0x20, /** Warn about whitespace. */ FSL_DIFF_WS_WARNING = 0x40, /** Suppress optimizations (debug). */ FSL_DIFF_NOOPT = 0x0100, /** Invert the diff (debug). */ FSL_DIFF_INVERT = 0x0200, /** Use context even if zero. */ FSL_DIFF_CONTEXT_EX = 0x0400, /** Only display if not "too big." */ FSL_DIFF_NOTTOOBIG = 0x0800 }; /** ** Generates a textual diff from two text inputs and writes ** it to the given output function. ** ** pA and pB are the buffers to diff. ** ** contextLines is the number of lines of context to output (or ** some default if <= 0). This parameter has a built-in limit ** of 2^16, and values larger than that get truncated. ** ** sbsWidth specifies the width (in characters) of the side-by-side ** columns. If sbsWidth is not 0 then this function behaves as if ** diffFlags contains the FSL_DIFF_SIDEBYSIDE flag. If sbsWidth is ** negative, OR if diffFlags explicitly contains ** FSL_DIFF_SIDEBYSIDE and sbsWidth is 0, then some default width ** is used. This parameter has a built-in limit of 255, and values ** larger than that get truncated to 255. ** ** diffFlags is a mask of fsl_diff_flag_t values. Not all of the ** fsl_diff_flag_t flags are yet [sup]ported. ** ** The output is sent to out(outState,...). If out() returns non-0 ** during processing, processing stops and that result is returned ** to the caller of this function. ** ** Returns 0 on success, FSL_RC_OOM on allocation error, ** FSL_RC_MISUSE if any arguments are invalid, FSL_RC_TYPE if any ** of the content appears to be binary (contains embedded NUL ** bytes). ** ** None of (pA, pB, out) may be NULL. ** ** TODOs: ** ** - Add a predicate function for outputing only matching ** differences, analog to fossil(1)'s regex support (but more ** flexible). ** ** - Expose the raw diff-generation bits via the internal API ** to facilitate/enable the creation of custom diff formats. */ int fsl_diff_text(fsl_buffer const *pA, fsl_buffer const *pB, fsl_output_f out, void * outState, short contextLines, short sbsWidth, int diffFlags ); /** ** Functionally equivalent to: ** ** @code: ** fsl_diff_text(pA, pB, fsl_output_f_buffer, pOut, ** contextLines, sbsWidth, diffFlags); ** @endcode ** ** Except that it returns FSL_RC_MISUSE if !pOut. */ int fsl_diff_text_to_buffer(fsl_buffer const *pA, fsl_buffer const *pB, fsl_buffer *pOut, short contextLines, short sbsWidth, int diffFlags ); #if defined(__cplusplus) } /*extern "C"*/ #endif #endif /* NET_FOSSIL_SCM_FSL_UTIL_H_INCLUDED */