💾 Archived View for gmi.noulin.net › sheepy › libsheepyUserGuide.md captured on 2024-08-25 at 10:07:07.

View Raw

More Information

⬅️ Previous capture (2023-07-10)

-=-=-=-=-=-=-

# Libsheepy User Guide

Libsheepy is a generic C library handling text files, strings, json and more.

For an introduction, see [libsheepy](https://spartatek.se/r/libsheepy/file/README.md.html).

Libsheepy has a build tool called [sheepy](https://spartatek.se/r/sheepy/file/README.md.html) which runs C programs like scripts

__This document__ shows how to use libsheepy for a user perspective. There is a detailed documentation at [https://spartatek.se/libsheepy/](https://spartatek.se/libsheepy/) where each function has a description.

# Sheepy setup

## Install

git clone https://spartatek.se/git/sheepy.git

cd sheepy

sudo -H ./install.sh


## First Sheepy Program

Create program with `sheepy` and run:

sheepy -n example

run:

./example.c


# Overview

Libsheepy has a few concepts and conventions described in the [libsheepy overview](https://spartatek.se/libsheepy/LSH_OVERVIEW_PAGE.html) page in the doxygen documentation:

- top-level includes
- function categories
- naming conventions
- memory management
- classes and objects

It is also helpful to look at the [examples](https://spartatek.se/r/libsheepy/files.html).

`libsheepy.h` is the API operating on basic data types.

The [doxygen documentation](https://spartatek.se/libsheepy/LSH_OVERVIEW_PAGE.html) is more detailed than this userguide and the source code is available to browse.

# Defines

| Name | Description |
| --- | --- |
| `LIBSHEEPY_VERSION` | current libsheepy version, `libsheepy` can be updated independently of `sheepy` |
| `internal` or `local` | alias for `static` |
| `var` | let the compiler choose the variable type: `var c = TRUE;` |
| `boolS(boolVar)` | convert bool value to `const char*` |
| `XSUCCESS`, `XFAILURE` and `exitFailure(data)` | exit the program |
| `init0Var` | initialize array or struct to zero |
| `typ` | typedef |
| `ret` | return |
| `elif` | else if |
| `cast(type, casted, toCast)` | define variable and cast pointer |
| `EVA(var, func)` | Evaluate, assign result from func and return result using the comma operator |
| `charToS(dst, c)` | convert char to string by declaring string dst with c in it |
| `put` | print an empty line |
| `toUpper(c)` | upper case and store the result in c and return the result |
| `toLower(c)` | lower case and store the result in c and return the result |
| `orS(string, alternative)` | return string if non empty, alternative string when string is empty |
| `orBlankS(string, alternative)` | return string if non blank, alternative string when string is blank (empty or only white spaces)|
| `nS(string)` | null String - replace null string with "" string (empty string) |
| `and` | `&&` (iso646.h) |
| `or` | `||` (iso646.h) |
| `not` | `!` (iso646.h) |
| `UNIQVAR(name)` | create a unique variable name by appending the line number (for declaring variables in macros) |
| `_` | "\"" |
|`UNUSED`| set gcc attribute unused on a variable or function parameter |
|`DEPRECATED`| set gcc attribute deprecated on a symbol |

Example code:

local bool abool = false; // static bool

puts(boolS(abool)); // convert bool value to string

put // new line

typ struct { u32 a; char *s;} datat; // typedef

datat data = init0Var;

if (not abool or !data.s) {

data.s = strdup("string");

toUpper(data.s[0]);

ret;

}

elif (data.s and eqG(data.s, "Quit")) { // else if

XSUCCESS; // exit(0);

}

void func(int a UNUSED, int b UNUSED) {

ret;

}


- For further information, read [libsheepy.h](https://spartatek.se/libsheepy/libsheepy_8h.html)

# Integer And Float Types

| Libsheepy type | Standard C type |
| --- | --- |
| `i8` |  int8_t |
| `i16` | int16_t |
| `i32` | int32_t |
| `i64` | int64_t |
| `u8` |  uint8_t |
| `u16` | uint16_t |
| `u32` | uint32_t |
| `u64` | uint64_t |
| `f32` | float |
| `f64` | double |

- For further information, read [libsheepy.h](https://spartatek.se/libsheepy/libsheepy_8h.html)

# Macros

| Name | Description |
| --- | --- |
| `MAX(a, b)` | return max value (a and b are evaluted multiple times) |
| `MIN(a, b)` | return min value (a and b are evaluted multiple times) |
| `MAX3(a, b, c)` | return max value (a, b and c are evaluted multiple times) |
| `MIN3(a, b, c)` | return min value (a, b and c are evaluted multiple times) |
| `ABS(a)` | return absolute value |
| `CLAMP(x, low, high)` | return x when low <= x <= high, return low when x < low and return high when x > high (x, high and low are evaluted multiple times) |
| `COUNT_ELEMENTS(arr)` or `ARRAY_SIZE(arr)`| return element count in a static array: `char *arr[100]; logVarG(COUNT_ELEMENTS(arr));` |
| `EXTRACT(x, msb, lsb)` | extract a bit field (the bit field starts at bit 0) |
| `CMP(a, b)` | compare a to b, return 0 when a equals b, -1 when a is less than b, 1 when a is more than b |
| `BUCKETS(count, divider)` | divide count by divider and add one when remainder is not zero. this is used in segmented arrays to count the number of buckets from the element count |
| `swapV(a, b)` | swap a and b, a and b should have the same type |
| `setMax(result, a, b)` | max a,b and store result in result, a and b are evaluated only once |
| `setMin(result, a, b)` | min a,b and store result in result, a and b are evaluated only once |
| `maxV(a, b)` | max a,b and return result, a and b are evaluated only once |
| `minV(a, b)` | min a,b and return result, a and b are evaluated only once |
| `absV(a)` | absV return absolute value for a, a is evaluated only once |
| `FIELD_SIZEOF(t, f)` | get the size of a struct's field |
| `freen(ptr)` | free pointer and set it to NULL |
| `QSORT(N, LESS, SWAP)` | traditional Quicksort implementation |
| `BSEARCH(RESULT_INDEX, SEARCH_ELEMENT, B_N, B_LESS, B_EQUAL)` | binary search |
| `emptyS(string)` | assign empty string to string pointer  |
| `bEmptyS(string)` | string buffer empty - set 0 at index 0 |
| `listEmptyS(list)` | assign empty list (char * *) to list pointer |
| `newPtr(name, type)` | create name variable and allocate it on heap |
| `new0Ptr(name, type)` | create name variable and calloc it on heap |
| `allocAPtr(name)` | allocate struct on heap and assign address |
| `callocAPtr(name)` | calloc struct on heap and assign address |
| `newArray(name, type, count)` | create name variable and allocate array of type on heap |
| `new0Array(name, type, count)` | reate name variable and calloc array of type on heap |
| `allocArray(name, count)` | allocate array |
| `allocAArray(name, count)` | allocate and assign array |
| `callocArray(name, count)` | calloc array |
| `callocAArray(name, count)` | calloc and assign array |
| `reallocArray(name, count)` | realloc array |
| `toUnsignedType(var)` | convert a variable number type to unsigned type, to declare a new variable or cast a value |

- For further information, read [libsheepy.h](https://spartatek.se/libsheepy/libsheepy_8h.html)

# Error Reporting

The error reporting macros print an error message and the backtrace (glibc only).

| Name | Description |
| --- | --- |
| `pFuncError` | print function name and system error (errno string) |
| `pStrError(str)` | print string and system error |
| `shPrintError` | print error with line number, function name and file name to stderr |
| `shEPrintfS(const char *fmt, ...)` | printf to stderr |
| `pError(func)` | print error when function failed. The error code must be -1 |
| `pError0(func)` | print error when function failed. The error code must be 0 |
| `pErrorNot0(func)` | print error when function failed. The error code must be not 0 |
| `pErrorNULL(func)` | print error when function failed. The error code must be NULL |
| `pErrorValue(func, errorValue)` | print error when function failed. The error code must be -1 |
| `pTestError(test)` | print error when test is true |
| `pTestErrorCmd(test, cmd)` | print error and run command when test is true |
| `pErrorCmd(func, test, cmd)` | print error and run cmd when test is true |
| `pErrorResult(result, func, test)` | print error when test is true and return func result in result |
| `pErrorResultCmd(result, func, test, cmd)` | print error and run cmd when test is true and return func result in result |
| `logE(fmt, ...)` | log error |

- For further information, read [libsheepy.h](https://spartatek.se/libsheepy/libsheepy_8h.html)

# Logging

- For further information, read [libsheepy.h](https://spartatek.se/libsheepy/libsheepy_8h.html)

## Variables

There are a few macros logging variable name and their values, mainly for debugging:

int a = 1;

Log:

a=1


| Name | Description |
| --- | --- |
| `logVarG(var)` | generic for logging any basic type and libsheepy objects |
| `logVar(var, format)` | log variable and its value. `format` is the variable type: %d, %c... |
| `logMVar(mask, var, format)` | log variable and its value. `format` is the variable type: %d, %c... this log is maskable, see Mask section below for more information about masks |
| `logBoolVar(var)` | log bool variable by printing the value as TRUE or FALSE |
| `logMBoolVar(mask, var)` | maskable log bool |
| `logPtr(pointer)` | log pointer value |
| `logMPtr(mask, pointer)` | maskable log pointer |


## Configuration

The logs are printed to the stdout by default, use `setLogFile(char *filename)` to set a log file or multiple log files (max 15). When initLibsheepy is called, the log files are closed at program exit, use `closeLogFiles(void)` to explicitly close the log files.

The log mode configuration controls which information (date, function, program,...) is printed in the log, there are 8 modes:

| Name | Description |
| --- | --- |
| `LOG_VERBOSE` | log symbol, filename, function, line, date `[CRITICAL] _pLogT() (libsheepyTest.c:173) at Wed Apr 24 03:58:45 2019` |
| `LOG_CONCISE` | log symbol `[!] pLog test` |
| `LOG_DATE` | log symbol and date `[!] 19-04-24 03:58:45 pLog test` |
| `LOG_FUNC` | log symbol and function `[!] _pLogT 195: pLog test` |
| `LOG_PROG` | log symbol and program name `[!] progname: pLog test` |
| `LOG_PROGNDATE` | log symbol, program name and date `[!] progname 19-04-24 03:58:45: pLog test` |
| `LOG_VOID` | log message only `pLog test` |
| `LOG_UTF8` | UTF8 symbols and concise `[x]pLog test` |

Use `setLogMode(int mode)` to configure a log mode and `getLogMode(void)` to get current log mode.

The log symbols indicate the log level and are printed at the beginning of the first line. The log symbols can be set independently of the log mode, use `getLogSymbols(void)` to get current log mode for symbols and `setLogSymbols(int mode)` to set log symbols, choose LOG_VERBOSE for words, LOG_UTF8 for emojis, LOG_VOID for no symbols, LOG_INVALID_MODE (reset log symbols) for default log mode symbols, anything else (LOG_CONCISE,...) for symbols (!*+->~).

The short path configuration (`setLogShortPath(bool shortPath)` and `getLogShortPath(void)`) controls the length of the filename in the LOG_VERBOSE mode.

The max log level configuration (`setMaxLogLevel(int logLevel)` and `getMaxLogLevel(void)`) allows skipping the higher log level or completely disable all logs at runtime.

To disable logs at compile time anywhere in the code (local to the source file), undefine the `pLog` macro:

/* enable/disable logging */

undef pLog

define pLog(...)


To disable the logs at runtime, run:

setMaxLogLevel(LOG_DISABLE);


The libsheepy functions print log messages when errors are encountered, these logs are disabled with the `disableLibsheepyErrorLogs` macro:

// Mask libsheepy error logs

disableLibsheepyErrorLogs;


| Name | Description |
| --- | --- |
| `setLogFile(char *filename)` | add a log file, maximum 15 files |
| `closeLogFiles(void)` | close logfiles opened with setLogFile (not needed when initLibsheepy is called) |
| `setLogMode(int mode)` | set log mode LOG_VERBOSE, LOG_CONCISE, ... |
| `getLogMode(void)` | get current log mode (LOG_VERBOSE, LOG_CONCISE, ...) |
| `setLogSymbols(int mode)` | set log symbols, LOG_VERBOSE for words, LOG_UTF8 for emojis, LOG_VOID for no symbols, LOG_INVALID_MODE (reset log symbols) for default log mode symbols, anything else (LOG_CONCISE,...) for symbols (!*+->~) |
| `getLogSymbols(void)` | current log symbols |
| `setLogShortPath(bool shortPath)` | set log long/short file path value for VERBOSE mode |
| `getLogShortPath(void)` | get current log long/short path value, default is TRUE (short paths) |
| `setMaxLogLevel(int logLevel)` | set max log level, logs above logMaxLevel are skipped |
| `getMaxLogLevel(void)` | current max log level |
| `disableLibsheepyErrorLogs;` | disable log prints from libsheepy |
| `btraceEnable(void)` | enable backtrace in error messages  |
| `btraceDisable(void)` | disable backtrace in error messages |
| `btraceConfig(void)` | get current backtrace configuration |

## Functions

There are 5 log levels: critical, error, warning, pass and info. The functions for the log level end with the first letter of the log level: `logC` for critical, `logI` for info...

| Name | Description |
| --- | --- |
| `logI(fmt,...)` | info level |
| `logP(fmt,...)` | pass level |
| `logW(fmt,...)` | warning level |
| `logE(fmt,...)` | error level |
| `logC(fmt,...)` | critical level |
| `AT;`| log line number, function name and filename |
| `logSI(fmt,string)` | info level, log string and free: logSI("The list: %s", catS("1", "2")); |
| `logSP(fmt,string)` | pass level, log string and free |
| `logSW(fmt,string)` | warning level, log string and free |
| `logSE(fmt,string)` | error level, log string and free |
| `logSC(fmt,string)` | critical level, log string and free |
| `logSystem(cmd)` or `logExec(cmd)` | log cmd and run |
| `char** logSystemOut(cmd)` or `char** logExecOut(cmd)` | log cmd, run and return stdout lines |
| `logSystemf(fmt, ...)` or `logExecf(fmt, ...)` | build command with format fmt, log commad and run |
| `logSystemOutf(fmt, ...)` or `logExecOutf(fmt, ...)` | build command with format fmt, log commad, run and return stdout lines |
| `logBtrace;` | log backtrace |
| `logG(self)` | log array or dictionary, one line per element |
| `loghex(const void *buf, size_t len)` | print buffer as hexadecimal string |

## Mask

The logM macros are maskable at runtime. The mask configuration is stored in the `logMask` variable and libsheepy uses bit 63 (`libsheepyErrorMask`) in logMask.

`showLogsInMask(mask)` and `hideLogsInMask(mask)` shows or hides logs in a mask.

To disable the logM macros at compile time, undefine pLogMask:

undef pLogMask

define pLogMask(...)


For example:

define group1 0x03

define group11 0x01

define group12 0x02

define group2 0x04

showLogsInMask(group11);

logMI(group1, "is shown when logMask has bit 0 or 1 set");

logMI(group11, "is shown when logMask has bit 0 set");

logMI(group12, "is shown when logMask has bit 1 set");

logMI(group2, "is shown when logMask has bit 2 set");


| Name | Description |
| --- | --- |
| `logMI(mask, ...)` | info level mask |
| `logMP(mask, ...)` | pass level mask |
| `logMW(mask, ...)` | warning level mask |
| `logME(mask, ...)` | error level mask |
| `logMC(mask, ...)` | critical level mask |
| `logSMI(mask, ...)` | info level mask, log string and free: logSMI(0x1, "The list: %s", catS("1", "2")); |
| `logSMP(mask, ...)` | pass level mask, log string and free |
| `logSMW(mask, ...)` | warning level mask, log string and free  |
| `logSME(mask, ...)` | error level mask, log string and free |
| `logSMC(mask, ...)` | critical level mask, log string and free |
| `showLogsInMask(mask)` | set bits in logMask |
| `hideLogsInMask(mask)` | unset bits in logMask |

# Loops

Libsheepy has a loop breaker system that breaks possible infinite loops. `loopBreakerInit` initializes the loop breaker before the loop, `loopBreakerReset` resets the loop breaker for the next loop and `loopBreaker(breakCount)` breaks the loop after `breakCount` loops.

Usage:

loopBreakerInit;

forever {

loopBreaker(20);

}

if (didBreak) logE("infinite loop detected");

loopBreakerReset;

forever {

loopBreaker(100);

}

if (didBreak) logE("infinite loop detected");


| Loop Name | Description |
| --- | --- |
|`forever`| forever loop |
|`range(index, maxCount)`| range loop |
|`rangeInf(index)`| increase the index infinitly |
|`rangeDown(index, maxCount)`| range down loop, index is ssize_t |
|`rangeDownTo(index, maxCount, to)`| range down loop to to index, index is ssize_t |
|`rangeFrom(index, from, maxCount)`| range loop starting at value from |
|`arange(index, array)`| loop on the elements of C static array of any type. Example: `u32 array[20]; arange(i, array) {}` |
|`arangeDown(index, array)`| loop on the elements of C static array of any type from highest index down to 0 |
|`arangeDownTo(index, array, to)`| loop on the elements of C static array of any type from highest index down to index 'to' |
|`arangeFrom(index, from, array)`| loop on the elements of C static array of any type starting at index 'from' |
|`circular(index, from, maxCount)`| range from value from to maxCount-1 then from 0 to from-1 |
|`circularDown(index, from, maxCount)`| range from value from down to 0 then from maxCount-1 to from+1 |
|`rangeStep(index, maxCount, step)`| range step loop |
|`rangeDownStep(index, maxCount, step)`| range down setp loop, index is int64_t |
|`rangeFromStep(index, from, maxCount, step)`| range step loop starting at value from |
|`loop(maxCount)`| loops without index |
|`loopDownTo(maxCount, to)`| loop to to index |
|`loopFrom(from, maxCount)`| loop starting at value from |
|`loopStep(maxCount, step)`| step loop |
|`loopFromStep(from, maxCount, step)`| step loop starting at value from |
|`forEachCharP(list, element)`| forEach - loop macro on `char**` list. To access the element in the loop, use `*element` |
|`forEachS(list, element)`| forEach - loop macro on `char**` list. To access the element in the loop, use `element` |
|`forEachType(type, list, element)`| forEach - loop macro on `type**` list. To access the element in the loop, use `*element` |
|`enumerateCharP(list, element, index)`| enumerate `char**` list. To access the element in the loop, use `*element` |
|`enumerateS(list, element, index)`| enumerate `char**` list. To access the element in the loop, use element |
|`enumerateType(type, list, element, index)`| enumerate `type**` list. To access the element in the loop, use `*element` |
|`lForEach(node, startNode)`| loop for linked lists from startNode to last |
|`lForEachDown(node, startNode)` or `lForEachPrev(node, startNode)` | loop for linked lists from startNode to head |
|`loopBreakerInit;`|  declare and reset loop breaker variables |
|`loopBreakerReset;`| reset loop breaker  |
|`loopBreaker(breakCount)`| break loop after count, the didBreak variable is set to true |

There are also iterators for the libsheepy objects implementing the iterator interface. The libsheepy classes with iterator interfaces are: `smallArrayt`, `smallDictt` and `smallJsont`

For example:

var array = createSA("1", "2", "3");

iter(array, elem) {

logVarG(elem);

}


| Iterator Name | Description |
| --- | --- |
|`iter(obj, element)`| Loop on obj elements |
|`iterLast(obj, element)`| Loop from last element to first element |
|`iterFrom(obj, index, element)`| Loop on obj elements starting at index |
|`iterFromStep(obj, index, step, element)`| Loop on obj elements starting at index incrementing index by step |
|`iterType(type, obj, element)`| Loop on obj elements and cast element to type |
|`iterTypeLast(type, obj, element)`| Loop from last element to first element and cast element to type |
|`iterTypeFrom(type, obj, index, element)`| Loop on obj elements starting at index and cast element to type |
|`iterTypeFromStep(type, obj, index, step, element)`| Loop on obj elements starting at index incrementing index by step and cast element to type |
|`iterK(obj, key)`| Loop on obj elements and set element `key` (use getG to get the element) |
|`iterIndexG(self)`| Current index |
|`iterKeyG(self)`| Current key |

- For further information, read [libsheepy.h](https://spartatek.se/libsheepy/libsheepy_8h.html)

# Printf

## Specifiers

The specifiers are available when libsheepy is compiled against glibc.

| Name | Description |
| --- | --- |
|`%k`| foreground hex color. Example: `printf("%k%KRGB color" RST, 0x99EEFF, 0x666666);` |
|`%K`| background hex color |
|`%b`| print bool as FALSE/TRUE |
|`%m`| print baset objects |

## Terminal Colors And Effects

The terminal colors can be added in any string that will be printed in a terminal. The string part with the effect starts with the chosen effect, for example `BLD` and ends with `RST` to cancel the effect. Terminal colors and effects are allowed to be combined: `BLD RED "bold red" RST`.

For example:

char *s = "This " BLD"color"RST " is " RED"red"RST ".";

- This and is have normal color

- color is bold

- red is red



| Name | Description |
| --- | --- |
| `RST` | reset |
| `BLD` | bold |
| `FNT` | faint |
| `UDL` | underline |
| `INV` | inverse |
| `COC` | conceal/hidden |
| `CRD` | crossed |
| `BLK` | foreground black |
| `RED` | foreground red |
| `GRN` | foreground green |
| `YLW` | foreground yellow |
| `BLU` | foreground blue |
| `MGT` | foreground magenta |
| `CYN` | foreground cyan |
| `WHT` | foreground white |
| `BGBLK` | background black |
| `BGRED` | background red |
| `BGGRN` | background green |
| `BGYLW` | background yellow |
| `BGBLU` | background blue |
| `BGMGT` | background magenta |
| `BGCYN` | background cyan |
| `BGWHT` | background white |

Use `stripCtrlS` to remove terminal colors from a string.

When libsheepy is linked to glibc, it is possible to print RGB colors with `%k` and `%K`, the colors are coded as hexadecimal RGB:

logI("%k%KRGB color" RST, 0x99EEFF, 0x666666);


- For further information, read [libsheepy.h](https://spartatek.se/libsheepy/libsheepy_8h.html)

# Stopwatch And Timer

| Name | Description |
| --- | --- |
| `timeNs(func)` | print how long time (in nanoseconds) was spent in `func` |
| `timeUs(func)` | time a function in microseconds |
| `timeMs(func)` | time a function in miliseconds |
| `timeSec(func)` | time a function in seconds |
| `stopwatchStart` | start the stopwatch |
| `stopwatchLog` | print stopwatch value in ns since last start (in nanoseconds) |
| `stopwatchLogUs` | print stopwatch value in microseconds since last start |
| `stopwatchLogMs` | print stopwatch value in milliseconds since last start |
| `stopwatchLogSec` | print stopwatch value in seconds since last start |

For example:

stopwatchStart;

... code ...

stopwatchLogUs; // log time spent in code section


- For further information, read [libsheepy.h](https://spartatek.se/libsheepy/libsheepy_8h.html) and [libsheepy.c](https://spartatek.se/libsheepy/libsheepy_8c.html)

# Naming conventions

| Name | Description |
| --- | --- |
|ending with `O`| macro calling an object method |
|ending with `G`| generic for libsheepy objects |
|ending with `S`| function operating on `char*` |
|ending with `UTF8`| UTF8 function operating on `char*` |
|starting with `b` | function operating on `char*` returning the result in the first parameter: the caller allocates the buffer |
|starting with `bL` | function operating on `char*` returning the result in the first parameter: the caller allocates the buffer and gives the buffer size |
|starting with `ic` | ignore case function |
|starting with `i` | in place function that reallocates `char*` buffers |
|starting with `list` and ending with `S`| function operating on `char**` |
|starting with `list` | function operating on `void**` |

# Libsheepy Classes

All classes in libsheepy inherit from the `baset` class, the baset methods are: `free`, `terminate`, `toString`, `duplicate`.

All classes have a set of functions for creating and destroying objects:

- `create*`, `createAllocate*` declare and allocate objects. `create*` declare local objects that need to be freed (with `freeG`) but cannot be terminated. `createAllocate*` declare a pointer and allocate the object, the object has to be terminated (or smashed, `terminateG` or `smashG`)
- `initiate*`, `initiateAllocate*` allocate already declared objects
- `alloc*` allocate objects and return them, an initial value is sometime required.

These function names end with either: `SmallArray`, `SmallBool`, `SmallBytes`, `SmallContainer`, `SmallDict`, `SmallDouble`, `SmallInt`, `SmallJson`, `SmallString`, `Undefined`

For example: `createSmallJson(jsonObject)` declares a local json object. `freeG(jsonObject)` frees the internal buffers.

The class name are: `smallArrayt`, `smallBoolt`, `smallBytest`, `smallContainert`, `smallDictt`, `smallDoublet`, `smallIntt`, `smallJsont`, `smallStringt`, `undefinedt`

Objects of type:
- `smallArrayt` hold objects of type `smallArrayt`, `smallBoolt`, `smallBytest`, `smallContainert`, `smallDictt`, `smallDoublet`, `smallIntt`, `smallStringt`, `undefinedt`
- `smallBoolt` hold a bool value
- `smallBytest` hold a void buffer of bytes
- `smallContainert` hold a void pointer
- `smallDictt` are dictionaries of key-values with key as strings (char*) and with values of type `smallArrayt`, `smallBoolt`, `smallBytest`, `smallContainert`, `smallDictt`, `smallDoublet`, `smallIntt`, `smallStringt`, `undefinedt`
- `smallDoublet` hold a double
- `smallIntt` hold an int64_t
- `smallJsont` hold either a `smallArrayt`, a `smallBoolt`, a `smallDictt`, a `smallDoublet`, a `smallIntt`, a `smallStringt` or an `undefinedt`
- `smallStringt` hold a string (char*)
- `undefinedt` don't hold any data and are represented as `null`

Use `sheepy -C classname` to generate your own baset class from templates.

# Generics

The macros `create*` and `createAllocate*` declare and initialize new object:

createAllocteSmallArray(array);

createSmallDict(dict);


Objects can be declared like other variables and then initialized with `initiateG` or `allocG`

smallArrayt *array;

smallDict dict;

smallStringt *string;

initiateG(&array);

initiateG(&dict);

string = allocG("new string");


The regular generic call format is:

methodG(object, other parameters...);

result = method2G(object, other parameters...);



To get the value in smallBool, smallDouble, smallInt, smallString use `getValG(self)`.

To get a value in smallArrayt, smallDictt or smallJsont use `getG(self, returnType, key)`.

To set a value in smallBool, smallDouble, smallInt, smallString use `setFromG(self, value)`.

To set a value in smallArrayt, smallDictt or smallJsont use `setG(self, returnType, key)`.

`getG` and `setG` support smallBool, smallDouble, smallInt, smallString types by setting `returnType` to `unusedV`.

The generics support these types where it makes sense:

- int, uint
- double
- `char*`
- `char**`
- smallArrayt
- smallBoolt
- smallBytest
- smallContainert
- smallDictt
- smallDoublet
- smallIntt
- smallJsont
- smallStringt
- undefinedt

For type `char*` and `char**`, the functions in lisheepy.h are called.

The generics returning a value have a `returnType` parameter, the possible values for `returnType` are:

- rtBaset
- rtBool
- rtBoolP
- rtDouble
- rtDoubleP
- rtInt64_t
- rtInt64_tP
- rtInt32_t
- rtInt32_tP
- rtUint64_t
- rtUint64_tP
- rtUint32_t
- rtUint32_tP
- rtF32
- rtF64
- rtF64P
- rtI64
- rtI64P
- rtI32
- rtI32P
- rtU64
- rtU64P
- rtU32
- rtU32P
- rtU8
- rtU16
- rtChar for `char*`
- rtSmallArrayt
- rtSmallBoolt
- rtSmallBytest
- rtSmallDictt
- rtSmallDoublet
- rtSmallIntt
- rtSmallJsont
- rtSmallStringt
- rtSmallContainert
- undefined or rtUndefinedt
- rtVoid

For example `getG(dict, rtBool, "a")` returns a bool and with `rtBoolP` it returns a pointer to a bool.

| Name | Description |
| --- | --- |
|`initiateG(self)` | give the address of the object to initialize (`smallArrayt` or `smallArrayt*`) |
|`allocG(value)` | allocate a smallObject corresponding to value type and assign value to the object |
|`freeG(self)` | free smallObject, `char**` and any pointer type |
|`freeManyG(paramType, ...)` | free baset objects |
|`terminateG(obj)` | free baset container and internal buffers, for objects allocated on the head only |
|`terminateManyG` | free containers and internal buffers |
|`isOTypeG(obj, className)` | test obj type |
|`isOSmallArray(obj)` | test if obj type is smallArray  |
|`isOSmallBool(obj)` | test if obj type is smallBool |
|`isOSmallBytes(obj)` | test if obj type is smallBytes |
|`isOSmallContainer(obj)` | test if obj type is smallContainer |
|`isOSmallDict(obj)` | test if obj type is smallDictt |
|`isOSmallDouble(obj)` | test if obj type is smallDouble |
|`isOSmallInt(obj)` | test if obj type is smallInt |
|`isOSmallJson(obj)` | test if obj type is smallJson |
|`isOSmallString(obj)` | test if obj type is smallString |
|`isOUndefined(obj)` | test if obj type is undefined |
|`getOType(obj)` | return obj type in a string |
|`duplicateG(obj)` | create a copy of obj |
|`smashG(obj)` | free object and keep data |
|`smashManyO(paramType, ...)` | smash many baset objects |
|`finishG(obj)` | free container only |
|`finishManyG(paramType, ...)` | finish many baset objects |
|`getValG` | get the value in smallBool, smallDouble, smallInt, smallString |
|`getPG(self)` | get pointer to value in smallBool, smallDouble, smallInt |
|`setFromG(self, value)` | set value in smallBool, smallDouble, smallInt, smallString |
|`setTopG(self, value)` | set top value in smallJson or set value in smallBool, smallDouble, smallInt, smallString |
|`setTopNFreeG(self, value)` | set top value in smallJson and free container |
|`getTopG(self, returnType)` | get top object in smallJson |
|`pushG(self, value)` | add value at the end of the object, char literals are accepted. When self is `char*` or `char**` give `&self` in first parameter because self might be reallocated |
|`pushNFreeG(self, value)` | push and free container. When self is `char*` or `char**` give `&self` in first parameter because self might be reallocated |
|`setG(self, key, value)` | set value at key |
|`setNFreeG(self, key, value)` | set value at key and free container |
|`setPG(self, key, value)` | set smallObject pointer at key (more info about **memory management** on [libsheepy overview](https://spartatek.se/libsheepy/LSH_OVERVIEW_PAGE.html)) |
|`setNFreePG(self, key, value)` | set smallObject pointer at key and free container |
|`getG(self, returnType, key)` | get value of type returnType at key |
|`getNDupG(self, returnType, key)` | get and duplicate value of type returnType at key |
|`getNumG(self, key)` | get a double value |
|`appendG(self, obj)` | append an object of type self. When self is `char*` or `char**` give `&self` in first parameter because self might be reallocated |
|`appendNSmashG(self, obj)` | append object and free array/dict keeping the elements. When self is `char*` or `char**` give `&self` in first parameter because self might be reallocated |
|`prependG(self, value)` | prepend an object of type self. When self is `char*` or `char**` give `&self` in first parameter because self might be reallocated |
|`prependNFreeG(self, obj)` | prepend an object of type self and free array keeping the elements. When self is `char*` or `char**` give `&self` in first parameter because self might be reallocated |
|`delG(self, start, end)` | delete elements between `start` and `end`. When self is a smallArray, the remaining elements keep their indexes, the deleted elements are set to NULL, use compactG to remove these NULL elements |
|`delElemG(self, index)` | delete the element at `index`. When self is a smallArray, the remaining elements keep their indexes, the deleted element is set to NULL, use compactG to remove the NULL element |
|`popG(self, returnType)` | return and remove last element |
|`dequeueG(self, returnType)` | return and remove first element |
|`getRealProgPathG(returnType)` | get program path |
|`systemG(cmd)` | run cmd |
|`systemNFreeG(cmd)` | run and free cmd  |
|`getModificationTimeG(path)` | get modification time for path |
|`setModificationTimeG(path, mtime)` | set modification time for path |
|`equalModificationTimesG(path1, path2)` | return true when path1 and path2 have equal modification times |
|`timeToSG(returnType, t)` | convect `time_t` to string |
|`shDirnameG(path)` | dirname |
|`expandHomeG(path)` | expand home ~/ |
|`normalizePathG(path)` | normalize path |
|`getCwdG(returnType)` | get current working directory |
|`chDirG(path)` | change directory |
|`isDirG(path)` | true when path is directory |
|`isLinkG(path)` | true when path is symbolic link |
|`fileExistsG(path)` | file and dir exists |
|`fileChmodG(path, mode)` | chmod "721": `fileChmodG(path, 0721 /*octal*/);` |
|`fileSizeG(path)` | file size |
|`readFileG(self, path)` | read file, when self is smallJson, json and yml files are parsed. . For `char*` or `char**`, `self` specifies the return type: `char *content = NULL; content = readFileG(content, "filename");` |
|`readTextG(self, path)` | read text file, each line is an array element |
|`writeFileG(self, path)` | write file, when self is smallJson, json and yml files are generated |
|`writeTextG(self, path)` | write text file |
|`zipG(self, keys, values)` | merge key,value pairs to self. keys and values are arrays |
|`walkDirG(returnType, path)` | walkDir lists files only |
|`walkDirDirG(returnType, path)` | walkDirDir lists directories |
|`readDirG(returnType, path)` | readDir lists files in a directory |
|`readDirDirG(returnType, path)` | readDirDir lists directories in a directory |
|`walkDirAllG(returnType, path)` | walkDirAll lists files and directories |
|`readDirAllG(returnType, path)` | readDirAll lists files and directories in a directory |
|`mkdirParentsG(path)` | recursive mkdir |
|`rmAllG(path)` | delete files and directories |
|`copyG(path1, path2)` | copy files recursively |
|`randomSG(returnType, length)` | generate random string |
|`randomAlphaNumSG(returnType, length)` | generate random alpha numerical string |
|`readG(returnType)` | read user input (one line) as a string |
|`readLineG(returnType, fp)` | read line in a text file |
|`dupG(self)` | duplicate object or `char*` string |
|`replaceG(self, olds, news, max)` | replace |
|`icReplaceG(self, olds, news, max)` | ignore case replace |
|`eqG(self, obj)` | equality (all libsheepy types) |
|`icEqG(self, obj)` | ignore case equality (all libsheepy types) |
|`eqIG(self, obj, index)` | equality at `index` |
|`startsWithG(self, obj)` | look for obj at self start |
|`endsWithG(self, obj)` | look for obj at self end |
|`countG(self, obj)` | count number of (non-overlapping) occurrences of obj |
|`icStartsWithG(self, obj)` | ignore case startsWith |
|`icEndsWithG(self, obj)` | ignore case endsWith |
|`icCountG(self, obj)` | ignore case count |
|`isNumberG(self)` | true when string is a number (integer or float) |
|`isIntG(self)` | true when string is an integer |
|`parseIntG(self)` | convert string to int |
|`intToG(self, n)` | convert int to string |
|`parseDoubleG(self)` | convert string to double |
|`doubleToG(self, n)` | convert double to string |
|`lenG(self)` | length |
|`upperG(self)` | uppercase |
|`lowerG(self)` | lowercase |
|`trimG(self)` | remove space at right and left |
|`lTrimG(self)` | left trim |
|`rTrimG(self)` | right trim |
|`uniqG(self, c)` | remove successive repetitions of char c |
|`icUniqG(self, c)` | ignore case uniq |
|`sliceG(self, start, end)` | slice string |
|`copyRngG(self, start, end)` | copy range from start to end and duplicate elements |
|`insertG(self, index, toInsert)` | insert object of type self at index |
|`insertNSmashG(self, index, toInsert)` | insert object of type self at index and free array keeping the elements |
|`injectG(self, index, value)` | insert an element at index |
|`injectNFreeG(self, index, value)` | insert an element at index and free container |
|`findG(self, needle)` | find |
|`hasG(self, needle)` | true when self has needle |
|`indexOfG(self, needle)` | index of needle |
|`keyByG(self, needle)` | key for needle |
|`icFindG(self, needle)` | ignore case find |
|`icHasG(self, needle)` | ignore case has |
|`icIndexOfG(self, needle)` | ignore case indexOf |
|`icKeyByG(self, needle)` | ignore case keyBy |
|`emptyG(self)` | empty self |
|`isEmptyG(self)` | true when self is empty |
|`isBlankG(self)` | true when self has only white spaces or is empty |
|`fromArrayG(self, array, size)` | set strings from array of size `size` |
|`splitG(self, delim)` | split |
|`icSplitG(self, delim)` | ignore case split |
|`joinG(self, delim)` | join |
|`joinSG(self, delim)` | join and return value of type `char*` |
|`extractG(self, delim1, delim2)` | extract string between delim1 and delim2 |
|`icExtractG(self, delim1, delim2)` | ignore case extract |
|`reverseG(self)` | reverse |
|`addG(self, list)` | append |
|`sortG(self)` | sort |
|`binarySearchG(self, string)` | binary search |
|`icSortG(self)` | ignore case sort |
|`icBinarySearchG(self, string)` | ignore case binary search |
|`compactG(self)` | remove blank elements |
|`parseG(self, input)` | parse json string, smallJson only |
|`parseYMLG(self, input)` | parse yml string, smallJson only |
|`execG(cmd, out, err)` | run cmd and return stdout lines in out |
|`renameG(src, dst)` | rename |
|`moveG(src, dst)` | move files recursively |
|`logG(self)` | print self, one line per element |
|`catG(self, ...)` |  append smallObjects |
|`catSG(self, ...)` | append `char*` strings |
|`pushManyG(self, ...)` | push objects |
|`pushManySG(self, ...)` | push `char*` strings |
|`pushNFreeManyG(self, ...)` | push and free containers |
|`pushNFreeManySG(self, ...)` | push and free `char*` strings |
|`pushBufferG(self, data, size)` | smallBytes pushBuffer |
|`disposeG(self)` | free sObject index but not elements, self becomes empty |
|`helpG(self)` | print class help |
|`resetG(self)` | remove reference to internal sObject, set NULL and free the iterator. This function is useful for object not allocated on the heap to free the iterator element when the object is not used anymore |
|`getsoG(self)` | get the sobject, data in the container |
|`setsoG(self, so)` | set the sobject, data in the container, the iterator is reset |
|`mirrorG(self)` | allocate a new container for the sobject, the iterator state is copied. After this function is executed, there are 2 containers for one sobject, only one container should be freed or terminated, the other one should be finished |
|`fromArrayNFreeG(self, array, size)` | fromArray and free array |
|`ssGet(obj)` | get `char*` from object (must be smallStringt) |
|`sjGet(obj)` | get `char*` from object (must be smallJsont) |
|`replaceManyG(self, olds, ...)` | replace many |
|`icReplaceManyG(self, olds, ...)` | ignore case replace many |
|`toStringG(obj)` | convert data in obj to string |
|`putsG(obj)` | print obj |

- For further information, read:
  - [libsheepyObject.h](https://spartatek.se/libsheepy/libsheepyObject_8h.html) lists all the generics
  - the class header files (libsheepyC*.h) have detailed method descriptions for each class:
    - [libsheepyCSmallArray.h](https://spartatek.se/libsheepy/libsheepyCSmallArray_8h.html)
    - [libsheepyCSmallBool.h](https://spartatek.se/libsheepy/libsheepyCSmallBool_8h.html)
    - [libsheepyCSmallBytes.h](https://spartatek.se/libsheepy/libsheepyCSmallBytes_8h.html)
    - [libsheepyCSmallContainer.h](https://spartatek.se/libsheepy/libsheepyCSmallContainer_8h.html)
    - [libsheepyCSmallDict.h](https://spartatek.se/libsheepy/libsheepyCSmallDict_8h.html)
    - [libsheepyCSmallDouble.h](https://spartatek.se/libsheepy/libsheepyCSmallDouble_8h.html)
    - [libsheepyCSmallInt.h](https://spartatek.se/libsheepy/libsheepyCSmallInt_8h.html)
    - [libsheepyCSmallJson.h](https://spartatek.se/libsheepy/libsheepyCSmallJson_8h.html)
    - [libsheepyCSmallString.h](https://spartatek.se/libsheepy/libsheepyCSmallString_8h.html)
    - [libsheepyCUndefined.h](https://spartatek.se/libsheepy/libsheepyCUndefined_8h.html)

# System Functions

| Name | Description |
| --- | --- |
|`initLibsheepy(progPath)`| initialize segfault handler, prog path, thread pool, register printf specifiers |
|`int64_t getStackLimit(void);` | get current stack limit - returns 0 when error |
|`int setStackLimit(int64_t stackSize);` | set stack limit (-1 for unlimited) - returns 0 when error |
|`smallDictt *shSysinfo(void);`| Sheepy sysinfo. The keys are: uptime, loads, totalram, freeram, sharedram, bufferram, totalswap, freeswap, procs |
|`const char *getProgName(void);` | get program name |
|`bool setProgName(const char *name);` | set program name |
|`void setDefaultProgName(void);` | set default program name |
|`const char *getProgPath(void);` or `smallStringt *getRealProgPathO(void);` | get program path as given in the shell |
|`const char *getRealProgPath(void);` or `smallStringt *getRealProgPathO(void);` | get real program path, allocates path string internally |
|`void freeRealProgPath(void);` | free real program path |
|`int systemO(smallStringt *command);`| run system command in a smallString |
|`systemNFree(char *command)` or`systemNFreeO(smallStringt *command)` | run system command and free command buffer |
|`int execO(const char *cmd, smallArrayt *out, smallArrayt *err);` or `int execSmallStringO(smallStringt *cmd, smallArrayt *out, smallArrayt *err);`| execute command and return stdout from cmd in *out |
|`char **execOut(const char *cmd);` or `char **systemOut(const char *cmd);` | run command and return stdout |
|`char **execOutf(const char *fmt, ...);` or `char **systemOutf(const char *fmt, ...);` | system command with formatting and return stdout |
|`int execf(const char *fmt, ...);` or `int systemf(const char *fmt, ...);` | system command with formatting |
|`time_t getCurrentUnixTime(void);` | get current unix time |
|`time_t strToUnixTime(const char *date, const char *format);` | convert date string to unix time |
|`char *timeToS(const time_t t);` or `smallStringt *timeToSO(const time_t t);`| convert unix time to string |
|`char *timeToYMDS(const time_t t);` | convert unix time to Y-m-d H:M:S string |
|`char *getCurrentDate(void);` | get current date in ctime format |
|`char *getCurrentDateYMD(void);` | get current date in Y-m-d H:M:S format |
|`int randomUrandomOpen(void);` | open /dev/urandom in libsheepy |
|`uint64_t randomWord(void);` | return random 64 bit unsigned integer |
|`uint64_t randomWordFromHW(void);` | return random 64 bit unsigned integer from the cpu |
|`uint64_t randomChoice(uint64_t range);` | return a random value between 0 and range `0<=value<range` |
|`char *randomS(uint64_t length);` | generate random string |
|`char *randomAlphaNumS(uint64_t length);` | generate random alpha numerical string |
|`char *readS(void);` | read user input (one line) as a string |
|`char *readPasswordS(void);` | read hidden password as a string - like getpass |
|`bool zeroS(char *string);` | write zero to all bytes in string with memset, for clearing password buffers |
|`bool zeroBuf(void *buf, size_t len);` | write zero to all bytes in buffer with memset |
|`void *memdup(const void *buf, size_t size);` | allocate and copy buffer |
|`void readEnter(void);` | wait until press the enter key |
|`uint64_t getMonotonicTime(void);`| get monotonic time in ns |
|`nanoSleep(time)`| sleep nanoseconds |
|`nanoSleepE(time, cmd)`| nanoSleep and run `cmd` when there is an error |
|`usSleep(time)`| sleep microseconds |
|`msSleep(time)`| sleep miliseconds |

- For further information, read [libsheepy.h](https://spartatek.se/libsheepy/libsheepy_8h.html) and [libsheepy.c](https://spartatek.se/libsheepy/libsheepy_8c.html)

# File Functions

| Name | Description |
| --- | --- |
|`time_t getModificationTime(const char *path);` | get modification time for path |
|`int setModificationTime(const char *path, time_t mtime);` | set modification time for path |
|`bool isReadable(const char *path);` | true when path is readable |
|`bool isWritable(const char *path);` | true when path is writable |
|`bool isExecutable(const char *path);` | true when path is executable |
|`bool equalModificationTimes(const char *path1, const char *path2);` | compare modification times for path1 and path2 |
|`char *shDirname(const char *path);` | dirname |
|`char *expandHome(const char *path);` | expand home ~/ |
|`char *normalizePath(const char *path);` | normalize path |
|`char *relPath(const char *path, const char *start);` | relative path |
|`char *getHomePath(void);` | get home path |
|`char *getCwd(void);` | get current working directory |
|`int chDir(const char *path);` | change directory |
|`bool isDir(const char *path);` | true when path is directory |
|`char *shReadlink(const char *path);` | read link to a new string |
|`char *endlink(const char *path);` | read link chain to the end to a new string |
|`bool isLink(const char *path);` | true when path is symbolic link |
|`bool fileExists(const char *filePath);` or `bool isPath(const char *filePath);` | file and dir exists |
|`bool fileChmod(const char *filePath, mode_t mode);` | chmod "721": `fileChmod(path, 0721 /*octal*/);` |
|`ssize_t fileSize(const char *filePath);` or `ssize_t fileSizeFP(FILE *fp);` | file size |
|`void *readFileToS(const char *filePath);` | read file |
|`int writeFileS(const char *filePath, const char *string);` | write file |
|`bool appendFileS(const char *filePath, const char *string);` | append string to file |
|`char **walkDir(const char* dirPath);` | walkDir lists files only |
|`char **walkDirDir(const char* dirPath);` | walkDirDir lists directories |
|`char **readDir(const char *dirPath);` | readDir lists files in a directory |
|`char **readDirDir(const char *dirPath);` | readDirDir lists directories in a directory |
|`char **walkDirAll(const char* dirPath);` | walkDirAll lists files and directories |
|`char **readDirAll(const char *dirPath);` | readDirAll lists files and directories in a directory |
|`mode_t getumask(void);` | get umask |
|`mode_t getCurrentPermissions(void);` | get current permissions for creating directories |
|`int mkdirParents(const char* path);` | recursive mkdir |
|`int rmAll(const char* path);` | delete files and directories |
|`int copy(const char* src, const char* dst);` | copy files recursively |
|`int shRename(const char* src, const char* dst);` | rename file |
|`int shMove(const char* src, const char* dst);` | move files recursively |
|`char *readLine(FILE *fp);` | readLine |

- For further information, read [libsheepy.h](https://spartatek.se/libsheepy/libsheepy_8h.html) and [libsheepy.c](https://spartatek.se/libsheepy/libsheepy_8c.html)

# String Functions

| Name | Description |
| --- | --- |
|`void *readFileToS(const char *filePath);` | read file |
|`ssize_t readFile(const char *filePath, void **buffer);` | read file |
|`void *readStreamToS(FILE *fp);` | read file |
|`int writeFileS(const char *filePath, const char *string);` | write file |
|`int writeFile(const char *filePath, void *buffer, size_t len);` | write file |
|`int writeStreamS(FILE *fp, const char *string);` | write file |
|`int writeLStream(FILE *fp, void *buffer, size_t len);` | write file |
|`bool appendFileS(const char *filePath, const char *string);` | append string to file |
|`char *randomS(uint64_t length);` | generate random string |
|`char *randomAlphaNumS(uint64_t length);` | generate random alpha numerical string |
|`char *readS(void);` | read user input (one line) as a string |
|`char *readPasswordS(void);` | read hidden password as a string - like getpass |
|`bool zeroS(char *string);` | write zero to all bytes in string with memset, for clearing password buffers |
|`freeManyS(...)` | free many char* |
|`char *dupS(const char *string);` | duplicate string |
|`void shPrintfS(const char *fmt, ...);` | print like printf, the formating can be NULL |
|`void shEPrintfS(const char *fmt, ...);` | stderr printf, the formating can be NULL |
|`void logNFree(char *s);` | print and free s |
|`void loghex(const void *buf, size_t len);` | print buf as hexadecimal |
|`char *toHexS(const void *buf, size_t len);` | create a string with bytes in buf converted to hex strings: 0xff, |
|`char *toHexSepS(const void *buf, size_t len, const char *separator);` | create a string with bytes in buf converted to hex strings separated by separator: 0xffSEP |
|`char *toHexHeadSepS(const void *buf, size_t len, const char *head, const char *separator);` | create a string with bytes in buf converted to hex strings separated by separator and with head string in front of earch byte: HEADffSEP |
|`put;` | print new line |
|`char *strCpy(char *dst, const char *src);` | copy src to dst |
|`char *strNCpy(char *dst, const char *src, size_t srcSize);` | copy string to buffer given string length: strNCpy(buffer, string, lenS(string)); |
|`char *strLCpy(char *dst, size_t dstSize, const char *src);` | copy string |
|`char *strCat(char *dst, const char *src);` | concatenate src to dst |
|`char *strNCat(char *dst, const char *src, size_t srcLen);` | concatenate src to dst |
|`char *strLCat(char *dst, size_t dstSize, const char *src);` | concatenate src to dst |
|`char *strLNCat(char *dst, size_t dstSize, const char *src, size_t srcLen);` | concatenate src to dst |
|`catS(...)` | cat: catS("qwd ", str," werr ", str2) |
|`iCatS(dst, ...)` | cat and copy result to dst buffer |
|`char *formatS(const char *fmt, ...);` | allocate and format string using asprintf |
|`char *appendS(const char *string1, const char *string2);` | append strings |
|`char *prependS(const char *string1, const char *string2);` | prepend string |
|`char *replaceS(const char *s, const char *olds, const char *news, size_t max);` | string replace |
|`replaceManyS(s, ...)` | string replace many olds with news (s, olds1, news1, olds2, news2,...) |
|`char *icReplaceS(const char *s, const char *olds, const char *news, size_t max);` | ignore case string replace |
|`bool eqS(const char *string1, const char *string2);` | string equal (compare content) |
|`bool eqIS(const char *string1, const char *string2, intmax_t index);` | string equal at index (compare content) |
|`bool startsWithS(const char *string1, const char *string2);` | look for string2 at string1 start |
|`bool endsWithS(const char *string1, const char *string2);` | look for string2 at string1 end |
|`ssize_t countS(const char *s, const char *needle);` | count number of (non-overlapping) occurrences of a substring |
|`bool icEqS(const char *string1, const char *string2);` | ignore case string equal (compare content) |
|`bool icEqIS(const char *string1, const char *string2, intmax_t index);` | ignore case string equal at index (compare content) |
|`bool icStartsWithS(const char *string1, const char *string2);` | ignore case and look for string2 at string1 start |
|`bool icEndsWithS(const char *string1, const char *string2);` | ignore case look for string2 at string1 end |
|`ssize_t icCountS(const char *s, const char *needle);` | ignore case and count number of (non-overlapping) occurrences of a substring |
|`bool hasCtrlChar(const char *string);` | has terminal control char (for example colors) |
|`char *stripCtrlS(const char *string);` | remove terminal control char from string |
|`bool isNumber(const char *string);` | true when string is a number (integer or float) |
|`bool isInt(const char *string);` | true when string is an integer |
|`intmax_t parseInt(const char *string);` | parseInt |
|`double parseDouble(const char *string);` | parseDouble |
|`uint64_t parseHex(const char *string);` | parse hexadecimal string: 0xff |
|`char *intToS(intmax_t n);` | convert int to string |
|`char *doubleToS(double n);` | convert double to string |
|`size_t lenS(const char *string);` | length |
|`char *upperS(const char *string);` | duplicate and upper case |
|`char *lowerS(const char *string);` | duplicate and lower case |
|`char *trimS(const char *string);` | duplicate and trim |
|`char *lTrimS(const char *string);` | left trim |
|`char *rTrimS(const char *string);` | right trim |
|`char *uniqS(const char *string, char c);` | remove successive repetitions of char c |
|`uniqSlash(s)` | remove successive repetitions of / |
|`char *icUniqS(const char *string, char c);` | ignore case and remove successive repetitions of char c |
|`char *repeatS(const char *string, size_t count);` | repeat string count times |
|`ssize_t repeatLenS(const char *string, size_t count);` | length of string repeated count times |
|`char *ellipsisStartS(const char *string, size_t targetLength, const char *ellipsisString);` | ellipsisStart string |
|`ssize_t ellipsisLenS(const char *string, size_t targetLength, const char *ellipsisString);` | length of string after ellipsis |
|`char *ellipsisEndS(const char *string, size_t targetLength, const char *ellipsisString);` | ellipsisEnd string |
|`char *padStartS(const char *string, size_t targetLength, const char *padString);` | padStart string |
|`ssize_t padStartLenS(const char *string, size_t targetLength, const char *padString);` | length of string after padStart |
|`char *padEndS(const char *string, size_t targetLength, const char *padString);` | padEnd string |
|`ssize_t padEndLenS(const char *string, size_t targetLength, const char *padString);` | length of string after padEnd |
|`char getS(const char *string, intmax_t index);` | get char at python index |
|`char *setS(char *string, intmax_t index, char c);` | set char at python index |
|`char *swapS(char *string, intmax_t index1, intmax_t index2);` | swap characters in a string |
|`char *sliceS(const char *string, intmax_t start, intmax_t end);` | slice string, function to slice parts of a string [1:10] - python style indexes 0..len-1 -1..-len+1 |
|`char *insertS(const char *string, intmax_t index, const char *toInsert);` | insert string in string |
|`char *injectS(const char *string, intmax_t index, char toInject);` | inject a char in string |
|`char *delS(const char *string, intmax_t start, intmax_t end);` | del string, function to delete parts of a string [1:10] - python style indexes 0..len-1 -1..-len+1 |
|`char *delElemS(const char *string, intmax_t index);` | del a character in string |
|`char *findS(const char *string, const char *needle);` | find substring |
|`ssize_t indexOfS(const char *string, const char *needle);` | index of substring |
|`bool hasS(const char *string, const char *needle);` | true when needle is found |
|`char *icFindS(const char *string, const char *needle);` | ignore case find substring |
|`ssize_t icIndexOfS(const char *string, const char *needle);` | ignore case index of substring |
|`bool icHasS(const char *string, const char *needle);` | ignore case, true when needle is found |
|`char *tokS(const char *s, const char *delim, char **saveptr);` | parse s string with delim - works like strtok_r from stdlib |
|`char *icTokS(const char *s, const char *delim, char **saveptr);` | ignore case and parse s string with delim - work like strtok_r from stdlib |
|`emptyS(string)` | create empty string |
|`bool isEmptyS(const char *string);` | is empty string |
|`orS(string, alternative)` | orS - if string is empty, the value is alternative |
|`bool isBlankS(const char *string);` | true when string is empty or white spaces |
|`orBlankS(string, alternative)` | if string is blank(white spaces) or empty, the value is alternative |
|`nS(string)` | nS - null String - replace null string with "" string (empty string) |
|`ssize_t intIndex(intmax_t index, intmax_t length);` | convert python index (int, positive and negative) to always positive index (uint), this function is more generic than listIntIndexS |

- For further information, read [libsheepy.h](https://spartatek.se/libsheepy/libsheepy_8h.html) and [libsheepy.c](https://spartatek.se/libsheepy/libsheepy_8c.html)

# UTF8

| Name | Description |
| --- | --- |
|`typedef int rune;` | rune is a 32 bit unicode integer |
|`size_t lenUTF8(const char *s);` | character length of UTF-8 encoded string |
|`bool isUTF8(const char * string);` | is string valid UTF-8 encoded string |
|`bool isCodeUTF8(const char *code);` | is string a valid UTF-8 code point |
|`codeSizeUTF8(utf8)` | size in bytes of UTF-8 code point |
|`nextCodeUTF8(utf8)` | move pointer to next UTF-8 code point, no checks are done, the utf8 pointer parameter is unchanged |
|`nxtCodeUTF8(utf8)` | change the utf8 pointer parameter to next UTF-8 code point, like char *s; s++; |
|`char *nextUTF8(const char *utf8);` | next code point, works only when utf8 points to a valid code point |
|`char *findNextUTF8(const char *string, size_t utf8Size, const char *utf8);` | find next code point even when utf8 points inside a code point |
|`char *prevUTF8(const char *utf8);` | previous code point, undefined behavior when utf8 points to the start of the string |
|`char *bPrevUTF8(const char *string, const char *utf8);` | previous code point |
|`char *idx2PtrUTF8(const char *utf8, intmax_t index);` | character index to pointer |
|`intmax_t ptr2IdxUTF8(const char *utf8, const char *pos);` | pointer to character index |
|`char *makeValidUTF8(const char *utf8);` | make new valid UTF-8 encoded string |

- For further information, read [libsheepy.h](https://spartatek.se/libsheepy/libsheepy_8h.html) and [libsheepy.c](https://spartatek.se/libsheepy/libsheepy_8c.html)

# Arrays, Vector, Slice, Indexer, Slab, Bitsets

`slice`, `staticSlice`, `vector`, `dVector`, `staticArray`, `dArray`, `slab`, `staticBitset`, `bitset` are data structures defined in `libsheepy.h`.

They are arrays of user defined element type with counters and the other properties not available with C arrays.

The elements are accessed directly like regular C arrays with the `At` macros: `vectorAt(&vectr, 1) = 3;`.

| Name | Description |
| --- | --- |
|`slice`| dynamic array in one chunk of memory with element count (similar to vector and slab), the array is realloced when adding elements |
|`staticSlice`| C array with variable element count |
|`vector`| dynamic array in one chunk of memory with element count and maximum element count (similar to slab below) |
|`dVector`| dynamic segmented vector, the elements are stored in segments, adding elements adds new mallocated segments |
|`staticArray`| this type of array has a static maximum element count (fixed), head and last indexes, this allows dequeuing from head elements fast. It is used as a circular buffer, queue, fifo... |
|`dArray`| dynamic segmented array with maximum element count, head and last indexes, adding elements adds new mallocated segments |
|`slab`| dynamic array in one chunk of memory with maximum element count, head and last indexes |
|`staticBitset`| static bitset holding a fixed bit count |
|`bitset`| bitset macros for creating dynamic bitsets using slice |

The `indexer` allows seperating the data from the maximum count, head and last indexes. The `indexer` macros operate on a struct holding count, head and last indexes.

`slice`, `staticSlice`, `vector`, `dVector`, `staticArray`, `dArray`, `slab` are prefixes for the macros operating on the data structures. The macros define the types and handle the elements.

| Name | Description |
| --- | --- |
|`*T`| declare type, for example `sliceT(mysliceType, char*);` |
|`create*(typeName, name)` | declare variable name and call `*Init` |
|`create*Count(typeName, name, count)` | declare variable name and initialize count |
|`create*ClearCount(typeName, name, count)` | declare variable name, calloc array and initialize count |
|`createAllocate*(typeName, name)` | declare variable name pointer and initialize |
|`createAllocate*Count(typeName, name, count)` | declare variable name pointer and initialize count |
|`createAllocate*ClearCount(typeName, name, count)` | declare variable name pointer, calloc array and initialize count |
|`*Terminate(name)` | free elements and name pointer |
|`*Init(name)`| initialize array |
|`*InitCount(name, countInt)`| initialize array and count |
|`*Calloc(name, countInt)`| initialize array and count and set elements to 0 |
|`*Resize(name, countInt)`| resize array |
|`*ClearResize(name, countInt)`| resize array and clear new elements with memset  |
|`*Free(name)`| free internal buffers |
|`*ElemType(name)`| element type |
|`*ElemPtrType(name)`| element type pointer |
|`*Dup(name)`| duplicate |
|`*CreateNDup(name, dest)`| declare variable dest and duplicate name |
|`*BDup(name, dest)`| duplicate to already declared dest of type name |
|`*Data(name)`| direct access to underlying array |
|`*From(name, array, countInt)`| copy data from array |
|`*Mirror(name, start, end)`| mirror a range and return struct, the data is not copied to dest, to copy data see `*Copy` or `*BCopy` |
|`*BMirror(name, dest, start, end)`| mirror a range o already declared dest of type name, the data is not copied to dest, to copy data see `*Copy` or `*BCopy` |
|`*MirrorFrom(name, array, countInt)`| mirror from array, the data is not copied to dest |
|`*Clear(name)`| set 0 in elements |
|`*ClearRange(name, start, end)`| set 0 in a range of elements |
|`*Empty(name)`| set count to 0 |
|`*IsEmpty(name)`| true when array is empty |
|`*Fit(name)`| reallac to fit element count |
|`*Count(name)`| return element count |
|`*MaxCount(name)`| return max count |
|`*ElemSize(name)`| element size |
|`*Alloc(name)`|  allocate an element, only when the array is full |
|`*ClearElem(name, index)`| clear (set 0) in element at index |
|`*Push(name)`| push element and expand the array, no data is set in the new element |
|`*Append(name, v)`| append element and expand the array |
|`*ClearPush(name)`|  push element and expand the array, the new element is cleared |
|`*Pop(name)`| pop element, return last element and decrease the element count |
|`*DelLast(name)`| delete the last element |
|`*Set(name, index, v)`| set value at index and clearResize array when index is outside array count |
|`*At(name, index)`| get / set element at index (direct access to element) |
|`*Ptr(name, index)`| get pointer to element at index |
|`*Last(name)`| last element |
|`*LastPtr(name)`| pointer to last element |
|`*LastIndex(name)`| index of last element |
|`*First(name)`| first element |
|`*WriteFilename(name, filename)`| write the array content to filename file |
|`*Write(name, file)`| write the array content to disk |
|`*ReadFilename(name, filename)`| read an array from filename file |
|`*Read(name, file)`| read an array from disk |
|`forEachV(name, index)` | loop on indexes of `slice`, `staticSlice`, `vector` and `dVector` |
|`*Inject(name, index)`| insert an element at index |
|`*Prepend(name, v)`| prepend element |
|`*Dequeue(name)`| return and remove first element |
|`*DelFirst(name)`| delete first element in array |
|`*DelElem(name, index)`| delete an element in array |
|`*Del(name, start, end)`| delete range in array |
|`*VAppend(name, slice)`|  append slice to array name, the data is copied |
|`*AppendFrom(name, array, countInt)`| append array to array name, the data is copied |
|`*VPrepend(name, slice)`|  prepend array to array name, the data in array name is moved and the data in slice is copied to array name |
|`*PrependFrom(name, array, countInt)`| prepend array to array name, the data in slice is moved and the data in array is copied to array name |
|`*Insert(name, index, slice)`| insert slice at position index, the data in array name is moved and the data in slice is copied to array name |
|`*InsertFrom(name, index, array, countInt)`| insert array at position index, the data in array name is moved and the data in array is copied to array name |
|`*Slice(name, start, end)`|  slice array name, keep only elements between start and end, start must be between 0 and last index, end must be between 1 and count, the slice is returned |
|`*Copy(name, start, end)`| copy array name elements between start and end to a new array, start must be between 0 and last index, end must be between 1 and count, the new array is returned and must be freed with sliceTerminate |
|`*BCopy(name, dest, start, end)`| copy elements between start and end to dest |
|`*Sort(name, compareFunction)`| sort array  |
|`*Eq(name, slice, eqFunction)`| array equality |
|`*Has(name, value, eqFunction)`| return true when array name has value |
|`*IndexOf(name, value, eqFunction)`| return index (ssize_t) of value in array name |
|`*BinarySearch(name, value, less, equal)`| binary search  |
|`*Uniq(name, eqFunction)`| Uniquify elements |

Bitset macros:

| Name | Description |
| --- | --- |
|`*staticBitset0(name, index)` or `bitset0(name, at, index)`| set 0 at index |
|`*staticBitset1(name, index)` or `bitset1(name, at, index)`| set 1 at index |
|`*staticBitsetInv(name, index)` or `bitsetInv(name, at, index)`| invert bit at index |
|`*staticBitsetGet(name, index)` or `bitsetGet(name, at, index)`| get bit at index |

Examples:

sliceT(typeName, type);

typeName slce;

sliceInit(&slce);

// or

sliceInitCount(&slce, 17);

sliceAppend(&slce, value);

// get an element

int a = sliceAt(&slce, 0);

// set

sliceAt(&slce, 1) = 3;

sliceFree(&slce);

staticSliceT(typeName, type, 10);

typeName slce;

staticSliceInit(&slce);

staticSliceAppend(&slce, value);

// get an element

int a = staticSliceAt(&slce, 0);

// set

staticSliceAt(&slce, 1) = 3;

staticSliceFree(&slce);

vectorT(typeName, type);

typeName vectr;

vectorInit(&vectr);

// or

vectorInitCount(&vectr, 17);

vectorAppend(&vectr, value);

// get an element

int a = vectorAt(&vectr, 0);

// set

vectorAt(&vectr, 1) = 3;

vectorFree(&vectr);

dVectorT(typeName, type);

typeName dvector;

dVectorInit(&dvector);

// or

dVectorInitCount(&dvector, 17);

dVectorAppend(&dvector, value);

// get an element

int a = dVectorAt(&dvector, 0);

// set

dVectorAt(&dvector, 1) = 3;

dVectorFree(&dvector);

typedef struct {

int a;

char *key;

} element;

staticArrayT(typeName, element, 10);

typeName array;

staticArrayInit(array);

staticArrayPush(array);

staticArrayLast(array).a = fork();

val = staticArrayLast(array).a;

staticArrayPop(array);

char array[10][5];

// declare an indexer with smaller counters (default is int64_t):

indexerT(typeName, i8);

typeName indx;

indexerInit(indx, 10);

indexerPush(indx);

array[indexerLast(indx)][0] = '0';

// or

indexerPush(indx);

array[indx.last][0] = '0';

indexerPop(indx);

// accessing the first/head element

char c = array[indexerFirst(indx)][0];

char c = array[indx.head][0];

dArrayT(typeName, type);

typeName darray;

dArrayInit(&darray);

// or

dArrayInitCount(&darray, 17);

dArrayAppend(&darray, value);

// get an element

int a = dArrayAt(&darray, 0);

// set

dArrayAt(&darray, 1) = 3;

dArrayFree(&darray);

slabT(typeName, type);

typeName slab;

slabInit(&slab);

// or

slabInitCount(&slab, 17);

slabAppend(&slab, value);

// get an element

int a = slabAt(&slab, 0);

// set

slabAt(&slab, 1) = 3;

slabFree(&slab);


- For further information, read [libsheepy.h](https://spartatek.se/libsheepy/libsheepy_8h.html)

# Thread Pool

The thread pool is initialized by initLibsheepy and the prefix for the thread pool is `tpool`.

The thread pool runs functions of type `void f(void *p)` where p is a pointer of your choice.

The functions are added to the thread pool queue using `tpoolAdd` and the first available thread runs the first function in the queue.

There is one thread per core and the threads are started with CPU affinity so they always run on the same core.

`tpollWait` waits until all the functions in the thread pool queue are finished.

`tpool.h` is the header for the thread pool and is included in `libsheepyObject.h`.

Thread pool function list:

| Name | Description |
| --- | --- |
| `tpoolAdd(task, args)` | add a function to the thread pool queue |
| `tpoolWait;` | wait until all functions in the thread pool are finished |
| `tpoolKill;` | stop/kill the thread pool |
| `tpoolPause;` | pause the thread pool |
| `tpoolResume;` | resume the thread pool |
| `tpoolNum;` | show number of working threads |

Example:

int i = 0;

void emptyTask() {

puts("the empty task");

}

void incTask(void *p) {

int *i = (int*)p;

sleep(1);

(*i)++;

}

int main(int ARGC, char** ARGV) {

initLibsheepy(ARGV[0]);

tpoolAdd(emptyTask, NULL);

tpoolAdd(incTask, &i);

puts("Threads are running");

tpoolWait;

puts("All functions are finished");

}


# Further Information

- [libsheepy.h](https://spartatek.se/libsheepy/libsheepy_8h.html) and [libsheepy.c](https://spartatek.se/libsheepy/libsheepy_8c.html) have detailed function descriptions
- [libsheepyObject.h](https://spartatek.se/libsheepy/libsheepyObject_8h.html) the API file to include in user programs
- the class header files (libsheepyC*.h) have detailed method descriptions for each class:
  - [libsheepyCSmallArray.h](https://spartatek.se/libsheepy/libsheepyCSmallArray_8h.html)
  - [libsheepyCSmallBool.h](https://spartatek.se/libsheepy/libsheepyCSmallBool_8h.html)
  - [libsheepyCSmallBytes.h](https://spartatek.se/libsheepy/libsheepyCSmallBytes_8h.html)
  - [libsheepyCSmallContainer.h](https://spartatek.se/libsheepy/libsheepyCSmallContainer_8h.html)
  - [libsheepyCSmallDict.h](https://spartatek.se/libsheepy/libsheepyCSmallDict_8h.html)
  - [libsheepyCSmallDouble.h](https://spartatek.se/libsheepy/libsheepyCSmallDouble_8h.html)
  - [libsheepyCSmallInt.h](https://spartatek.se/libsheepy/libsheepyCSmallInt_8h.html)
  - [libsheepyCSmallJson.h](https://spartatek.se/libsheepy/libsheepyCSmallJson_8h.html)
  - [libsheepyCSmallString.h](https://spartatek.se/libsheepy/libsheepyCSmallString_8h.html)
  - [libsheepyCUndefined.h](https://spartatek.se/libsheepy/libsheepyCUndefined_8h.html)