libsheepy overview

Table of Contents


The libsheepy API is available in 2 includes: libsheepy.h and libsheepyObject.h

There are examples for both libsheepy.h and libsheepyObject.h in the example folder.


There are 4 function categories:

For string and list, there are these sub function categories:

libsheepy.h also has:

It is advised to use the C11 generics from libsheepyObject.h instead of the libsheepy.h functions directly because there are many functions.

For detailed usage of each function, see libsheepyTest.c


libsheepyObject.h is an API for handling data in objects like JSON. The functions are similar to the ones in libsheepy.h and are object oriented. The library is compatible with both C99 and C11. The use of generics (only C11) greatly simplify the API.

The classes are: baset: base class, all other classes inherit baset (libsheepyObject.h)

The file and system functions accepting objects in parameters are declared in libsheepyObject.h.

The method implementation is dynamic, all objects have an array of functions (obj->f->), the functions can be provided at runtime.

The object model is available at the objects git repo and the template for new classes is in libsheepyCClassTemplate.h, libsheepyCClassTemplateInternal.h and libsheepyCClassTemplate.c.

For functions returning a status value, the value for errors is 0, false, NULL or specified otherwise in the function description. In general, errors are detected with "if (!func)".


The C11 generics are the main interface to libsheepy. Generics simplify greatly libsheepy development since only a few functions are needed and there are many functions in libsheepy (thousands).

The generics are defined in libsheepyObject.h and their names end with G: freeG, setG.

They accept any small object, char, char*, int64_t, uint64_t, double...

All small object methods have a generic in libsheepyObject.h, my advice is to use the generics all the time.

There are also the defines for C99 ending in O.

The main generics are:

Generics returning a value have a returnType parameter to select the return type.

Base class

The baset classes listed above are the API classes, the data is stored in s objects inside. When a baset object is created, also in s object is created. The s objects are defined in libsheepySmall.h.

The baset objects are containers for s objects.


All objects have free, terminate, toString, duplicate methods and create*, createAllocate*, initiate*, initiateAllocate*, finalize* and alloc* functions.

smallBoolt myBool, myBool2;
myBool2 = allocSmallBool(true);

The object type strings for isOTypeG or return by getOTypeG are:

Object Life cycle

Objects have to be created

or declared and initialized

use the free method to free the s object inside the object, use the finish method to free the container and keep the s object inside and when the object is not used anymore terminate the object


Allocating objects

allocG and initiateG both initialize objects, for some classes allocG take an initial parameter.

smallBoolt myBool;
smallBoolt *myBoolP;
// allocG
smallStringt *s = allocG("allocate new string");
void *buffer;
double dbl = 0;
smallDoublet *dblo = allocG(dbl);
int64_t intv = 0;
smallIntt * into = allocG(intv);

Adding objects to Arrays, Dictionaries and Json

The set functions in smallDict duplicate the given key string in parameter to avoid memory management problems when freeing the smallDict dictionary.

When the sObject pointer is updated by realloc, the sObject pointer in the smallArray has to be updated with setP. The operations reallocating the sObjects are:

The object is duplicated for the following types:

char * (unused: cBool, cDouble, cInt, stringt)

Get object in array or dictionary

The get function in smallArrayt and smallDictt creates a baset object and copies the pointer to the data to it. When the operations on the array or dictionary element are finished, the baset object needs to freed, but the data inside to be kept, so the finish function is used, see smallObjectsUsage.c.

// the S object is created and has a pointer to the value for "s" in dict
S = getG(dict, S, "s")

Sometimes, the data reallocated and the setP function is used to update the pointer in the array or dictionary, see smallObject.c.

// the st object is created by getAtSmallString and holds a pointer to
// the value at 0
st = anotherStringArray->f->getAtSmallString(anotherStringArray, 0)
st->f->color(st, BLD BGRED);
// setPAtNFreeSmallString updates the pointer at 0 and free the st baset object
anotherStringArray->f->setPAtNFreeSmallString(anotherStringArray, 0, st);

setNFreePG is the generics to update the pointer in an array or a dictionary and free the baset object, see smallObjectsUsage.c.

// add Dict2 to dict and free Dict2 object
setNFreeG(dict, "Dict2", Dict2);

pushNFree adds data at the end of the array and frees the baset object.

