forked from Telodendria/Telodendria
Start documenting the headers.
This commit is contained in:
parent
1087069416
commit
8e8ac04505
7 changed files with 817 additions and 65 deletions
|
@ -21,6 +21,25 @@
|
|||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Array.h: A simple array data structure that is automatically
|
||||
* resized when new values are added. This implementation does not
|
||||
* actually store the values of the items it; it only stores pointers
|
||||
* to the data. As such, you will still have to manually maintain all
|
||||
* your data. The advantage of this is that this array implementation
|
||||
* doesn't have to copy items, and thus doesn't have to know how big
|
||||
* they are.
|
||||
*
|
||||
* This array is optimized for storage space and appending. Deletions
|
||||
* are expensive in that all the items of the list are moved down
|
||||
* to fill the hole where the deletion occurred. Insertions are
|
||||
* also expensive in that all the elements are shifted to make room
|
||||
* for the new element.
|
||||
*
|
||||
* Due to these, this array implementation is really intended to be
|
||||
* used primarily for linear writing and linear or random reading.
|
||||
*/
|
||||
#ifndef TELODENDRIA_ARRAY_H
|
||||
#define TELODENDRIA_ARRAY_H
|
||||
|
||||
|
@ -28,31 +47,171 @@
|
|||
|
||||
typedef struct Array Array;
|
||||
|
||||
/*
|
||||
* Create a new, empty array on the heap.
|
||||
*
|
||||
* Params: none
|
||||
*
|
||||
* Return: A pointer to an Array, or NULL if there was an error
|
||||
* allocating memory for the Array.
|
||||
*/
|
||||
extern Array *
|
||||
ArrayCreate(void);
|
||||
|
||||
/*
|
||||
* Get the size of the provided array. Note that this is the number
|
||||
* of elements in the array, not how much memory has been allocated
|
||||
* for it.
|
||||
*
|
||||
* This is an extremely cheap operation, because the size does not
|
||||
* need to be computed; rather it is just pulled right out of the
|
||||
* Array and returned to the caller.
|
||||
*
|
||||
* Params:
|
||||
*
|
||||
* (Array *) The array to check the size of.
|
||||
*
|
||||
* Return: The number of elements in the provided array, or 0 if the
|
||||
* provided array is NULL.
|
||||
*/
|
||||
extern size_t
|
||||
ArraySize(Array * array);
|
||||
ArraySize(Array *);
|
||||
|
||||
/*
|
||||
* Get an element out of the provided array at the provided index.
|
||||
*
|
||||
* Params:
|
||||
*
|
||||
* (Array *) The array to get an element from.
|
||||
* (size_t) The index of the array where the desired element is
|
||||
* located.
|
||||
*
|
||||
* Return: A pointer to the data located at the given index, or NULL
|
||||
* if no array was provided, or the index is greater than or equal
|
||||
* to the size of the array.
|
||||
*/
|
||||
extern void *
|
||||
ArrayGet(Array * array, size_t index);
|
||||
ArrayGet(Array *, size_t);
|
||||
|
||||
/*
|
||||
* Insert an element into the array at the given index.
|
||||
*
|
||||
* Params:
|
||||
*
|
||||
* (Array *) The array to get the element from.
|
||||
* (void *) The value to insert into the array.
|
||||
* (size_t) The index at which the given value.
|
||||
*
|
||||
* Return: A boolean value that indicates whether or not the insert
|
||||
* was successful. A return value of 0 indicates that the insert was
|
||||
* NOT successful, and a return value of anything else indicates that
|
||||
* the insert was successful.
|
||||
*/
|
||||
extern int
|
||||
ArrayInsert(Array *, void *value, size_t index);
|
||||
ArrayInsert(Array *, void *, size_t);
|
||||
|
||||
/*
|
||||
* Append an element to the end of the array. This function actually
|
||||
* uses ArrayInsert() under the hood, but it makes appending to an
|
||||
* array more convenient because you don't necessarily have to keep
|
||||
* track of the array's size.
|
||||
*
|
||||
* Params:
|
||||
*
|
||||
* (Array *) The array to append to.
|
||||
* (void *) The value to append to the array.
|
||||
*
|
||||
* Return: The result of appending the element, which is the same as
|
||||
* a call to ArrayInsert().
|
||||
*/
|
||||
extern int
|
||||
ArrayAdd(Array * array, void *value);
|
||||
ArrayAdd(Array *, void *);
|
||||
|
||||
/*
|
||||
* Delete an element from an array by shifting all the elements that
|
||||
* come after it down one index.
|
||||
*
|
||||
* Params:
|
||||
*
|
||||
* (Array *) The array to delete a value from.
|
||||
* (size_t) The desired index to delete. All elements above this
|
||||
* index are then shifted down to fill the gap.
|
||||
*
|
||||
* Return: A pointer to the deleted element, so that it can be freed
|
||||
* or otherwise dealt with, or NULL if the array is NULL or the index
|
||||
* is out of bounds.
|
||||
*/
|
||||
extern void *
|
||||
ArrayDelete(Array * array, size_t index);
|
||||
ArrayDelete(Array *, size_t);
|
||||
|
||||
/*
|
||||
* Sort the array using a simple quick-sort algorithm. This function
|
||||
* works by taking a caller-specified compare function, so that no
|
||||
* assumptions about the data stored in the array need to be made by
|
||||
* this code.
|
||||
*
|
||||
* Params:
|
||||
*
|
||||
* (Array *) The array to sort. Note that the sort will be done
|
||||
* in-place.
|
||||
* (int (*)(void *, void *)) A function that takes in two void
|
||||
* pointers and returns an integer. This function is
|
||||
* responsible for comparing the passed items, and
|
||||
* returning a code that indicates how they should be
|
||||
* ordered. A return value of 0 indicates that the two
|
||||
* items are identical. A return value greater than 0
|
||||
* indicates that the first item is "bigger" than the
|
||||
* second item and should thus appear after it in the
|
||||
* array, and a return value less than zero indicates
|
||||
* the opposite: that the second element should appear
|
||||
* after the first in the array.
|
||||
*
|
||||
*/
|
||||
extern void
|
||||
ArraySort(Array *, int (*compare) (void *, void *));
|
||||
ArraySort(Array *, int (*) (void *, void *));
|
||||
|
||||
/*
|
||||
* Free all the memory associated with the given array. Note that this
|
||||
* does not free any of the values themselves; you should explicitly
|
||||
* iterate over the array and free all the values stored inside it
|
||||
* before calling this function, otherwise you may lose all the
|
||||
* pointers the array contains, and thus have a memory leak.
|
||||
*
|
||||
* Params:
|
||||
*
|
||||
* (Array *) The array to free.
|
||||
*
|
||||
*/
|
||||
extern void
|
||||
ArrayFree(Array * array);
|
||||
ArrayFree(Array *);
|
||||
|
||||
/*
|
||||
* "Trim" the array by reallocating it with only the memory it needs
|
||||
* to hold the items it currently has. This function might be beneficial
|
||||
* to call on long-lived arrays that will be read-only, because it
|
||||
* frees any memory on the end of the array that isn't being used. The
|
||||
* array resizing algorithm will most likely allocate too much memory
|
||||
* for most arrays as elements are added, because there's no way to
|
||||
* know exactly how many elements will be stored.
|
||||
*
|
||||
* For example, a library that generates an Array to return to the
|
||||
* user may wish to call this function on it right before returning to
|
||||
* the caller if it is not expected that the caller will be modifying
|
||||
* the array and may hang on to it for a long time.
|
||||
*
|
||||
* Params:
|
||||
*
|
||||
* (Array *) The array to trim extra memory (if any) off the end.
|
||||
* Note that the array will still be fully-functional; if
|
||||
* you add more elements, then more memory will be
|
||||
* allocated like normal.
|
||||
*
|
||||
* Return: Whether or not the trim was successful. The trim may fail if
|
||||
* realloc() fails, or NULL was passed for the array. If realloc()
|
||||
* fails, this function is careful not to clobber the array. Upon
|
||||
* failure of this function, the array is guaranteed to be unaltered.
|
||||
*/
|
||||
extern int
|
||||
ArrayTrim(Array * array);
|
||||
ArrayTrim(Array *);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -21,27 +21,135 @@
|
|||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Base64.h: An efficient base64 encoder and decoder that supports
|
||||
* both regular base64, and the Matrix spec's "unpadded base64."
|
||||
*/
|
||||
#ifndef TELODENDRIA_BASE64_H
|
||||
#define TELODENDRIA_BASE64_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/*
|
||||
* Compute the encoded size, including padding, of an input with the
|
||||
* provided size.
|
||||
*
|
||||
* Params:
|
||||
*
|
||||
* (size_t) The size of the input data to be encoded.
|
||||
*
|
||||
* Return: The size of the string needed to hold the data in its
|
||||
* encoded form. Note that base64 is not compression; base64 strings
|
||||
* are actually 25% larger than the unencoded input.
|
||||
*/
|
||||
extern size_t
|
||||
Base64EncodedSize(size_t inputSize);
|
||||
Base64EncodedSize(size_t);
|
||||
|
||||
/*
|
||||
* Compute the decoded size of the provide base64 input and length.
|
||||
*
|
||||
* Note that both the size and the actual base64 string itself is
|
||||
* needed for this computation, unlike Base64EncodedSize(). This is
|
||||
* because base64 strings are padded, and that padding is used in the
|
||||
* calculations.
|
||||
*
|
||||
* Params:
|
||||
*
|
||||
* (const char *) A padded base64 string. If you are dealing with
|
||||
* potentially user-provided base64, you should call
|
||||
* Base64Pad() on it to normalize it before computing
|
||||
* the decoded size.
|
||||
* (size_t) The length of the base64 string. Instead of scanning the
|
||||
* string for a null terminator, and then working backwards,
|
||||
* the length of the string must be passed here.
|
||||
*
|
||||
* Return: The number of bytes that can be decoded from this base64
|
||||
* string. Note that this will be smaller than the length of the base64
|
||||
* string because base64 is larger than the unencoded form.
|
||||
*/
|
||||
extern size_t
|
||||
Base64DecodedSize(const char *base64, size_t len);
|
||||
Base64DecodedSize(const char *, size_t);
|
||||
|
||||
/*
|
||||
* Copy the given input string to a new string, base64 encoding it in
|
||||
* the process. This function will produce standard padded base64. If
|
||||
* you want unpadded base64, call Base64Unpad() on the return value
|
||||
* of this function.
|
||||
*
|
||||
* Params:
|
||||
*
|
||||
* (const char *) The raw, unencoded input to be encoded as base64.
|
||||
* (size_t) The length of the unencoded input string.
|
||||
*
|
||||
* Return: A new string, allocated on the heap, that holds the base64
|
||||
* representation of the input. This string must be free()-ed when it
|
||||
* is no longer needed. If the allocation of the proper size fails,
|
||||
* or the input is inaccessible, then this function will return NULL.
|
||||
*/
|
||||
extern char *
|
||||
Base64Encode(const char *input, size_t len);
|
||||
Base64Encode(const char *, size_t);
|
||||
|
||||
/*
|
||||
* Decode a standard padded base64 string. This function expects that
|
||||
* the input will be padded, so if you are recieving untrusted input,
|
||||
* you should run Base64Pad() on it before attempting to decode it.
|
||||
*
|
||||
* Params:
|
||||
*
|
||||
* (const char *) The base64 string to decode.
|
||||
* (size_t) The length of the base64 string to decode.
|
||||
*
|
||||
* Return: A new string, allocated on the heap, that contains the
|
||||
* decoded string, or NULL if a decoding error occurred.
|
||||
*/
|
||||
extern char *
|
||||
Base64Decode(const char *input, size_t len);
|
||||
Base64Decode(const char *, size_t);
|
||||
|
||||
/*
|
||||
* Remove the padding from a base64 string. This is to implement the
|
||||
* Matrix spec's "unpadded base64" functionality. When base64 strings
|
||||
* are sent to other servers and clients, their padding must be
|
||||
* stripped.
|
||||
*
|
||||
* Params:
|
||||
*
|
||||
* (char *) The base64 string to remove padding from. Note that
|
||||
* this string is modified in place.
|
||||
* (size_t) The length of the provided base64 string.
|
||||
*
|
||||
*/
|
||||
extern void
|
||||
Base64Unpad(char *base64, size_t length);
|
||||
Base64Unpad(char *, size_t);
|
||||
|
||||
/*
|
||||
* Pad a base64 string in place. This is to implement the Matrix spec's
|
||||
* "unpadded base64." As we will most likely be getting unpadded base64
|
||||
* from clients and other servers, we should pad it before attempting
|
||||
* to decode it.
|
||||
*
|
||||
* I technically could have just had the decoder accept unpadded as
|
||||
* well as padded strings, but Matrix is the only thing I know of that
|
||||
* actually makes "unpadded" base64 a thing, so I thought it best to
|
||||
* make it clear in this library that unpadded base64 is an extension,
|
||||
* not the norm.
|
||||
*
|
||||
* Params:
|
||||
*
|
||||
* (char **) A pointer to a base64 string pointer. The reason we
|
||||
* take a pointer pointer is because the string may need
|
||||
* to be reallocated, as characters may be added to the
|
||||
* end of it. If the string is reallocated, then the
|
||||
* passed pointer must be updated. If the string is not
|
||||
* reallocated, the original pointer is not touched.
|
||||
* (size_t) The length of the given base64 string.
|
||||
*
|
||||
* Return: Whether or not the pad operation was successful. This
|
||||
* function will fail if a larger string cannot be allocated when it
|
||||
* is needed. Note that not all cases require the string to be
|
||||
* reallocated.
|
||||
*/
|
||||
extern int
|
||||
Base64Pad(char **base64Ptr, size_t length);
|
||||
Base64Pad(char **, size_t);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -21,13 +21,66 @@
|
|||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* CanonicalJson.h: An expansion of the JSON encoding functionality
|
||||
* that is specifically designed to produce the Matrix spec's
|
||||
* "canonical" JSON.
|
||||
*
|
||||
* Canonical JSON is defined as JSON that:
|
||||
*
|
||||
* - Does not have any unecessary whitespace.
|
||||
* - Has all object keys lexicographically sorted.
|
||||
* - Does not contain any float values.
|
||||
*
|
||||
* The regular JSON encoder has no such rules, because normally they
|
||||
* are not needed. However, Canonical JSON is needed to be able to
|
||||
* sign JSON objects in a consistent way.
|
||||
*/
|
||||
#ifndef TELODENDRIA_CANONICALJSON_H
|
||||
#define TELODENDRIA_CANONICALJSON_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <HashMap.h>
|
||||
|
||||
/*
|
||||
* Encode a JSON object following the rules of canonical JSON. See
|
||||
* JsonEncode() for more details on how JSON encoding operates.
|
||||
*
|
||||
* This function exists as an alternative to JsonEncode(), but should
|
||||
* not be preferred to JsonEncode() in normal circumstances. It is
|
||||
* a lot more costly, as it must lexicographically sort all keys and
|
||||
* strip out float values. If at all possible, use JsonEncode(),
|
||||
* because it is much cheaper in terms of memory and CPU time.
|
||||
*
|
||||
* Params:
|
||||
*
|
||||
* (HashMap *) The JSON object to encode. Note that all values must
|
||||
* be JsonValues.
|
||||
* (FILE *) The output stream to write the JSON object to.
|
||||
*
|
||||
* Return: Whether or not the JSON encoding was successful. This
|
||||
* function may fail if NULL was given for any parameter.
|
||||
*/
|
||||
extern int
|
||||
CanonicalJsonEncode(HashMap * object, FILE * out);
|
||||
CanonicalJsonEncode(HashMap *, FILE *);
|
||||
|
||||
/*
|
||||
* Encode the JSON object to a string. The regular JSON encoding
|
||||
* library doesn't have a way to send JSON to strings, because there's
|
||||
* absolutely no reason to handle JSON strings. However, the sole
|
||||
* reason canonical JSON exists is so that JSON objects can be signed.
|
||||
* Thus, you need a string to pass to the signing function.
|
||||
*
|
||||
* Params:
|
||||
*
|
||||
* (HashMap *) The JSON object to encode. Note that all values must
|
||||
* be JsonValues.
|
||||
*
|
||||
* Return: A string containing the canonical JSON representation of
|
||||
* the given object, or NULL if the encoding failed.
|
||||
*/
|
||||
extern char *
|
||||
CanonicalJsonEncodeToString(HashMap *);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -21,6 +21,22 @@
|
|||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Config.h: A heavily-modified version of Conifer2, a configuration
|
||||
* file format specification and C parsing library written by Jordan
|
||||
* Bancino. This library differs from Conifer2 in that the function
|
||||
* naming convention has been updated to be consistent with Telodendria,
|
||||
* and the underlying data structures have been overhauled to use the
|
||||
* data structure libraries provided by Telodendria.
|
||||
*
|
||||
* Conifer2 was originally a learning project. It was very thoroughly
|
||||
* debugged, however, and the configuration syntax was elegant,
|
||||
* certainly more elegant than using JSON for a configuration file,
|
||||
* so it was chosen to be the format for Telodendria's configuration
|
||||
* file. The original Conifer2 project is now dead; Conifer2 lives on
|
||||
* only as Telodendria's Config parsing library.
|
||||
*/
|
||||
#ifndef TELODENDRIA_CONFIG_H
|
||||
#define TELODENDRIA_CONFIG_H
|
||||
|
||||
|
@ -29,32 +45,164 @@
|
|||
#include <HashMap.h>
|
||||
#include <Array.h>
|
||||
|
||||
/*
|
||||
* A configuration directive is a single key that may have at least one
|
||||
* value, and any number of children.
|
||||
*/
|
||||
typedef struct ConfigDirective ConfigDirective;
|
||||
|
||||
/*
|
||||
* The parser returns a parse result object. This stores whether or
|
||||
* not the parse was successful, and then also additional information
|
||||
* about the parse, such as the line number on which parsing failed,
|
||||
* or the collection of directives if the parsing succeeded.
|
||||
*
|
||||
* There are a number of ConfigParseResult methods that can be used
|
||||
* to query the result of parsing.
|
||||
*/
|
||||
typedef struct ConfigParseResult ConfigParseResult;
|
||||
|
||||
/*
|
||||
* Parse a configuration file, and generate the structures needed to
|
||||
* make it easy to read.
|
||||
*
|
||||
* Params:
|
||||
*
|
||||
* (FILE *) The input stream to read from.
|
||||
*
|
||||
* Return: A ConfigParseResult, which can be used to check whether or
|
||||
* not the parsing was successful. If the parsing was sucessful, then
|
||||
* this object contains the root directive, which can be used to
|
||||
* retrieve configuration values out of. If the parsing failed, then
|
||||
* this object contains the line number at which the parsing was
|
||||
* aborted.
|
||||
*/
|
||||
extern ConfigParseResult *
|
||||
ConfigParse(FILE * stream);
|
||||
ConfigParse(FILE *);
|
||||
|
||||
/*
|
||||
* Get whether or not a parse result indicates that parsing was
|
||||
* successful or not. This function should be used to determine what
|
||||
* to do next. If the parsing failed, your program should terminate
|
||||
* with an error, otherwise, you can proceed to parse the configuration
|
||||
* file.
|
||||
*
|
||||
* Params:
|
||||
*
|
||||
* (ConfigParseResult *) The output of ConfigParse() to check.
|
||||
*
|
||||
* Return: 0 if the configuration file is malformed, or otherwise
|
||||
* could not be parsed. Any non-zero return value indicates that the
|
||||
* configuration file was successfully parsed.
|
||||
*/
|
||||
extern unsigned int
|
||||
ConfigParseResultOk(ConfigParseResult * result);
|
||||
ConfigParseResultOk(ConfigParseResult *);
|
||||
|
||||
/*
|
||||
* If, and only if, the configuration file parsing failed, then this
|
||||
* function can be used to get the line number it failed at. Typically,
|
||||
* this will be reported to the user and then the program will be
|
||||
* terminated.
|
||||
*
|
||||
* Params:
|
||||
*
|
||||
* (ConfigParseResult *) The output of ConfigParse() to get the
|
||||
* line number from.
|
||||
*
|
||||
* Return: The line number on which the configuration file parser
|
||||
* choked, or 0 if the parsing was actually successful.
|
||||
*/
|
||||
extern size_t
|
||||
ConfigParseResultLineNumber(ConfigParseResult * result);
|
||||
ConfigParseResultLineNumber(ConfigParseResult *);
|
||||
|
||||
/*
|
||||
* Convert a ConfigParseResult into a HashMap containing the entire
|
||||
* configuration file, if, and only if, the parsing was successful.
|
||||
*
|
||||
* Params:
|
||||
*
|
||||
* (ConfigParseResult *) The output of ConfigParse() to get the
|
||||
* actual configuration data from.
|
||||
*
|
||||
* Return: A HashMap containing all the configuration data, or NULL
|
||||
* if the parsing was not successful. This HashMap is a map of string
|
||||
* keys to ConfigDirective objects. Use the standard HashMap methods
|
||||
* to get ConfigDirectives, and then use the ConfigDirective functions
|
||||
* to get information out of them.
|
||||
*/
|
||||
extern HashMap *
|
||||
ConfigParseResultGet(ConfigParseResult * result);
|
||||
ConfigParseResultGet(ConfigParseResult *);
|
||||
|
||||
/*
|
||||
* Free the memory being used by the given ConfigParseResult. Note that
|
||||
* it is safe to free the ConfigParseResult immediately after you have
|
||||
* retrieved either the line number or the configuration data from it.
|
||||
* Freeing the parse result does not free the configuration data.
|
||||
*
|
||||
* Params:
|
||||
*
|
||||
* (ConfigParseResult *) The output of ConfigParse() to free. This
|
||||
* object will be invalidated, but pointers to
|
||||
* the actual configuration data will still be
|
||||
* valid.
|
||||
*/
|
||||
extern void
|
||||
ConfigParseResultFree(ConfigParseResult * result);
|
||||
ConfigParseResultFree(ConfigParseResult *);
|
||||
|
||||
/*
|
||||
* Get an array of values associated with the given configuration
|
||||
* directive. Directives can have any number of values, which are
|
||||
* made accessible via the Array API.
|
||||
*
|
||||
* Params:
|
||||
*
|
||||
* (ConfigDirective *) The configuration directive to get the values
|
||||
* for.
|
||||
*
|
||||
* Return: An array that contains at least 1 value. Configuration files
|
||||
* cannot have value-less directives. If the passed directive is NULL,
|
||||
* or there is an error allocating memory for an array, then NULL is
|
||||
* returned.
|
||||
*/
|
||||
extern Array *
|
||||
ConfigValuesGet(ConfigDirective * directive);
|
||||
ConfigValuesGet(ConfigDirective *);
|
||||
|
||||
/*
|
||||
* Get a map of children associated with the given configuration
|
||||
* directive. Configuration files can recurse with no practical limit,
|
||||
* so directives can have any number of child directives.
|
||||
*
|
||||
* Params:
|
||||
*
|
||||
* (ConfigDirective *) The configuratio ndirective to get the
|
||||
* children of.
|
||||
*
|
||||
* Return: A HashMap containing child directives, or NULL if the passed
|
||||
* directive is NULL or has no children.
|
||||
*/
|
||||
extern HashMap *
|
||||
ConfigChildrenGet(ConfigDirective * directive);
|
||||
ConfigChildrenGet(ConfigDirective *);
|
||||
|
||||
/*
|
||||
* Free all the memory associated with the given configuration hash
|
||||
* map. Note: this will free *everything*. All Arrays, HashMaps,
|
||||
* ConfigDirectives, and even strings will be invalidated. As such,
|
||||
* this should be done after you either copy the values you want, or
|
||||
* are done using them. It is highly recommended to use this function
|
||||
* near the end of your program's execution during cleanup, otherwise
|
||||
* copy any values you need into your own buffers.
|
||||
*
|
||||
* Note that this should only be run on the root configuration object,
|
||||
* not any children. Running on children will produce undefined
|
||||
* behavior. This function is recursive; it will get all the children
|
||||
* under it.
|
||||
*
|
||||
* Params:
|
||||
*
|
||||
* (HashMap *) The configuration data to free.
|
||||
*
|
||||
*/
|
||||
extern void
|
||||
ConfigFree(HashMap * conf);
|
||||
ConfigFree(HashMap *);
|
||||
|
||||
#endif /* TELODENDRIA_CONFIG_H */
|
||||
#endif
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* HashMap.h: The public interface for Telodendria's hash map
|
||||
* implementation. This hash map is designed to be simple, well
|
||||
|
@ -31,8 +32,6 @@
|
|||
* Fundamentally, this is an entirely generic map implementation. It
|
||||
* can be used for many general purposes, but it is designed to only
|
||||
* implement the features that Telodendria needs to function well.
|
||||
*
|
||||
* Copyright (C) 2022 Jordan Bancino <@jordan:bancino.net>
|
||||
*/
|
||||
#ifndef TELODENDRIA_HASHMAP_H
|
||||
#define TELODENDRIA_HASHMAP_H
|
||||
|
@ -48,61 +47,137 @@
|
|||
typedef struct HashMap HashMap;
|
||||
|
||||
/*
|
||||
* HashMapCreate: Create a new HashMap object.
|
||||
* Create a new HashMap object.
|
||||
*
|
||||
* Returns: A HashMap object that is ready to be used by the rest of
|
||||
* Return: A HashMap object that is ready to be used by the rest of
|
||||
* the HashMap functions, or NULL if memory could not be allocated on
|
||||
* the heap.
|
||||
*/
|
||||
extern HashMap *
|
||||
HashMapCreate(void);
|
||||
|
||||
/*
|
||||
* Set the maximum load of the hash map before it is expanded. When the
|
||||
* hash map reaches the given capacity, it is grown. You don't want
|
||||
* to only grow hash maps when their full, because that makes them
|
||||
* perform very poorly.
|
||||
*
|
||||
* The default max load on new HashMap objects is 0.75, which should be
|
||||
* good enough for most purposes, but if you need finer tuning, feel
|
||||
* free to play with the max load with this function. The changes take
|
||||
* effect on the next insert.
|
||||
*
|
||||
* Params:
|
||||
*
|
||||
* (HashMap *) The HashMap to modify the maximum load for.
|
||||
* (float) The new maximum load. This should be a value
|
||||
* between 0 and 1, which specifies the percentange
|
||||
* of "fullness" at which the HashMap will be
|
||||
* expanded. If the new max load is out of bounds,
|
||||
* this function does nothing.
|
||||
*/
|
||||
extern void
|
||||
HashMapMaxLoadSet(HashMap * map, float load);
|
||||
HashMapMaxLoadSet(HashMap *, float);
|
||||
|
||||
/*
|
||||
* HashMapSet: Set the given key in the HashMap to the given value. Note
|
||||
* that the value is not copied into the HashMap's own memory space;
|
||||
* only the pointer is stored. It is the caller's job to ensure that the
|
||||
* value's memory remains valid for the life of the HashMap.
|
||||
* Set the given key in the HashMap to the given value. Note that the
|
||||
* key nor the value is copied into the HashMap's own memory space;
|
||||
* only pointers is stored. It is the caller's job to ensure that the
|
||||
* key and value memory remains valid for the life of the HashMap, and
|
||||
* are freed when they're no longer needed.
|
||||
*
|
||||
* Returns: The previous value at the given key, or NULL if the key did
|
||||
* Params:
|
||||
*
|
||||
* (HashMap *) The hash map to set a key in.
|
||||
* (char *) The key to set.
|
||||
* (void *) The value to set at the given key.
|
||||
*
|
||||
* Return: The previous value at the given key, or NULL if the key did
|
||||
* not previously exist or any of the parameters provided are NULL. All
|
||||
* keys must have values; you can't set a key to NULL. To delete a key,
|
||||
* use HashMapDelete.
|
||||
* use HashMapDelete().
|
||||
*/
|
||||
extern void *
|
||||
HashMapSet(HashMap * map, char *key, void *value);
|
||||
HashMapSet(HashMap *, char *, void *);
|
||||
|
||||
/*
|
||||
* HashMapGet: Get the value for the given key.
|
||||
* Get the value for the given key.
|
||||
*
|
||||
* Returns: The value at the given key, or NULL if the key does not
|
||||
* Params:
|
||||
*
|
||||
* (HashMap *) The hash map to check.
|
||||
* (char *) The key to get the value for.
|
||||
*
|
||||
* Return: The value at the given key, or NULL if the key does not
|
||||
* exist, no map was provided, or no key was provided.
|
||||
*/
|
||||
extern void *
|
||||
HashMapGet(HashMap * map, const char *key);
|
||||
HashMapGet(HashMap *, const char *);
|
||||
|
||||
/*
|
||||
* HashMapDelete: Delete the value for the given key.
|
||||
* Delete the value for the given key.
|
||||
*
|
||||
* Returns: The value at the given key, or NULL if the key does not
|
||||
* Params:
|
||||
*
|
||||
* (HashMap *) The map to delete the given key from.
|
||||
* (const char *) The key to delete.
|
||||
*
|
||||
* Return: The value at the given key, or NULL if the key does not
|
||||
* exist or the map or key was not provided.
|
||||
*/
|
||||
extern void *
|
||||
HashMapDelete(HashMap * map, const char *key);
|
||||
|
||||
extern int
|
||||
HashMapIterate(HashMap * map, char **key, void **value);
|
||||
HashMapDelete(HashMap *, const char *);
|
||||
|
||||
/*
|
||||
* HashMapFree: Free the hash map, returning its memory to the operating
|
||||
* system. Note that this function does not free the values stored in
|
||||
* Iterate over all the keys and values of a hash map. This function
|
||||
* works similarly to the POSIX getopt(), where calls are repeatedly
|
||||
* made in a "while" loop until there are no more items to go over.
|
||||
*
|
||||
* The difference is that this function does not rely on globals. This
|
||||
* function takes pointer pointers, and stores necessary state inside
|
||||
* the hash map structure itself.
|
||||
*
|
||||
* This function can be tricky to use in some scenarios, as it
|
||||
* continues where it left off on each call, until there are no more
|
||||
* elements. Then it returns 0 and resets the iterator, so that it can
|
||||
* start over for the next iteration. This means that if you are not
|
||||
* iterating over the entire map at one, and break the loop, the next
|
||||
* time you try to iterate the HashMap, you'll start somewhere in the
|
||||
* middle. Thus, it's recommended to iterate over the entire map. For
|
||||
* scenarios in which the entire map needs to be iterated, such as
|
||||
* when freeing all the keys and values, this function does well.
|
||||
*
|
||||
* Params:
|
||||
*
|
||||
* (HashMap *) The hash map to iterate over.
|
||||
* (char **) A character pointer that will be set to the current
|
||||
* key.
|
||||
* (void **) A void pointer that will be set to the current value.
|
||||
*
|
||||
* Return: 1 if there are still elements left in this iteration of the
|
||||
* hash map, or 0 if no valid hash map was provided, or there are no
|
||||
* more elements in it for this iteration. Note that after this
|
||||
* function returns 0 on a hash map, subsequent iterations will start
|
||||
* from the beginning.
|
||||
*/
|
||||
extern int
|
||||
HashMapIterate(HashMap *, char **, void **);
|
||||
|
||||
/*
|
||||
* Free the hash map, returning its memory to the operating system.
|
||||
* Note that this function does not free the keys or values stored in
|
||||
* the map since this hash map implementation has no way of knowing
|
||||
* what actually is stored in it. You should use HashMapIterate to
|
||||
* what actually is stored in it. You should use HashMapIterate() to
|
||||
* free the values using your own algorithm.
|
||||
*
|
||||
* Params:
|
||||
*
|
||||
* (HashMap *) The hash map to free. The pointer can be safely
|
||||
* discarded when this function returns. In fact,
|
||||
* accessing it after this function returns is undefined
|
||||
* behavior.
|
||||
*/
|
||||
extern void
|
||||
HashMapFree(HashMap *);
|
||||
|
||||
#endif /* TELODENDRIA_HASHMAP_H */
|
||||
#endif
|
||||
|
|
|
@ -21,6 +21,30 @@
|
|||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Json.h: A fully-featured JSON API for C using Arrays and HashMaps.
|
||||
* This API builds on the foundations of Arrays and HashMaps, because
|
||||
* that's all a JSON object really is. It provides a JsonValue, which
|
||||
* is used to encapsulate arbitrary values while being able to identify
|
||||
* them in the future, so that JSON can be effectively handled.
|
||||
*
|
||||
* This implementation is just to get the job done in parsing and
|
||||
* generating JSON. It is extremely strict; it will fail on syntax
|
||||
* errors. This is fine for Matrix, because we can just return
|
||||
* M_BAD_JSON anything in here fails.
|
||||
*
|
||||
* One thing to note about this implementation is that it focuses
|
||||
* primarily on serialization and deserialization to and from streams.
|
||||
* What this means is that it does not provide facilities for handling
|
||||
* JSON strings; it only writes JSON to output streams, and reading
|
||||
* them from input streams. Of course, you could use the POSIX
|
||||
* fmemopen() and open_memstream() functions if you really want to deal
|
||||
* with JSON strings, but JSON is intended to be an exchange format.
|
||||
* Data should be converted to JSON when it is leaving, and converted
|
||||
* from JSON when it is coming in. Ideally, most of the program would
|
||||
* have no idea what JSON actually is.
|
||||
*/
|
||||
#ifndef TELODENDRIA_JSON_H
|
||||
#define TELODENDRIA_JSON_H
|
||||
|
||||
|
@ -30,27 +54,87 @@
|
|||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/*
|
||||
* All the possible JSON types. This enumeration is used to identify
|
||||
* the type of the value stored in a JsonValue.
|
||||
*/
|
||||
typedef enum JsonType
|
||||
{
|
||||
JSON_OBJECT,
|
||||
JSON_ARRAY,
|
||||
JSON_STRING,
|
||||
JSON_INTEGER,
|
||||
JSON_FLOAT,
|
||||
JSON_BOOLEAN,
|
||||
JSON_NULL
|
||||
JSON_NULL, /* Maps to nothing. */
|
||||
JSON_OBJECT, /* Maps to a HashMap of JsonValues */
|
||||
JSON_ARRAY, /* Maps to an Array of JsonValues */
|
||||
JSON_STRING, /* Maps to a C string */
|
||||
JSON_INTEGER, /* Maps to a C long */
|
||||
JSON_FLOAT, /* Maps to a C double */
|
||||
JSON_BOOLEAN /* Maps to a C 1 or 0 */
|
||||
} JsonType;
|
||||
|
||||
/*
|
||||
* A JsonValue encapsulates all the possible values that can be stored
|
||||
* in a JSON object as a single type, so as to provide a consistent
|
||||
* API for accessing and setting them. It is an opaque structure that
|
||||
* can be managed entirely by the functions defined in this API.
|
||||
*
|
||||
* Note that in the case of objects, arrays, and strings, this structure
|
||||
* only stores pointers to allocated data, it doesn't store the data
|
||||
* itself. JsonValues only store integers, floats, booleans, and NULL
|
||||
* in their memory. Anything else must be freed separately.
|
||||
*/
|
||||
typedef struct JsonValue JsonValue;
|
||||
|
||||
/*
|
||||
* Get the type of a JsonValue.
|
||||
*
|
||||
* Params:
|
||||
*
|
||||
* (JsonValue *) The value to get the type of.
|
||||
*
|
||||
* Return: A JsonType that tells what the provided value is, or
|
||||
* JSON_NULL if the passed value is NULL. Note that even a fully
|
||||
* valid JsonValue may still be of type JSON_NULL, so this function
|
||||
* should not be used to check whether or not the JSON value is valid.
|
||||
*/
|
||||
extern JsonType
|
||||
JsonValueType(JsonValue * value);
|
||||
JsonValueType(JsonValue *);
|
||||
|
||||
/*
|
||||
* Wrap a HashMap into a JsonValue that represents a JSON object. Note
|
||||
* that the HashMap should contain only JsonValues. Any other contents
|
||||
* are not supported and will lead to undefined behavior.
|
||||
*
|
||||
* Params:
|
||||
*
|
||||
* (HashMap *) The hash map of JsonValues to wrap in a JsonValue.
|
||||
*
|
||||
* Return: A JsonValue that holds a pointer to the given object, or
|
||||
* NULL if there was an error allocating memory.
|
||||
*/
|
||||
extern JsonValue *
|
||||
JsonValueObject(HashMap * object);
|
||||
JsonValueObject(HashMap *);
|
||||
|
||||
/*
|
||||
* Get a HashMap from a JsonValue that represents a JSON object.
|
||||
*
|
||||
* Params:
|
||||
*
|
||||
* (JsonValue *) The value to extract the object from.
|
||||
*
|
||||
* Return: A HashMap of JsonValues, or NULL if no value was provided,
|
||||
* or the value is not of type JSON_OBJECT.
|
||||
*/
|
||||
extern HashMap *
|
||||
JsonValueAsObject(JsonValue * value);
|
||||
JsonValueAsObject(JsonValue *);
|
||||
|
||||
/*
|
||||
* The following methods very closely resemble the ones above, and
|
||||
* behave pretty much the exact same. To save on time and effort,
|
||||
* I'm choosing not to explicitly document all of these. If something
|
||||
* is unclear about how these functions work, consult the source code,
|
||||
* and then feel free to write the documentation yourself.
|
||||
*
|
||||
* Otherwise, reach out to the official Matrix room, and someone will
|
||||
* be able to help you.
|
||||
*/
|
||||
|
||||
extern JsonValue *
|
||||
JsonValueArray(Array * array);
|
||||
|
@ -70,25 +154,118 @@ extern JsonValue *
|
|||
extern JsonValue *
|
||||
JsonValueBoolean(int boolean);
|
||||
|
||||
/*
|
||||
* Create a JsonValue that represents a JSON null. Because Arrays and
|
||||
* HashMaps should not contain NULL values, I thought it appropriate
|
||||
* to provide support for JSON nulls. Yes, a small amount of memory is
|
||||
* allocated just to point to a NULL, but this keeps all the APIs
|
||||
* clean.
|
||||
*
|
||||
* Return: A JsonValue that represents a JSON null, or NULL if memory
|
||||
* could not be allocated.
|
||||
*/
|
||||
extern JsonValue *
|
||||
JsonValueNull(void);
|
||||
|
||||
/*
|
||||
* Free the memory being used by a JSON value. Note that this will
|
||||
* recursively free all Arrays, HashMaps, and other JsonValues that
|
||||
* are reachable from this one. It will invoke free() on strings as
|
||||
* well, so make sure passed string pointers point to strings on the
|
||||
* heap, not the stack. This will be the case for all strings returned
|
||||
* by JsonDecode(), which is why this assumption is made. However, if
|
||||
* you are manually creating JsonObjects and stitching them together,
|
||||
* you'll have to manually free them as well. Calling this on a
|
||||
* JsonValue that contains a pointer to a stack string is undefined.
|
||||
*
|
||||
* Params:
|
||||
*
|
||||
* (JsonValue *) The JsonValue to recursively free.
|
||||
*/
|
||||
extern void
|
||||
JsonValueFree(JsonValue * value);
|
||||
JsonValueFree(JsonValue *);
|
||||
|
||||
/*
|
||||
* Recursively free a HashMap of JsonValues. This iterates over all
|
||||
* the JsonValues in a HashMap and frees them using JsonValueFree(),
|
||||
* which will in turn call JsonFree() on values of type JSON_OBJECT.
|
||||
*
|
||||
* Params:
|
||||
*
|
||||
* (HashMap *) The hash map of JsonValues to recursively free.
|
||||
*/
|
||||
extern void
|
||||
JsonFree(HashMap * object);
|
||||
JsonFree(HashMap *);
|
||||
|
||||
/*
|
||||
* Encode the given string in such a way that it can be embedded in a
|
||||
* JSON stream. This entails:
|
||||
*
|
||||
* - Escaping quotes, backslashes, and other special characters using
|
||||
* their backslash escape
|
||||
* - Encoding bytes that are not UTF-8 using \u escapes.
|
||||
* - Wrapping the entire string in double quotes.
|
||||
*
|
||||
* This function is provided via the public API so it is accessible to
|
||||
* custom JSON encoders, such as the CanonicalJson API. This will
|
||||
* typically be used for encoding JSON keys; for values, just use
|
||||
* JsonEncodeValue().
|
||||
*
|
||||
* Params:
|
||||
*
|
||||
* (const char *) The C string to serialize as a JSON string.
|
||||
* (FILE *) The output stream to write the encoded string to.
|
||||
*/
|
||||
extern void
|
||||
JsonEncodeString(const char *str, FILE * out);
|
||||
JsonEncodeString(const char *, FILE *);
|
||||
|
||||
/*
|
||||
* Serialize a JsonValue as it would appear in JSON output. This is
|
||||
* a recursive function that will also encode all child values
|
||||
* reachable from the given JsonValue.
|
||||
*
|
||||
* This is exposed via the public API so that custom JSON encoders
|
||||
* such as CanonicalJson can take advantage of it. Normal users that
|
||||
* are writing custom encoders should just use JsonEncode() to encode
|
||||
* an entire object.
|
||||
*
|
||||
* Params:
|
||||
*
|
||||
* (JsonValue *) The value to encode.
|
||||
* (FILE *) The output stream to write the given value to.
|
||||
*/
|
||||
extern void
|
||||
JsonEncodeValue(JsonValue * value, FILE * out);
|
||||
|
||||
/*
|
||||
* Encode a HashMap of JsonValues into a fully-valid, minimized JSON
|
||||
* object. This function is recursive; it will serialize everything
|
||||
* accessible from the passed object into JSON.
|
||||
*
|
||||
* Params:
|
||||
*
|
||||
* (HashMap *) The HashMap of JsonValues to encode and write to the
|
||||
* output stream.
|
||||
* (FILE *) The output stream to write the given HashMap to.
|
||||
*
|
||||
* Return: Whether or not the operation was successful. This function
|
||||
* will fail if either the passed HashMap or file stream are NULL. In
|
||||
* all other cases, this function succeeds.
|
||||
*/
|
||||
extern int
|
||||
JsonEncode(HashMap * object, FILE * out);
|
||||
JsonEncode(HashMap *, FILE *);
|
||||
|
||||
/*
|
||||
* Decode the given input stream into a HashMap of JsonValues.
|
||||
*
|
||||
* Params:
|
||||
*
|
||||
* (FILE *) The input stream to parse JSON from.
|
||||
*
|
||||
* Return: A HashMap of JsonValues, or NULL if there was an error
|
||||
* parsing the JSON.
|
||||
*/
|
||||
extern HashMap *
|
||||
JsonDecode(FILE * in);
|
||||
JsonDecode(FILE *);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -21,12 +21,35 @@
|
|||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Log.h: A heavily-modified version of Shlog, a simple C logging
|
||||
* facility that allows for colorful output, timestamps, and custom
|
||||
* log levels. This library differs from Shlog in that the naming
|
||||
* conventions have been updated to be consistent with Telodendria.
|
||||
*
|
||||
* Shlog was originally a learning project. It worked well, however,
|
||||
* and produced elegant logging output, so it was chosen to be the
|
||||
* main logging mechanism of Telodendria. The original Shlog project
|
||||
* is now dead; Shlog lives on now only as Telodendria's logging
|
||||
* mechanism.
|
||||
*
|
||||
* In the name of simplicity and portability, I opted to use an
|
||||
* in-house logging system instead of syslog(), or other system logging
|
||||
* mechanisms. However, this API could easily be patched to allow
|
||||
* logging via other mechanisms that support the same features.
|
||||
*/
|
||||
#ifndef TELODENDRIA_LOG_H
|
||||
#define TELODENDRIA_LOG_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/*
|
||||
* There are five log "levels," each one showing more information than
|
||||
* the previous one. A level of LOG_ERROR shows only errors, while a
|
||||
* level of LOG_DEBUG shows all output possible.
|
||||
*/
|
||||
typedef enum LogLevel
|
||||
{
|
||||
LOG_ERROR,
|
||||
|
@ -36,11 +59,20 @@ typedef enum LogLevel
|
|||
LOG_DEBUG
|
||||
} LogLevel;
|
||||
|
||||
/*
|
||||
* The possible flags that can be applied to alter the behavior of
|
||||
* the logger
|
||||
*/
|
||||
typedef enum LogFlag
|
||||
{
|
||||
LOG_FLAG_COLOR = (1 << 0)
|
||||
LOG_FLAG_COLOR = (1 << 0) /* Enable color output on TTYs */
|
||||
} LogFlag;
|
||||
|
||||
/*
|
||||
* The log configurations structure in which all settings exist.
|
||||
* It's not super elegant to pass around a pointer to the logging
|
||||
* configuration
|
||||
*/
|
||||
typedef struct LogConfig LogConfig;
|
||||
|
||||
extern LogConfig *
|
||||
|
|
Loading…
Reference in a new issue