setNFreeG frees the data already present, sets a pointer to the new data and frees the baset object.

getNDupG duplicates the data and creates a baset object.

appendNSmashG appends arrays, the elements of the second array are push in the first array. The smash function frees the second array (not the elements) and frees the baset object, see smallObjectsUsage.c.

// the array a is pushed in gotArray
appendNSmashG(gotArray, a);
// same operation with smashG
// Dispose example
// append a array and keep the baset object
// dispose frees the array but not the elements and the baset object is kept

Duplicating objects

duplicateG duplicates objects of classes inheriting baset.

dupG duplicates objects of classes inheriting baset like duplicateG and also char* strings and char** lists.


eqG compares 2 objects of any type and returns true when they are equal. When the objects have different types, they are converted to allow comparison. If the conversion is impossible then the objects have incompatible types and false is returned.

For example, when a string is compared to an int, the string is converted to an int with the parseIntS function and then compared.

char c = '1';
int32_t i = 1;
if (eqG(c, i)) puts("c and i are equal");

Insert and Inject

insertG add elements from the object in parameter at given. When self and the parameter have different types, the object in parameter is added at the index. InjectG always add the object in parameter at the index.

insertG(a, -1, a1);
// a becomes [elements in a, elements from a1];
injectG(a, -1, a1);
// a becomes [elements in a, [a1]]

Terminal colors

The colors and effects are defined libsheepy.h, the effect codes can be added to static strings directly. For dynamic strings, there is the color method in the smallString class, see smallObject.c.

// coloring a static string
puts(BLD RED "At least 2 arguments are needed" RST);
// coloring string
st->f->color(st, BLD BGRED);

Loops and range

The simplest loops for libsheepy.h are forEachCharP and forEachS, and for libsheepyObject.h the simplest loops are the iterators.


The smallArray and smallDict classes have iterators, the iterator methods start with the prefix iter.

There is an iter macro to loop on all elements in the object:

iter(list, e)
smallStringt *s = (smallStringt*)e // or castS(s,e);

The memory is managed by the iterator.

There are also a few macros in libsheepy.h for iterating conveniently on integers:

Loop methods

The smallArray and smallDict classes have loop methods:

These methods take in parameters:

forEach, range

The objects used in the loops have to be valid (not NULL).

In libsheepy.h:

// forEach, see demo.c
char **list
listPushS(&list, " libsheepy ");
forEachCharP(list, element)
// to access the element use *element
range(i, 10)
printf("%d", i);

In libsheepyObject.h:

// forEachSmallArray, see demoStatic.c
smallStringt *s = (smallStringt*)e // or castS(s,e);
// free loop element for each loop
// enumerateSmallArray, see demoStatic.c
enumerateSmallArray(list2, e, index)
smallStringt *s = (smallStringt*)e // or castS(s,e);
print '%d - %s', index+1, s->f->get(s)
// free loop element for each loop
// forEachSmallDict, see json.c example
char *V = toStringG(value);
free V
// free loop element for each loop
// free libsheepyInternalKeys at the end of the loops

The sObjects are not duplicated by push, set, append...

To limit the number of memory allocations, functions (push, set, append, ...) copy pointers and sObjects are shared.

C primitives are duplicated, including strings (char*).

Given this code:

// Example 1
smallStringt *s = allocG("string");
pushG(a, s);
// Example 2 - to duplicate the sObject
smallStringt *s = allocG("string");
// convert s to string (char*)
pushG(a, ssGet(s));
// or use dupG
// Example 3 - append array

The sString sObject in s and in a[0] have identical pointers. When a function updates the sObject pointer in s, this sObject pointer has to be updated in a[0] with the setP function.

The terminate function cannot be used to free s since it frees the shared sObject, instead use smashG.

Reading and writing files

readFileG and writeFileG are the generics for reading and writing files, they work diffently depending on the type given in the first paramenter.

readFileG and writeFileG are suitable for small files since they process the complete file at once.

The data is stored in buffers (void*, char*,...) or arrays (char**, smallArray) where each line is an element.

When the data is stored in a small object, the object has to be allocated before calling readFileG or writeFileG since they call the object method to load/save the file.

// loading file to a string buffer
char *s = readFileG(rtChar, path);
// loading file to smallString object
smallStringt *so = allocG("");
readFileG(so, path);
writeFileG(so, path2);