libsheepy
libsheepy reference

Table of Contents

This is the list of macros and functions in libsheepy.h and libsheepyObject.h with their descriptions.

libsheepy.h

Short list

internal
#undef TRUE /* avoid conflict with ncurses */
const bool TRUE
#undef FALSE /* avoid conflict with ncurses */
const bool FALSE
pError(func)
pError0(func)
pErrorValue(func, errorValue)
pTestErrorCmd(test, cmd)
pErrorCmd(func, test, cmd)
pErrorResult(result, func, test)
pErrorResultCmd(result, func, test, cmd)
setJump(slot)
try(slot)
throw(slot)
tryV(result, slot)
throwV(slot, value)
goNLabel(go, label)
MAX(a, b)
MIN(a, b)
MIN3(a, b, c)
MAX3(a, b, c)
ABS(a)
CLAMP(x, low, high)
EXTRACT(x, msb, lsb)
setMax(result, a, b)
setMin(result, a, b)
cast(type, casted, toCast)
EVA(var, func)
loopBreaker(breakCount)
UNIQVAR(name)
logVar(var, format)
logPtr(pointer)
BGRED
timeNs(func)
}while(0)
timeDivs(func, div, timeunit)
}while(0)
timeUs(func)
timeMs(func)
timeSec(func)
uint64_t shStopwatch(uint8_t op)
stopwatchLogDivs(div, timeunit)
#undef LOG_WARNING // conflict with syslog.h
#undef LOG_INFO // conflict with syslog.h
FILE *SH_PREFIX(setLogFile)(char *filename)
int getMaxLogLevel(void)
void setMaxLogLevel(int logLevel)
void closeLogFiles(void)
int getLogMode(void)
void setLogMode(int mode)
bool getLogShortPath(void)
void setLogShortPath(bool shortPath)
pLog(level, ...)
void _pLog(int, const char *, const char *, int, const char *, ...)
logI(...)
logW(...)
logE(...)
logC(...)
uint64_t logMask
pLogMask(mask, level, ...)
logMI(mask, ...)
logMW(mask, ...)
logME(mask, ...)
logMC(mask, ...)
Q_SORT3(q_a1, q_a2, q_a3, Q_LESS, Q_SWAP)
Q_PARTITION(q_l, q_r, q_i, q_j, Q_UINT, Q_LESS, Q_SWAP)
Q_INSERTION_SORT(q_l, q_r, Q_UINT, Q_LESS, Q_SWAP)
Q_LOOP(Q_UINT, Q_N, Q_LESS, Q_SWAP)
Q_SUBFILES(q_l1, q_r1, q_l2, q_r2)
QSORT(Q_N, Q_LESS, Q_SWAP)
BSEARCH(RESULT_INDEX, SEARCH_ELEMENT, B_N, B_LESS, B_EQUAL)
typedef void(*initLibsheepyObjectP)(void)
void initLibsheepyF(const char *progPath, initLibsheepyObjectP initF)
initLibsheepy(progPath)
int64_t getStackLimit(void)
int setStackLimit(int64_t stackSize)
const char *getProgPath(void)
const char *getRealProgPath(void)
void freeRealProgPath(void)
systemNFree(command)
int systemNFreeF(char *command, int line, const char *thisFunc, const char *thisFileName)
time_t getModificationTime(const char *path)
int setModificationTime(const char *path, time_t mtime)
bool equalModificationTimes(const char *path1, const char *path2)
time_t getCurrentUnixTime(void)
time_t strToUnixTime(const char *date, const char *format)
char *timeToS(const time_t t)
char *bTimeToS(char *dst, const time_t t)
char *bLTimeToS(char *dst, size_t dstSize, const time_t t)
char *timeToYMDS(const time_t t)
char *bTimeToYMDS(char *dst, const time_t t)
char *bLTimeToYMDS(char *dst, size_t dstSize, const time_t t)
char *getCurrentDate(void)
char *bGetCurrentDate(char *dst)
char *bLGetCurrentDate(char *dst, size_t dstSize)
char *getCurrentDateYMD(void)
char *bGetCurrentDateYMD(char *dst)
char *bLGetCurrentDateYMD(char *dst, size_t dstSize)
char *shDirname(const char *path)
char *bDirname(char *path)
char *bLDirname(char *path, size_t pathSize)
char *expandHome(const char *path)
char *iExpandHome(char **path)
char *bExpandHome(char *path)
char *bLExpandHome(char *path, size_t pathSize)
char *normalizePath(const char *path)
char *iNormalizePath(char **path)
char *bNormalizePath(char *path)
char *bLNormalizePath(char *path, size_t pathSize)
char *getHomePath(void)
char *bGetHomePath(char *path)
char *bLGetHomePath(char *path, size_t pathSize)
const char *getCHomePath(void)
char *getCwd(void)
char *bLGetCwd(char *path, size_t pathSize)
int chDir(const char *path)
bool isDir(const char *path)
char *shReadlink(const char *path)
char *endlink(const char *path)
bool isLink(const char *path)
bool fileExists(const char *filePath)
bool fileChmod(const char *filePath, mode_t mode)
ssize_t fileSize(const char *filePath)
ssize_t fileSizeFP(FILE *fp)
void *readFileToS(const char *filePath)
void *bReadFileToS(const char *filePath, void *dst)
void *bLReadFileToS(const char *filePath, void *dst, size_t dstSize)
ssize_t readFile(const char *filePath, void **buffer)
ssize_t bReadFile(const char *filePath, void *buffer)
ssize_t bLReadFile(const char *filePath, void *buffer, size_t dstSize)
void *readStreamToS(FILE *fp)
void *bReadStreamToS(FILE *fp, void *dst)
void *bLReadStreamToS(FILE *fp, void *dst, size_t dstSize)
int writeFileS(const char *filePath, const char *string)
int writeFile(const char *filePath, void *buffer, size_t len)
int writeStreamS(FILE *fp, const char *string)
int writeLStream(FILE *fp, void *buffer, size_t len)
bool appendFileS(const char *filePath, const char *string)
bool appendFile(const char *filePath, void *buffer, size_t len)
char **walkDir(const char* dirPath)
char **walkDirDir(const char* dirPath)
char **readDir(const char *dirPath)
char **readDirDir(const char *dirPath)
char **walkDirAll(const char* dirPath)
char **readDirAll(const char *dirPath)
mode_t getumask(void)
int mkdirParents(const char* path)
int rmAll(const char* path)
int copy(const char* src, const char* dst)
int shRename(const char* src, const char* dst)
int shMove(const char* src, const char* dst)
uint64_t randomWord(void)
uint64_t randomWordFromHW(void)
uint64_t randomChoice(uint64_t range)
char *randomS(uint64_t length)
char *bRandomS(char *dst, size_t length)
char *randomAlphaNumS(uint64_t length)
char *bRandomAlphaNumS(char *dst, size_t dstSize)
char *readS(void)
char *bLReadS(char *dst, size_t dstSize)
char *readPasswordS(void)
bool zeroS(char *string)
bool zeroBuf(void *buf, size_t len)
void readEnter(void)
char *readLine(FILE *fp)
charToS(dst, c)
void freeManySF(char *paramType, ...)
char *dupS(const char *string)
void shPrintfS(const char *fmt, ...)
void shEPrintfS(const char *fmt, ...)
void logNFree(char *s)
void loghex(const void *buf, size_t len)
char *strCpy(char *dst, const char *src)
char *strNCpy(char *dst, const char *src, size_t srcSize)
char *strLCpy(char *dst, size_t dstSize, const char *src)
char *strCat(char *dst, const char *src)
char *strNCat(char *dst, const char *src, size_t srcLen)
char *strLCat(char *dst, size_t dstSize, const char *src)
char *strLNCat(char *dst, size_t dstSize, const char *src, size_t srcLen)
char *catSF(const char *paramType, ...)
catS(...)
char *iCatSF(char *dst, const char *paramType, ...)
iCatS(dst, ...)
char *bLCatSF(char *dst, size_t dstSize, const char *paramType, ...)
bLCatS(dst, dstSize, ...)
char *formatS(const char *fmt, ...)
char *appendS(const char *string1, const char *string2)
char *appendCharS(const char *string1, char c)
char *appendSChar(char c, const char *string2)
char *iAppendS(char **string1, const char *string2)
char *iAppendCharS(char **string1, char c)
char *iAppendNFreeS(char **string1, char *string2)
char *iAppendManySF(char **string, const char *paramType, ...)
iAppendManyS(s, s1, ...)
char *bAppendManySF(char *string, const char *paramType, ...)
bAppendManyS(s, s1, ...)
char *bLAppendManySF(char *string, size_t stringSize, const char *paramType, ...)
bLAppendManyS(s, sSize, s1, ...)
char *prependS(const char *string1, const char *string2)
char *prependCharS(const char *string1, char c)
char *prependSChar(char c, const char *string2)
char *iPrependS(char **string1, const char *string2)
char *iPrependCharS(char **string1, char c)
char *iPrependNFreeS(char **string1, char *string2)
char *bPrependS(char *string1, const char *string2)
char *bLPrependS(char *string1, size_t string1Size, const char *string2)
char *replaceS(const char *s, const char *olds, const char *news, size_t max)
char *replaceCharSS(const char *s, char olds, const char *news, size_t max)
char *replaceSCharS(const char *s, const char *olds, char news, size_t max)
char *replaceCharCharS(const char *s, char olds, char news, size_t max)
replaceS_max(s,olds,news)
char* iReplaceS(char **s, const char *olds, const char *news, size_t max)
char* iReplaceCharSS(char **s, char olds, const char *news, size_t max)
char* iReplaceSCharS(char **s, const char *olds, char news, size_t max)
char* iReplaceCharCharS(char **s, char olds, char news, size_t max)
iReplaceS_max(s,olds,news)
char* bReplaceS(char *s, const char *olds, const char *news, size_t max)
bReplaceS_max(s,olds,news)
char* bLReplaceS(char *s, size_t sSize, const char *olds, const char *news, size_t max)
bLReplaceS_max(s,sSize,olds,news)
char *replaceManySF(const char *paramType, ...)
replaceManyS(s, ...)
char *iReplaceManySF(char **string, char *paramType, ...)
iReplaceManyS(s, olds, ...)
char *bReplaceManySF(char *s, char *paramType, ...)
bReplaceManyS(s, olds, ...)
char *bLReplaceManySF(char *s, size_t sSize, char *paramType, ...)
bLReplaceManyS(s, sSize, olds, ...)
char *icReplaceS(const char *s, const char *olds, const char *news, size_t max)
char *icReplaceCharSS(const char *s, char olds, const char *news, size_t max)
char *icReplaceSCharS(const char *s, const char *olds, char news, size_t max)
char *icReplaceCharCharS(const char *s, char olds, char news, size_t max)
icReplaceS_max(s,olds,news)
char* iicReplaceS(char **s, const char *olds, const char *news, size_t max)
char* iicReplaceCharSS(char **s, char olds, const char *news, size_t max)
char* iicReplaceSCharS(char **s, const char *olds, char news, size_t max)
char* iicReplaceCharCharS(char **s, char olds, char news, size_t max)
iicReplaceS_max(s,olds,news)
char* bicReplaceS(char *s, const char *olds, const char *news, size_t max)
bicReplaceS_max(s,olds,news)
char* bLicReplaceS(char *s, size_t sSize, const char *olds, const char *news, size_t max)
bLicReplaceS_max(s,sSize,olds,news)
char *icReplaceManySF(const char *paramType, ...)
char *iicReplaceManySF(char **string, char *paramType, ...)
iicReplaceManyS(s, olds, ...)
char *bicReplaceManySF(char *s, char *paramType, ...)
bicReplaceManyS(s, olds, ...)
char *bLicReplaceManySF(char *s, size_t sSize, char *paramType, ...)
bLicReplaceManyS(s, sSize, olds, ...)
bool eqS(const char *string1, const char *string2)
bool eqCharS(char c, const char *string2)
bool eqSChar(const char *string1, char c)
bool eqIS(const char *string1, const char *string2, intmax_t index)
bool eqICharS(const char *string1, char c, intmax_t index)
bool startsWithS(const char *string1, const char *string2)
bool startsWithCharS(const char *string1, char c)
bool endsWithS(const char *string1, const char *string2)
bool endsWithCharS(const char *string1, char c)
ssize_t countS(const char *s, const char *needle)
ssize_t countCharS(const char *s, char c)
bool icEqS(const char *string1, const char *string2)
bool icEqCharS(char c, const char *string2)
bool icEqSChar(const char *string1, char c)
bool icEqIS(const char *string1, const char *string2, intmax_t index)
bool icEqICharS(const char *string1, char c, intmax_t index)
bool icStartsWithS(const char *string1, const char *string2)
bool icStartsWithCharS(const char *string1, char c)
bool icEndsWithS(const char *string1, const char *string2)
bool icEndsWithCharS(const char *string1, char c)
ssize_t icCountS(const char *s, const char *needle)
ssize_t icCountCharS(const char *s, char c)
bool hasCtrlChar(const char *string)
bool isNumber(const char *string)
bool isInt(const char *string)
intmax_t parseInt(const char *string)
intmax_t parseIntChar(char c)
double parseDouble(const char *string)
double parseDoubleChar(char c)
uint64_t parseHex(const char *string)
char *intToS(intmax_t n)
char *bIntToS(char *s, intmax_t n)
char *doubleToS(double n)
char *bDoubleToS(char *s, double n)
size_t lenS(const char *string)
char *upperS(const char *string)
char *iUpperS(char **string)
char *bUpperS(char *string)
char *lowerS(const char *string)
char *iLowerS(char **string)
char *bLowerS(char *string)
char *trimS(const char *string)
char *iTrimS(char **string)
char *bTrimS(char *string)
char *lTrimS(const char *string)
char *iLTrimS(char **string)
char *bLTrimS(char *string)
char *rTrimS(const char *string)
char *iRTrimS(char **string)
char *bRTrimS(char *string)
char *uniqS(const char *string, char c)
char *iUniqS(char **string, char c)
char *bUniqS(char *string, char c)
char *icUniqS(const char *string, char c)
char *iicUniqS(char **string, char c)
char *bicUniqS(char *string, char c)
char getS(const char *string, intmax_t index)
char *setS(char *string, intmax_t index, char c)
char *sliceS(const char *string, intmax_t start, intmax_t end)
char *iSliceS(char **string, intmax_t start, intmax_t end)
char *bSliceS(char *string, intmax_t start, intmax_t end)
char *bLSliceS(char *string, size_t stringSize, intmax_t start, intmax_t end)
char *insertS(const char *string, intmax_t index, const char *toInsert)
char *insertNFreeS(const char *string, intmax_t index, char *toInsert)
char *iInsertS(char **string, intmax_t index, const char *toInsert)
char *iInsertNFreeS(char **string, intmax_t index, char *toInsert)
char *bInsertS(char *string, intmax_t index, const char *toInsert)
char *bLInsertS(char *string, size_t stringSize, intmax_t index, const char *toInsert)
char *injectS(const char *string, intmax_t index, char toInject)
char *iInjectS(char **string, intmax_t index, char toInject)
char *bInjectS(char *string, intmax_t index, char toInject)
char *bLInjectS(char *string, size_t stringSize, intmax_t index, char toInject)
char *delS(const char *string, intmax_t start, intmax_t end)
char *iDelS(char **string, intmax_t start, intmax_t end)
char *bDelS(char *string, intmax_t start, intmax_t end)
char *bLDelS(char *string, size_t stringSize, intmax_t start, intmax_t end)
char *delElemS(const char *string, intmax_t index)
char *iDelElemS(char **string, intmax_t index)
char *bDelElemS(char *string, intmax_t index)
char *bLDelElemS(char *string, size_t stringSize, intmax_t index)
char *findS(const char *string, const char *needle)
char *findCharS(const char *string, char c)
ssize_t indexOfS(const char *string, const char *needle)
ssize_t indexOfCharS(const char *string, char c)
bool hasS(const char *string, const char *needle)
bool hasCharS(const char *string, char c)
char *icFindS(const char *string, const char *needle)
char *icFindCharS(const char *string, char c)
ssize_t icIndexOfS(const char *string, const char *needle)
ssize_t icIndexOfCharS(const char *string, char c)
bool icHasS(const char *string, const char *needle)
bool icHasCharS(const char *string, char c)
char *tokS(const char *s, const char *delim, char **saveptr)
char *icTokS(const char *s, const char *delim, char **saveptr)
typedef int rune
size_t lenUTF8(const char *s)
size_t bLLenUTF8(const char *s, size_t maxSize)
bool isUTF8(const char * string)
bool bLIsUTF8(const char * string, size_t stringSize)
bool isCodeUTF8(const char *code)
const uint8_t codeSzUTF8[256]
char *nextUTF8(const char *utf8)
char *bLNextUTF8(const char *string, size_t utf8Size, const char *utf8)
char *findNextUTF8(const char *string, size_t utf8Size, const char *utf8)
char *prevUTF8(const char *utf8)
char *bPrevUTF8(const char *string, const char *utf8)
char *idx2PtrUTF8(const char *utf8, intmax_t index)
char *bLIdx2PtrUTF8(const char *utf8, size_t utf8Size, intmax_t index)
intmax_t ptr2IdxUTF8(const char *utf8, const char *pos)
intmax_t bPtr2IdxUTF8(const char *start, const char *utf8, const char *pos)
intmax_t bLPtr2IdxUTF8(const char *utf8, size_t utf8Size, const char *pos)
intmax_t bLPtr2NegIdxUTF8(const char *utf8, size_t utf8Size, const char *pos)
char *makeValidUTF8(const char *utf8)
char *bMakeValidUTF8(char *utf8)
char *nMakeValidUTF8(const char *utf8, size_t utf8Len)
char *bNMakeValidUTF8(char *dst, const char *utf8, size_t utf8Len)
char *bLMakeValidUTF8(char *dst, size_t dstSize, const char *utf8)
char *bLNMakeValidUTF8(char *dst, size_t dstSize, const char *utf8, size_t utf8Len)
char *strNCpyUTF8(char *dst, const char *src, size_t srcLen)
char *strLCpyUTF8(char *dst, size_t dstSize, const char *src)
char *strNCatUTF8(char *dst, const char *src, size_t srcLen)
char *strLCatUTF8(char *dst, size_t dstSize, const char *src)
char *strLNCatUTF8(char *dst, size_t dstSize, const char *src, size_t srcLen)
char* icReplaceUTF8(const char *s, const char *olds, const char *news, size_t max)
char *icReplaceCharSUTF8(const char *s, char olds, const char *news, size_t max)
char *icReplaceSCharUTF8(const char *s, const char *olds, char news, size_t max)
char* iicReplaceUTF8(char **s, const char *olds, const char *news, size_t max)
char *iicReplaceCharSUTF8(char **s, char olds, const char *news, size_t max)
char *iicReplaceSCharUTF8(char **s, const char *olds, char news, size_t max)
char* bicReplaceUTF8(char *s, const char *olds, const char *news, size_t max)
char* bLicReplaceUTF8(char *s, size_t sSize, const char *olds, const char *news, size_t max)
char *icReplaceManyUTF8F(const char *paramType, ...)
char *iicReplaceManyUTF8F(char **s, char *paramType, ...)
char *bicReplaceManyUTF8F(char *s, char *paramType, ...)
char *bLicReplaceManyUTF8F(char *s, size_t sSize, char *paramType, ...)
bool eqIUTF8(const char *string1, const char *string2, intmax_t index)
bool eqICharUTF8(const char *string1, char c, intmax_t index)
bool icEqUTF8(const char *string1, const char *string2)
bool icEqCharUTF8(char c, const char *string2)
bool icEqUTF8Char(const char *string1, char c)
bool icEqIUTF8(const char *string1, const char *string2, intmax_t index)
bool icEqICharUTF8(const char *string1, char c, intmax_t index)
bool icStartsWithUTF8(const char *string1, const char *string2)
bool icEndsWithUTF8(const char *string1, const char *string2)
ssize_t icCountUTF8(const char *s, const char *needle)
rune code2RuneUTF8(const char *code)
rune code2RuneLUTF8(const char *code, uint8_t *n)
size_t bRune2CodeUTF8(char *dst, rune c)
uint8_t runeLenUTF8(rune r)
char *upperUTF8(const char *string)
char *iUpperUTF8(char **string)
char *bUpperUTF8(char *string)
char *lowerUTF8(const char *string)
char *iLowerUTF8(char **string)
char *bLowerUTF8(char *string)
char *casefoldUTF8(const char *utf8)
char *uniqUTF8(const char *string, const char *code)
char *iUniqUTF8(char **string, const char *code)
char *bUniqUTF8(char *string, const char *code)
char *icUniqUTF8(const char *string, const char *code)
char *iicUniqUTF8(char **string, const char *code)
char *bicUniqUTF8(char *string, char c)
rune getUTF8(const char *string, intmax_t index)
char *setUTF8(char *string, intmax_t index, rune c)
char *sliceUTF8(const char *string, intmax_t start, intmax_t end)
char *iSliceUTF8(char **string, intmax_t start, intmax_t end)
char *bSliceUTF8(char *string, intmax_t start, intmax_t end)
char *bLSliceUTF8(char *string, size_t stringSize, intmax_t start, intmax_t end)
char *insertUTF8(const char *string, intmax_t index, const char *toInsert)
char *insertNFreeUTF8(const char *string, intmax_t index, char *toInsert)
char *iInsertUTF8(char **string, intmax_t index, const char *toInsert)
char *iInsertNFreeUTF8(char **string, intmax_t index, char *toInsert)
char *bInsertUTF8(char *string, intmax_t index, const char *toInsert)
char *bLInsertUTF8(char *string, size_t stringSize, intmax_t index, const char *toInsert)
char *delUTF8(const char *string, intmax_t start, intmax_t end)
char *iDelUTF8(char **string, intmax_t start, intmax_t end)
char *bDelUTF8(char *string, intmax_t start, intmax_t end)
char *bLDelUTF8(char *string, size_t stringSize, intmax_t start, intmax_t end)
ssize_t indexOfUTF8(const char *string, const char *needle)
ssize_t icIndexOfUTF8(const char *string, const char *needle)
bool icHasUTF8(const char *string, const char *needle)
char *icTokUTF8(const char *s, const char *delim, char **saveptr)
char **icExtractUTF8(const char *string, const char* delim1, const char* delim2)
char **icExtractCharSUTF8(const char *string, char delim1, const char* delim2)
char **icExtractSCharUTF8(const char *string, const char* delim1, char delim2)
char **icListSortUTF8(char **list)
char **iicListSortUTF8(char ***list)
bool icListEqUTF8(char **list1, char **list2)
bool icListHasUTF8(char **list, const char *string)
ssize_t icListIndexOfUTF8(char **list, const char *string)
ssize_t icListBinarySearchUTF8(char **list, const char *string)
char **icListUniqUTF8(char **list)
char **iicListUniqUTF8(char ***list)
emptyS(string)
char *emptySF(void)
char *iEmptySF(char **string)
bEmptyS(string)
bool isEmptyS(const char *string)
orS(string, alternative)
bool isBlankS(const char *string)
orBlankS(string, alternative)
nS(string)
ssize_t intIndex(intmax_t index, intmax_t length)
char **listEmptySF(void)
char **iListEmptySF(char ***list)
bool listIsEmptyS(char **list)
bool listIsBlankS(char **list)
char **listCreateSF(const char *paramType, ...)
char **listFromArrayS(char **array, size_t size)
char **listPushS(char ***list, const char *s)
char **listPushCharS(char ***list, char c)
char **iListPushS(char ***list, char *s)
char *listPopS(char ***list)
char **listPrependS(char ***list, const char *s)
char **listPrependCharS(char ***list, char c)
char **iListPrependS(char ***list, char *s)
char *listDequeueS(char ***list)
void listFreeS(char **list)
void listFreeManySF(char **paramType, ...)
size_t listLengthS(char **list)
ssize_t listIntIndexS(char **list, intmax_t index)
char **listAddrS(char **list, intmax_t index)
char *listGetS(char **list, intmax_t index)
char *iListGetS(char **list, intmax_t index)
char **listSetS(char **list, intmax_t index, const char *s)
char **listSetCharS(char **list, intmax_t index, char c)
char **iListSetS(char **list, intmax_t index, char *s)
char **split(const char *string, const char* delim)
char **splitChar(const char *string, char delim)
char **icSplit(const char *string, const char* delim)
char **icSplitChar(const char *string, char delim)
char *join(char **list, const char* delim)
char *joinChar(char **list, char delim)
char *bJoin(char *string, char **list, const char* delim)
char *bJoinChar(char *string, char **list, char delim)
char *bLJoin(char *string, size_t stringSize, char **list, const char* delim)
char *bLJoinChar(char *string, size_t stringSize, char **list, char delim)
char **extractS(const char *string, const char* delim1, const char* delim2)
char **extractCharSS(const char *string, char delim1, const char* delim2)
char **extractSCharS(const char *string, const char* delim1, char delim2)
char **extractCharCharS(const char *string, char delim1, char delim2)
char **icExtractS(const char *string, const char* delim1, const char* delim2)
char **icExtractCharSS(const char *string, char delim1, const char* delim2)
char **icExtractSCharS(const char *string, const char* delim1, char delim2)
char **icExtractCharCharS(const char *string, char delim1, char delim2)
char **listDupS(char **list)
char **iListDupS(char **list)
char **listReverseS(char **list)
char **iListReverseS(char ***list)
char **listCatSF(char **paramType, ...)
char **listAppendS(char ***list1, char **list2)
char **iListAppendS(char ***list1, char **list2)
char **iListAppendNSmashS(char ***list1, char **list2)
char **listAddS(char **list1, char **list2)
char **listSliceS(char **list, intmax_t start, intmax_t end)
char **iListCopyS(char **list, intmax_t start, intmax_t end)
char **iListSliceS(char ***list, intmax_t start, intmax_t end)
char **listInsertS(char **list, intmax_t index, char **toInsert)
char **iListInsertS(char ***list, intmax_t index, char **toInsert)
char **iListInsertNFreeS(char ***list, intmax_t index, char **toInsert)
char **listInjectS(char **list, intmax_t index, char *toInject)
char **listInjectCharS(char **list, intmax_t index, char toInject)
char **iListInjectS(char ***list, intmax_t index, char *toInject)
char **listDelS(char **list, intmax_t start, intmax_t end)
char **iListDelS(char ***list, intmax_t start, intmax_t end)
char **listDelElemS(char **list, intmax_t index)
char **iListDelElemS(char ***list, intmax_t index)
int listPrintS(char **list)
range(index, maxCount)
rangeInf(index)
rangeDown(index, maxCount)
rangeDownTo(index, maxCount, to)
rangeFrom(index, from, maxCount)
circular(index, from, maxCount)
circularDown(index, from, maxCount)
rangeStep(index, maxCount, step)
rangeDownStep(index, maxCount, step)
rangeFromStep(index, from, maxCount, step)
loop(maxCount)
loopDownTo(maxCount, to)
loopFrom(from, maxCount)
loopStep(maxCount, step)
loopFromStep(from, maxCount, step)
forEachCharP(list, element)
forEachS(list, element)
forEachType(type, list, element)
enumerateCharP(list, element, index)
enumerateS(list, element, index)
enumerateType(type, list, element, index)
lForEach(node, startNode)
lForEachDown(node, startNode)
typedef int (*shCmpt)(const void * a, const void * b)
char **listSortS(char **list)
char **iListSortS(char ***list)
char **listSortFS(char **list, shCmpt compareFunction)
char **iListSortFS(char ***list, shCmpt compareFunction)
char **icListSortS(char **list)
char **iicListSortS(char ***list)
char **readText(const char *filePath)
char **readStream(FILE *fp)
bool writeText(const char *filePath, char **list)
bool writeStream(FILE *fp, char **list)
bool appendText(const char *filePath, char **list)
char **execOut(const char *cmd)
char **systemOutf(const char *fmt, ...)
int systemf(const char *fmt, ...)
bool listEqS(char **list1, char **list2)
bool listHasS(char **list, const char *string)
bool listHasCharS(char **list, char c)
ssize_t listIndexOfS(char **list, const char *string)
ssize_t listIndexOfCharS(char **list, char c)
ssize_t listBinarySearchS(char **list, const char *string)
ssize_t listBinarySearchCharS(char **list, char c)
char **listUniqS(char **list)
char **iListUniqS(char ***list)
bool icListEqS(char **list1, char **list2)
bool icListHasS(char **list, const char *string)
bool icListHasCharS(char **list, char c)
ssize_t icListIndexOfS(char **list, const char *string)
ssize_t icListIndexOfCharS(char **list, char c)
ssize_t icListBinarySearchS(char **list, const char *string)
ssize_t icListBinarySearchCharS(char **list, char c)
char **icListUniqS(char **list)
char **iicListUniqS(char ***list)
char **listCompactS(char **list)
char **iListCompactS(char ***list)
void btraceEnable(void)
void btraceDisable(void)
bool btraceConfig(void)
char **btrace(void)
#if __APPLE__
listEmpty(list)
void **listEmptyF(void)
void **iListEmptyF(void ***list)
bool listIsEmpty(void **list)
void **listCreateF(void *paramType, ...)
void **listFromArray(void **array, size_t size)
void **listPush(void ***list, void *s)
void *listPop(void ***list)
void **listPrepend(void ***list, void *s)
void *listDequeue(void ***list)
void listFree(void **list)
void listFreeManyF(void **paramType, ...)
size_t listLength(void **list)
void *listGet(void **list, intmax_t index)
void **listSet(void **list, intmax_t index, void *s)
void **listDup(void **list)
void **listReverse(void **list)
void **iListReverse(void ***list)
void **listCatF(void **paramType, ...)
listCat(...)
void **listAppend(void ***list1, void **list2)
void **listAdd(void **list1, void **list2)
void **listSlice(void **list, intmax_t start, intmax_t end)
void **iListSlice(void ***list, intmax_t start, intmax_t end)
void **listInsert(void **list, intmax_t index, void **toInsert)
void **iListInsert(void ***list, intmax_t index, void **toInsert)
void **listDel(void **list, intmax_t start, intmax_t end)
void **iListDel(void ***list, intmax_t start, intmax_t end)
newArray(name, type, count)
typedef struct {
staticArrayT(typeName, element, MAXCOUNT)
staticArrayGet(name, index)
staticArrayGetIndex(name, index)
staticArrayRef(name, index)
staticArrayRefIndex(name, index)
staticArrayWriteFilename(name, filename)
staticArrayReadFilename(name, filename)
indexerT(typeName, INT_TYPE)
indexerInit(name, MAXCOUNT)
indexerRef(name, index)
indexerPRef(name, index)
int ringInit(void *ring, int maxCount)
int ringEmpty(void *ring)
int ringIsEmpty(void *ring)
int ringIsFull(void *ring)
ssize_t ringCount(void *ring)
i64 ringPush(void *ring)
int ringPop(void *ring)
i64 ringPrepend(void *ring)
int ringDequeue(void *ring)
ringGet(name, index)
ringRef(name, index)
ringLast(name)
ringFirst(name)
ringSendSt(status, name, value)
ringRecv(name, result)
ringRecvSt(status, name, result)
void scheduler(void)
typedef struct {int slot;} fiberBaseT
staticArrayT(fiberLT, int, tCount)
typedef struct {
fiberCtx(thisSlot)
typedef void (*fiberFT)(int)
bool fiberAdd(void *ctx, int thisSlot, fiberFT func)
bool fiberPrepend(void *ctx, int thisSlot, fiberFT func)
startJump(func)
yield(slotValue, slot)
fiberEnd(slot)
schedulerYield(backToSlot)
dArrayT(typeName, elementType)
dArrayInitCount(a, count)
dArrayResize(a, count)
dArrayAt(a, index)
dArrayPtr(a, index)
dArrayWriteFilename(a, filename)
dArrayReadFilename(a, filename)
slabT(typeName, elementType)
slabInitCount(a, count)
slabResize(a, count)
slabEmpty(name)
slabCount(name)
slabAt(a, index)
slabPtr(a, index)
slabWriteFilename(a, filename)
slabReadFilename(a, filename)
uint64_t getMonotonicTime(void)
int nanoSleepF(uint64_t time)
nanoSleep(time)
nanoSleep(time)
nanoSleepE(time, cmd)
usSleep(time)
msSleep(time)

Prototypes and macros

#define internal static
#define var __auto_type
#undef TRUE /* avoid conflict with ncurses */
extern const bool TRUE;
#undef FALSE /* avoid conflict with ncurses */
extern const bool FALSE;
#define boolS(x) x ? "TRUE" : "FALSE"
/*
* success
*/
#define XSUCCESS exit(EXIT_SUCCESS);
/*
* failure
*/
#define XFAILURE exit(EXIT_FAILURE);
/*
* exit failure
*/
#define exitFailure(data) \
/*
* stringify Expression - Turn expression into a string literal
* Example:
* #define PRINT_COND_IF_FALSE(cond) \
* ((cond) || printf("%s is false!", stringifyExpr(cond)))
*/
#define stringifyExpr(expr) stringifyExpr1(expr)
/* Double-indirection required to stringify expansions */
#define stringifyExpr1(expr) #expr
/*
* print function name and system error
* to print error, use either pFuncError and shEPrintfS
* or shPrintError and shEPrintfS
*/
#define pFuncError do{ perror(__func__);logEBtrace; }while(0);
/*
* print error with line number, function name and file name to stderr
* to print error, use either pFuncError and shEPrintfS
* or shPrintError and shEPrintfS
*/
#define shPrintError do{ fprintf(stderr, "Error line "stringifyExpr(__LINE__)", function %s, file "__FILE__"\n", __func__);logEBtrace; }while(0);
/*
* print error when function failed. The error code must be -1
*/
#define pError(func) if (func == -1) shPrintError
/*
* print error when function failed. The error code must be 0
*/
#define pError0(func) if (func == 0) shPrintError
/*
* print error when function failed. The error code must be not 0
*/
#define pErrorNot0(func) if (func != 0) shPrintError
/*
* print error when function failed. The error code must be NULL
*/
#define pErrorNULL(func) if (func == NULL) shPrintError
/*
* print error when function failed. The error code must be -1
*/
#define pErrorValue(func, errorValue) if (func == errorValue) shPrintError
/*
* print error when test is true
*/
#define pTestError(test) if (test) shPrintError
/*
* print error and run command when test is true
*/
#define pTestErrorCmd(test, cmd) if (test) { shPrintError cmd; }
/*
* print error and run cmd when test is true
*/
#define pErrorCmd(func, test, cmd) if (func test) { shPrintError cmd; }
/*
* print error when test is true and return func result in result
* Example:
* pErrorResult(k, randomWordF(), == 0)
*/
#define pErrorResult(result, func, test) if ((result = func) test) shPrintError
/*
* print error and run cmd when test is true and return func result in result
* Example:
* pErrorResultCmd(k, randomWordF(), == 0, XFAILURE)
*/
#define pErrorResultCmd(result, func, test, cmd) if ((result = func) test) { shPrintError cmd; }
/*
* setjmp buffers for try/throw,throwV macros
*/
#define maxTryThrowCount 16
/*
* run setjmp using slot in tryJumpBuffers
*/
#define setJump(slot) setjmp(tryJumpBuffers[slot])
/*
* try throw else
* try(slot) saves the environment in slot
* throw(slot) executes the else associated with try(slot)
* there are 16 slots
* Example:
* try(0) {
* throw(0);
* }
* else
* puts("except");
*/
#define try(slot) if (!setjmp(tryJumpBuffers[slot]))
/*
* throw goes to else associated with try(slot)
*/
#define throw(slot) longjmp(tryJumpBuffers[slot], 1)
/*
* tryV stores the value from setjmp in result
* it is valid to try with throwV and tryV with throw (returns 1)
* Example:
*/
#define tryV(result, slot) if (!(result = setjmp(tryJumpBuffers[slot])))
/*
* throwV returns value and goes to else associated with tryV(slot)
*/
#define throwV(slot, value) longjmp(tryJumpBuffers[slot], value)
// limited use macro - for test only
#define goNLabel(go, label) goto go; label:
/*
* types
*/
#define i8 int8_t
#define i16 int16_t
#define i32 int32_t
#define i64 int64_t
#define u8 uint8_t
#define u16 uint16_t
#define u32 uint32_t
#define u64 uint64_t
#define f32 float
#define f64 double
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define MIN3(a, b, c) MIN((typeof(a))MIN(a, b), c)
#define MAX3(a, b, c) MAX((typeof(a))MAX(a, b), c)
#define ABS(a) (((a) < 0) ? -(a) : (a))
#define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
#define COUNT_ELEMENTS(arr) (sizeof (arr) / sizeof ((arr)[0]))
#define ARRAY_SIZE COUNT_ELEMENTS
#define EXTRACT(x, msb, lsb) ((~(0xFFFFFFFFFFFFFFFEUL << (msb)) & (x)) >> (lsb))
#define setMax(result, a, b) do{\
#define setMin(result, a, b) do{\
/*
* FIELD_SIZEOF - get the size of a struct's field
* @t: the target struct
* @f: the target struct's field
* Return: the size of @f in the struct definition without having a
* declared instance of @t.
*/
#define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f))
/*
* typ definition as alternative to typedef
*/
#define typ typedef
/*
* ret definition as alternative to return
*/
#define ret return
/*
* elif definition as alternative to else if
*/
#define elif else if
/*
* define variable and cast pointer
*/
#define cast(type, casted, toCast) type casted = (type) (toCast);
/*
* Evaluate and assign
* Evaluate, assign result from func and return result using the comma operator
* Example:
* save pointer returned by a function in a function parameter:
* void *p;
* func2( EVA(p,func1()) );
* free(p);
* Using libsheepy functions:
* char *s;
* puts( EVA(s, normalizePath("/wef/./../")) );
* free(s);
*/
#define EVA(var, func) (var = func, var)
/*
* initialize the loop breaker
* declares loop breaker variables
* Example:
* loopBreakerInit;
* forever {
* loopBreaker(20);
* }
* if (didBreak) logE("infinite loop detected");
* loopBreakerReset;
* forever {
* loopBreaker(100);
* }
* if (didBreak) logE("infinite loop detected");
*/
#define loopBreakerInit\
/*
* reset the loop breaker variables
*/
#define loopBreakerReset\
/*
* break the loop when the counter exceed breakCount
*/
#define loopBreaker(breakCount)\
#define FILE_LINE __FILE__":"stringifyExpr(__LINE__)
#define PFILE_LINE puts(FILE_LINE)
/*
* print file, function name and line
* Example:
* AT;
* libsheepy.c, main:9149
*/
#define AT pLog(LOG_INFO, __FILE__", %s:"stringifyExpr(__LINE__)"\n",__func__);
// macros for token paste for automatically creating unique variable names
// used in forEachCharP
#define TOKENPASTE2(a, b) a ## b
#define TOKENPASTE(a, b) TOKENPASTE2(a, b)
#define UNIQVAR(name) TOKENPASTE(name, __LINE__)
/*
* log variable and its value
* Example:
* logVar(k, PRIu64)
* k=14
*/
#define logVar(var, format) logI("%s=%" format, stringifyExpr(var), var);
#define logBoolVar(var) logVar(var, "b");
/*
* log pointer
*/
#define logPtr(pointer) logI("%s=%p", stringifyExpr(pointer), pointer);
// colors and effects
#define RST "\x1B[0m"
#define BLD "\x1B[1m"
#define FNT "\x1B[2m"
#define UDL "\x1B[4m"
#define INV "\x1B[7m"
#define COC "\x1B[8m"
#define CRD "\x1B[9m"
// foreground
#define BLK "\x1B[30m"
#define RED "\x1B[31m"
#define GRN "\x1B[32m"
#define YLW "\x1B[33m"
#define BLU "\x1B[34m"
#define MGT "\x1B[35m"
#define CYN "\x1B[36m"
#define WHT "\x1B[37m"
// background
#define BGBLK "\x1B[40m"
#define BGRED "\x1B[41m"
#define BGGRN "\x1B[42m"
#define BGYLW "\x1B[43m"
#define BGBLU "\x1B[44m"
#define BGMGT "\x1B[45m"
#define BGCYN "\x1B[46m"
#define BGWHT "\x1B[47m"
// bug in cg_c.py
#define sheepyRGBFP len = fprintf(stream, "%*s", (info->left ? -info->width : info->width), b)
#define sheepyBOOLFP len = fprintf(stream, "%*s", (info->left ? -info->width : info->width), boolS(value))
/*
* time a function in nanoseconds
* Example:
* timeNs(func(anInt));
*/
#define timeNs(func) do{\
}while(0)
#define TIMEUNITUS "us"
#define TIMEUNITMS "ms"
#define TIMEUNITSC "s"
/*
* time a function with div
* Example:
* timeDivs(func(anInt), 1E3);
*/
#define timeDivs(func, div, timeunit) do{\
}while(0)
/*
* time a function in microseconds
* Example:
* timeUs(func(anInt));
*/
#define timeUs(func) timeDivs(func,1E3, TIMEUNITUS)
/*
* time a function in miliseconds
* Example:
* timeMs(func(anInt));
*/
#define timeMs(func) timeDivs(func,1E6, TIMEUNITMS)
/*
* time a function in seconds
* Example:
* timeSec(func(anInt));
*/
#define timeSec(func) timeDivs(func,1E9, TIMEUNITSC)
// nanosecond stopwatch, the returned value is in ns. op parameter: 0 to start, 1 to get the stopwatch value
uint64_t shStopwatch(uint8_t op);
#define stopwatchStart shStopwatch(0)
/*
* print stopwatch value in ns since last start
*/
#define stopwatchLog printf(BLD GRN "time" RST ": %" PRIu64 "ns\n", shStopwatch(1))
/*
* print stopwatch value in provided unit since last start
*/
#define stopwatchLogDivs(div, timeunit) printf(BLD GRN "time" RST ": %f"timeunit"\n", ((float)shStopwatch(1))/div)
/*
* print stopwatch value in microseconds since last start
*/
#define stopwatchLogUs stopwatchLogDivs(1E3, TIMEUNITUS)
/*
* print stopwatch value in milliseconds since last start
*/
#define stopwatchLogMs stopwatchLogDivs(1E6, TIMEUNITMS)
/*
* print stopwatch value in seconds since last start
*/
#define stopwatchLogSec stopwatchLogDivs(1E9, TIMEUNITSC)
/*
* LOG LEVELS
*/
#define LOG_CRITICAL 0
#define LOG_ERROR 1
#undef LOG_WARNING // conflict with syslog.h
#define LOG_WARNING 2
#undef LOG_INFO // conflict with syslog.h
#define LOG_INFO 3
#define LOG_INVALID 4
#define LOG_DISABLE -1
/*
* LOG MODES
* when a new mode is added, add symbols in log_tags in libsheepy.c
*/
/*
* log symbol, filename, function, line, date
*/
#define LOG_VERBOSE 0
/*
* log symbol
*/
#define LOG_CONCISE 1
/*
* log symbol and date
*/
#define LOG_DATE 2 // default
/*
* log symbol and function
*/
#define LOG_FUNC 3
/*
* log symbol and program name
*/
#define LOG_PROG 4
/*
* log symbol, program name and date
*/
#define LOG_PROGNDATE 5
/*
* log message only
*/
#define LOG_VOID 6
/*
* invalid
*/
#define LOG_INVALID_MODE 7
// add a log file, maximum 15 files
FILE *SH_PREFIX(setLogFile)(char *filename);
// current max log level
int getMaxLogLevel(void);
// set max log level, logs above logMaxLevel are skipped
void setMaxLogLevel(int logLevel);
// close logfiles opened with setLogFile
void closeLogFiles(void);
// get current log mode (LOG_VERBOSE, LOG_CONCISE, ...)
int getLogMode(void);
// set log mode LOG_VERBOSE, LOG_CONCISE, ...
void setLogMode(int mode);
// get current log long/short path value, default is TRUE (short paths)
bool getLogShortPath(void);
// set log long/short file path value for VERBOSE mode
void setLogShortPath(bool shortPath);
/*
* print logging levels
* to disable logging, empty pLog define:
* #undef pLog
* #define pLog
* \param
* level LOG_CRITICAL, LOG_ERROR, LOG_WARNING or LOG_INFO, anything else has log level LOG_INVALID
* \param
* message like printf
*/
#define pLog(level, ...) _pLog(level, __FILE__, __func__, __LINE__, __VA_ARGS__);
void _pLog(int, const char *, const char *, int, const char *, ...);
#define logI(...) pLog(LOG_INFO, __VA_ARGS__)
#define logW(...) pLog(LOG_WARNING, __VA_ARGS__)
#define logE(...) pLog(LOG_ERROR, __VA_ARGS__)
#define logC(...) pLog(LOG_CRITICAL, __VA_ARGS__)
extern uint64_t logMask;
/*
* print mask logging levels
* print logs with a mask in logMask
* normally, mask is 1 bit wide.
* pLogMask allows enabling/disabling groups of logs
* to disable logging, empty pLogMask define:
* #undef pLogMask
* #define pLogMask
* Example:
* #define group1 0x03
* #define group11 0x01
* #define group12 0x02
* #define group2 0x04
* logMask = 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");
* \param
* level LOG_CRITICAL, LOG_ERROR, LOG_WARNING or LOG_INFO, anything else has log level LOG_INVALID
* \param
* message like printf
*/
#define pLogMask(mask, level, ...) if (mask & logMask) pLog(level, __VA_ARGS__)
#define logMI(mask, ...) pLogMask(mask, LOG_INFO, __VA_ARGS__)
#define logMW(mask, ...) pLogMask(mask, LOG_WARNING, __VA_ARGS__)
#define logME(mask, ...) pLogMask(mask, LOG_ERROR, __VA_ARGS__)
#define logMC(mask, ...) pLogMask(mask, LOG_CRITICAL, __VA_ARGS__)
// QSORT
/*
* Copyright (c) 2013, 2017 Alexey Tourbin
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/*
* https://github.com/svpv/qsort.git
* commit 21f056356e901467b7362240dac70edeedfa2b89
*/
/*
* This is a traditional Quicksort implementation which mostly follows
* [Sedgewick 1978]. Sorting is performed entirely on array indices,
* while actual access to the array elements is abstracted out with the
* user-defined `LESS` and `SWAP` primitives.
* Synopsis:
* QSORT(N, LESS, SWAP);
* where
* N - the number of elements in A[];
* LESS(i, j) - compares A[i] to A[j];
* SWAP(i, j) - exchanges A[i] with A[j].
* Examples:
* - int array:
* int A[] = {3,2,1};
* int tmp;
* #define LESS(i, j) A[i] < A[j]
* #define SWAP(i, j) tmp = A[i], A[i] = A[j], A[j] = tmp
* QSORT(3, LESS, SWAP);
* #undef LESS
* #undef SWAP
* - string array/list:
* char **strs = listCreateS("fsd", "sdf", "ffds","asd");
* char *tmp;
* #define LESS(i,j) (strcmp(strs[i], strs[j]) < 0)
* #define SWAP(i,j) tmp = strs[i], strs[i] = strs[j], strs[j] = tmp
* QSORT(listLengthS(strs), LESS, SWAP);
* #undef LESS
* #undef SWAP
*/
/* Sort 3 elements. */
#define Q_SORT3(q_a1, q_a2, q_a3, Q_LESS, Q_SWAP) do {\
/* Partition [q_l,q_r] around a pivot. After partitioning,
* [q_l,q_j] are the elements that are less than or equal to the pivot,
* while [q_i,q_r] are the elements greater than or equal to the pivot. */
#define Q_PARTITION(q_l, q_r, q_i, q_j, Q_UINT, Q_LESS, Q_SWAP) do {\
/* Insertion sort is applied to small subfiles - this is contrary to
* Sedgewick's suggestion to run a separate insertion sort pass after
* the partitioning is done. The reason I don't like a separate pass
* is that it triggers extra comparisons, because it can't see that the
* medians are already in their final positions and need not be rechecked.
* Since I do not assume that comparisons are cheap, I also do not try
* to eliminate the (q_j > q_l) boundary check. */
#define Q_INSERTION_SORT(q_l, q_r, Q_UINT, Q_LESS, Q_SWAP) do {\
/* When the size of [q_l,q_r], i.e. q_r-q_l+1, is greater than or equal to
* Q_THRESH, the algorithm performs recursive partitioning. When the size
* drops below Q_THRESH, the algorithm switches to insertion sort.
* The minimum valid value is probably 5 (with 5 items, the second and
* the middle items, the middle itself being rounded down, are distinct). */
#define Q_THRESH 16
/* The main loop. */
#define Q_LOOP(Q_UINT, Q_N, Q_LESS, Q_SWAP) do {\
/* The missing part: dealing with subfiles.
* Assumes that the first subfile is not smaller than the second. */
#define Q_SUBFILES(q_l1, q_r1, q_l2, q_r2) do {\
/* And now, ladies and gentlemen, may I proudly present to you... */
#define QSORT(Q_N, Q_LESS, Q_SWAP) do {\
// QSORT END
// BINARY SEARCH
/*
* binary search macro
* Synopsis:
* BSEARCH(RESULT_INDEX, SEARCH_ELEMENT, N, LESS, EQUAL);
* where
* RESULT_INDEX - variable holding the result index, signed int type (example: ssize_t),
* declare RESULT_INDEX before calling BSEARCH;
* SEARCH_ELEMENT - element to search in the array;
* N - the number of elements in A[];
* LESS(i, SEARCH_ELEMENT) - compares A[i] to SEARCH_ELEMENT, 1 when less;
* EQUAL(i, SEARCH_ELEMENT) - compares A[i] to SEARCH_ELEMENT, 1 when equal;
* Example:
* int A[] = {1,5,7,9,10,65};
* ssize_t bsr;
* #define LESS(i, se) A[i] < se
* #define EQUAL(i, se) A[i] == se
* BSEARCH(bsr, 9, COUNT_ELEMENTS(A), LESS, EQUAL);
* #undef LESS
* #undef EQUAL
* logVar(bsr,"zd");
*/
#define BSEARCH(RESULT_INDEX, SEARCH_ELEMENT, B_N, B_LESS, B_EQUAL) do {\
// BINARY SEARCH END
// initialize libsheepy (optional, for debug)
typedef void(*initLibsheepyObjectP)(void);
void initLibsheepyF(const char *progPath, initLibsheepyObjectP initF);
#define initLibsheepy(progPath) initLibsheepyF(progPath, NULL)
// free internal buffers at exit
// get current stack limit - returns 0 when error
int64_t getStackLimit(void);
// set stack limit (-1 for unlimited) - returns 0 when error
int setStackLimit(int64_t stackSize);
// get program path as given in the shell
const char *getProgPath(void);
// get real program path, allocates path string internally
const char *getRealProgPath(void);
// free real program path
void freeRealProgPath(void);
// run system command and free command buffer
#define systemNFree(command) systemNFreeF(command, __LINE__, __func__, __FILE__)
int systemNFreeF(char *command, int line, const char *thisFunc, const char *thisFileName);
// get modification time for path
time_t getModificationTime(const char *path);
// set modification time for path
int setModificationTime(const char *path, time_t mtime);
// compare modification times for path1 and path2
bool equalModificationTimes(const char *path1, const char *path2);
// get current unix time
time_t getCurrentUnixTime(void);
// convert date string to unix time
time_t strToUnixTime(const char *date, const char *format);
// convert unix time to string
char *timeToS(const time_t t);
char *bTimeToS(char *dst, const time_t t);
char *bLTimeToS(char *dst, size_t dstSize, const time_t t);
// convert unix time to Y-m-d H:M:S string
char *timeToYMDS(const time_t t);
char *bTimeToYMDS(char *dst, const time_t t);
char *bLTimeToYMDS(char *dst, size_t dstSize, const time_t t);
// get current date in ctime format
char *getCurrentDate(void);
char *bGetCurrentDate(char *dst);
char *bLGetCurrentDate(char *dst, size_t dstSize);
// get current date in Y-m-d H:M:S format
char *getCurrentDateYMD(void);
char *bGetCurrentDateYMD(char *dst);
char *bLGetCurrentDateYMD(char *dst, size_t dstSize);
// dirname
char *shDirname(const char *path);
char *bDirname(char *path);
char *bLDirname(char *path, size_t pathSize);
// expand home ~/
char *expandHome(const char *path);
char *iExpandHome(char **path);
char *bExpandHome(char *path);
char *bLExpandHome(char *path, size_t pathSize);
// normalize path
char *normalizePath(const char *path);
char *iNormalizePath(char **path);
char *bNormalizePath(char *path);
char *bLNormalizePath(char *path, size_t pathSize);
// get home path
char *getHomePath(void);
char *bGetHomePath(char *path);
char *bLGetHomePath(char *path, size_t pathSize);
const char *getCHomePath(void);
// get current working directory
char *getCwd(void);
char *bLGetCwd(char *path, size_t pathSize);
// change directory
int chDir(const char *path);
// true when path is directory
bool isDir(const char *path);
// read link to a new string
char *shReadlink(const char *path);
// read link chain to the end to a new string
char *endlink(const char *path);
// true when path is symbolic link
bool isLink(const char *path);
// file and dir exists
bool fileExists(const char *filePath);
// chmod "721"
bool fileChmod(const char *filePath, mode_t mode);
// file size
ssize_t fileSize(const char *filePath);
ssize_t fileSizeFP(FILE *fp);
// read file
void *readFileToS(const char *filePath);
void *bReadFileToS(const char *filePath, void *dst);
void *bLReadFileToS(const char *filePath, void *dst, size_t dstSize);
ssize_t readFile(const char *filePath, void **buffer);
ssize_t bReadFile(const char *filePath, void *buffer);
ssize_t bLReadFile(const char *filePath, void *buffer, size_t dstSize);
void *readStreamToS(FILE *fp);
void *bReadStreamToS(FILE *fp, void *dst);
void *bLReadStreamToS(FILE *fp, void *dst, size_t dstSize);
// write file
int writeFileS(const char *filePath, const char *string);
int writeFile(const char *filePath, void *buffer, size_t len);
int writeStreamS(FILE *fp, const char *string);
int writeLStream(FILE *fp, void *buffer, size_t len);
// append string to file
bool appendFileS(const char *filePath, const char *string);
bool appendFile(const char *filePath, void *buffer, size_t len);
// walkDir lists files only
char **walkDir(const char* dirPath);
// walkDirDir lists directories
char **walkDirDir(const char* dirPath);
// readDir lists files in a directory
char **readDir(const char *dirPath);
// readDirDir lists directories in a directory
char **readDirDir(const char *dirPath);
// walkDirAll lists files and directories
char **walkDirAll(const char* dirPath);
// readDirAll lists files and directories in a directory
char **readDirAll(const char *dirPath);
// get umask
mode_t getumask(void);
// get current permissions for creating directories
mode_t getCurrentPermissions(void);
// recursive mkdir
int mkdirParents(const char* path);
// delete files and directories
int rmAll(const char* path);
// copy files recursively
int copy(const char* src, const char* dst);
// rename file
int shRename(const char* src, const char* dst);
// move files recursively
int shMove(const char* src, const char* dst);
// use /dev/urandom as a source of random numbers
void setSoftwareRandom(void);
// use cpu random instruction as a source of random numbers
void setHardwareRandom(void);
// open /dev/urandom in libsheepy
// close /dev/urandom in libsheepy
void randomUrandomClose(void);
// return random 64 bit unsigned integer
uint64_t randomWord(void);
// return random 64 bit unsigned integer from the cpu
uint64_t randomWordFromHW(void);
// return a random value between 0 and range 0<=value<range
uint64_t randomChoice(uint64_t range);
// generate random string
char *randomS(uint64_t length);
char *bRandomS(char *dst, size_t length);
// generate random alpha numerical string
char *randomAlphaNumS(uint64_t length);
char *bRandomAlphaNumS(char *dst, size_t dstSize);
// read user input (one line) as a string
char *readS(void);
char *bLReadS(char *dst, size_t dstSize);
// read hidden password as a string - like getpass
char *readPasswordS(void);
// write zero to all bytes in string with memset, for clearing password buffers
bool zeroS(char *string);
// write zero to all bytes in buffer with memset
bool zeroBuf(void *buf, size_t len);
// wait until press the enter key
void readEnter(void);
// TODO writeLine - copy cg_c code
// readLine
char *readLine(FILE *fp);
// convert char to string by declaring string dst with c in it
#define charToS(dst, c) \
// free many char*
void freeManySF(char *paramType, ...);
#define freeManyS(...) freeManySF("", __VA_ARGS__, NULL)
// duplicate string
char *dupS(const char *string);
// print like printf, the formating can be NULL
void shPrintfS(const char *fmt, ...);
// stderr printf, the formating can be NULL
void shEPrintfS(const char *fmt, ...);
// print and free s
void logNFree(char *s);
// print buf as hexadecimal
void loghex(const void *buf, size_t len);
// print new line
#define put puts("");
// copy src to dst
char *strCpy(char *dst, const char *src);
// copy string to buffer given string length: strNCpy(buffer, string, lenS(string));
// null safe version of strncpy
char *strNCpy(char *dst, const char *src, size_t srcSize);
char *strLCpy(char *dst, size_t dstSize, const char *src);
// concatenate src to dst
char *strCat(char *dst, const char *src);
char *strNCat(char *dst, const char *src, size_t srcLen);
char *strLCat(char *dst, size_t dstSize, const char *src);
char *strLNCat(char *dst, size_t dstSize, const char *src, size_t srcLen);
// cat: f("qwd ", str," werr ", str2)
char *catSF(const char *paramType, ...);
#define catS(...) catSF("", __VA_ARGS__, NULL)
// cat and copy result to dst buffer
char *iCatSF(char *dst, const char *paramType, ...);
#define iCatS(dst, ...) iCatSF(dst, "", __VA_ARGS__, NULL)
#define bCatS iCatS
char *bLCatSF(char *dst, size_t dstSize, const char *paramType, ...);
#define bLCatS(dst, dstSize, ...) bLCatSF(dst, dstSize, "", __VA_ARGS__, NULL)
// allocate and format string using asprintf
char *formatS(const char *fmt, ...);
#define bFormatS sprintf
#define bLFormatS snprintf
// append strings
char *appendS(const char *string1, const char *string2);
char *appendCharS(const char *string1, char c);
char *appendSChar(char c, const char *string2);
char *iAppendS(char **string1, const char *string2);
char *iAppendCharS(char **string1, char c);
char *iAppendNFreeS(char **string1, char *string2);
char *iAppendManySF(char **string, const char *paramType, ...);
#define iAppendManyS(s, s1, ...) iAppendManySF(s, s1, __VA_ARGS__, NULL)
char *bAppendManySF(char *string, const char *paramType, ...);
#define bAppendManyS(s, s1, ...) bAppendManySF(s, s1, __VA_ARGS__, NULL)
char *bLAppendManySF(char *string, size_t stringSize, const char *paramType, ...);
#define bLAppendManyS(s, sSize, s1, ...) bLAppendManySF(s, sSize, s1, __VA_ARGS__, NULL)
// prepend string
char *prependS(const char *string1, const char *string2);
char *prependCharS(const char *string1, char c);
char *prependSChar(char c, const char *string2);
char *iPrependS(char **string1, const char *string2);
char *iPrependCharS(char **string1, char c);
char *iPrependNFreeS(char **string1, char *string2);
char *bPrependS(char *string1, const char *string2);
char *bLPrependS(char *string1, size_t string1Size, const char *string2);
// string replace
char *replaceS(const char *s, const char *olds, const char *news, size_t max);
char *replaceCharSS(const char *s, char olds, const char *news, size_t max);
char *replaceSCharS(const char *s, const char *olds, char news, size_t max);
char *replaceCharCharS(const char *s, char olds, char news, size_t max);
#define replaceS_max(s,olds,news) replaceS(s,olds,news, 0)
char* iReplaceS(char **s, const char *olds, const char *news, size_t max);
char* iReplaceCharSS(char **s, char olds, const char *news, size_t max);
char* iReplaceSCharS(char **s, const char *olds, char news, size_t max);
char* iReplaceCharCharS(char **s, char olds, char news, size_t max);
#define iReplaceS_max(s,olds,news) iReplaceS(s,olds,news, 0)
char* bReplaceS(char *s, const char *olds, const char *news, size_t max);
#define bReplaceS_max(s,olds,news) bReplaceS(s,olds,news, 0)
char* bLReplaceS(char *s, size_t sSize, const char *olds, const char *news, size_t max);
#define bLReplaceS_max(s,sSize,olds,news) bLReplaceS(s,sSize,olds,news, 0)
// string replace many olds with news (s, olds1, news1, olds2, news2,...)
char *replaceManySF(const char *paramType, ...);
#define replaceManyS(s, ...) replaceManySF(s, __VA_ARGS__, NULL)
char *iReplaceManySF(char **string, char *paramType, ...);
#define iReplaceManyS(s, olds, ...) iReplaceManySF(s, olds, __VA_ARGS__, NULL)
char *bReplaceManySF(char *s, char *paramType, ...);
#define bReplaceManyS(s, olds, ...) bReplaceManySF(s, olds, __VA_ARGS__, NULL)
char *bLReplaceManySF(char *s, size_t sSize, char *paramType, ...);
#define bLReplaceManyS(s, sSize, olds, ...) bLReplaceManySF(s, sSize, olds, __VA_ARGS__, NULL)
// ignore case string replace
char *icReplaceS(const char *s, const char *olds, const char *news, size_t max);
char *icReplaceCharSS(const char *s, char olds, const char *news, size_t max);
char *icReplaceSCharS(const char *s, const char *olds, char news, size_t max);
char *icReplaceCharCharS(const char *s, char olds, char news, size_t max);
#define icReplaceS_max(s,olds,news) icReplaceS(s,olds,news, 0)
char* iicReplaceS(char **s, const char *olds, const char *news, size_t max);
char* iicReplaceCharSS(char **s, char olds, const char *news, size_t max);
char* iicReplaceSCharS(char **s, const char *olds, char news, size_t max);
char* iicReplaceCharCharS(char **s, char olds, char news, size_t max);
#define iicReplaceS_max(s,olds,news) iicReplaceS(s,olds,news, 0)
char* bicReplaceS(char *s, const char *olds, const char *news, size_t max);
#define bicReplaceS_max(s,olds,news) bicReplaceS(s,olds,news, 0)
char* bLicReplaceS(char *s, size_t sSize, const char *olds, const char *news, size_t max);
#define bLicReplaceS_max(s,sSize,olds,news) bLicReplaceS(s,sSize,olds,news, 0)
// string replace many olds with news (s, olds1, news1, olds2, news2,...)
char *icReplaceManySF(const char *paramType, ...);
#define icReplaceManyS(s, ...) icReplaceManySF(s, __VA_ARGS__, NULL)
char *iicReplaceManySF(char **string, char *paramType, ...);
#define iicReplaceManyS(s, olds, ...) iicReplaceManySF(s, olds, __VA_ARGS__, NULL)
char *bicReplaceManySF(char *s, char *paramType, ...);
#define bicReplaceManyS(s, olds, ...) bicReplaceManySF(s, olds, __VA_ARGS__, NULL)
char *bLicReplaceManySF(char *s, size_t sSize, char *paramType, ...);
#define bLicReplaceManyS(s, sSize, olds, ...) bLicReplaceManySF(s, sSize, olds, __VA_ARGS__, NULL)
// string equal (compare content)
bool eqS(const char *string1, const char *string2);
#define strEq eqS
bool eqCharS(char c, const char *string2);
bool eqSChar(const char *string1, char c);
// string equal at index (compare content)
bool eqIS(const char *string1, const char *string2, intmax_t index);
#define strIEq eqIS
bool eqICharS(const char *string1, char c, intmax_t index);
// look for string2 at string1 start
bool startsWithS(const char *string1, const char *string2);
bool startsWithCharS(const char *string1, char c);
// look for string2 at string1 end
bool endsWithS(const char *string1, const char *string2);
bool endsWithCharS(const char *string1, char c);
// count number of (non-overlapping) occurrences of a substring
ssize_t countS(const char *s, const char *needle);
ssize_t countCharS(const char *s, char c);
// ignore case string equal (compare content)
bool icEqS(const char *string1, const char *string2);
bool icEqCharS(char c, const char *string2);
bool icEqSChar(const char *string1, char c);
// ignore case string equal at index (compare content)
bool icEqIS(const char *string1, const char *string2, intmax_t index);
bool icEqICharS(const char *string1, char c, intmax_t index);
// ignore case and look for string2 at string1 start
bool icStartsWithS(const char *string1, const char *string2);
bool icStartsWithCharS(const char *string1, char c);
// ignore case look for string2 at string1 end
bool icEndsWithS(const char *string1, const char *string2);
bool icEndsWithCharS(const char *string1, char c);
// ignore case and count number of (non-overlapping) occurrences of a substring
ssize_t icCountS(const char *s, const char *needle);
ssize_t icCountCharS(const char *s, char c);
// has terminal control char (for example colors)
bool hasCtrlChar(const char *string);
// true when string is a number (integer or float)
bool isNumber(const char *string);
// true when string is an integer
bool isInt(const char *string);
// parseInt
intmax_t parseInt(const char *string);
intmax_t parseIntChar(char c);
// parseDouble
double parseDouble(const char *string);
double parseDoubleChar(char c);
// parse hexadecimal string: 0xff
uint64_t parseHex(const char *string);
// TODO parseHexChar
// convert int to string
char *intToS(intmax_t n);
char *bIntToS(char *s, intmax_t n);
// convert double to string
char *doubleToS(double n);
char *bDoubleToS(char *s, double n);
// length
size_t lenS(const char *string);
/*
* upper case and store the result in c and return the result
*/
#define toUpper(c) ((c) = toupper(c), c)
// duplicate and upper case
char *upperS(const char *string);
char *iUpperS(char **string);
char *bUpperS(char *string);
/*
* lower case and store the result in c and return the result
*/
#define toLower(c) ((c) = tolower(c), c)
// duplicate and lower case
char *lowerS(const char *string);
char *iLowerS(char **string);
char *bLowerS(char *string);
// duplicate and trim
char *trimS(const char *string);
char *iTrimS(char **string);
char *bTrimS(char *string);
char *lTrimS(const char *string);
char *iLTrimS(char **string);
char *bLTrimS(char *string);
char *rTrimS(const char *string);
char *iRTrimS(char **string);
char *bRTrimS(char *string);
// remove successive repetitions of char c
char *uniqS(const char *string, char c);
char *iUniqS(char **string, char c);
char *bUniqS(char *string, char c);
#define uniqSlash(s) uniqS(s, '/')
#define iUniqSlash(s) iUniqS(&(s), '/')
#define bUniqSlash(s) bUniqS(s, '/')
// ignore case and remove successive repetitions of char c
char *icUniqS(const char *string, char c);
char *iicUniqS(char **string, char c);
char *bicUniqS(char *string, char c);
// get char at python index
char getS(const char *string, intmax_t index);
// set char at python index
char *setS(char *string, intmax_t index, char c);
// slice string
// function to slice parts of a string [1:10] - python style indexes 0..len-1 -1..-len+1
char *sliceS(const char *string, intmax_t start, intmax_t end);
char *iSliceS(char **string, intmax_t start, intmax_t end);
char *bSliceS(char *string, intmax_t start, intmax_t end);
char *bLSliceS(char *string, size_t stringSize, intmax_t start, intmax_t end);
// insert string in string
char *insertS(const char *string, intmax_t index, const char *toInsert);
char *insertNFreeS(const char *string, intmax_t index, char *toInsert);
char *iInsertS(char **string, intmax_t index, const char *toInsert);
char *iInsertNFreeS(char **string, intmax_t index, char *toInsert);
char *bInsertS(char *string, intmax_t index, const char *toInsert);
char *bLInsertS(char *string, size_t stringSize, intmax_t index, const char *toInsert);
// inject a char in string
char *injectS(const char *string, intmax_t index, char toInject);
char *iInjectS(char **string, intmax_t index, char toInject);
char *bInjectS(char *string, intmax_t index, char toInject);
char *bLInjectS(char *string, size_t stringSize, intmax_t index, char toInject);
// del string
// function to delete parts of a string [1:10] - python style indexes 0..len-1 -1..-len+1
char *delS(const char *string, intmax_t start, intmax_t end);
char *iDelS(char **string, intmax_t start, intmax_t end);
char *bDelS(char *string, intmax_t start, intmax_t end);
char *bLDelS(char *string, size_t stringSize, intmax_t start, intmax_t end);
// del a character in string
char *delElemS(const char *string, intmax_t index);
char *iDelElemS(char **string, intmax_t index);
char *bDelElemS(char *string, intmax_t index);
char *bLDelElemS(char *string, size_t stringSize, intmax_t index);
// find substring
char *findS(const char *string, const char *needle);
char *findCharS(const char *string, char c);
ssize_t indexOfS(const char *string, const char *needle);
ssize_t indexOfCharS(const char *string, char c);
// true when needle is found
bool hasS(const char *string, const char *needle);
bool hasCharS(const char *string, char c);
// ignore case find substring
char *icFindS(const char *string, const char *needle);
char *icFindCharS(const char *string, char c);
ssize_t icIndexOfS(const char *string, const char *needle);
ssize_t icIndexOfCharS(const char *string, char c);
// ignore case, true when needle is found
bool icHasS(const char *string, const char *needle);
bool icHasCharS(const char *string, char c);
// parse s string with delim - work like strtok_r from stdlib
char *tokS(const char *s, const char *delim, char **saveptr);
// ignore case and parse s string with delim - work like strtok_r from stdlib
char *icTokS(const char *s, const char *delim, char **saveptr);
//
// UTF8 string functions
//
// rune is a 32 bit unicode integer
typedef int rune;
// character length of UTF-8 encoded string
size_t lenUTF8(const char *s);
size_t bLLenUTF8(const char *s, size_t maxSize);
// is string valid UTF-8 encoded string
bool isUTF8(const char * string);
bool bLIsUTF8(const char * string, size_t stringSize);
// is string a valid UTF-8 code point
bool isCodeUTF8(const char *code);
extern const uint8_t codeSzUTF8[256];
#define codeSizeUTF8(utf8) codeSzUTF8[*(const uint8_t *)(utf8)]
#define nextCodeUTF8(utf8) (char *)((utf8) + codeSizeUTF8(utf8))
#define nxtCodeUTF8(utf8) EVA(utf8, nextCodeUTF8(utf8))
#define nxCodeUTF8(utf8) (utf8 = nextCodeUTF8(utf8))
// next code point, works only when utf8 points to a valid code point
char *nextUTF8(const char *utf8);
char *bLNextUTF8(const char *string, size_t utf8Size, const char *utf8);
// find next code point even when utf8 points inside a code point
char *findNextUTF8(const char *string, size_t utf8Size, const char *utf8);
// previous code point, undefined behavior when utf8 points to the start of the string
char *prevUTF8(const char *utf8);
// previous code point
char *bPrevUTF8(const char *string, const char *utf8);
// character index to pointer
char *idx2PtrUTF8(const char *utf8, intmax_t index);
char *bLIdx2PtrUTF8(const char *utf8, size_t utf8Size, intmax_t index);
// pointer to character index
intmax_t ptr2IdxUTF8(const char *utf8, const char *pos);
intmax_t bPtr2IdxUTF8(const char *start, const char *utf8, const char *pos);
intmax_t bLPtr2IdxUTF8(const char *utf8, size_t utf8Size, const char *pos);
intmax_t bLPtr2NegIdxUTF8(const char *utf8, size_t utf8Size, const char *pos);
// make new valid UTF-8 encoded string
char *makeValidUTF8(const char *utf8);
// make utf8 a valid UTF-8 encoded string
char *bMakeValidUTF8(char *utf8);
char *nMakeValidUTF8(const char *utf8, size_t utf8Len);
char *bNMakeValidUTF8(char *dst, const char *utf8, size_t utf8Len);
char *bLMakeValidUTF8(char *dst, size_t dstSize, const char *utf8);
char *bLNMakeValidUTF8(char *dst, size_t dstSize, const char *utf8, size_t utf8Len);
// strncpy where srcLen is number of characters
char *strNCpyUTF8(char *dst, const char *src, size_t srcLen);
// strLCpy for UTF-8 encoded strings
char *strLCpyUTF8(char *dst, size_t dstSize, const char *src);
// strncat where srcLen is number of characters
char *strNCatUTF8(char *dst, const char *src, size_t srcLen);
// strLCat for UTF-8 encoded strings
char *strLCatUTF8(char *dst, size_t dstSize, const char *src);
// strLNCat for UTF-8 encoded strings
char *strLNCatUTF8(char *dst, size_t dstSize, const char *src, size_t srcLen);
// TODO
char* icReplaceUTF8(const char *s, const char *olds, const char *news, size_t max);
// TODO
char *icReplaceCharSUTF8(const char *s, char olds, const char *news, size_t max);
// TODO
char *icReplaceSCharUTF8(const char *s, const char *olds, char news, size_t max);
// TODO
char* iicReplaceUTF8(char **s, const char *olds, const char *news, size_t max);
// TODO
char *iicReplaceCharSUTF8(char **s, char olds, const char *news, size_t max);
// TODO
char *iicReplaceSCharUTF8(char **s, const char *olds, char news, size_t max);
// TODO
char* bicReplaceUTF8(char *s, const char *olds, const char *news, size_t max);
// TODO
char* bLicReplaceUTF8(char *s, size_t sSize, const char *olds, const char *news, size_t max);
// TODO
char *icReplaceManyUTF8F(const char *paramType, ...);
// TODO
char *iicReplaceManyUTF8F(char **s, char *paramType, ...);
// TODO
char *bicReplaceManyUTF8F(char *s, char *paramType, ...);
// TODO
char *bLicReplaceManyUTF8F(char *s, size_t sSize, char *paramType, ...);
// UTF8 encoded string Index Equal
bool eqIUTF8(const char *string1, const char *string2, intmax_t index);
// UTF8 encoded string Index Equal
bool eqICharUTF8(const char *string1, char c, intmax_t index);
// ignore case UTF8 encoded string Equal
bool icEqUTF8(const char *string1, const char *string2);
bool icEqCharUTF8(char c, const char *string2);
bool icEqUTF8Char(const char *string1, char c);
// TODO
bool icEqIUTF8(const char *string1, const char *string2, intmax_t index);
// TODO
bool icEqICharUTF8(const char *string1, char c, intmax_t index);
// starts with for UTF-8 encoded string
bool icStartsWithUTF8(const char *string1, const char *string2);
// ends with for UTF-8 encoded string
bool icEndsWithUTF8(const char *string1, const char *string2);
// ignore case count UTF8 encoded String
ssize_t icCountUTF8(const char *s, const char *needle);
// UTF-8 code point to rune
rune code2RuneUTF8(const char *code);
rune code2RuneLUTF8(const char *code, uint8_t *n);
// rune to UTF-8 code point
size_t bRune2CodeUTF8(char *dst, rune c);
// rune length as UTF-8 code point
uint8_t runeLenUTF8(rune r);
// rune toupper UTF8
rune toupperUTF8(rune c);
// upper case UTF-8 encoded string
char *upperUTF8(const char *string);
char *iUpperUTF8(char **string);
// TODO
char *bUpperUTF8(char *string);
// rune tolower UTF8
rune tolowerUTF8(rune c);
// lower case UTF-8 String
char *lowerUTF8(const char *string);
char *iLowerUTF8(char **string);
// TODO
char *bLowerUTF8(char *string);
// transform UTF-8 string to make it comparable regardless of case
char *casefoldUTF8(const char *utf8);
// uniquify code point in UTF-8 String
char *uniqUTF8(const char *string, const char *code);
char *iUniqUTF8(char **string, const char *code);
char *bUniqUTF8(char *string, const char *code);
// TODO
char *icUniqUTF8(const char *string, const char *code);
// TODO
char *iicUniqUTF8(char **string, const char *code);
// TODO
char *bicUniqUTF8(char *string, char c);
// get rune in UTF8 encoded string
rune getUTF8(const char *string, intmax_t index);
// TODO
char *setUTF8(char *string, intmax_t index, rune c);
// slice UTF8 encoded String
char *sliceUTF8(const char *string, intmax_t start, intmax_t end);
char *iSliceUTF8(char **string, intmax_t start, intmax_t end);
char *bSliceUTF8(char *string, intmax_t start, intmax_t end);
char *bLSliceUTF8(char *string, size_t stringSize, intmax_t start, intmax_t end);
// insert string in UTF8 encoded string at index
char *insertUTF8(const char *string, intmax_t index, const char *toInsert);
char *insertNFreeUTF8(const char *string, intmax_t index, char *toInsert);
char *iInsertUTF8(char **string, intmax_t index, const char *toInsert);
char *iInsertNFreeUTF8(char **string, intmax_t index, char *toInsert);
char *bInsertUTF8(char *string, intmax_t index, const char *toInsert);
char *bLInsertUTF8(char *string, size_t stringSize, intmax_t index, const char *toInsert);
// delete UTF8 encoded string
char *delUTF8(const char *string, intmax_t start, intmax_t end);
char *iDelUTF8(char **string, intmax_t start, intmax_t end);
char *bDelUTF8(char *string, intmax_t start, intmax_t end);
char *bLDelUTF8(char *string, size_t stringSize, intmax_t start, intmax_t end);
// indexOf UTF8 encoded String
ssize_t indexOfUTF8(const char *string, const char *needle);
// TODO
ssize_t icIndexOfUTF8(const char *string, const char *needle);
// ignore case has UTF8 encoded String
bool icHasUTF8(const char *string, const char *needle);
// TODO
char *icTokUTF8(const char *s, const char *delim, char **saveptr);
// TODO
char **icExtractUTF8(const char *string, const char* delim1, const char* delim2);
char **icExtractCharSUTF8(const char *string, char delim1, const char* delim2);
char **icExtractSCharUTF8(const char *string, const char* delim1, char delim2);
// ignore case list Sort UTF8 encoded String
char **icListSortUTF8(char **list);
char **iicListSortUTF8(char ***list);
// ignore case list Equal UTF8 encoded String
bool icListEqUTF8(char **list1, char **list2);
// ignore case and return true when list has UTF8 encoded string
bool icListHasUTF8(char **list, const char *string);
// ignore case and return index of UTF8 encoded string in list
ssize_t icListIndexOfUTF8(char **list, const char *string);
// ignore case list binary search UTF8 encoded string
ssize_t icListBinarySearchUTF8(char **list, const char *string);
// ignore case and uniquify UTF8 encoded elements of list
char **icListUniqUTF8(char **list);
char **iicListUniqUTF8(char ***list);
//
// End UTF8 string functions
//
// create empty string
#define emptyS(string) \
char *emptySF(void);
char *iEmptySF(char **string);
// string buffer empty - set 0 at index 0
#define bEmptyS(string) \
// is empty string
bool isEmptyS(const char *string);
/*
* orS - if string is empty, the value is alternative
*/
#define orS(string, alternative) \
// true when string is empty or white spaces
bool isBlankS(const char *string);
/*
* blankS - if string is blank(white spaces) or empty, the value is alternative
*/
#define orBlankS(string, alternative) \
/*
* nS - null String - replace null string with "" string (empty string)
*/
#define nS(string) \
// convert python index (int, positive and negative) to always positive index (uint), this function is more generic than listIntIndexS
ssize_t intIndex(intmax_t index, intmax_t length);
// create empty list
#define listEmptyS(list) \
char **listEmptySF(void);
char **iListEmptySF(char ***list);
// false when there are elements in the list
bool listIsEmptyS(char **list);
// false when there are non blank elements in the list
bool listIsBlankS(char **list);
// String Lists
// createList(...)
char **listCreateSF(const char *paramType, ...);
#define listCreateS(...) listCreateSF("", __VA_ARGS__, NULL)
// copy array to new list
char **listFromArrayS(char **array, size_t size);
// push and pop (append) str
// modifies the list
char **listPushS(char ***list, const char *s);
char **listPushCharS(char ***list, char c);
char **iListPushS(char ***list, char *s);
// copy last string and free it in the list
char *listPopS(char ***list);
// prepend and dequeue (append) str
// modifies the list
char **listPrependS(char ***list, const char *s);
char **listPrependCharS(char ***list, char c);
char **iListPrependS(char ***list, char *s);
// copy fist string and free it in the list
char *listDequeueS(char ***list);
// freeList
void listFreeS(char **list);
// free many char**
void listFreeManySF(char **paramType, ...);
#define listFreeManyS(...) listFreeManySF(NULL, __VA_ARGS__, NULL)
// length
size_t listLengthS(char **list);
// convert python index (int) to always positive index (uint)
ssize_t listIntIndexS(char **list, intmax_t index);
// pointer to the char* at python index
char **listAddrS(char **list, intmax_t index);
// list get - get a string at python index
char *listGetS(char **list, intmax_t index);
char *iListGetS(char **list, intmax_t index);
// list set - replace a string at python index
char **listSetS(char **list, intmax_t index, const char *s);
char **listSetCharS(char **list, intmax_t index, char c);
char **iListSetS(char **list, intmax_t index, char *s);
// split
char **split(const char *string, const char* delim);
char **splitChar(const char *string, char delim);
// ignore case split
char **icSplit(const char *string, const char* delim);
char **icSplitChar(const char *string, char delim);
// join
char *join(char **list, const char* delim);
char *joinChar(char **list, char delim);
char *bJoin(char *string, char **list, const char* delim);
char *bJoinChar(char *string, char **list, char delim);
char *bLJoin(char *string, size_t stringSize, char **list, const char* delim);
char *bLJoinChar(char *string, size_t stringSize, char **list, char delim);
// extract string
char **extractS(const char *string, const char* delim1, const char* delim2);
char **extractCharSS(const char *string, char delim1, const char* delim2);
char **extractSCharS(const char *string, const char* delim1, char delim2);
char **extractCharCharS(const char *string, char delim1, char delim2);
// ignore case extract string
char **icExtractS(const char *string, const char* delim1, const char* delim2);
char **icExtractCharSS(const char *string, char delim1, const char* delim2);
char **icExtractSCharS(const char *string, const char* delim1, char delim2);
char **icExtractCharCharS(const char *string, char delim1, char delim2);
// duplicate list
char **listDupS(char **list);
char **iListDupS(char **list);
// duplicate and reverse list
char **listReverseS(char **list);
char **iListReverseS(char ***list);
// listCatS: f(l1, l2, l3)
char **listCatSF(char **paramType, ...);
#define listCatS(...) listCatSF(NULL, __VA_ARGS__, NULL)
// append lists
char **listAppendS(char ***list1, char **list2);
char **iListAppendS(char ***list1, char **list2);
char **iListAppendNSmashS(char ***list1, char **list2);
// add lists
char **listAddS(char **list1, char **list2);
// slice - python style indexes 0..len-1 -1..-len+1
char **listSliceS(char **list, intmax_t start, intmax_t end);
char **iListCopyS(char **list, intmax_t start, intmax_t end);
char **iListSliceS(char ***list, intmax_t start, intmax_t end);
// insert list in list
char **listInsertS(char **list, intmax_t index, char **toInsert);
char **iListInsertS(char ***list, intmax_t index, char **toInsert);
char **iListInsertNFreeS(char ***list, intmax_t index, char **toInsert);
// inject string in list
char **listInjectS(char **list, intmax_t index, char *toInject);
char **listInjectCharS(char **list, intmax_t index, char toInject);
char **iListInjectS(char ***list, intmax_t index, char *toInject);
// del - python style indexes 0..len-1 -1..-len+1
char **listDelS(char **list, intmax_t start, intmax_t end);
char **iListDelS(char ***list, intmax_t start, intmax_t end);
// del element in list
char **listDelElemS(char **list, intmax_t index);
char **iListDelElemS(char ***list, intmax_t index);
// print list
int listPrintS(char **list);
/*
* forever loop
*/
#define forever while(1)
/*
* range loop
* ;size_t UNIQVAR needed to avoid: error: a label can only be part of a statement and a declaration is not a statement
* on older compilers
*/
#define range(index, maxCount) \
/*
* infinity loop
* increase the index infinitly
*/
#define rangeInf(index) \
/*
* range down loop, index is ssize_t
*/
#define rangeDown(index, maxCount) \
/*
* range down loop to to index, index is ssize_t
* ;ssize_t UNIQVAR needed to avoid: error: a label can only be part of a statement and a declaration is not a statement
* on older compilers
*/
#define rangeDownTo(index, maxCount, to) \
/*
* range loop starting at value from
* ;size_t UNIQVAR needed to avoid: error: a label can only be part of a statement and a declaration is not a statement
* on older compilers
*/
#define rangeFrom(index, from, maxCount) \
/*
* range from value from to maxCount-1 then from 0 to from-1
* Example:
* circular(i, 2, 4)
* counts: 2, 3, 0, 1
* ;bool UNIQVAR needed to avoid: error: a label can only be part of a statement and a declaration is not a statement
* on older compilers
*/
#define circular(index, from, maxCount) \
/*
* range from value from down to 0 then from maxCount-1 to from+1
* Example:
* circularDown(i, 2, 4)
* counts: 2, 1, 0, 3
* ;bool UNIQVAR needed to avoid: error: a label can only be part of a statement and a declaration is not a statement
* on older compilers
*/
#define circularDown(index, from, maxCount) \
/*
* range step loop
* ;size_t UNIQVAR needed to avoid: error: a label can only be part of a statement and a declaration is not a statement
* on older compilers
*/
#define rangeStep(index, maxCount, step) \
/*
* range down setp loop, index is int64_t
*/
#define rangeDownStep(index, maxCount, step) \
/*
* range step loop starting at value from
* ;size_t UNIQVAR needed to avoid: error: a label can only be part of a statement and a declaration is not a statement
* on older compilers
*/
#define rangeFromStep(index, from, maxCount, step) \
/*
* loops without index
* ;size_t UNIQVAR needed to avoid: error: a label can only be part of a statement and a declaration is not a statement
* on older compilers
*/
#define loop(maxCount) \
/*
* loop to to index
* ;ssize_t UNIQVAR needed to avoid: error: a label can only be part of a statement and a declaration is not a statement
* on older compilers
*/
#define loopDownTo(maxCount, to) \
/*
* loop starting at value from
* ;size_t UNIQVAR needed to avoid: error: a label can only be part of a statement and a declaration is not a statement
* on older compilers
*/
#define loopFrom(from, maxCount) \
/*
* step loop
* ;size_t UNIQVAR needed to avoid: error: a label can only be part of a statement and a declaration is not a statement
* on older compilers
*/
#define loopStep(maxCount, step) \
/*
* step loop starting at value from
* ;size_t UNIQVAR needed to avoid: error: a label can only be part of a statement and a declaration is not a statement
* on older compilers
*/
#define loopFromStep(from, maxCount, step) \
/*
* forEach - loop macro on list indexes
* to access the element in the loop, use *element
*/
#define forEachCharP(list, element) \
/*
* forEach - loop macro on list indexes
* to acess the element in the loop, use element
* ;size_t UNIQVAR needed to avoid: error: a label can only be part of a statement and a declaration is not a statement
* on older compilers
*/
#define forEachS(list, element) \
/*
* forEach - loop macro on list indexes
*/
#define forEachType(type, list, element) \
/*
* enumerateCharP list
* to access the element in the loop, use *element
* ;size_t UNIQVAR needed to avoid: error: a label can only be part of a statement and a declaration is not a statement
* on older compilers
*/
#define enumerateCharP(list, element, index) \
/*
* enumerateCharP list
* to acess the element in the loop, use element
* ;size_t UNIQVAR needed to avoid: error: a label can only be part of a statement and a declaration is not a statement
* on older compilers
*/
#define enumerateS(list, element, index) \
/*
* enumerateCharP list
* ;size_t UNIQVAR needed to avoid: error: a label can only be part of a statement and a declaration is not a statement
* on older compilers
*/
#define enumerateType(type, list, element, index) \
/*
* loop for linked lists from startNode to last
* node must be a pointer to a struct with a next member pointing
* to the next node in the list
* when node->next is NULL, the list end is reached
*/
#define lForEach(node, startNode)\
/*
* loop for linked lists from startNode to head
* node must be a pointer to a struct with a prev member pointing
* to the previous node in the list
* when node->prev is NULL, the list head is reached
*/
#define lForEachDown(node, startNode)\
#define lForEachPrev lForEachDown
// user defined function for sort functions
typedef int (*shCmpt)(const void * a, const void * b);
// duplicate and sort
char **listSortS(char **list);
char **iListSortS(char ***list);
char **listSortFS(char **list, shCmpt compareFunction);
char **iListSortFS(char ***list, shCmpt compareFunction);
// ignore case, duplicate and sort
char **icListSortS(char **list);
char **iicListSortS(char ***list);
// open text file and return lines in list
char **readText(const char *filePath);
// read opened text file and return lines in list
// the file is left open
char **readStream(FILE *fp);
// write text file
bool writeText(const char *filePath, char **list);
// write buffer
bool writeStream(FILE *fp, char **list);
// append text to file
bool appendText(const char *filePath, char **list);
// execOut
char **execOut(const char *cmd);
// convenience define
#define systemOut execOut
// system command with formatting
char **systemOutf(const char *fmt, ...);
// convenience define
#define execOutf systemOutf
int systemf(const char *fmt, ...);
// compare lists
bool listEqS(char **list1, char **list2);
// has
bool listHasS(char **list, const char *string);
bool listHasCharS(char **list, char c);
// indexOf
ssize_t listIndexOfS(char **list, const char *string);
ssize_t listIndexOfCharS(char **list, char c);
// list binary search string
ssize_t listBinarySearchS(char **list, const char *string);
ssize_t listBinarySearchCharS(char **list, char c);
// duplicate and uniquify
char **listUniqS(char **list);
char **iListUniqS(char ***list);
// ignore case and compare lists
bool icListEqS(char **list1, char **list2);
// ignore case has
bool icListHasS(char **list, const char *string);
bool icListHasCharS(char **list, char c);
// ignore case indexOf
ssize_t icListIndexOfS(char **list, const char *string);
ssize_t icListIndexOfCharS(char **list, char c);
// ignore case list binary search string
ssize_t icListBinarySearchS(char **list, const char *string);
ssize_t icListBinarySearchCharS(char **list, char c);
// ignore case, duplicate and uniquify
char **icListUniqS(char **list);
char **iicListUniqS(char ***list);
// duplicate and compact
char **listCompactS(char **list);
char **iListCompactS(char ***list);
void btraceEnable(void);
void btraceDisable(void);
bool btraceConfig(void);
// get backtrace
char **btrace(void);
// print backtrace
#if __APPLE__
// TODO readelf missing in macOS
#define logBtrace
#define logBtrace char **UNIQVAR(r)=btrace();if(UNIQVAR(r)){puts("\n"BLD WHT"Backtrace:"RST);listPrintS(UNIQVAR(r));listFreeS(UNIQVAR(r));puts("---");}
extern bool btraceCfg;
#define logEBtrace if (btraceCfg) { logBtrace; }
// **************************
// void ** lists
// **************************
// create empty list
#define listEmpty(list) \
void **listEmptyF(void);
void **iListEmptyF(void ***list);
// false when there are elements in the list
bool listIsEmpty(void **list);
// createList(...)
void **listCreateF(void *paramType, ...);
#define listCreate(...) listCreateF(NULL, __VA_ARGS__, NULL)
// copy array to new list
void **listFromArray(void **array, size_t size);
// push and pop (append) element
// modifies the list
void **listPush(void ***list, void *s);
// return last element and remove it from the list
void *listPop(void ***list);
// prepend and dequeue (append) element
// modifies the list
void **listPrepend(void ***list, void *s);
// return fist element and remove it from the list
void *listDequeue(void ***list);
// freeList
void listFree(void **list);
// free many void**
void listFreeManyF(void **paramType, ...);
#define listFreeMany(...) listFreeManyF(NULL, __VA_ARGS__, NULL)
// length
size_t listLength(void **list);
// list get - get an element at python index
void *listGet(void **list, intmax_t index);
// list set - replace a string at python index
void **listSet(void **list, intmax_t index, void *s);
// duplicate list
void **listDup(void **list);
// duplicate and reverse list
void **listReverse(void **list);
void **iListReverse(void ***list);
// listCatS: f(l1, l2, l3)
void **listCatF(void **paramType, ...);
#define listCat(...) listCatF(NULL, __VA_ARGS__, NULL)
// append lists
void **listAppend(void ***list1, void **list2);
// add lists
void **listAdd(void **list1, void **list2);
// slice - python style indexes 0..len-1 -1..-len+1
void **listSlice(void **list, intmax_t start, intmax_t end);
void **iListSlice(void ***list, intmax_t start, intmax_t end);
// insert list in list
void **listInsert(void **list, intmax_t index, void **toInsert);
void **iListInsert(void ***list, intmax_t index, void **toInsert);
// del - python style indexes 0..len-1 -1..-len+1
void **listDel(void **list, intmax_t start, intmax_t end);
void **iListDel(void ***list, intmax_t start, intmax_t end);
// duplicate and sort
//TODO void **listSort(void **list);
//TODO void iListSort(void ***list);
// compare lists
//TODO bool listEq(void **list1, void **list2);
// indexOf
//TODO ssize_t listIndexOf(void **list, const void *string);
// list binary search string
//TODO ssize_t listBinarySearch(void **list, const void *string);
// duplicate and uniquify
//TODO void **listUniq(void **list);
//TODO void iListUniq(void ***list);
// duplicate and compact
//TODO void **listCompact(void **list);
//TODO void iListCompact(void ***list);
// array of type on heap
#define newArray(name, type, count)\
/*
* staticArray type definition
* this type of array has a static maximum element count (fixed)
* it is used as a circular buffer, queue, fifo...
* a ring is a pointer to a staticArray
* no sanity checks are done
* Usage:
* to declare an array:
* 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);
* Array variables:
* array.list: elements
* array.maxCount: maximum element count allowed
* Note: some functions are macros to be able to have structs as element and
* access the struct members directly, for example:
* staticArrayLast(chan).a = 0;
*/
//
// TODO add print elements func
// TODO check boundaries
/*
* base type for all staticArrays and rings
*/
typedef struct {
/*
* declares type for staticArray or ring
* \param
* typeName staticArray/ring type name
* \param
* element type of elements (int, struct, pointer...)
* \pointer
* MAXCOUNT array/ring buffer size
*/
#define staticArrayT(typeName, element, MAXCOUNT)\
/*
* initialize count in array/static ring
* this macro can initialize rings if the struct is accessed directly
* \param
* name variable name for staticArray
*/
#define staticArrayInit(name)\
/*
* Empty Array
* Allocated buffers in the list must be freed before running staticArrayEmpty
*/
#define staticArrayEmpty(name)\
/*
* is Array Empty
*/
#define staticArrayIsEmpty(name) ((name).isEmpty)
/*
* is Array Full
*/
#define staticArrayIsFull(name) ((name).isEmpty ? 0 : ((((name).last+1) % (name).maxCount) == (name).head))
/*
* return elements count
*/
#define staticArrayCount(name) ((name).isEmpty ? 0 : ((((name).last) >= ((name).head)) ? ((name).last-(name).head+1) : (((name).maxCount-(name).head + (name).last+1))) )
/*
* push element to array (only increases last)
* use staticArrayLast to access the element
*/
#define staticArrayPush(name)\
/*
* pop element from array (only decreases last)
*/
#define staticArrayPop(name)\
#define staticArrayDelLast staticArrayPop
/*
* prepend element to array (only decreases head)
* use staticArrayFirst to access the element
*/
#define staticArrayPrepend(name)\
/*
* dequeue element from array (only increases head)
*/
#define staticArrayDequeue(name)\
#define staticArrayDelFirst staticArrayDequeue
/*
* get element at index, negative index is supported
*/
#define staticArrayGet(name, index) (name).list[(((index) >= 0) ? (index) : staticArrayCount(name) + (index) )]
/*
* index of element for an index relative to 0, negative index is supported
*/
#define staticArrayGetIndex(name, index) ((((index) >= 0) ? (index) : staticArrayCount(name) + (index) ))
/*
* get element at index with name->head index 0, negative index is supported
*/
#define staticArrayRef(name, index) (name).list[((((index) >= 0) ? (index) : staticArrayCount(name) + (index) ) + name.head) % name.maxCount]
/*
* index of element for an index relative to head, negative index is supported
*/
#define staticArrayRefIndex(name, index) (((((index) >= 0) ? (index) : staticArrayCount(name) + (index) ) + name.head) % name.maxCount)
/*
* last element in array
*/
#define staticArrayLast(name) (name).list[(name).last]
/*
* index of last element
*/
#define staticArrayLastIndex(name) (name).last
/*
* first element in array
*/
#define staticArrayFirst(name) (name).list[(name).head]
/*
* index of first element
*/
#define staticArrayFirstIndex(name) (name).head
/*
* write the staticArray content to filename file
* No NULL checks are done on the parameters
* \param
* filename file name string
*/
#define staticArrayWriteFilename(name, filename) do {\
/*
* write the staticArray content to disk
* No NULL checks are done on the parameters
* \param
* file already opened file
*/
#define staticArrayWrite(name, file) do {\
/*
* read name staticArray from filename file
* No NULL checks are done on the parameters
* \param
* filename file name string
*/
#define staticArrayReadFilename(name, filename) do {\
/*
* read name staticArray from disk
* No NULL checks are done on the parameters
* \param
* file already opened file
*/
#define staticArrayRead(name, file) do {\
/*
* indexer is a staticArray without the list
* It indexes an independent array
* Usage:
* declare an array:
* char array[10][5];
* declare an indexer:
* indexer indx;
* or 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];
* For pointer to indexers (idxP), use:
* indexerPInit,
* indexerPEmpty,
* indexerPIsEmpty,
* indexerPIsFull,
* indexerPCount,
* indexerPPush,
* indexerPPop,
* indexerPPrepend,
* indexerPDequeue,
* indexerPRef,
* indexerPLast or idxP->last,
* indexerPFirst or idxP->head
*/
/*
* base type, same as staticArray
*/
#define indexer staticArrayBase
/*
* declare an indexer type with INT_TYPE counters instead of the default i64
* INT_TYPE has to be signed integer
* The indexers of this type are not compatible with the indexerP* functions
*/
#define indexerT(typeName, INT_TYPE)\
/*
* initialize count in array/static ring
* this macro can initialize rings if the struct is accessed directly
* \param
* name variable name for staticArray
* \param
* MAXCOUNT max count for name type
*/
#define indexerInit(name, MAXCOUNT)\
#define indexerPInit ringInit
/*
* Empty Array
* Allocated buffers in the list must be freed before running staticArrayEmpty
*/
#define indexerEmpty staticArrayEmpty
#define indexerPEmpty ringEmpty
/*
* is Array Empty
*/
#define indexerIsEmpty staticArrayIsEmpty
#define indexerPIsEmpty ringIsEmpty
/*
* is Array Full
*/
#define indexerIsFull staticArrayIsFull
#define indexerPIsFull ringIsFull
/*
* return elements count
*/
#define indexerCount staticArrayCount
#define indexerPCount ringCount
/*
* push element to array (only increases last)
* use staticArrayLast to access the element
*/
#define indexerPush staticArrayPush
#define indexerPPush ringPush
/*
* pop element from array (only decreases last)
*/
#define indexerPop staticArrayPop
#define indexerPPop ringPop
/*
* prepend element to array (only decreases head)
* use staticArrayFirst to access the element
*/
#define indexerPrepend staticArrayPrepend
#define indexerPPrepend ringPrepend
/*
* dequeue element from array (only increases head)
*/
#define indexerDequeue staticArrayDequeue
#define indexerPDequeue ringDequeue
/*
* index element at index with name->head index 0, negative index is supported
*/
#define indexerRef(name, index) (((((index) >= 0) ? (index) : indexerCount(name) + (index) ) + name.head) % name.maxCount)
#define indexerPRef(name, index) (((((index) >= 0) ? (index) : indexerPCount(name) + (index) ) + name->head) % name->maxCount)
/*
* index of last element in array
*/
#define indexerLast(name) name.last
#define indexerPLast(name) (name)->last
/*
* index of first element in array
*/
#define indexerFirst(name) (name.head)
#define indexerPFirst(name) (name)->head
/*
* rings usage
* Make the ring type:
* #define chanMax 30 // max message count in ring type chanT
* ringMake(chanT, int, chanMax); // ring type is chanT, list 30 of ints
* Add ring to a fiber context:
* typedef struct {int slot; int a; chanT *c;} AArgs;
* Declare a ring of type chanT and initialize:
* chanT c;
* ringInit(&c, chanMax);
* When the ring is empty, ringLast and ringFirst are valid and equal (same index).
* Send and receive data through the ring:
* ringSend(ctx->c, 10);
* int r;
* if (!ringIsEmpty(ctx->c))
* ringRecv(ctx->c, r);
* Note: some functions are macros to be able to have structs as element and
* access the struct members directly, for example:
* ringLast(chan).a = 0;
*/
/*
* base type, same as staticArray
*/
#define ringBase staticArrayBase
/*
* declares type for staticArray or ring
* staticArrayT(typeName, element, MAXCOUNT)
* \param
* typeName staticArray/ring type name
* \param
* element type of elements (int, struct, pointer...)
* \pointer
* MAXCOUNT array/ring buffer size
*/
#define ringMake staticArrayT
/*
* initialize count in array/static ring
* staticArrayInit(name, MAXCOUNT)
* this macro can initialize rings if the struct is accessed directly
* \param
* name variable name for ring
*/
#define ringStaticInit staticArrayInit
// initialize ring/pointer to staticArray
int ringInit(void *ring, int maxCount);
// empty ring
int ringEmpty(void *ring);
// is ring Empty
int ringIsEmpty(void *ring);
// is ring Full
int ringIsFull(void *ring);
// return elements count
ssize_t ringCount(void *ring);
// push element to ring (only increases last, use ringSend), use ringLast to access the element
i64 ringPush(void *ring);
// pop element from ring (only decreases last)
int ringPop(void *ring);
// prepend element to ring (only decreases head), use ringFirst to access the element
i64 ringPrepend(void *ring);
// dequeue element from ring (only increases head, use ringRecv)
int ringDequeue(void *ring);
/*
* get element at index, negative index is supported
*/
#define ringGet(name, index) (name)->list[(((index) >= 0) ? (index) : ringCount(name) + (index) )]
/*
* get element at index with name->head index 0, negative index is supported
*/
#define ringRef(name, index) (name)->list[((((index) >= 0) ? (index) : ringCount(name) + (index) ) + name->head) % name->maxCount]
/*
* last element in ring
*/
#define ringLast(name) (name)->list[(name)->last]
/*
* index of last element
*/
#define ringLastIndex(name) (name)->last
/*
* last element in ring
*/
#define ringFirst(name) (name)->list[(name)->head]
/*
* send data in ring
* \param
* name variable name for ring
* \param
* value data
*/
#define ringSend(name, value)\
// send data and get ring status
#define ringSendSt(status, name, value)\
/*
* receive data from ring
* \param
* name variable name for ring
* \param
* result previously declared variable to store the data
*/
#define ringRecv(name, result)\
// receive data and get ring status
#define ringRecvSt(status, name, result)\
/*
* fiber usage
* The stack is not restored, so all local variables should
* be stored in the context struct.
* Declare a context type for the fiber:
* typedef struct {int slot; int a; chanT *c;} AArgs;
* the context type must start with int slot;
* in this example, the fiber has a ring c of type chanT
* Declare a function of type:
* void fiberA(int thisSlot) {
* static AArgs *ctx;
* int slot;
* ctx = fiberCtx(thisSlot);
* ...
* }
* several fibers can have the function fiberA with different slots
* To yield, add:
* yield(slot, ctx->slot); // switch to scheduler
* ctx = fiberCtx(slot); // restore the context for this fiber
* The next steps show how to start the fibers
* Declare a variable for the context and create the ring chanT:
* AArgs Aa;
* chanT c;
* ringInit(&c, chanMax);
* Initialize the fiber:
* Aa.a = 0;
* Aa.c = &c;
* fiberAdd(&Aa, 1, fiberA);
* this can also be done from a running fiber
* Finally, start the scheduler:
* scheduler();
*/
// schedule fibers
void scheduler(void);
// the scheduler takes slot 0
// the system can handle tCount-1 fibers
#define tCount 10
/*
* all contexts must start with fiberBaseT
* Example:
* typedef struct {int slot; int a;} AArgs;
*/
typedef struct {int slot;} fiberBaseT;
/*
* staticArray to hold the fiber slots
*/
staticArrayT(fiberLT, int, tCount);
/*
* data type for fiber system
*/
typedef struct {
/*
* data for fiber system
*/
extern fibersT fibers;
/*
* get fiber context for thisSlot
*/
#define fiberCtx(thisSlot) fibers.context[thisSlot]
/*
* fiber function type
*/
typedef void (*fiberFT)(int);
/*
* add new fiber
*/
bool fiberAdd(void *ctx, int thisSlot, fiberFT func);
/*
* add new fiber and start immediately after next yield
*/
bool fiberPrepend(void *ctx, int thisSlot, fiberFT func);
/*
* fibers with setjmp (not ucontext)
* internal
* startJump starts another fiber
* slot is the index in fiberJumpBuffers for current fiber
* func is the fiber to start
* the first fiber has to finish last
*/
#define startJump(func)\
/*
* yield jumps back to other fiber
* slot should be a local variable in the fiber
* slot is set to the index in fiberJumpBuffers for current fiber
* backToSlot is the index in fiberJumpBuffers for the other fiber
*/
#define yield(slotValue, slot)\
/*
* return to scheduler and end the fiber
*/
#define fiberEnd(slot)\
// internal for scheduler
#define schedulerYield(backToSlot)\
/*
* dynamic array
* this type of array has a dynamic element count
* pushing elements into the array increases the element count
* no sanity checks are done
* usage examples: regular array, stack, lifo, fifo
* the prefix is dArray
* to declare an array:
* 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);
* Note: dont combine the macros, it gives wrong results:
* a = dArrayAt(&darray, dArrayPop(&darray2));
* dArrayPop is run several time, more than one element is popped
* Note: some functions are macros to be able to have structs as element and
* access the struct members directly, for example:
* dArrayLast(chan).a = 0;
*/
// user parameters
/*
* chunk size: 2^dArrayBits elements
*/
#define dArrayBits 6
// user parameters end
#define dArraySz (1<<dArrayBits)
#define dArrayMask (dArraySz-1)
/*
* declares type for dynamic array
* \param
* typeName dArray type name
* \param
* element type of elements (int, struct, pointer...)
*/
#define dArrayT(typeName, elementType)\
/*
* initialize dynamic array with minimum element count
* \param
* a variable name for dArray
*/
#define dArrayInit(a) do{\
/*
* initialize dynamic array and count
* \param
* a variable name for dArray
* \param
* count initial element count for name type
*/
#define dArrayInitCount(a, count) do{\
#define dArrayResize(a, count) do{\
/*
* free the internal buffers
* \param
* a dynamic array
*/
#define dArrayFree(a) do{\
/*
* Empty Array
* Allocated buffers in the array must be freed before running dArrayEmpty
*/
#define dArrayEmpty(name) do{\
/*
* is Array Empty
*/
#define dArrayIsEmpty(name) ((name)->head == (name)->last)
/*
* return element count
*/
#define dArrayCount(name) ((name)->last - (name)->head)
/*
* return max element count
*/
#define dArrayMaxCount(name) ((name)->maxCount * dArraySz)
/*
* allocate buffer for new elements
* only when the array is full
* \param
* a dynamic array
*/
#define dArrayAlloc(a) do{\
/*
* push element and expand the dynamic array
* no data (random) is set in the new element.
* \param
* a dynamic array
* \param
* v element to push
*/
#define dArrayPush(a) do{\
/*
* append element and expand the dynamic array
* \param
* a dynamic array
* \param
* v element to push
*/
#define dArrayAppend(a, v) do{\
/*
* pop element
* the index of the last element is decreased
* NOTE: using comma operator to avoid warning
* warning: operation on ‘b.head’ may be undefined [-Wsequence-point]
* \param
* a dynamic array
*/
#define dArrayPop(a) ((a)->last--, *((typeof((a)->element)*)((a)->buffers[((a)->last)>>dArrayBits])+(((a)->last)&dArrayMask)))
/*
* delete the last element
* useful for avoiding warning: right-hand operand of comma expression has no effect
* when the poped value is not used
*/
#define dArrayDelLast(a) ((a)->last--)
/*
* prepend element
* \param
* a dynamic array
* \param
* v element to prepend
*/
#define dArrayPrepend(a, v) do{\
/*
* dequeue element
* the index of the head element is increased
* NOTE: using comma operator to avoid warning
* warning: operation on ‘b.head’ may be undefined [-Wsequence-point]
* \param
* a dynamic array
*/
#define dArrayDequeue(a) ((a)->head++, *((typeof((a)->element)*)((a)->buffers[((a)->head-1)>>dArrayBits])+(((a)->head-1)&dArrayMask)))
/*
* delete the first element
* useful for avoiding warning: right-hand operand of comma expression has no effect
* when the dequeued value is not used
*/
#define dArrayDelFirst(a) ((a)->head++)
/*
* get / set element at index
* \param
* a dynamic array
* \param
* index index in array
*/
#define dArrayAt(a, index) (*((typeof((a)->element)*)((a)->buffers[(index)>>dArrayBits])+((index)&dArrayMask)))
/*
* get pointer to element at index
* \param
* a dynamic array
* \param
* index index in array
*/
#define dArrayPtr(a, index) ((typeof((a)->element)*)((a)->buffers[(index)>>dArrayBits])+((index)&dArrayMask))
/*
* last element
* \param
* a dynamic array
*/
#define dArrayLast(a) (*((typeof((a)->element)*)((a)->buffers[((a)->last-1)>>dArrayBits])+(((a)->last-1)&dArrayMask)))
/*
* pointer to last element
* \param
* a dynamic array
*/
#define dArrayLastPtr(a) ((typeof((a)->element)*)((a)->buffers[((a)->last-1)>>dArrayBits])+(((a)->last-1)&dArrayMask))
/*
* index of last element
*/
#define dArrayLastIndex(a) ((a)->last-1)
/*
* direct access to the last element index variable for assignments
*/
#define dArrayLastIndexVar(a) ((a)->last)
/*
* first element
* \param
* a dynamic array
*/
#define dArrayFirst(a) (*((typeof((a)->element)*)((a)->buffers[((a)->head)>>dArrayBits])+((a)->head)&dArrayMask))
/*
* index of first element
*/
#define dArrayFirstIndex(a) ((a)->head)
/*
* write the dArray content to filename file
* No NULL checks are done on the parameters
* \param
* filename file name string
*/
#define dArrayWriteFilename(a, filename) do {\
/*
* write the dArray content to disk
* No NULL checks are done on the parameters
* \param
* file already opened file
*/
#define dArrayWrite(a, file) do {\
/*
* read a dArray from filename file
* No NULL checks are done on the parameters
* \param
* filename file name string
*/
#define dArrayReadFilename(a, filename) do {\
/*
* read a dArray from disk
* No NULL checks are done on the parameters
* \param
* file already opened file
*/
#define dArrayRead(a, file) do {\
/*
* end dynamic array
*/
/*
* slab - dynamic array in one chunk of memory
* slap supports shrinking through slabResize, the slab is reset when head or last are outside the new size
* this type of array has a dynamic element count
* pushing elements into the array increases the element count
* no sanity checks are done
* usage examples: regular array, stack, lifo, fifo
* the prefix is slab
* to declare an array:
* 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);
* Note: dont combine the macros, it gives wrong results:
* a = slabAt(&slab, slabPop(&slab2));
* slabPop is run several time, more than one element is popped
* Note: some functions are macros to be able to have structs as element and
* access the struct members directly, for example:
* slabLast(chan).a = 0;
*/
#define slabSz 64
/*
* declares type for dynamic array
* \param
* typeName slab type name
* \param
* element type of elements (int, struct, pointer...)
*/
#define slabT(typeName, elementType)\
/*
* initialize dynamic array with minimum element count
* \param
* a variable name for slab
*/
#define slabInit(a) do{\
/*
* initialize slab and count
* \param
* a variable name for slab
* \param
* count initial element count for name type
*/
#define slabInitCount(a, count) do{\
#define slabResize(a, count) do{\
/*
* free the internal buffers
* \param
* a slab
*/
#define slabFree(a) free((a)->array);
/*
* Empty Array
*/
#define slabEmpty(name) do{\
/*
* is Array Empty
*/
#define slabIsEmpty(name) ((name)->head == (name)->last)
/*
* return element count
*/
#define slabCount(name) ((name)->last - (name)->head)
/*
* return max element count
*/
#define slabMaxCount(name) (name)->maxCount
/*
* allocate buffer for new elements
* only when the slab is full
* \param
* a dynamic array
*/
#define slabAlloc(a) do{\
/*
* push element and expand the slab
* no data (random) is set in the new element.
* \param
* a slab
* \param
* v element to push
*/
#define slabPush(a) do{\
/*
* append element and expand the slab
* \param
* a slab
* \param
* v element to push
*/
#define slabAppend(a, v) do{\
/*
* pop element
* the index of the last element is decreased
* NOTE: using comma operator to avoid warning
* warning: operation on ‘b.head’ may be undefined [-Wsequence-point]
* \param
* a slab
*/
#define slabPop(a) ((a)->last--, *((a)->array + (a)->last))
/*
* delete the last element
* useful for avoiding warning: right-hand operand of comma expression has no effect
* when the poped value is not used
*/
#define slabDelLast(a) ((a)->last--)
/*
* prepend element
* \param
* a slab
* \param
* v element to prepend
*/
#define slabPrepend(a, v) do{\
/*
* dequeue element
* the index of the head element is increased
* NOTE: using comma operator to avoid warning
* warning: operation on ‘b.head’ may be undefined [-Wsequence-point]
* \param
* a slab
*/
#define slabDequeue(a) ((a)->head++, *((a)->array + (a)->head -1))
/*
* delete the first element
* useful for avoiding warning: right-hand operand of comma expression has no effect
* when the dequeued value is not used
*/
#define slabDelFirst(a) ((a)->head++)
/*
* get / set element at index
* \param
* a slab
* \param
* index index in array
*/
#define slabAt(a, index) (*((a)->array + index))
/*
* get pointer to element at index
* \param
* a slab
* \param
* index index in array
*/
#define slabPtr(a, index) ((a)->array + index)
/*
* last element
* \param
* a slab
*/
#define slabLast(a) (*((a)->array + (a)->last -1))
/*
* pointer to last element
* \param
* a slab
*/
#define slabLastPtr(a) ((a)->array + (a)->last -1)
/*
* index of last element
*/
#define slabLastIndex(a) ((a)->last-1)
/*
* direct access to the last element index variable for assignments
*/
#define slabLastIndexVar(a) ((a)->last)
/*
* first element
* \param
* a slab
*/
#define slabFirst(a) (*((a)->array + (a)->head))
/*
* index of first element
*/
#define slabFirstIndex(a) ((a)->head)
/*
* write the slab content to filename file
* No NULL checks are done on the parameters
* \param
* filename file name string
*/
#define slabWriteFilename(a, filename) do {\
/*
* write the slab content to disk
* No NULL checks are done on the parameters
* \param
* file already opened file
*/
#define slabWrite(a, file) fwrite((a)->array + (a)->head, 1, sizeof(*((a)->array)) * slabCount(a), file);
/*
* read a slab from filename file
* No NULL checks are done on the parameters
* \param
* filename file name string
*/
#define slabReadFilename(a, filename) do {\
/*
* read a slab from disk
* No NULL checks are done on the parameters
* \param
* file already opened file
*/
#define slabRead(a, file) do {\
/*
* end slab
*/
// get monotonic time in ns
uint64_t getMonotonicTime(void);
// sleep nanoseconds
int nanoSleepF(uint64_t time);
#define nanoSleep(time) pError0(nanoSleepF(time))
#define nanoSleep(time) pError0(nanoSleepF(time))
#define nanoSleepE(time, cmd) pErrorCmd(nanoSleepF(time), == 0, cmd)
#define usSleep(time) pError0(nanoSleepF(1000 * (uint64_t)time))
#define msSleep(time) pError0(nanoSleepF(1000000 * (uint64_t)time))
#define DEPRECATED __attribute__ ((deprecated))
#define DEPRECATED

Functions

Functions are in 4 groups:

/* type bool true (glibc true is not bool), for use in generics */
const bool TRUE = true;
/* type bool false (glibc true is not bool), for use in generics */
const bool FALSE = false;
/* backtrace in error messages is enabled by default */
bool btraceCfg = true;
/*
* setjmp buffers for try/throw,throwV macros
*/
jmp_buf tryJumpBuffers[maxTryThrowCount];
/*
* program/library path to find the debug symbols for the program using libsheepy
*/
static const char *libSheepyArg0 = NULL;
/*
* segmentation fault handler
* prints line and file where the segfault crash occured
*/
#if (!(__arm__ || __APPLE__ || __i386__ || __FreeBSD__))
/*
* nanosecond stopwatch
* \param
* op operation: 0 start, 1 get stopwatch value
* \return
* 0 when op is 0
* time since last start in ns when op is 1
*/
uint64_t shStopwatch(uint8_t op)
/* set log level, logs above logMaxLevel are skipped */
static int logMaxLevel = LOG_INVALID;
uint64_t logMask = 0xFFFFFFFFFFFFFFFF;
static FILE *_logging_files[16] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
static int _log_current_mode = LOG_DATE;
static bool _log_verbose_short_path = true;
// logging file 0 is stdout
static uint16_t _current_log_file = 1;
static const char *log_tags[LOG_INVALID_MODE][5] = { { "[CRITICAL] ", "[ERROR] ", "[WARNING] ", "[INFO] ", "[INVALID LOG LEVEL] "}, { "[!] ", "[*] ", "[-] ", "[+] ", "[~] " }, { "[!] ", "[*] ", "[-] ", "[+] ", "[~] " }, { "[!] ", "[*] ", "[-] ", "[+] ", "[~] " }, { "[!] ", "[*] ", "[-] ", "[+] ", "[~] " }, { "[!] ", "[*] ", "[-] ", "[+] ", "[~] " }, { "", "", "", "", "" }};
//
static const char *LOG_DATE_FORMAT[LOG_INVALID_MODE] = { "%c\n", "CONCISE HAS NO DATE", "%y-%m-%d %H:%M:%S", "FUNC", "PROG", "%y-%m-%d %H:%M:%S", "VOID"};
/*
* get current max log level
* default is LOG_INVALID, to show all log levels
* -1 hides all logs
*/
int getMaxLogLevel(void)
/*
* set max log level
* logs above logMaxLevel are skipped
* default is LOG_INVALID, to show all log levels
* LOG_DISABLE hides all logs
* \param
* logLevel from LOG_DISABLE to LOG_INVALID
*/
void setMaxLogLevel(int logLevel)
/*
* set log file
* the logs are appended to all log files set with this function
* there is a maximum of 15 log files
* \return
* log file handle
* NULL when filename is NULL or more than 15 log files are set
*/
FILE *setLogFile(char *filename)
/*
* close logfiles opened with setLogFile
*/
void closeLogFiles(void)
/*
* get current log mode (verbose, concise)
* \return
* current mode LOG_VERBOSE, LOG_CONCISE, ...
*/
int getLogMode(void)
/*
* set log mode LOG_VERBOSE, LOG_CONCISE, ..
* the default log mode is LOG_DATE
*/
void setLogMode(int mode)
/*
* get current log long/short path value
* The default value is TRUE (short paths)
* TRUE shows short file paths in logs
* FALSE shows long file paths in logs
* \return
* current long/short file path configuration value for VERBOSE mode
*/
bool getLogShortPath(void)
/*
* set log long/short file path value for VERBOSE mode
* TRUE shows short file paths in logs
* FALSE shows long file paths in logs
* the default long/short path value is TRUE
*/
void setLogShortPath(bool shortPath)
/*
* print logging levels
* logs messages to all log file
* in LOG_VERBOSE mode, logs loglevel, filename, function name, time, line number and msg
* in LOG_CONCISE mode, logs loglevel and msg
* the maximum message length is 10240
*/
#define MAX_MSG_LEN 10240
/*
* printf RGB Colors
* %k and %K type specifier to GNU printf for RBG colors
* - %k foreground hex color
* - %K background hex color
* Example:
* printf("%k%KRGB color" RST, 0x99EEFF, 0x666666);
*/
/*
* %k printf type specifier, RGB foreground, uint32_t
* 0x00RRGGBB
*/
int print_k(FILE *stream, const struct printf_info *info, const void *const *args)
/*
* %K printf type specifier, RGB background, uint32_t
* 0x00RRGGBB
*/
int print_K(FILE *stream, const struct printf_info *info, const void *const *args)
/*
* procress printf argument
*/
int print_k_arginfo(const struct printf_info *info UNUSED, size_t n, int *argtypes, int* size)
/*
* %b printf type specifier, print bool as FALSE/TRUE
*/
int print_b(FILE *stream, const struct printf_info *info, const void *const *args)
/*
* procress printf argument
*/
int print_b_arginfo(const struct printf_info *info UNUSED, size_t n, int *argtypes, int* size)
/*
* initialize libsheepy (optional, for debug)
* initialize segfault handler for crash debug
* the segfault handler prints the line and file where the segfault occured
* initialize the fibers
* initialize libsheepyObject
*/
#if ((__APPLE__ || __FreeBSD__ || __TERMUX__))
/*
* finalize libsheepy char at exit
* free internal buffers in this file:
* realprogpath
* urandomFp software random file
*/
/*
* get current stack limit
* \return
* current stack limit
* -1 unlimited
* 0 when error
*/
int64_t getStackLimit(void)
/*
* set stack limit
* \param
* stackSize stack size in bytes, set -1 for unlimited size
* \return
* !0 when ok
* 0 when it failed
*/
int setStackLimit(int64_t stackSize)
/*
* get program path
* When initLibsheepy is called before this function, it returns the given program path.
* When initLibsheepy has not been called before this function, it returns the real program path.
* \return
* program path or real program path
*/
const char *getProgPath(void)
/*
* get real program path
* The first call allocates libSheepyRealProgPath, it is freed with freeRealProgPath
* \return
* real program path
*/
const char *getRealProgPath(void)
/*
* free real program path
* finalizeLibsheepy calls this function
*/
void freeRealProgPath(void)
/*
* run system command and free command buffer
* a message is printed when an error occurs
* \return
* 0 success
*/
int systemNFreeF(char *command, int line, const char *thisFunc, const char *thisFileName)
/*
* get modification time for path
* \param
* path
* \return
* modification time
* 0 when an error occured
*/
time_t getModificationTime(const char *path)
/*
* set modification time for path
* \param
* path
* \param
* mtime (for example, from the getModificationTime function)
* \return
* 1 ok
* 0 when an error occured
*/
int setModificationTime(const char *path, time_t mtime)
/*
* compare modification times for path1 and path2
* \param
* path1
* \param
* path2
* \return
* true when mtime is equal for path1 and path2
* false when mtime is different for path1 and path2 or when there is an error
*/
bool equalModificationTimes(const char *path1, const char *path2)
/*
* get current unix time in seconds
* time_t is either int32_t or int64_t
*/
time_t getCurrentUnixTime(void)
/*
* convert date string to unix time
* \param
* date string
* \param
* format for strptime
* \return
* time
* -1 error
*/
time_t strToUnixTime(const char *date, const char *format)
/*
* time To String
* convert unix time to string
* (ctime is not used here because it adds \n at the end of the string)
* \param
* unix time to convert
* \return
* string representing the unix time
*/
char *timeToS(const time_t t)
/*
* time To Year-Month-Day Hour:Minute:Second String
* convert unix time to string
* \param
* unix time to convert
* \return
* string representing the unix time
*/
char *timeToYMDS(const time_t t)
/*
* get current date in ctime format
*/
char *getCurrentDate(void)
/*
* get current date in Y-m-d H:M:S format
*/
char *getCurrentDateYMD(void)
/*
* sheepy dirname
* the returned string has to be freed
* \param
* path
* \return
* path without basename (last item in the path)
* "./" when path is blank or when there is only one item in the path
* NULL when path is NULL
*/
char *shDirname(const char *path)
/*
* buffer dirname
* the buffer size (path) must be at least 3 chars
* \param
* path
* \return
* path without basename (last item in the path)
* "./" when path is blank or when there is only one item in the path
* NULL when path is NULL
*/
char *bDirname(char *path)
/*
* buffer size dirname
* the buffer size (path) must be at least 3 chars
* \param
* path
* \param
* pathSize path buffer size, the path strlen will be at most pathSize-1
* \return
* path without basename (last item in the path)
* "./" when path is blank or when there is only one item in the path
* NULL when path is NULL
*/
char *bLDirname(char *path, size_t pathSize)
/*
* expands ~/ ($HOME) or ~USER\n
* duplicate and expand path. The original remains unchanged.
* \param path string
* \return new string path or NULL
*/
char *expandHome(const char* path)
/*
* expands ~/ ($HOME) or ~USER\n
* duplicate and expand path.
* \param
* path: string
* \return
* path modified path\n
* NULL error
*/
char *iExpandHome(char **path)
/*
* buffer expands ~/ ($HOME) or ~USER\n
* expand path
* \param
* path: string
* \return
* path modified path\n
* NULL error
*/
char *bExpandHome(char *path)
/*
* buffer size expands ~/ ($HOME) or ~USER\n
* expand path
* \param
* path: string
* \param
* pathSize path buffer size, the path strlen will be at most pathSize-1
* \return
* path modified path\n
* NULL error
*/
char *bLExpandHome(char *path, size_t pathSize)
/*
* normalize path
* remove unecessary /, .. and .
* leading / is kept
* leading .. is kept
* leading . is removed
* '/../' becomes '/'
* \param
* path
* \return
* new normalized path
* NULL when path is NULL
*/
char *normalizePath(const char *path)
/*
* normalize path
* remove unecessary /, .. and .
* leading / is kept
* leading .. is kept
* leading . is removed
* '/../' becomes '/'
* \param
* path
* \return
* path modified path
* NULL when path is NULL
*/
char *iNormalizePath(char **path)
/*
* buffer normalize path
* remove unecessary /, .. and .
* leading / is kept
* leading .. is kept
* leading . is removed
* '/../' becomes '/'
* \param
* path
* \return
* path modified path
* NULL when path is NULL
*/
char *bNormalizePath(char *path)
/*
* buffer size normalize path
* path must be at least 2 chars
* remove unecessary /, .. and .
* leading / is kept
* leading .. is kept
* leading . is removed
* '/../' becomes '/'
* \param
* path
* \param
* pathSize path buffer size, the path strlen will be at most pathSize-1
* \return
* path modified path
* NULL when path is NULL
*/
char *bLNormalizePath(char *path, size_t pathSize)
/*
* get home path
* \return
* home path
*/
char *getHomePath(void)
/*
* copy home path to path
* \param
* path buffer large enough for home path
* \return
* path pointer
*/
char *bGetHomePath(char *path)
/*
* copy home path to path maximum pathSize
* \param
* path buffer large enough for home path
* \param
* pathSize size of path
* \return
* path pointer
*/
char *bLGetHomePath(char *path, size_t pathSize)
/*
* get home path as a const char*
* \return
* home path
*/
const char *getCHomePath(void)
/*
* get current working directory
* \return
* current path
*/
char *getCwd(void)
/*
* change directory
* \param
* path
* \return
* 1 success
* 0 error
*/
int chDir(const char *path)
/*
* is directory
* \param
* path
* \return
* true when path is a directory
* false path is not a directory, filePath is NULL or empty string
*/
bool isDir(const char *path)
/*
* sheepy read link
* read the first target in the link chain
* the returned string has to be freed
* \param
* path symbolic link path
* \return
* path to linked file or directory
* NULL failed: path is blank or NULL
* path is not a symlink
* malloc failed to allocate the result buffer
* readlink failed
*/
char *shReadlink(const char *path)
/*
* end link
* read the link chain of a symbolic link to the end
* the returned string has to be freed
* \param
* path symbolic link path
* \return
* path to linked file or directory
* NULL failed: path is blank or NULL
* path is not a symlink
* malloc failed to allocate the result buffer
* readlink failed
*/
char *endlink(const char *path)
/*
* is symbolic link
* \param
* path
* \return
* true when path is a symbolic link
* false path is not a symbolic link, filePath is NULL or empty string
*/
bool isLink(const char *path)
/*
* detect files and directories
* \param
* filePath: path to file or directory
* \return
* true exists
* false non existant
* false filePath is NULL or empty string
*/
bool fileExists(const char *filePath)
/*
* like chmod in stdlibc but return true/false
* \param
* filePath: path to file or directory
* mode: permissions
* \return
* true success
* false filePath doesnt exist, not enough permissions...
* false filePath is NULL or empty string
*/
bool fileChmod(const char *filePath, mode_t mode)
/*
* get file size
* \param
* filePath: path to file
* \return
* ssize_t >= 0 size
* -1 an error occured or filePath is NULL or empty string
*/
ssize_t fileSize(const char *filePath)
/*
* get file size from file pointer
* \param
* file pointer
* \return
* ssize_t >= 0 size
* -1 an error occured or file pointer is NULL
*/
ssize_t fileSizeFP(FILE *fp)
/*
* read file to string
* 0 is added at the end to terminate the string
* \param
* filePath: path to file
* \return
* data in file
* NULL an error occured
*/
void *readFileToS(const char *filePath)
/*
* read file to string
* 0 is added at the end to terminate the string
* \param
* file pointer
* \return
* data in file
* NULL an error occured
*/
void *readStreamToS(FILE *fp)
/*
* buffer read file to string
* 0 is added at the end to terminate the string
* \param
* dst: destination buffer
* \param
* filePath: path to file
* \return
* data in file
* NULL an error occured
*/
void *bReadFileToS(const char *filePath, void *dst)
/*
* buffer read file to string
* 0 is added at the end to terminate the string
* \param
* dst: destination buffer
* \param
* file pointer
* \return
* data in file
* NULL an error occured
*/
void *bReadStreamToS(FILE *fp, void *dst)
/*
* buffer size read file to string
* 0 is added at the end to terminate the string
* \param
* filePath: path to file
* \param
* dst: destination buffer
* \param
* dstSize path buffer size, the path strlen will be at most dstSize-1
* \return
* data in file
* NULL an error occured
*/
void *bLReadFileToS(const char *filePath, void *dst, size_t dstSize)
/*
* buffer size read file to string
* 0 is added at the end to terminate the string
* \param
* dst: destination buffer
* \param
* file pointer
* \return
* data in file
* NULL an error occured
*/
void *bLReadStreamToS(FILE *fp, void *dst, size_t dstSize)
/*
* read file to buffer
* The function allocates the buffer
* \param
* filePath path to file
* \param
* buffer unallocated buffer
* \return
* data from file in buffer
* buffer size
* -1 error
*/
ssize_t readFile(const char *filePath, void **buffer)
/*
* buffer read file to buffer
* The function allocates the buffer
* \param
* filePath path to file
* \param
* buffer already allocated buffer
* \return
* data from file in buffer
* buffer size
* -1 error
*/
ssize_t bReadFile(const char *filePath, void *buffer)
/*
* buffer size read file to buffer
* The function allocates the buffer
* \param
* filePath path to file
* \param
* buffer already allocated buffer
* \param
* dstSize path buffer size
* \return
* data from file in buffer
* buffer size
* -1 error
*/
ssize_t bLReadFile(const char *filePath, void *buffer, size_t dstSize)
/*
* write string to file
* \param
* filePath path to file
* string
* \return
* 1 success
* 0 error
*/
int writeFileS(const char *filePath, const char *string)
/*
* write buffer to file
* \param
* filePath path to file
* buffer
* len buffer size in bytes
* \return
* 1 success
* 0 error
*/
int writeFile(const char *filePath, void *buffer, size_t len)
/*
* write string to file
* \param
* file pointer
* string
* \return
* 1 success
* 0 error
*/
int writeStreamS(FILE *fp, const char *string)
/*
* write buffer to file
* \param
* filePath path to file
* buffer
* len buffer size in bytes
* \return
* 1 success
* 0 error
*/
int writeLStream(FILE *fp, void *buffer, size_t len)
/*
* append string to filePath
* \param
* filePath
* list
* \return
* true success
* false failed, filePath or list are NULL
*/
bool appendFileS(const char *filePath, const char *string)
/*
* append buffer to file
* \param
* filePath path to file
* buffer
* len buffer size in bytes
* \return
* true success
* false error
*/
bool appendFile(const char *filePath, void *buffer, size_t len)
/*
* list all files in a directory recursively
* and sort the list
* directories are not listed
* \param
* dirPath: path to directory
* \return
* list of files
* empty list when the directory is not found
*/
char **walkDir(const char* dirPath)
/*
* list all directories in a directory recursively
* and sort the list
* files are not listed
* \param
* dirPath: path to directory
* \return
* list of directories
* empty list when the directory is not found
*/
char **walkDirDir(const char* dirPath)
/*
* list files in a directory
* and sort the list
* directories are not listed
* \param
* dirPath: path to directory
* \return
* list of files, dirPath is not prepended to the file names
* empty list when the directory is not found
*/
char **readDir(const char *dirPath)
/*
* list directories in a directory
* and sort the list
* files are not listed
* \param
* dirPath: path to directory
* \return
* list of directories, dirPath is not prepended to the names
* empty list when the directory is not found
*/
char **readDirDir(const char *dirPath)
/*
* list all files and directories in a directory recursively
* and sort the list
* directories are listed
* \param
* dirPath: path to directory
* \return
* list of files
* empty list when the directory is not found
*/
char **walkDirAll(const char* dirPath)
/*
* list files in a directory
* and sort the list
* directories are listed
* \param
* dirPath: path to directory
* \return
* list of files, dirPath is not prepended to the file names
* empty list when the directory is not found
*/
char **readDirAll(const char *dirPath)
/*
* get umask
*/
mode_t getumask(void)
/*
* get current permissions for creating directories
*/
/*
* recursive mkdir
* \param
* path
* \return
* 1 success
* 0 when path is NULL or empty
*/
int mkdirParents(const char* path)
/*
* remove all
* delete recursively files and directories
* \param
* path
* \return
* 1 success
* 0 when path is NULL or empty
*/
int rmAll(const char* path)
/*
* copy files recursively
* This function is equivalent to 'cp -Ra' without wildcards and circular link detection
* when src ends with /, the files in src are copied to dst
* when src does't end with /, the last directory name in src is copied to dst
* The permissions are copied to the destination
* \param
* src source path
* dst destination path
* \return
* 1 success
* 0 when src or dst are NULL or empty
*/
int copy(const char* src, const char* dst)
/*
* rename file
* \param
* src source path
* dst destination path
* \return
* 1 success
* 0 when src or dst are NULL or empty
*/
int shRename(const char* src, const char* dst)
/*
* move files recursively
* copy and then delete source
* called shMove because it conflicts with move in ncurses
* \param
* src source path
* dst destination path
* \return
* 1 success
* 0 when src or dst are NULL or empty
*/
int shMove(const char* src, const char* dst)
/*
* use software random numbers
* works on all cpu architectures
* the default random function is software
*/
/*
* use cpu hardware random number generator
*/
/*
* open /dev/urandom in libsheepy
* call this function before calling randomWord and randomChoice
* when random are not needed anymore call randomUrandomClose
* \return
* 1 success
* 0 error
*/
/*
* close /dev/urandom in libsheepy
* call this function when random are not needed anymore
*/
/*
* return random 64 bit unsigned integer
* call randomUrandomOpen before this calling function
* \return
* random uint64 integer
* 0 error urandomFp file is NULL or fread failed
*/
uint64_t randomWord(void)
/*
* return random 64 bit unsigned integer from the cpu
* when the cpu doesn't have the random generator instruction, the program
* stops with 'Illegal instruction'
*/
uint64_t randomWordFromHW(void)
/*
* return a random value between 0 and range 0<=value<range
* call randomUrandomOpen before this calling function
* \param
* range - must be > 0
* \return
* random uint64 0<=value<range
* range error
*/
uint64_t randomChoice(uint64_t range)
/*
* random string
* allocate and generate a random string in charset "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-,"
* \param
* string length
* \return
* random string
* NULL error opening /dev/urandom, malloc failed, fread /dev/urandom failed, length is 0
*/
char *randomS(uint64_t length)
/*
* buffer random string
* allocate and generate a random string in charset "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-,"
* \param
* dst destination buffer
* \param
* dstSize destination buffer size, must be at least 2, to have at least 1 random char in the string
* \return
* random string
* NULL error opening /dev/urandom, malloc failed, fread /dev/urandom failed, length is 0
*/
char *bRandomS(char *dst, size_t dstSize)
/*
* random alpha numerical string
* allocate and generate a random string in charset "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
* \param
* string length
* \return
* random string
* NULL error opening /dev/urandom, malloc failed, fread /dev/urandom failed, length is 0
*/
char *randomAlphaNumS(uint64_t length)
/*
* random alpha numerical string
* allocate and generate a random string in charset "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
* \param
* dst destination buffer
* \param
* dstSize destination buffer size, must be at least 2, to have at least 1 random char in the string
* \return
* random string
* NULL error opening /dev/urandom, malloc failed, fread /dev/urandom failed, length is 0
*/
char *bRandomAlphaNumS(char *dst, size_t dstSize)
/*
* read String
* read user input (one line) as a string
* \return
* line from the user
* NULL when buffer allocation failed
*/
char *readS(void)
/*
* buffer read String
* read user input (one line) as a string
* \param
* dst destination buffer
* \param
* dstSize destination buffer size, must be at least 2, to have at least 1 char from the user in the string
* \return
* line from the user
* NULL when buffer allocation failed
*/
char *bLReadS(char *dst, size_t dstSize)
/*
* sheepy get pass
* like getpass, read password from tty
* currently used in Termux because getpass is missging
*/
char *shGetpass(void)
/*
* read hidden password string
* \return
* newly allocated password string
*/
char *readPasswordS(void)
/*
* write zero to all bytes in string with memset, for clearing password buffers
* \param
* string
* \return
* true 0s are written
* false error string is NULL
*/
bool zeroS(char *string)
/*
* write zero to all bytes in buffer with memset
* \param
* buf buffer
* \param
* len length
* \return
* true 0s are written
* false error string is NULL
*/
bool zeroBuf(void *buf, size_t len)
/*
* read Enter key
* wait until press the enter key
*/
void readEnter(void)
/*
* readLine from file stream
* the fist new line is converted to 0
* \param
* fp: file stream
* \return
* one line in a string
* empty string when stream is empty or when there is an error reading the stream
* NULL when the stream is NULL
*/
char *readLine(FILE *fp)
/*
* free Many String
* free variable list of pointers
* freeManyS(s1, s2, ...);
*/
void freeManySF(char *paramType, ...)
/*
* duplicate string
* \param
* string
* \return
* new identical string
* NULL when string is NULL
*/
char *dupS(const char *string)
/*
* sheepy Print String
* same as printf
* when the formating string is NULL, "(null)" is printed
* \param
* format string - can be NULL
* data
*/
void shPrintfS(const char *fmt, ...)
/*
* sheepy Error printf String
* print to stderr
* when the formating string is NULL, "(null)" is printed
* \param
* format string like printf
* \return
* print to stderr
*/
void shEPrintfS(const char *fmt, ...)
/*
* log and free
* \param
* string to print, can be NULL
*/
void logNFree(char *s)
/*
* print buffer as hexadecimal string
*/
void loghex(const void *buf, size_t len)
/*
* strCpy - copy src to dst
* like strcpy with sanity checks
* \param
* dst destination buffer
* \param
* src source string
* \return
* dst string
* NULL error
*/
char *strCpy(char *dst, const char *src)
/*
* strNCpy - copy src to dst
* null safe version of strncpy
* \param
* dst destination buffer
* \param
* src source string
* \param
* srcSize source buffer size
* \return
* dst string
* NULL error
*/
char *strNCpy(char *dst, const char *src, size_t srcSize)
/*
* strLCpy - copy src to dst
* like strncpy and the NUL char is always added at the end of the string
* \param
* dst destination buffer
* \param
* dstSize destination buffer size, result string will be no longer than dstSize-1
* \param
* src source string
* \return
* dst string
* NULL error
*/
char *strLCpy(char *dst, size_t dstSize, const char *src)
/*
* strCat - concatenate two strings
* like strcat with sanity checks
* \param
* dst destination buffer
* \param
* src source string
* \return
* string with input strings concatenated
* NULL error
*/
char *strCat(char *dst, const char *src)
/*
* strNCat - concatenate two strings
* like strncat with sanity checks
* \param
* dst destination buffer
* \param
* src source string
* \param
* srcLen max source len
* \return
* string with input strings concatenated
* NULL error
*/
char *strNCat(char *dst, const char *src, size_t srcLen)
/*
* strLCat - concatenate two strings
* like strlcat with sanity checks
* \param
* dst destination buffer
* \param
* src source string
* \param
* dstSize destination buffer size, result string will be no longer than dstSize-1
* \return
* string with input strings concatenated
* NULL error
*/
/* same/slower than the other implementation with -O2 and kaby lake */
/*
* strLNCat - concatenate two strings
* like strlcat with sanity checks
* \param
* dst destination buffer
* \param
* src source string
* \param
* dstSize destination buffer size, result string will be no longer than dstSize-1
* \param
* srcLen max source len
* \return
* string with input strings concatenated
* NULL error
*/
char *strLNCat(char *dst, size_t dstSize, const char *src, size_t srcLen)
/*
* cat String Function
* \param
* arbitrary list of strings seperated by commas
* \return
* string with input strings concatenated
*/
char *catSF(const char *paramType, ...)
/*
* cat and copy String Function
* dst has to be big enough to hold the result
* \param
* dst result destination buffer
* arbitrary list of strings seperated by commas
* \return
* dst string with input strings concatenated
*/
char *iCatSF(char *dst, const char *paramType, ...)
/*
* cat and copy String Function
* \param
* dst result destination buffer
* arbitrary list of strings seperated by commas
* \return
* dst string with input strings concatenated
*/
char *bLCatSF(char *dst, size_t dstSize, const char *paramType, ...)
/*
* format string
* allocate and format string using asprintf
* \param
* format string and other parameters
* \return
* allocated and formated string
* NULL when fmt is NULL or asprintf fails
*/
char *formatS(const char *fmt, ...)
/*
* append strings
* \param
* string1 string
* string2 string to append at the end of string1
* \return
* new string string1+string2
* NULL when string1 or string2 are NULL
*/
char *appendS(const char *string1, const char *string2)
/*
* append char to string
* when c is 0 the result is string1
* \param
* string1 string
* c char to append
* \return
* new string string1+c
* NULL when string1 is NULL
*/
char *appendCharS(const char *string1, char c)
/*
* append string to char
* \param
* string1 string
* c char to append
* \return
* new string string1+c
* NULL when string1 is NULL
*/
char *appendSChar(char c, const char *string2)
/*
* append strings
* \param
* string1 string, which is reallocated.
* string2 string to append at the end of string1
* \return
* string1 modified string1 (realloc), string1+string2
* NULL no change when string1 or string2 are NULL
*/
char *iAppendS(char **string1, const char *string2)
/*
* append char to string
* \param
* string1 string, which is reallocated.
* c char to append at the end of string1
* \return
* string1 modified string1 (realloc), string1+c
* NULL no change when string1 is NULL
*/
char *iAppendCharS(char **string1, char c)
/*
* append and free strings
* string2 is freed (except when there is an error)
* \param
* string1 string, which is reallocated.
* string2 string to append at the end of string1
* \return
* string1 modified string1 (realloc), string1+string2
* NULL no change when string1 or string2 are NULL
*/
char *iAppendNFreeS(char **string1, char *string2)
/*
* append many strings
* \param
* string1 string, which is reallocated.
* string2 string to append at the end of string1
* \return
* string1 modified string1, string1+string2
* NULL no change when string1 or string2 are NULL
*/
char *iAppendManySF(char **string, const char *paramType, ...)
/*
* buffer append many strings
* \param
* string1 string
* string2 string to append at the end of string1
* \return
* string1 modified string1, string1+string2
* NULL no change when string1 or string2 are NULL
*/
char *bAppendManySF(char *string, const char *paramType, ...)
/*
* buffer size append many strings
* \param
* string1 string
* string2 string to append at the end of string1
* \return
* string1 modified string1, string1+string2
* NULL no change when string1 or string2 are NULL
*/
char *bLAppendManySF(char *string, size_t stringSize, const char *paramType, ...)
/*
* prepend strings
* \param
* string1 string
* string2 string to prepend at the beginning of string1
* \return
* new string string2+string1
* NULL when string1 or string2 are NULL
*/
char *prependS(const char *string1, const char *string2)
/*
* prepend char to string
* \param
* string1 string
* c char to prepend at the beginning of string1
* \return
* new string c+string1
* NULL when string1 is NULL
*/
char *prependCharS(const char *string1, char c)
/*
* prepend string to char
* \param
* c char
* string2 string to prepend at the beginning of c
* \return
* new string string2+c
* NULL when string2 is NULL
*/
char *prependSChar(char c, const char *string2)
/*
* prepend strings
* \param
* string1 string, which is reallocated.
* string2 string to prepend at the beginning of string1
* \return
* string1 modified string1, string2+string1
* NULL no change when string1 or string2 are NULL
*/
char *iPrependS(char **string1, const char *string2)
/*
* prepend char to string
* \param
* string1 string, which is reallocated.
* c char to prepend at the beginning of string1
* \return
* string1 modified string1, c+string1
* NULL no change when string1 is NULL
*/
char *iPrependCharS(char **string1, char c)
/*
* prepend and free strings
* string2 is freed
* \param
* string1 string, which is reallocated.
* string2 string to prepend at the beginning of string1
* \return
* string1 modified string1, string2+string1
* NULL no change when string1 or string2 are NULL
*/
char *iPrependNFreeS(char **string1, char *string2)
/*
* buffer prepend strings
* \param
* string1 string
* string2 string to prepend at the beginning of string1
* \return
* string1 modified string1, string2+string1
* NULL no change when string1 or string2 are NULL
*/
char *bPrependS(char *string1, const char *string2)
/*
* buffer prepend strings
* \param
* string1 string
* string2 string to prepend at the beginning of string1
* \return
* string1 modified string1, string2+string1
* NULL no change when string1 or string2 are NULL
*/
char *bLPrependS(char *string1, size_t string1Size, const char *string2)
/*
* replace String
* the original remains unchanged
* duplicate s
* the olds string is replaced with the news string max times in the result
* 0 for max means replace all olds strings
* \param
* s: string
* olds: old string to be replaced in s
* news: new string replacing olds in s
* max: number of times to replace olds, 0 to replace all found olds
* \return
* new string
* "" when s is empty
* NULL when s is NULL
* NULL when olds is empty
*/
char* replaceS(const char *s, const char *olds, const char *news, size_t max )
/*
* replace String
* the olds string is replaced with the news string max times in the result
* 0 for max means replace all olds strings
* \param
* s: string
* olds: old string to be replaced in s
* news: new string replacing olds in s
* max: number of times to replace olds, 0 to replace all found olds
* \return
* modified s string
* NULL s not modified when s is NULL or empty and when olds is empty
*/
char* iReplaceS(char **s, const char *olds, const char *news, size_t max )
/*
* buffer replace String
* the olds string is replaced with the news string max times in the result
* 0 for max means replace all olds strings
* \param
* s: string
* olds: old string to be replaced in s
* news: new string replacing olds in s
* max: number of times to replace olds, 0 to replace all found olds
* \return
* modified s string
* NULL s not modified when s is NULL or empty and when olds is empty
*/
char* bReplaceS(char *s, const char *olds, const char *news, size_t max )
/*
* buffer size replace String
* the olds string is replaced with the news string max times in the result
* 0 for max means replace all olds strings
* \param
* s: string
* olds: old string to be replaced in s
* news: new string replacing olds in s
* max: number of times to replace olds, 0 to replace all found olds
* \return
* modified s string
* NULL s not modified when s is NULL or empty and when olds is empty
*/
char* bLReplaceS(char *s, size_t sSize, const char *olds, const char *news, size_t max)
/*
* replace Many Strings
* the original remains unchanged
* duplicate s
* the olds string is replaced with the news string max times in the result
* Example:
* r = replaceManyS("asd", "s", "BNM", "a", "AAA")
* ^olds ^news ^olds ^news
* \param
* s: string
* olds: old string to be replaced in s
* news: new string replacing olds in s
* ...
* \return
* new string
* "" when s is empty
* NULL when s is NULL
* NULL when only 2 parameters are given
* NULL when any olds is empty
*/
char *replaceManySF(const char *paramType, ...)
/*
* replace Many Strings
* the olds string is replaced with the news string max times in the result
* Example:
* iReplaceManyS(s, "s", "BNM", "a", "AAA")
* ^olds ^news ^olds ^news
* \param
* string
* olds: old string to be replaced in s
* news: new string replacing olds in s
* ...
* \return
* modified string
* NULL not modified when s is empty, when s is NULL, when only 2 parameters are given,
* when any olds is empty
*/
char *iReplaceManySF(char **s, char *paramType, ...)
/*
* buffer replace Many Strings
* the olds string is replaced with the news string max times in the result
* Example:
* bReplaceManyS(s, "s", "BNM", "a", "AAA")
* ^olds ^news ^olds ^news
* \param
* string
* olds: old string to be replaced in s
* news: new string replacing olds in s
* ...
* \return
* modified string
* NULL not modified when s is empty, when s is NULL, when only 2 parameters are given,
* when any olds is empty
*/
char *bReplaceManySF(char *s, char *paramType, ...)
/*
* buffer size replace Many Strings
* the olds string is replaced with the news string max times in the result
* Example:
* bReplaceManyS(s, "s", "BNM", "a", "AAA")
* ^olds ^news ^olds ^news
* \param
* string
* olds: old string to be replaced in s
* news: new string replacing olds in s
* ...
* \return
* modified string
* NULL not modified when s is empty, when s is NULL, when only 2 parameters are given,
* when any olds is empty
*/
char *bLReplaceManySF(char *s, size_t sSize, char *paramType, ...)
/*
* ignore case Replace String
* the original remains unchanged
* duplicate s
* the olds string is replaced with the news string max times in the result
* 0 for max means replace all olds strings
* \param
* s: string
* olds: old string to be replaced in s
* news: new string replacing olds in s
* max: number of times to replace olds, 0 to replace all found olds
* \return
* new string
* "" when s is empty
* NULL when s is NULL
* NULL when olds is empty
*/
char* icReplaceS(const char *s, const char *olds, const char *news, size_t max )
/*
* in place ignore case replace String
* the olds string is replaced with the news string max times in the result
* 0 for max means replace all olds strings
* \param
* s: string
* olds: old string to be replaced in s
* news: new string replacing olds in s
* max: number of times to replace olds, 0 to replace all found olds
* \return
* modified s string
* NULL s not modified when s is NULL or empty and when olds is empty
*/
char* iicReplaceS(char **s, const char *olds, const char *news, size_t max )
/*
* buffer ignore case replace String
* the olds string is replaced with the news string max times in the result
* 0 for max means replace all olds strings
* \param
* s: string
* olds: old string to be replaced in s
* news: new string replacing olds in s
* max: number of times to replace olds, 0 to replace all found olds
* \return
* modified s string
* NULL s not modified when s is NULL or empty and when olds is empty
*/
char* bicReplaceS(char *s, const char *olds, const char *news, size_t max )
/*
* buffer size ignore case replace String
* the olds string is replaced with the news string max times in the result
* 0 for max means replace all olds strings
* \param
* s: string
* olds: old string to be replaced in s
* news: new string replacing olds in s
* max: number of times to replace olds, 0 to replace all found olds
* \return
* modified s string
* NULL s not modified when s is NULL or empty and when olds is empty
*/
char* bLicReplaceS(char *s, size_t sSize, const char *olds, const char *news, size_t max)
/*
* ignore case replace Many Strings
* the original remains unchanged
* duplicate s
* the olds string is replaced with the news string max times in the result
* Example:
* r = replaceManyS("asd", "s", "BNM", "a", "AAA")
* ^olds ^news ^olds ^news
* \param
* s: string
* olds: old string to be replaced in s
* news: new string replacing olds in s
* ...
* \return
* new string
* "" when s is empty
* NULL when s is NULL
* NULL when only 2 parameters are given
* NULL when any olds is empty
*/
char *icReplaceManySF(const char *paramType, ...)
/*
* in place ignore case replace Many Strings
* the olds string is replaced with the news string max times in the result
* Example:
* iicReplaceManyS(s, "s", "BNM", "a", "AAA")
* ^olds ^news ^olds ^news
* \param
* string
* olds: old string to be replaced in s
* news: new string replacing olds in s
* ...
* \return
* modified string
* NULL not modified when s is empty, when s is NULL, when only 2 parameters are given,
* when any olds is empty
*/
char *iicReplaceManySF(char **s, char *paramType, ...)
/*
* buffer ignore case replace Many Strings
* the olds string is replaced with the news string max times in the result
* Example:
* bReplaceManyS(s, "s", "BNM", "a", "AAA")
* ^olds ^news ^olds ^news
* \param
* string
* olds: old string to be replaced in s
* news: new string replacing olds in s
* ...
* \return
* modified string
* NULL not modified when s is empty, when s is NULL, when only 2 parameters are given,
* when any olds is empty
*/
char *bicReplaceManySF(char *s, char *paramType, ...)
/*
* buffer size ignore case replace Many Strings
* the olds string is replaced with the news string max times in the result
* Example:
* bReplaceManyS(s, "s", "BNM", "a", "AAA")
* ^olds ^news ^olds ^news
* \param
* string
* olds: old string to be replaced in s
* news: new string replacing olds in s
* ...
* \return
* modified string
* NULL not modified when s is empty, when s is NULL, when only 2 parameters are given,
* when any olds is empty
*/
char *bLicReplaceManySF(char *s, size_t sSize, char *paramType, ...)
/*
* string Equal
* compare string1 to string2
* \param
* 2 strings
* \return
* true the strings have identical content
* false they differ
*/
bool eqS(const char *string1, const char *string2)
/*
* string Index Equal
* compare string1 at index to string2
* when string2 is empty, the result is false
* \param
* 2 strings
* \return
* true string1 at index is equal to string2
* false they differ
*/
bool eqIS(const char *string1, const char *string2, intmax_t index)
/*
* starts With String
* compare start of string1 with string2
* \param
* 2 strings
* \return
* true when string1 starts with string2
* false for other cases
*/
bool startsWithS(const char *string1, const char *string2)
/*
* ends With String
* compare end of string1 with string2
* \param
* 2 strings
* \return
* true when string1 ends with string2
* false for other cases
*/
bool endsWithS(const char *string1, const char *string2)
/*
* count String
* count number of (non-overlapping) occurrences of a substring
* Example:
* assert(countS("aaa aaa", "a") == 6);
* assert(countS("aaa aaa", "ab") == 0);
* assert(countS("aaa aaa", "aa") == 2);
* \param
* 2 strings
* \return
* string count
* -1 when there is an error
*/
ssize_t countS(const char *s, const char *needle)
/*
* ignore case string Equal
* compare string1 to string2
* \param
* 2 strings
* \return
* true the strings have identical content
* false they differ
*/
bool icEqS(const char *string1, const char *string2)
/*
* ignore case string Index Equal
* compare string1 at index to string2
* when string2 is empty, the result is false
* \param
* 2 strings
* \return
* true string1 at index is equal to string2
* false they differ
*/
bool icEqIS(const char *string1, const char *string2, intmax_t index)
/*
* ignore case starts With String
* compare start of string1 with string2
* \param
* 2 strings
* \return
* true when string1 starts with string2
* false for other cases
*/
bool icStartsWithS(const char *string1, const char *string2)
/*
* ignore case ends With String
* compare end of string1 with string2
* \param
* 2 strings
* \return
* true when string1 ends with string2
* false for other cases
*/
bool icEndsWithS(const char *string1, const char *string2)
/*
* ignore case count String
* count number of (non-overlapping) occurrences of a substring
* Example:
* assert(countS("aaa aaa", "a") == 6);
* assert(countS("aaa aaa", "ab") == 0);
* assert(countS("aaa aaa", "aa") == 2);
* \param
* 2 strings
* \return
* string count
* -1 when there is an error
*/
ssize_t icCountS(const char *s, const char *needle)
/*
* has control char
* \return
* true when there is a terminal control in string
*/
bool hasCtrlChar(const char *string)
/*
* is Number (integer or float) String
* 1, -12
* 1e+4, -1.44E-1
* \param
* string
* \return
* true when string is a number
* false when string is not a number or string is empty or NULL
*/
bool isNumber(const char *string)
/*
* is Integer String
* \param
* string
* \return
* true when string is an integer
* false when string is not an integer or string is empty or NULL
*/
bool isInt(const char *string)
/*
* convert string to decimal integer
* \param
* string
* \return
* int64_t
* 0 when string represents 0 or doesnt represent a number or the input is NULL
*/
intmax_t parseInt(const char *string)
/*
* convert string to double
* \param
* string
* \return
* double
* 0 when string represents 0 or doesnt represent a number or the input is NULL
*/
double parseDouble(const char *string)
/*
* parse hexadecimal number in a string
* \param
* string hexadecimal string starting with 0x
* \return
* integer value
* 0 failed or the value is 0
*/
uint64_t parseHex(const char *string)
/*
* int To String
* convert int to string
* \param
* int64 number
* \return
* string representing the number
*/
char *intToS(intmax_t n)
/*
* buffer int To String
* convert int to string
* \param
* int64 number
* \return
* string representing the number
*/
char *bIntToS(char *s, intmax_t n)
/*
* double To String
* convert int to string
* \param
* double number
* \return
* string representing the number
*/
char *doubleToS(double n)
/*
* buffer double To String
* convert int to string
* \param
* double number
* \return
* string representing the number
*/
char *bDoubleToS(char *s, double n)
/*
* length string
* return strlen when possible
* \param
* string
* \return
* strlen value
* 0 when string is NULL
*/
size_t lenS(const char *string)
/*
* upper case String
* duplicate string
* \param
* string
* \return
* new upper case string
*/
char *upperS(const char *string)
/*
* upper case String
* \param
* string
* \return
* upper case string
* NULL error
*/
char *iUpperS(char **string)
/*
* buffer upper case String
* \param
* string
* \return
* upper case string
* NULL error
*/
char *bUpperS(char *string)
/*
* lower case String
* duplicate string
* \param
* string
* \return
* new lower case string
*/
char *lowerS(const char *string)
/*
* lower case String
* \param
* string
* \return
* lower case string
* NULL error
*/
char *iLowerS(char **string)
/*
* buffer lower case String
* \param
* string
* \return
* lower case string
* NULL error
*/
char *bLowerS(char *string)
/*
* trim String
* duplicate string
* \param
* string
* \return
* new string without leading or trailing spaces
*/
char *trimS(const char *string)
/*
* trim String
* \param
* string
* \return
* string without leading or trailing spaces
* NULL error
*/
char *iTrimS(char **string)
/*
* buffer trim String
* \param
* string
* \return
* string without leading or trailing spaces
* NULL error
*/
char *bTrimS(char *string)
/*
* left trim String
* duplicate string
* \param
* string
* \return
* new string without leading spaces
*/
char *lTrimS(const char *string)
/*
* left trim String
* duplicate string
* \param
* string
* \return
* string without leading spaces
* NULL error
*/
char *iLTrimS(char **string)
/*
* buffer left trim String
* duplicate string
* \param
* string
* \return
* string without leading spaces
* NULL error
*/
char *bLTrimS(char *string)
/*
* right trim String
* duplicate string
* \param
* string
* \return
* new string without trailing spaces
*/
char *rTrimS(const char *string)
/*
* right trim String
* duplicate string
* \param
* string
* \return
* string without trailing spaces
* NULL error
*/
char *iRTrimS(char **string)
/*
* buffer right trim String
* duplicate string
* \param
* string
* \return
* string without trailing spaces
* NULL error
*/
char *bRTrimS(char *string)
/*
* uniq String
* duplicate string
* remove successive repetitions of char c
* \param
* string
* c character to remove
* \return
* new string without successive repetitions of char c
*/
char *uniqS(const char *string, char c)
/*
* uniq String
* remove successive repetitions of char c
* \param
* string
* c character to remove
* \return
* string without successive repetitions of char c
* NULL error
*/
char *iUniqS(char **string, char c)
/*
* buffer uniq String
* remove successive repetitions of char c
* \param
* string
* c character to remove
* \return
* string without successive repetitions of char c
* NULL error
*/
char *bUniqS(char *string, char c)
/*
* ignore case uniq String
* duplicate string
* remove successive repetitions of char c
* \param
* string
* c character to remove
* \return
* new string without successive repetitions of char c
*/
char *icUniqS(const char *string, char c)
/*
* in place ignore case uniq String
* remove successive repetitions of char c
* \param
* string
* c character to remove
* \return
* string without successive repetitions of char c
* NULL error
*/
char *iicUniqS(char **string, char c)
/*
* ignore case buffer uniq String
* remove successive repetitions of char c
* \param
* string
* c character to remove
* \return
* string without successive repetitions of char c
* NULL error
*/
char *bicUniqS(char *string, char c)
/*
* get string
* get char at python index
*/
char getS(const char *string, intmax_t index)
/*
* set string
* set char at python index
*/
char *setS(char *string, intmax_t index, char c)
/*
* slice String
* return new string which is the string between start and end
* negative indexes are allowed
* (copy substring from start to end)
* \param
* string to slice
* start: start index, must be in the string
* end: end index, must be in the string after start
* \return
* new sliced string
* "" when start=end
* NULL when start and end are not set correctly
*/
char *sliceS(const char *string, intmax_t start, intmax_t end)
/*
* slice String
* return string which is the string between start and end
* negative indexes are allowed
* \param
* string to slice
* start: start index, must be in the string
* end: end index, must be in the string after start
* \return
* sliced string
* "" when start=end
* NULL unchanged string when start and end are not set correctly
*/
char *iSliceS(char **string, intmax_t start, intmax_t end)
/*
* buffer slice String
* return string which is the string between start and end
* negative indexes are allowed
* \param
* string to slice
* start: start index, must be in the string
* end: end index, must be in the string after start
* \return
* sliced string
* "" when start=end
* NULL unchanged string when start and end are not set correctly
*/
char *bSliceS(char *string, intmax_t start, intmax_t end)
/*
* buffer size slice String
* return string which is the string between start and end
* negative indexes are allowed
* \param
* string to slice
* \param
* stringSize string buffer size
* \param
* start: start index, must be in the string
* \param
* end: end index, must be in the string after start
* \return
* sliced string
* "" when start=end
* NULL unchanged string when start and end are not set correctly
*/
char *bLSliceS(char *string, size_t stringSize, intmax_t start, intmax_t end)
/*
* insert string in string at index
* return new string with toInsert at index
* negative indexes are allowed
* index -1 is the end of the array and is equivalent to index len
* \param
* string
* index in string
* toInsert string
* \return
* new string
* NULL when string is NULL or invalid index
*/
char *insertS(const char *string, intmax_t index, const char *toInsert)
/*
* insert string in string at index and free toInsert
* return new string with toInsert at index
* negative indexes are allowed
* index -1 is the end of the array and is equivalent to index len
* \param
* string
* index in string
* toInsert string
* \return
* new string
* NULL when string is NULL or invalid index
*/
char *insertNFreeS(const char *string, intmax_t index, char *toInsert)
/*
* insert string in string at index
* return string with toInsert at index
* negative indexes are allowed
* index -1 is the end of the array and is equivalent to index len
* \param
* string
* index in string
* toInsert string
* \return
* modified string
* NULL unchanged string when string is NULL or invalid index
*/
char *iInsertS(char **string, intmax_t index, const char *toInsert)
/*
* insert string in string at index and free toInsert
* return string with toInsert at index
* negative indexes are allowed
* index -1 is the end of the array and is equivalent to index len
* \param
* string
* index in string
* toInsert string
* \return
* modified string
* NULL unchanged string when string is NULL or invalid index
*/
char *iInsertNFreeS(char **string, intmax_t index, char *toInsert)
/*
* buffer insert string in string at index
* return string with toInsert at index
* negative indexes are allowed
* index -1 is the end of the array and is equivalent to index len
* \param
* string
* index in string
* toInsert string
* \return
* modified string
* NULL unchanged string when string is NULL or invalid index
*/
char *bInsertS(char *string, intmax_t index, const char *toInsert)
/*
* buffer size insert string in string at index
* return string with toInsert at index
* negative indexes are allowed
* index -1 is the end of the array and is equivalent to index len
* \param
* string
* index in string
* toInsert string
* \return
* modified string
* NULL unchanged string when string is NULL or invalid index
*/
char *bLInsertS(char *string, size_t stringSize, intmax_t index, const char *toInsert)
/*
* inject a char in string at index
* return new string with toInject at index
* negative indexes are allowed
* index -1 is the end of the array and is equivalent to index len
* \param
* string
* index in string
* toInject char
* \return
* new string
* NULL when string is NULL or invalid index
*/
char *injectS(const char *string, intmax_t index, char toInject)
/*
* inject a char in string at index
* return string with toInject at index
* negative indexes are allowed
* index -1 is the end of the array and is equivalent to index len
* \param
* string
* index in string
* toInject char
* \return
* modified string
* NULL unchanged string when string is NULL or invalid index
*/
char *iInjectS(char **string, intmax_t index, char toInject)
/*
* buffer inject a char in string at index
* return string with toInject at index
* negative indexes are allowed
* index -1 is the end of the array and is equivalent to index len
* \param
* string
* index in string
* toInject char
* \return
* modified string
* NULL unchanged string when string is NULL or invalid index
*/
char *bInjectS(char *string, intmax_t index, char toInject)
/*
* buffer size inject a char in string at index
* return string with toInject at index
* negative indexes are allowed
* index -1 is the end of the array and is equivalent to index len
* \param
* string
* index in string
* toInject char
* \return
* modified string
* NULL unchanged string when string is NULL or invalid index
*/
char *bLInjectS(char *string, size_t stringSize, intmax_t index, char toInject)
/*
* delete string
* return new string without the string between start and end
* negative indexes are allowed
* \param
* string to delete
* start: start index, must be in the string
* end: end index, must be in the string after start
* \return
* new sliced string
* new identical string when start=end or when start and end are not set correctly
* NULL when input string is NULL or when malloc failed or when end is under start
*/
char *delS(const char *string, intmax_t start, intmax_t end)
/*
* delete string
* return string without the string between start and end
* negative indexes are allowed
* \param
* string to delete
* start: start index, must be in the string
* end: end index, must be in the string after start
* \return
* sliced string
* unchanged string when start=end
* NULL when start and end are not set correctly
* or when input string is NULL or when malloc failed or when end is under start
*/
char *iDelS(char **string, intmax_t start, intmax_t end)
/*
* buffer delete string
* return string without the string between start and end
* negative indexes are allowed
* \param
* string to delete
* start: start index, must be in the string
* end: end index, must be in the string after start
* \return
* sliced string
* unchanged string when start=end
* NULL when start and end are not set correctly
* or when input string is NULL or when malloc failed or when end is under start
*/
char *bDelS(char *string, intmax_t start, intmax_t end)
/*
* buffer size delete string
* return string without the string between start and end
* negative indexes are allowed
* \param
* string to delete
* \param
* stringSize string buffer size
* \param
* start: start index, must be in the string
* \param
* end: end index, must be in the string after start
* \return
* sliced string
* unchanged string when start=end
* NULL when start and end are not set correctly
* or when input string is NULL or when malloc failed or when end is under start
*/
char *bLDelS(char *string, size_t stringSize, intmax_t start, intmax_t end)
/*
* delete element/character string
* return new string without the character at given index
* negative indexes are allowed
* \param
* string to delete
* index: must be in the string, -1 is the last character in the string
* \return
* new string
* NULL when input string is NULL or when malloc failed
*/
char *delElemS(const char *string, intmax_t index)
/*
* delete element/character string
* return string without the character at given index
* negative indexes are allowed
* \param
* string to delete
* index: must be in the string, -1 is the last character in the string
* \return
* new string
* NULL when input string is NULL or when malloc failed
*/
char *iDelElemS(char **string, intmax_t index)
/*
* buffer delete element/character string
* return string without the character at given index
* negative indexes are allowed
* \param
* string to delete
* index: must be in the string, -1 is the last character in the string
* \return
* string with one less character
* NULL when input string is NULL or when malloc failed
*/
char *bDelElemS(char *string, intmax_t index)
/*
* buffer size delete element/character string
* return string without the character at given index
* negative indexes are allowed
* \param
* string to delete
* \param
* stringSize string buffer size
* \param
* index: must be in the string, -1 is the last character in the string
* \return
* string with one less character
* NULL when input string is NULL or when malloc failed
*/
char *bLDelElemS(char *string, size_t stringSize, intmax_t index)
/*
* find String
* \param
* string
* needle: string to find
* \return
* pointer to first occurence of needle in string
* NULL when needle is not found
* NULL when string or needle are NULL
*/
char *findS(const char *string, const char *needle)
/*
* indexOf String
* relative to start
* \param
* string
* needle: string to find
* \return
* index of first occurence of needle in string
* -1 when needle is not found
* -1 when string or needle are NULL
*/
ssize_t indexOfS(const char *string, const char *needle)
/*
* has String
* \param
* string
* needle: string to find
* \return
* true when needle is in string
* false when needle is not found
* false when string or needle are NULL
*/
bool hasS(const char *string, const char *needle)
/*
* ignore case Find String
* \param
* string
* needle: string to find
* \return
* pointer to first occurence of needle in string
* NULL when needle is not found
* NULL when string or needle are NULL
*/
char *icFindS(const char *string, const char *needle)
/*
* ignore case indexOf String
* relative to start
* \param
* string
* needle: string to find
* \return
* index of first occurence of needle in string
* -1 when needle is not found
* -1 when string or needle are NULL
*/
ssize_t icIndexOfS(const char *string, const char *needle)
/*
* ignore case has String
* \param
* string
* needle: string to find
* \return
* true when needle is in string
* false when needle is not found
* false when string or needle are NULL
*/
bool icHasS(const char *string, const char *needle)
/*
* token in String
* parse string into a sequence of tokens delimited by the ENTIRE DELIM string
* work like strtok_r from c stdlib
* (for strtok_r, when delim has multiple characters, each character is a delimiter)
* on first call s is the string to parse, optionally initialize *saveptr to NULL
* on next calls, s should be NULL
* \param
* s string to parse, the s string is modified
* delim string
* \return
* token
*saveptr is set to NULL when the last token is found
*/
char *tokS(const char *s, const char *delim, char **saveptr)
/*
* ignore case token in String
* parse string into a sequence of tokens delimited by the ENTIRE DELIM string
* work like strtok_r from c stdlib
* (for strtok_r, when delim has multiple characters, each character is a delimiter)
* on first call s is the string to parse, optionally initialize *saveptr to NULL
* on next calls, s should be NULL
* \param
* s string to parse, the s string is modified
* delim string
* \return
* token
*saveptr is set to NULL when the last token is found
*/
char *icTokS(const char *s, const char *delim, char **saveptr)
/*
* character length of UTF-8 string
* string is not checked for validity
*/
size_t lenUTF8(const char *s)
/*
* buffer character length of UTF-8 string
* string is not checked for validity
* bLLenUTF8 checks at most maxSize bytes
*/
size_t bLLenUTF8(const char *s, size_t maxSize)
/*
* is UTF-8 string
* check if string is a valid UTF-8 string
* \param
* string UTF-8 encoded string
* \return
* true string is valid UTF-8
* false string is invalid UTF-8
*/
bool isUTF8(const char * string)
/*
* buffer length is UTF-8 string
* check if string is a valid UTF-8 string
* \param
* string UTF-8 encoded string
* \return
* true string is valid UTF-8
* false string is invalid UTF-8
*/
bool bLIsUTF8(const char * string, size_t stringSize)
/*
* is code point UTF8 encoded string
* Check if a UTF8 code point is valid
* This function checks only the first code point
* \param
* bytes string, NUL-terminated or not, bytes can be a pointer inside a UTF8 encoded string
* \return
* true bytes is a valid UTF-8 code point
* false bytes is invalid code point
*/
bool isCodeUTF8(const char *code)
/* maximum rune value */
#define runeMax 0x10FFFF
/* code point length, 0 when invalid code point, x is first byte in code point */
#define UTFSEQ(x) ((((x) & 0x80) == 0x00) ? 1 /* 0xxxxxxx */ \
: (((x) & 0xC0) == 0x80) ? 0 /* 10xxxxxx */ \
: (((x) & 0xE0) == 0xC0) ? 2 /* 110xxxxx */ \
: (((x) & 0xF0) == 0xE0) ? 3 /* 1110xxxx */ \
: (((x) & 0xF8) == 0xF0) ? 4 /* 11110xxx */ \
: (((x) & 0xFC) == 0xF8) ? 5 /* 111110xx */ \
: (((x) & 0xFE) == 0xFC) ? 6 /* 1111110x */ \
: 0 )
#define BADRUNE(x) ((x) < 0 || (x) > runeMax \
|| ((x) & 0xFFFE) == 0xFFFE \
|| ((x) >= 0xD800 && (x) <= 0xDFFF) \
|| ((x) >= 0xFDD0 && (x) <= 0xFDEF))
#define UNICODE_LAST_CHAR_PART1 0x2FAFF
#define UNICODE_LAST_PAGE_PART1 762
#define UNICODE_MAX_TABLE_INDEX 10000
#define UNICODE_NOT_PRESENT_OFFSET 65535
/*
* Unicode types:
* UNICODE_CONTROL: General category "Other, Control" (Cc)
* UNICODE_FORMAT: General category "Other, Format" (Cf)
* UNICODE_UNASSIGNED: General category "Other, Not Assigned" (Cn)
* UNICODE_PRIVATE_USE: General category "Other, Private Use" (Co)
* UNICODE_SURROGATE: General category "Other, Surrogate" (Cs)
* UNICODE_LOWERCASE_LETTER: General category "Letter, Lowercase" (Ll)
* UNICODE_MODIFIER_LETTER: General category "Letter, Modifier" (Lm)
* UNICODE_OTHER_LETTER: General category "Letter, Other" (Lo)
* UNICODE_TITLECASE_LETTER: General category "Letter, Titlecase" (Lt)
* UNICODE_UPPERCASE_LETTER: General category "Letter, Uppercase" (Lu)
* UNICODE_SPACING_MARK: General category "Mark, Spacing" (Mc)
* UNICODE_ENCLOSING_MARK: General category "Mark, Enclosing" (Me)
* UNICODE_NON_SPACING_MARK: General category "Mark, Nonspacing" (Mn)
* UNICODE_DECIMAL_NUMBER: General category "Number, Decimal Digit" (Nd)
* UNICODE_LETTER_NUMBER: General category "Number, Letter" (Nl)
* UNICODE_OTHER_NUMBER: General category "Number, Other" (No)
* UNICODE_CONNECT_PUNCTUATION: General category "Punctuation, Connector" (Pc)
* UNICODE_DASH_PUNCTUATION: General category "Punctuation, Dash" (Pd)
* UNICODE_CLOSE_PUNCTUATION: General category "Punctuation, Close" (Pe)
* UNICODE_FINAL_PUNCTUATION: General category "Punctuation, Final quote" (Pf)
* UNICODE_INITIAL_PUNCTUATION: General category "Punctuation, Initial quote" (Pi)
* UNICODE_OTHER_PUNCTUATION: General category "Punctuation, Other" (Po)
* UNICODE_OPEN_PUNCTUATION: General category "Punctuation, Open" (Ps)
* UNICODE_CURRENCY_SYMBOL: General category "Symbol, Currency" (Sc)
* UNICODE_MODIFIER_SYMBOL: General category "Symbol, Modifier" (Sk)
* UNICODE_MATH_SYMBOL: General category "Symbol, Math" (Sm)
* UNICODE_OTHER_SYMBOL: General category "Symbol, Other" (So)
* UNICODE_LINE_SEPARATOR: General category "Separator, Line" (Zl)
* UNICODE_PARAGRAPH_SEPARATOR: General category "Separator, Paragraph" (Zp)
* UNICODE_SPACE_SEPARATOR: General category "Separator, Space" (Zs)
* These are the possible character classifications from the
* Unicode specification.
* See [Unicode Character Database](http://www.unicode.org/reports/tr44/#General_Category_Values).
*/
typedef enum
/*
* next UTF-8 code point
* find the next UTF-8 code point in the string
* the validity of the found UTF-8 code point is not checked
* nextUTF8 gives wrong result when utf8 is not on the first byte of a code point
* use findNextUTF8 to find next code point when utf8 is not at the start of a code point
* \param
* utf8 UTF-8 encoded string
* \return
* pointer to next UTF-8 code point
* NULL when the end string is reached or utf8 is NULL
*/
char *nextUTF8(const char *utf8)
/*
* buffer length next UTF-8 code point
* find the next UTF-8 code point in the string
* the validity of the found UTF-8 code point is not checked
* bLNextUTF8 gives wrong result when utf8 is not on the first byte of a code point
* use findNextUTF8 to find next code point when utf8 is not at the start of a code point
* \param
* string start of the UTF-8 encoded string
* \param
* utf8 pointer to a code point in string
* \param
* ut8Size string buffer size (including NUL, strlen(string) +1 when the buffer is full)
* \return
* pointer to next UTF-8 code point
* NULL when the end string is reached or utf8 is NULL or the start of the next code point is outside the string
*/
char *bLNextUTF8(const char *string, size_t utf8Size, const char *utf8)
/*
* find next UTF-8 code point
* even not at the start of a code point
* find the next UTF-8 code point in the string
* the validity of the found UTF-8 code point is not checked
* \param
* string start of the UTF-8 encoded string
* \param
* utf8 pointer in string
* \param
* ut8Size string buffer size (including NUL, strlen(string) +1 when the buffer is full)
* \return
* pointer to next UTF-8 code point
* NULL when the end string is reached or utf8 is NULL or the start of the next code point is outside the string
*/
char *findNextUTF8(const char *string, size_t utf8Size, const char *utf8)
/*
* previous UTF-8 code point
* find the previous UTF-8 code point in the string
* the validity of the found UTF-8 code point is not checked
* the behavior is undefined when utf8 is the start of the string, use instead findPrevUTF8 for safe handling
* \param
* utf8 UTF-8 encoded string
* \return
* pointer to previous UTF-8 code point
* NULL when utf8 is NULL
*/
char *prevUTF8(const char *utf8)
/*
* buffer previous UTF-8 code point
* find the previous UTF-8 code point in the string
* the validity of the found UTF-8 code point is not checked
* \param
* string UTF-8 encoded string
* \param
* utf8 pointer in UTF-8 encoded string
* \return
* pointer to previous UTF-8 code point
* NULL when utf8 is NULL
*/
char *bPrevUTF8(const char *string, const char *utf8)
/*
* index to pointer UTF8 encoded string
* Converts character index to pointer in utf8
* \param
* utf8 UTF8 encoded string
* \param
* index character index in utf8, positive or negative. -1 is the last character in the string
* \return
* pointer to character at index
* NULL when index is outside the string
*/
char *idx2PtrUTF8(const char *utf8, intmax_t index)
/*
* pointer to code point index UTF8 encoded string
* Converts pointer to character index
* This function works when utf8 and pos point inside code points
* \param
* utf8 pointer to a code point in a UTF8 encoded string
* \param
* pos pointer to a code point in a UTF8 encoded string
* \return
* Number of code points from utf8 to pos, positive or negative
* When utf8 < pos, the result is positive
* When pos < utf8, the result is negative
* 0 failed or index 0
*/
intmax_t ptr2IdxUTF8(const char *utf8, const char *pos)
/*
* buffer pointer to code point index UTF8 encoded string
* Converts pointer to character index
* Safe function for negative index
* This function works when utf8 and pos point inside code points
* \param
* start start of the UTF8 encoded string
* \param
* utf8 pointer to a code point in a UTF8 encoded string
* \param
* pos pointer to a code point in a UTF8 encoded string
* \return
* Number of code points from utf8 to pos, positive or negative
* When utf8 < pos, the result is positive
* When pos < utf8, the result is negative
* 0 failed or index 0
*/
intmax_t bPtr2IdxUTF8(const char *start, const char *utf8, const char *pos)
/*
* buffer size pointer to code point index UTF8 encoded string
* Converts pointer to character index
* This function works when utf8 and pos point inside code points
* \param
* utf8 pointer to a code point in a UTF8 encoded string
* \param
* utf8Size utf8 buffer size including NUL
* \param
* pos pointer to a code point in a UTF8 encoded string
* \return
* Number of code points from utf8 to pos, positive
* -1 failed
*/
intmax_t bLPtr2IdxUTF8(const char *utf8, size_t utf8Size, const char *pos)
/*
* buffer size pointer to negative code point index UTF8 encoded string
* Converts pointer to negative character index (from the end of the string)
* This function works when utf8 and pos point inside code points
* \param
* utf8 pointer to a code point in a UTF8 encoded string
* \param
* utf8Size utf8 buffer size including NUL
* \param
* pos pointer to a code point in a UTF8 encoded string
* \return
* Number of code points from utf8 end to pos, negative
* 0 failed
*/
intmax_t bLPtr2NegIdxUTF8(const char *utf8, size_t utf8Size, const char *pos)
/*
* make valid UTF-8 encoded string
* copy utf8 to newly allocated buffer, the invalid code points are
* replaced with '?'
* The result buffer size is the same as utf8 size
* \param
* utf8 valid or invalid UTF-8 encoded string
* \result
* new valid UTF-8 encoded string
* NULL failed
*/
char *makeValidUTF8(const char *utf8)
/*
* buffer make valid UTF-8 encoded string
* replace the invalid code points with '?' in utf8
* \param
* utf8 valid or invalid UTF-8 encoded string
* \result
* valid UTF-8 encoded string in utf8 buffer
* NULL failed
*/
char *bMakeValidUTF8(char *utf8)
/*
* length make valid UTF-8 encoded string
* copy utf8 to newly allocated buffer, the invalid code points are
* replaced with '?'
* The result buffer size is utf8Len+1
* \param
* utf8 valid or invalid UTF-8 encoded string
* \param
* utf8Len utf8 length
* \result
* new valid UTF-8 encoded string
* NULL failed
*/
char *nMakeValidUTF8(const char *utf8, size_t utf8Len)
/*
* buffer length make valid UTF-8 encoded string
* copy utf8 to the dst buffer, the invalid code points are
* replaced with '?'
* The result buffer size is utf8Len+1
* \param
* utf8 valid or invalid UTF-8 encoded string
* \param
* utf8Len utf8 length
* \result
* new valid UTF-8 encoded string
* NULL failed
*/
char *bNMakeValidUTF8(char *dst, const char *utf8, size_t utf8Len)
/*
* buffer destination size make valid UTF-8 encoded string
* copy utf8 to the dst buffer, the invalid code points are
* replaced with '?'
* The result buffer size is dstSize
* \param
* dst destination buffer
* \param
* dstSize size of dst
* \param
* utf8 valid or invalid UTF-8 encoded string
* \result
* new valid UTF-8 encoded string
* NULL failed
*/
char *bLMakeValidUTF8(char *dst, size_t dstSize, const char *utf8)
/*
* buffer destination size source length make valid UTF-8 encoded string
* copy utf8 to the dst buffer, the invalid code points are
* replaced with '?'
* This function always reads less than utf8Len+1 bytes in utf8 buffer
* The result buffer size is dstSize
* \param
* dst destination buffer
* \param
* dstSize size of dst
* \param
* utf8 valid or invalid UTF-8 encoded string
* \param
* utf8Len utf8 length
* \result
* new valid UTF-8 encoded string
* NULL failed
*/
char *bLNMakeValidUTF8(char *dst, size_t dstSize, const char *utf8, size_t utf8Len)
/*
* strNCpyUTF8 - copy src to dst with srcLen in code points
* copy srcLen code points from src (UTF-8 encoded string) to dst and add one NUL character when src
* end is not reached (unlike strncpy).
* \param
* dst destination buffer
* \param
* src source string
* \param
* srcLen source buffer size in code points
* \return
* dst string
* NULL error
*/
char *strNCpyUTF8(char *dst, const char *src, size_t srcLen)
/*
* strLCpyUTF8 - copy src to dst
* like strncpy and the NUL char is always added at the end of the string
* and the result string is always a valid UTF-8 encoded string
* \param
* dst destination buffer
* \param
* dstSize destination buffer size, result string will be no longer than dstSize-1
* \param
* src source string
* \return
* dst string
* NULL error
*/
char *strLCpyUTF8(char *dst, size_t dstSize, const char *src)
/*
* strNCatUTF8 - concatenate two UTF-8 encoded strings
* like strncat with sanity checks and srcLen is the number of code points
* \param
* dst destination buffer
* \param
* src source string
* \param
* srcLen max source len in code points
* \return
* string with input strings concatenated
* NULL error
*/
char *strNCatUTF8(char *dst, const char *src, size_t srcLen)
/*
* strLCatUTF8 - concatenate two UTF-8 encoded strings
* like strlcat with sanity checks
* the result string is always a valid UTF-8 encoded string
* \param
* dst destination buffer
* \param
* src source string
* \param
* dstSize destination buffer size, result string will be no longer than dstSize-1
* \return
* string with input strings concatenated
* NULL error
*/
char *strLCatUTF8(char *dst, size_t dstSize, const char *src)
/*
* strLNCatUTF8 - concatenate two UTF-8 encoded strings
* like strlcat with sanity checks and srcLen is the number of code points
* the result string is always a valid UTF-8 encoded string
* \param
* dst destination buffer
* \param
* src source string
* \param
* dstSize destination buffer size, result string will be no longer than dstSize-1
* \param
* srcLen max source len in code points
* \return
* string with input strings concatenated
* NULL error
*/
char *strLNCatUTF8(char *dst, size_t dstSize, const char *src, size_t srcLen)
/*
* ignore case Replace UTF8 encoded String
* the original remains unchanged
* duplicate s
* the olds string is replaced with the news string max times in the result
* 0 for max means replace all olds strings
* \param
* s: UTF8 encoded string
* olds: old UTF8 encoded string to be replaced in s
* news: new UTF8 encoded string replacing olds in s
* max: number of times to replace olds, 0 to replace all found olds
* \return
* new string
* "" when s is empty
* NULL when s is NULL
* NULL when olds is empty
*/
char* icReplaceUTF8(const char UNUSED *s, const char UNUSED *olds, const char UNUSED *news, size_t UNUSED max )
/*
* in place ignore case replace UTF8 encoded String
* the olds UTF8 encoded string is replaced with the news UTF8 encoded string max times in the result
* 0 for max means replace all olds strings
* \param
* s: UTF8 encoded string
* olds: old UTF8 encoded string to be replaced in s
* news: new UTF8 encoded string replacing olds in s
* max: number of times to replace olds, 0 to replace all found olds
* \return
* modified s string
* NULL s not modified when s is NULL or empty and when olds is empty
*/
char* iicReplaceUTF8(char UNUSED **s, const char UNUSED *olds, const char UNUSED *news, size_t UNUSED max )
/*
* buffer ignore case replace UTF8 encoded String
* the olds string is replaced with the news string max times in the result
* 0 for max means replace all olds strings
* \param
* s: string
* olds: old string to be replaced in s
* news: new string replacing olds in s
* max: number of times to replace olds, 0 to replace all found olds
* \return
* modified s string
* NULL s not modified when s is NULL or empty and when olds is empty
*/
char* bicReplaceUTF8(char UNUSED *s, const char UNUSED *olds, const char UNUSED *news, size_t UNUSED max )
/*
* buffer size ignore case replace UTF8 encoded String
* the olds string is replaced with the news string max times in the result
* 0 for max means replace all olds strings
* \param
* s: string
* olds: old string to be replaced in s
* news: new string replacing olds in s
* max: number of times to replace olds, 0 to replace all found olds
* \return
* modified s string
* NULL s not modified when s is NULL or empty and when olds is empty
*/
char* bLicReplaceUTF8(char UNUSED *s, size_t UNUSED sSize, const char UNUSED *olds, const char UNUSED *news, size_t max UNUSED)
/*
* ignore case replace Many UTF8 encoded Strings
* the original remains unchanged
* duplicate s
* the olds string is replaced with the news string max times in the result
* Example:
* r = replaceManyUTF8("asd", "s", "BNM", "a", "AAA")
* ^olds ^news ^olds ^news
* \param
* s: string
* olds: old string to be replaced in s
* news: new string replacing olds in s
* ...
* \return
* new string
* "" when s is empty
* NULL when s is NULL
* NULL when only 2 parameters are given
* NULL when any olds is empty
*/
char *icReplaceManyUTF8F(const char *paramType UNUSED, ...)
/*
* in place ignore case replace Many UTF8 encoded Strings
* the olds string is replaced with the news string max times in the result
* Example:
* iicReplaceManyUTF8(s, "s", "BNM", "a", "AAA")
* ^olds ^news ^olds ^news
* \param
* string
* olds: old string to be replaced in s
* news: new string replacing olds in s
* ...
* \return
* modified string
* NULL not modified when s is empty, when s is NULL, when only 2 parameters are given,
* when any olds is empty
*/
char *iicReplaceManyUTF8F(char **s UNUSED, char *paramType UNUSED, ...)
/*
* buffer ignore case replace Many UTF8 encoded Strings
* the olds string is replaced with the news string max times in the result
* Example:
* bReplaceManyUTF8(s, "s", "BNM", "a", "AAA")
* ^olds ^news ^olds ^news
* \param
* string
* olds: old string to be replaced in s
* news: new string replacing olds in s
* ...
* \return
* modified string
* NULL not modified when s is empty, when s is NULL, when only 2 parameters are given,
* when any olds is empty
*/
char *bicReplaceManyUTF8F(char *s UNUSED, char *paramType UNUSED, ...)
/*
* buffer size ignore case replace Many UTF8 encoded Strings
* the olds string is replaced with the news string max times in the result
* Example:
* bReplaceManyUTF8(s, "s", "BNM", "a", "AAA")
* ^olds ^news ^olds ^news
* \param
* string
* olds: old string to be replaced in s
* news: new string replacing olds in s
* ...
* \return
* modified string
* NULL not modified when s is empty, when s is NULL, when only 2 parameters are given,
* when any olds is empty
*/
char *bLicReplaceManyUTF8F(char *s UNUSED, size_t sSize UNUSED, char *paramType UNUSED, ...)
/*
* UTF8 encoded string Index Equal
* compare string1 at character index to string2
* when string2 is empty, the result is false
* \param
* 2 strings
* \return
* true string1 at index is equal to string2
* false they differ
*/
bool eqIUTF8(const char *string1, const char *string2, intmax_t index)
/*
* ignore case UTF8 encoded string Equal
* compare string1 to string2
* \param
* 2 strings
* \return
* true the strings have identical content
* false they differ
*/
bool icEqUTF8(const char *string1, const char *string2)
/*
* ignore case UTF8 encoded string Index Equal
* compare string1 at character index to string2
* when string2 is empty, the result is false
* \param
* 2 strings
* \return
* true string1 at index is equal to string2
* false they differ
*/
bool icEqIUTF8(const char *string1 UNUSED, const char *string2 UNUSED, intmax_t index UNUSED)
/*
* ignore case starts With UTF8 encoded String
* compare start of string1 with string2
* \param
* 2 strings
* \return
* true when string1 starts with string2
* false for other cases
*/
bool icStartsWithUTF8(const char *string1, const char *string2)
/*
* ignore case ends With UTF8 encoded String
* compare end of string1 with string2
* \param
* 2 strings
* \return
* true when string1 ends with string2
* false for other cases
*/
bool icEndsWithUTF8(const char *string1, const char *string2)
/*
* ignore case count UTF8 encoded String
* count number of (non-overlapping) occurrences of a substring
* Example:
* assert(countUTF8("aaa aaa", "a") == 6);
* assert(countUTF8("aaa aaa", "ab") == 0);
* assert(countUTF8("aaa aaa", "aa") == 2);
* \param
* 2 strings
* \return
* string count
* -1 when there is an error
*/
ssize_t icCountUTF8(const char *s, const char *needle)
/* some case convertions depend on the current LOCALE */
const char *locale = setlocale (LC_CTYPE, NULL);;
if (!locale) {
return(LOCALE_NORMAL);
}
switch (locale[0]) {
case 'a':
if (locale[1] == 'z') {
return(LOCALE_TURKIC);
}
break;
case 'l':
if (locale[1] == 't') {
}
break;
case 't':
if (locale[1] == 'r') {
return(LOCALE_TURKIC);
}
break;
}
return(LOCALE_NORMAL);
}
/*
* UTF-8 code point to rune
* \param
* code UTF-8 code point
* \return
* Rune
* 0 failed
*/
rune code2RuneUTF8(const char *code)
/*
* UTF-8 code point to rune and length
* the code point length is returned in *n
* \param
* code UTF-8 code point
* \param
* n pointer to returned code point length
* \return
* Rune
* 0 failed
*/
rune code2RuneLUTF8(const char *code, uint8_t *n)
/*
* rune to UTF-8 code point
* \param
* dst destination buffer at least 6 bytes or if NULL, the code point length is computed
* \param
* c UNICODE rune
* \return
* code point length and code point in dst
* when dst is NULL, return code point length only
* 0 bad rune, dst becomes an empty string
*/
size_t bRune2CodeUTF8(char *dst, rune c)
/*
* rune length as UTF-8 code point
* \param
* r UNICODE rune
* \return
* code point length
* 0 bad rune
*/
uint8_t runeLenUTF8(rune r)
/*
* rune toupper UTF8
* Converts a character to uppercase.
* \param
* c rune
* \return
* c converted to uppercase
* c unchanged if c has no upper case or is not lowercase or titlecase
*/
rune toupperUTF8(rune c) {
int t = RUNETYPE(c);;
rune val = ATTTABLE (c >> 8, c & 0xff);
if (val >= 0x1000000) {
const char *p = special_case_table + val - 0x1000000;;
val = code2RuneUTF8(p);
}
// Some lowercase letters, e.g., U+000AA, FEMININE ORDINAL INDICATOR,
// do not have an uppercase equivalent, in which case val will be
// zero.
return(val ? val : c);
}
else if (t == UNICODE_TITLECASE_LETTER) {
range(i, ARRAY_SIZE(title_table)) {
if (title_table[i][0] == c) {
return(title_table[i][1] ? title_table[i][1] : c);
}
}
}
return(c);
}
internal size_t _upperUTF8(char *dst, const char *utf8, localeType lcl) {
size_t len = 0;;
const char *last = NULL;
bool last_was_i = FALSE;;
while (*utf8) {
rune c = code2RuneUTF8(utf8);
int t = RUNETYPE(c);
last = utf8;
nxCodeUTF8(utf8);
if (lcl == LOCALE_LITHUANIAN) {
if (c == 'i') {
last_was_i = TRUE;
}
else {
if (last_was_i) {
size_t decompLen = runeFullyDecompose(c, decomp, ARRAY_SIZE(decomp));
range(i, decompLen) {
if (decomp[i] != 0x307) {
// COMBINING DOT ABOVE
len += bRune2CodeUTF8(dst ? dst + len : NULL, toupperUTF8(decomp[i]));;
}
}
len += output_marks(&utf8, dst ? dst + len : NULL, TRUE);;
continue;
}
if (!ISMARK(t)) {
last_was_i = FALSE;
}
}
}
if (lcl == LOCALE_TURKIC && c == 'i') {
// i => LATIN CAPITAL LETTER I WITH DOT ABOVE
len += bRune2CodeUTF8(dst ? dst + len : NULL, 0x130);
}
else if (c == 0x0345) {
// COMBINING GREEK YPOGEGRAMMENI
len += output_marks(&utf8, dst ? dst + len : NULL, FALSE);
// And output as GREEK CAPITAL LETTER IOTA
len += bRune2CodeUTF8(dst ? dst + len : NULL, 0x399);
}
rune val = ATTTABLE (c >> 8, c & 0xff);
if (val >= 0x1000000) {
len += output_special_case (dst ? dst + len : NULL, val - 0x1000000, t, t == UNICODE_LOWERCASE_LETTER ? 0 : 1);
}
else {
range(i, ARRAY_SIZE(title_table)) {
if (title_table[i][0] == c) {
val = title_table[i][1];
break;
}
}
}
// Some lowercase letters, e.g., U+000AA, FEMININE ORDINAL INDICATOR,
// do not have an uppercase equivalent, in which case val will be
// zero.
len += bRune2CodeUTF8(dst ? dst + len : NULL, val ? val : c);
}
}
else {
uint8_t codeLen = codeSizeUTF8(last);
if ((dst)) {
memcpy(dst + len, last, codeLen);
}
len += codeLen;;
}
}
if (dst) {
*(dst+len) = 0;
}
return(len);
}
/*
* upper case UTF-8 encoded string
* duplicate string
* \param
* string UTF-8 encoded string
* \return
* new upper case string
*/
char *upperUTF8(const char *utf8)
/*
* upper case UTF-8 encoded string
* \param
* string
* \return
* upper case string
* NULL error
*/
char *iUpperUTF8(char **utf8)
/*
* buffer upper case String
* \param
* string
* \return
* upper case string
* NULL error
*/
char *bUpperUTF8(char *utf8 UNUSED)
/*
* runeCombiningClass:
* @uc: a Unicode character
* Determines the canonical combining class of a Unicode character.
* Returns: the combining class of the character
* Since: 2.14
*/
int runeCombiningClass (rune uc) {
return(COMBINING_CLASS(uc));
}
/* traverses the string checking for characters with combining class == 230
* until a base character is found */
internal bool has_more_above (const char *str) {
const char *p = NULL;
int combining_class;
p = str;
while (*p) {
combining_class = runeCombiningClass(code2RuneUTF8(p));
if (combining_class == 230) {
return(TRUE);
}
else if (combining_class == 0) {
break;
}
}
return(FALSE);
}
/*
* rune tolower UTF8
* Converts a character to lower case.
* \param
* c UNICODE rune
* \return
* lowercase c
* c unchanged if c has lowercase or is not an uppercase or titlecase character
*/
rune tolowerUTF8(rune c) {
int t = RUNETYPE(c);
rune val = ATTTABLE (c >> 8, c & 0xff);
if (val >= 0x1000000) {
const char *p = special_case_table + val - 0x1000000;
return(code2RuneUTF8(p));
}
else {
// Not all uppercase letters are guaranteed to have a lowercase
// equivalent. If this is the case, val will be zero.
return(val ? val : c);
}
}
else if (t == UNICODE_TITLECASE_LETTER) {
range(i, ARRAY_SIZE(title_table)) {
if (title_table[i][0] == c) {
return(title_table[i][2]);
}
}
}
return(c);
}
internal size_t _lowerUTF8(char *dst, const char *utf8, localeType lcl) {
size_t len = 0;;
const char *last = NULL;
while (*utf8) {
rune c = code2RuneUTF8(utf8);
int t = RUNETYPE(c);
last = utf8;
nxCodeUTF8(utf8);
rune val;
if ((lcl == LOCALE_TURKIC && c == 'I')) {
if (code2RuneUTF8(utf8) == 0x0307) {
// I + COMBINING DOT ABOVE => i (U+0069)
len += bRune2CodeUTF8(dst ? dst + len : NULL, 0x0069);
nxCodeUTF8(utf8);
}
else {
// I => LATIN SMALL LETTER DOTLESS I
len += bRune2CodeUTF8(dst ? dst + len : NULL, 0x131);
}
}
// Introduce an explicit dot above when lowercasing capital I's and J's
// whenever there are more accents above. [SpecialCasing.txt]
else if (lcl == LOCALE_LITHUANIAN && (c == 0x00cc || c == 0x00cd || c == 0x0128)) {
len += bRune2CodeUTF8(dst ? dst + len : NULL, 0x0069);
len += bRune2CodeUTF8(dst ? dst + len : NULL, 0x0307);
switch (c) {
case 0x00cc:
len += bRune2CodeUTF8(dst ? dst + len : NULL, 0x0300);
break;
case 0x00cd:
len += bRune2CodeUTF8(dst ? dst + len : NULL, 0x0301);
break;
case 0x0128:
len += bRune2CodeUTF8(dst ? dst + len : NULL, 0x0303);
break;
}
}
else if (lcl == LOCALE_LITHUANIAN && (c == 'I' || c == 'J' || c == 0x012e) && has_more_above (utf8)) {
len += bRune2CodeUTF8(dst ? dst+len : NULL, tolowerUTF8(c));
len += bRune2CodeUTF8(dst ? dst+len : NULL, 0x0307);
}
else if (c == 0x03A3) {
// GREEK CAPITAL LETTER SIGMA
if (*utf8) {
rune next_c = code2RuneUTF8(utf8);;
int next_type = RUNETYPE(next_c);;
// SIGMA maps differently depending on whether it is
// final or not. The following simplified test would
// fail in the case of combining marks following the
// sigma, but I don't think that occurs in real text.
// The test here matches that in ICU.
// Lu,Ll,Lt,Lm,Lo
if (ISALPHA(next_type)) {
// GREEK SMALL SIGMA
val = 0x3c3;
}
else {
// GREEK SMALL FINAL SIGMA
val = 0x3c2;
}
}
else {
// GREEK SMALL FINAL SIGMA
val = 0x3c2;
}
len += bRune2CodeUTF8(dst ? dst + len : NULL, val);
}
val = ATTTABLE(c >> 8, c & 0xff);
if (val >= 0x1000000) {
len += output_special_case(dst ? dst + len : NULL, val - 0x1000000, t, 0);
}
else {
range(i, ARRAY_SIZE(title_table)) {
if (title_table[i][0] == c) {
val = title_table[i][2];
break;
}
}
}
// Not all uppercase letters are guaranteed to have a lowercase
// equivalent. If this is the case, val will be zero.
len += bRune2CodeUTF8(dst ? dst+len : NULL, val ? val : c);;
}
}
else {
uint8_t codeLen = codeSizeUTF8(last);
if ((dst)) {
memcpy(dst+len, last, codeLen);
}
len += codeLen;;
}
}
if (dst) {
*(dst+len) = 0;
}
return(len);
}
/*
* lower case UTF-8 String
* duplicate string
* \param
* string
* \return
* new lower case string
*/
char *lowerUTF8(const char *utf8)
/*
* lower case String
* \param
* string
* \return
* lower case string
* NULL error
*/
char *iLowerUTF8(char **utf8)
/*
* buffer lower case String
* \param
* string
* \return
* lower case string
* NULL error
*/
char *bLowerUTF8(char *string UNUSED)
/*
* casefold UTF-8 encoded string
* \param
* utf8 UTF-8 encoded string
* \return
* new string
* NULL when utf8 is NULL
*/
char *casefoldUTF8(const char *utf8)
/*
* uniq UTF-8 String
* duplicate string
* remove successive repetitions of UTF-8 code point code
* \param
* string
* c character to remove
* \return
* new string without successive repetitions of char c
*/
char *uniqUTF8(const char *string, const char *code)
/*
* uniq UTF-8 String
* remove successive repetitions of char c
* \param
* string
* c character to remove
* \return
* string without successive repetitions of char c
* NULL error
*/
char *iUniqUTF8(char **string, const char *code)
/*
* buffer uniq String
* remove successive repetitions of char c
* \param
* string
* c character to remove
* \return
* string without successive repetitions of char c
* NULL error
*/
char *bUniqUTF8(char *string, const char *code)
/*
* ignore case uniq String
* duplicate string
* remove successive repetitions of char c
* \param
* string
* c character to remove
* \return
* new string without successive repetitions of char c
*/
char *icUniqUTF8(const char *string UNUSED, const char *code UNUSED)
/*
* in place ignore case uniq String
* remove successive repetitions of char c
* \param
* string
* c character to remove
* \return
* string without successive repetitions of char c
* NULL error
*/
char *iicUniqUTF8(char **string UNUSED, const char *code UNUSED)
/*
* ignore case buffer uniq String
* remove successive repetitions of char c
* \param
* string
* c character to remove
* \return
* string without successive repetitions of char c
* NULL error
*/
char *bicUniqUTF8(char *string UNUSED, char c UNUSED)
/*
* get UTF8 encoded string
* get char at python index
*/
rune getUTF8(const char *string, intmax_t index)
/*
* set UTF8 encoded string
* set char at python index
* TODO this function might make the string invalid UTF8
* check codeSizeUTF8 and adjust the buffer
*/
char *setUTF8(char *string, intmax_t index, rune c)
/*
* slice UTF8 encoded String
* return new string which is the string between start and end
* negative indexes are allowed
* (copy substring from start to end)
* \param
* string to slice
* start: start character index, must be in the string
* end: end character index, must be in the string after start
* \return
* new sliced string
* "" when start=end
* NULL when start and end are not set correctly
*/
char *sliceUTF8(const char *string, intmax_t start, intmax_t end)
/*
* slice UTF8 encoded String
* return string which is the string between start and end
* negative indexes are allowed
* \param
* string to slice
* start: start character index, must be in the string
* end: end character index, must be in the string after start
* \return
* sliced string
* "" when start=end
* NULL unchanged string when start and end are not set correctly
*/
char *iSliceUTF8(char **string, intmax_t start, intmax_t end)
/*
* buffer slice UTF8 encoded String
* return string which is the string between start and end
* negative indexes are allowed
* \param
* string to slice
* start: start index, must be in the string
* end: end index, must be in the string after start
* \return
* sliced string
* "" when start=end
* NULL unchanged string when start and end are not set correctly
*/
char *bSliceUTF8(char *string, intmax_t start, intmax_t end)
/*
* buffer size slice UTF8 encoded String
* return string which is the string between start and end
* negative indexes are allowed
* \param
* string to slice
* \param
* stringSize string buffer size
* \param
* start: start character index, must be in the string
* \param
* end: end character index, must be in the string after start
* \return
* sliced string
* "" when start=end
* NULL unchanged string when start and end are not set correctly
*/
char *bLSliceUTF8(char *string, size_t stringSize, intmax_t start, intmax_t end)
/*
* insert string in UTF8 encoded string at index
* return new string with toInsert at index
* negative indexes are allowed
* index -1 is the end of the array and is equivalent to index len
* \param
* string UTF8 encoded string
* index character index in string
* toInsert UTF8 encoded string
* \return
* new string
* NULL when string is NULL or invalid index
*/
char *insertUTF8(const char *string, intmax_t index, const char *toInsert)
/*
* insert string in UTF8 encoded string at index and free toInsert
* return new string with toInsert at index
* negative indexes are allowed
* index -1 is the end of the array and is equivalent to index len
* \param
* string UTF8 encoded string
* index character index in string
* toInsert UTF8 encoded string
* \return
* new string
* NULL when string is NULL or invalid index
*/
char *insertNFreeUTF8(const char *string, intmax_t index, char *toInsert)
/*
* insert string in UTF8 encoded string at index
* return string with toInsert at index
* negative indexes are allowed
* index -1 is the end of the array and is equivalent to index len
* \param
* string UTF8 encoded string
* index character index in string
* toInsert UTF8 encoded string
* \return
* modified string
* NULL unchanged string when string is NULL or invalid index
*/
char *iInsertUTF8(char **string, intmax_t index, const char *toInsert)
/*
* insert string in UTF8 encoded string at index and free toInsert
* return string with toInsert at index
* negative indexes are allowed
* index -1 is the end of the array and is equivalent to index len
* \param
* string UTF8 encoded string
* index character index in string
* toInsert UTF8 encoded string
* \return
* modified string
* NULL unchanged string when string is NULL or invalid index
*/
char *iInsertNFreeUTF8(char **string, intmax_t index, char *toInsert)
/*
* buffer insert string in UTF8 encoded string at index
* return string with toInsert at index
* negative indexes are allowed
* index -1 is the end of the array and is equivalent to index len
* \param
* string UTF8 encoded string
* index character index in string
* toInsert UTF8 encoded string
* \return
* modified string
* NULL unchanged string when string is NULL or invalid index
*/
char *bInsertUTF8(char *string, intmax_t index, const char *toInsert)
/*
* buffer size insert string in UTF8 encoded string at index
* return string with toInsert at index
* negative indexes are allowed
* index -1 is the end of the array and is equivalent to index len
* \param
* string UTF8 encoded string
* index character index in string
* toInsert UTF8 encoded string
* \return
* modified string
* NULL unchanged string when string is NULL or invalid index
*/
char *bLInsertUTF8(char *string, size_t stringSize, intmax_t index, const char *toInsert)
/*
* delete UTF8 encoded string
* return new string without the string between start and end
* negative indexes are allowed
* \param
* string to delete
* start: start character index, must be in the string
* end: end character index, must be in the string after start
* \return
* new sliced string
* new identical string when start=end or when start and end are not set correctly
* NULL when input string is NULL or when malloc failed or when end is under start
*/
char *delUTF8(const char *string, intmax_t start, intmax_t end)
/*
* delete UTF8 encoded string
* return string without the string between start and end
* negative indexes are allowed
* \param
* string to delete
* start: start character index, must be in the string
* end: end character index, must be in the string after start
* \return
* sliced string
* unchanged string when start=end
* NULL when start and end are not set correctly
* or when input string is NULL or when malloc failed or when end is under start
*/
char *iDelUTF8(char **string, intmax_t start, intmax_t end)
/*
* buffer delete UTF8 encoded string
* return string without the string between start and end
* negative indexes are allowed
* \param
* string to delete
* start: start character index, must be in the string
* end: end character index, must be in the string after start
* \return
* sliced string
* unchanged string when start=end
* NULL when start and end are not set correctly
* or when input string is NULL or when malloc failed or when end is under start
*/
char *bDelUTF8(char *string, intmax_t start, intmax_t end)
/*
* buffer size delete UTF8 encoded string
* return string without the string between start and end
* negative indexes are allowed
* \param
* string to delete
* \param
* stringSize string buffer size
* \param
* start: start character index, must be in the string
* \param
* end: end character index, must be in the string after start
* \return
* sliced string
* unchanged string when start=end
* NULL when start and end are not set correctly
* or when input string is NULL or when malloc failed or when end is under start
*/
char *bLDelUTF8(char *string, size_t stringSize, intmax_t start, intmax_t end)
/*
* indexOf UTF8 encoded String
* relative to start
* \param
* string
* needle: string to find
* \return
* character index of first occurence of needle in string
* -1 when needle is not found
* -1 when string or needle are NULL
*/
ssize_t indexOfUTF8(const char *string, const char *needle)
/*
* ignore case indexOf UTF8 encoded String
* relative to start
* \param
* string
* needle: string to find
* \return
* character index of first occurence of needle in string
* -1 when needle is not found
* -1 when string or needle are NULL
*/
ssize_t icIndexOfUTF8(const char *string UNUSED, const char *needle UNUSED)
/*
* ignore case has UTF8 encoded String
* \param
* string
* needle: string to find
* \return
* true when needle is in string
* false when needle is not found
* false when string or needle are NULL
*/
bool icHasUTF8(const char *string, const char *needle)
/*
* ignore case token in UTF8 encoded String
* parse string into a sequence of tokens delimited by the ENTIRE DELIM string
* work like strtok_r from c stdlib
* (for strtok_r, when delim has multiple characters, each character is a delimiter)
* on first call s is the string to parse, optionally initialize *saveptr to NULL
* on next calls, s should be NULL
* \param
* s string to parse, the s string is modified
* delim string
* \return
* token
*saveptr is set to NULL when the last token is found
*/
char *icTokUTF8(const char *s UNUSED, const char *delim UNUSED, char **saveptr UNUSED)
/*
* ignore case split UTF8 encoded string with delim string
* return list
* \param
* string to split
* delim delimiter
* \return
* list of tokens
* NULL when list or delim are NULL
*/
char **icSplitUTF8(const char *string UNUSED, const char* delim UNUSED)
/*
* ignore case extract UTF8 encoded string between delim1 and delim2 strings
* return list
* \param
* string to split
* delim1 first delimiter
* delim2 second delimiter, has to different from delim1
* \return
* list of tokens
* NULL when list or delim are NULL
*/
char **icExtractUTF8(const char *string UNUSED, const char* delim1 UNUSED, const char* delim2 UNUSED)
/*
* ignore case list Sort UTF-8 encoded String Compare function
* in:
* a
* b
* out:
* test result
*/
internal int icListSortUTF8Cmp(const void * a, const void * b)
/*
* ignore case list Sort UTF8 encoded String
* duplicate list and sort
* \param
* list
* \return
* new sorted list
* empty list when list is empty
* NULL when list is NULL
*/
char **icListSortUTF8(char **list)
/*
* ignore case list Sort UTF8 encoded String
* \param
* list
* \return
* sorted list
* empty list when list is empty
* unchanged list when list is NULL
* NULL error
*/
char **iicListSortUTF8(char ***list)
/*
* ignore case list Equal UTF8 encoded String
* compare each element of list1 and list2
* \param
* 2 lists
* \return
* true the lists have identical elements
* false they differ
*/
bool icListEqUTF8(char **list1, char **list2)
/*
* ignore case and return true when list has UTF8 encoded string
* \param
* list
* string
* \return
* true when list has string
* false when the string is not found
* false when list or string are NULL
*/
bool icListHasUTF8(char **list, const char *string)
/*
* ignore case and return index of UTF8 encoded string in list
* \param
* list
* string
* \return
* index
* -1 when the string is not found
* -1 when list or string are NULL
*/
ssize_t icListIndexOfUTF8(char **list, const char *string)
/*
* ignore case list binary search UTF8 encoded string
* efficiently finds the index of string in list
* the list has be sorted with for example listSortS
* \param
* list
* string to search
* \return
* index of string
* -1 string not found or NULL input pointers
*/
ssize_t icListBinarySearchUTF8(char **list, const char *string) {
ssize_t first = 0, middle, last;;
if (!list || !string) {
return(-1);
}
char *s = casefoldUTF8(string);
last = listLengthS(list) - 1;
while (first <= last) {
middle = (first+last)/2;
char *m = casefoldUTF8(list[middle]);
if (strcmp(m, s) < 0) {
first = middle + 1;
}
else if (strcmp(m, s) == 0) {
free(m);
free(s);
return(middle);
}
else {
last = middle -1;
}
free(m);
}
free(s);
return(-1);
}
/*
* ignore case and uniquify UTF8 encoded elements of list
* duplicate list
* each elements are unique in the new list
* \param
* list
* \return
* new list with unique elements
* empty list when list is empty
* NULL when list is NULL
*/
char **icListUniqUTF8(char **list)
/*
* ignore case and uniquify UTF8 encoded elements of list
* each elements are unique in the list
* \param
* list
* \return
* list with unique elements
* empty list when list is empty
* unchanged list when list is NULL
* NULL error
*/
char **iicListUniqUTF8(char ***list)
/*
* empty String Function
* \return
* new empty string
*/
char *emptySF(void)
/*
* empty String Function
* when *string is NULL, it is freed
* \return
* empty string
* NULL nothing when string is NULL
*/
char *iEmptySF(char **string)
/*
* is Empty String
* \param
* string
* \return
* false when there are characters in the string
* true when string is empty
* true when string is NULL
*/
bool isEmptyS(const char *string)
/*
* is Blank String
* \param
* string
* \return
* false when there are non white space characters in the string
* true when there are only white spaces in the string
* true when string is empty
* true when string is NULL
*/
bool isBlankS(const char *string)
/*
* int to positive index
* index can be negative
* \param
* index: index in list, must be inside the list
* length: list length
* \return
* positive index
* -1 when length is 0 or index is not set correctly
*/
ssize_t intIndex(intmax_t index, intmax_t length)
/*
* list Empty String Function
* \return
* new empty list
*/
char **listEmptySF(void)
/*
* list Empty String Function
* \return
* empty list
* NULL error
*/
char **iListEmptySF(char ***list)
/*
* list Is Empty String
* \param
* list
* \return
* false when there are elements in the list
* true when list is empty
* true when list is NULL
*/
bool listIsEmptyS(char **list)
/*
* list Is Empty String
* \param
* list
* \return
* false when there are non blank elements in the list
* true when all elements are blank
* true when list is NULL
*/
bool listIsBlankS(char **list)
/*
* list Create String Function
* create a list from the list of parameters
* used from the listCreateS(...) macro
* \param
* list of strings seperated with commas
* \return
* list
* NULL when first element if NULL
*/
char **listCreateSF(const char *paramType, ...)
/*
* list From Array String
* copy array of 'size' strings to a new list
* NULL strings are not copied to the list
* \param
* array of strings
* size - number of strings in the array
* \return
* list
* empty list when size is 0
* NULL when array is NULL
*/
char **listFromArrayS(char **array, size_t size)
/*
* list Push String
* append s at the end of the list
* when list is NULL, a new list with one element is returned
* when list and s are NULL return list with 2 NULL elements
* when s is NULL, NULL is pushed at the end of the list
* the list is reallocated to add extra space
* \param
* pointer to list - becomes NULL when realloc fails
* s: string to push
* \return
* list success
* NULL error
*/
char **listPushS(char ***list, const char *s)
/*
* list Push String
* append s pointer at the end of the list
* when list is NULL, a new list with one element is returned
* when list and s are NULL return list with 2 NULL elements
* when s is NULL, NULL is pushed at the end of the list
* the list is reallocated to add extra space
* \param
* pointer to list - becomes NULL when realloc fails
* s: string to push
* \return
* list success
* NULL error
*/
char **iListPushS(char ***list, char *s)
/*
* list Pop String
* return last string from list and remove last element from the list
* \param
* pointer to list
* \return
* duplicated last string
* NULL when the list is NULL or empty (first element is NULL)
*/
char *listPopS(char ***list)
/*
* list Prepend String
* append s at the beginning of the list
* when list is NULL, a new list with one element is returned
* when list and s are NULL return list with 2 NULL elements
* when s is NULL, the operation is canceled
* the list is reallocated to add extra space
* \param
* pointer to list - becomes NULL when realloc fails
* s: string to prepend
* \return
* list success
* NULL error
*/
char **listPrependS(char ***list, const char *s)
/*
* list Prepend String
* append s pointer at the beginning of the list
* when list is NULL, a new list with one element is returned
* when list and s are NULL return list with 2 NULL elements
* when s is NULL, the operation is canceled
* the list is reallocated to add extra space
* \param
* pointer to list - becomes NULL when realloc fails
* s: string to prepend
* \return
* list success
* NULL error
*/
char **iListPrependS(char ***list, char *s)
/*
* list Dequeue String
* return first string from list and remove it from the list
* \param
* pointer to list
* \return
* first string
* NULL when the list is NULL or empty (first element is NULL)
*/
char *listDequeueS(char ***list)
/*
* list Free String
* \param
* list
* \return
* nothing
*/
void listFreeS(char **list)
/*
* list free many String
* free variable list of pointers
* listFreeManyS(l1, l2, ...);
*/
void listFreeManySF(char **paramType, ...)
/*
* list Length String
* return number of elements until the first NULL element
* \param
* list
* \return
* number of element until first NULL element
* 0 when list is NULL
*/
size_t listLengthS(char **list)
/*
* list int to index String
* index can be negative
* \param
* list
* index: index in list, must be inside the list
* \return
* positive index
* -1 when list is NULL or index is not set correctly
*/
ssize_t listIntIndexS(char **list, intmax_t index)
/*
* list address String
* index can be negative
* \param
* list
* index: index in list, must be inside the list
* \return
* pointer to char* at index
* NULL when list is NULL or index is not set correctly
*/
char **listAddrS(char **list, intmax_t index)
/*
* list Get String
* duplicate string at given index
* index can be negative
* \param
* list
* index: index in list, must be inside the list
* \return
* duplicated string
* NULL when list is NULL or index is not set correctly
*/
char *listGetS(char **list, intmax_t index)
/*
* list Get String
* index can be negative
* \param
* list
* index: index in list, must be inside the list
* \return
* string
* NULL when list is NULL or index is not set correctly
*/
char *iListGetS(char **list, intmax_t index)
/*
* list Set String
* duplicate string and store at given index, the existing element is freed
* index can be negative
* \param
* list
* index: index in list, must be inside the list
* string
* \return
* list success
* NULL error
* Does nothing when:
* when list is NULL, index is not set correctly or s is NULL
*/
char **listSetS(char **list, intmax_t index, const char *s)
/*
* list Set String
* store string at given index
* index can be negative
* \param
* list
* index: index in list, must be inside the list
* string
* \return
* list success
* NULL error
* Does nothing when:
* when list is NULL, index is not set correctly or s is NULL
*/
char **iListSetS(char **list, intmax_t index, char *s)
/*
* split string with delim string
* return list
* \param
* string to split
* delim delimiter
* \return
* list of tokens
* NULL when list or delim are NULL
*/
char **split(const char *string, const char* delim)
/*
* ignore case split string with delim string
* return list
* \param
* string to split
* delim delimiter
* \return
* list of tokens
* NULL when list or delim are NULL
*/
char **icSplit(const char *string, const char* delim)
/*
* join list, the elements are seperated with delim in the resulting string
* \param
* list
* delim: string seperator
* \return
* joined string
* NULL when list or delim are NULL
*/
char *join(char **list, const char* delim)
/*
* buffer join list, the elements are seperated with delim in the resulting string
* \param
* list
* delim: string seperator
* \return
* joined string
* NULL when list or delim are NULL
*/
char *bJoin(char *string, char **list, const char* delim)
/*
* buffer size join list, the elements are seperated with delim in the resulting string
* \param
* list
* delim: string seperator
* \return
* joined string
* NULL when list or delim are NULL
*/
char *bLJoin(char *string, size_t stringSize, char **list, const char* delim)
/*
* extract string between delim1 and delim2 strings
* return list
* \param
* string to split
* delim1 first delimiter
* delim2 second delimiter, has to different from delim1
* \return
* list of tokens
* NULL when list or delim are NULL
*/
char **extractS(const char *string, const char* delim1, const char* delim2)
/*
* ignore case extract string between delim1 and delim2 strings
* return list
* \param
* string to split
* delim1 first delimiter
* delim2 second delimiter, has to different from delim1
* \return
* list of tokens
* NULL when list or delim are NULL
*/
char **icExtractS(const char *string, const char* delim1, const char* delim2)
/*
* list Duplicate String
* \param
* list
* \return
* duplicated list
* NULL when list is NULL
*/
char **listDupS(char **list)
/*
* list Duplicate String
* copy pointers to new list
* After this function, free list with free instead of listFreeS
* Note: this function creates a new list, so char *** is not needed.
* Unlike iList functions.
* \param
* list
* \return
* new list pointing to the same string as list
* NULL when list is NULL
*/
char **iListDupS(char **list)
/*
* list Reverse String
* duplicate and reverse list, the last element is the first element of the new list
* \param
* list
* \return
* reversed list
* NULL when list is NULL
*/
char **listReverseS(char **list)
/*
* list Reverse String
* reverse list, the last element is the first element of the list
* \param
* list
* \return
* reversed list
* nothing when list is NULL
* NULL error
*/
char **iListReverseS(char ***list)
/*
* list Cat String
* \param
* arbitrary list of lists seperated by commas
* \return
* new list with input lists concatenated
*/
char **listCatSF(char **paramType, ...)
/*
* list Append String
* Append list2 at the end of list1
* list1 is reallocated to add extra space
* \param
* list1
* list2
* \return
* list1 and list2
* list1 not modified when list1 and list2 are NULL
* NULL error
*/
char **listAppendS(char ***list1, char **list2)
/*
* list Append String
* Append list2 at the end of list1 by copying the pointers
* from list2 to list1.
* After this function, free list2 with free instead of listFreeS
* list1 is reallocated to add extra space
* \param
* list1
* list2
* \return
* list1 and list2
* list1 not modified when list1 and list2 are NULL
* or when list1 is identical to list2 (same pointers)
* NULL error
*/
char **iListAppendS(char ***list1, char **list2)
/*
* list Append and smash String
* Append list2 at the end of list1 by copying the pointers
* from list2 to list1.
* list2 is freed (except when there is an error)
* list1 is reallocated to add extra space
* \param
* list1
* list2
* \return
* list1 and list2
* list1 not modified when list1 and list2 are NULL
* or when list1 is identical to list2 (same pointers)
* NULL error
*/
char **iListAppendNSmashS(char ***list1, char **list2)
/*
* list Add String
* add list1 and list2 in a new list
* \param
* list1
* list2
* \return
* new list with list1 and list2
* NULL when list1 and list2 are NULL
*/
char **listAddS(char **list1, char **list2)
/*
* list Slice String
* return new list with elements from start and end in list
* negative indexes are allowed
* \param
* list
* start index, must be in the list
* end index, must be in the list
* \return
* sliced list
* empty list when start=end
* NULL when list is empty
* NULL when list is NULL or when start and end are not set correctly
*/
char **listSliceS(char **list, intmax_t start, intmax_t end)
/*
* list Copy String
* return new list with element pointers from start and end in list
* negative indexes are allowed
* Note: this function creates a new list, so char *** is not needed.
* Unlike iList functions.
* \param
* list
* start index, must be in the list
* end index, must be in the list
* \return
* new list pointing to the same string as list
* empty list when start=end
* NULL when list is empty
* NULL when list is NULL or when start and end are not set correctly
*/
char **iListCopyS(char **list, intmax_t start, intmax_t end)
/*
* list Slice String
* return list with elements from start and end in list
* negative indexes are allowed
* \param
* list
* start index, must be in the list
* end index, must be in the list
* \return
* sliced list
* empty list when start=end
* unchanged when list is empty
* unchanged when list is NULL or when start and end are not set correctly
* NULL error
*/
char **iListSliceS(char ***list, intmax_t start, intmax_t end)
/*
* list Insert string
* insert list in list at index
* return new list with toInsert at index
* negative indexes are allowed
* index -1 is the end of the array and is equivalent to index len
* \param
* list
* index in list
* toInsert list
* \return
* new list
* NULL when list is NULL or invalid index
*/
char **listInsertS(char **list, intmax_t index, char **toInsert)
/*
* list Insert string
* insert list in list at index
* After this function, free toInsert with free instead of listFreeS
* return list with toInsert at index
* negative indexes are allowed
* index -1 is the end of the array and is equivalent to index len
* \param
* list
* index in list
* toInsert list
* \return
* list
* unchanged list when list is NULL or invalid index
* NULL error
*/
char **iListInsertS(char ***list, intmax_t index, char **toInsert)
/*
* list Insert string and free toInsert
* insert list in list at index
* After this function, free toInsert with free instead of listFreeS
* return list with toInsert at index
* negative indexes are allowed
* index -1 is the end of the array and is equivalent to index len
* \param
* list
* index in list
* toInsert list
* \return
* list
* unchanged list when list is NULL or invalid index
* NULL error
*/
char **iListInsertNFreeS(char ***list, intmax_t index, char **toInsert)
/*
* list Inject string
* Inject string in list at index
* return new list with toInject at index
* negative indexes are allowed
* index -1 is the end of the array and is equivalent to index len
* \param
* list
* index in list
* toInject string
* \return
* new list
* NULL when list is NULL or invalid index
*/
char **listInjectS(char **list, intmax_t index, char *toInject)
/*
* list Inject string
* Inject string pointer in list at index
* return list with toInject at index
* negative indexes are allowed
* index -1 is the end of the array and is equivalent to index len
* \param
* list
* index in list
* toInject string
* \return
* list
* unchanged list when list is NULL or invalid index
* NULL error
*/
char **iListInjectS(char ***list, intmax_t index, char *toInject)
/*
* list Delete String
* return new list without elements from start and end in list
* negative indexes are allowed
* \param
* list
* start index, must be in the list
* end index, must be in the list
* \return
* sliced list
* list copy when start=end or when start and end are not set correctly
* NULL when list is empty
* NULL when list is NULL or when end is under start
*/
char **listDelS(char **list, intmax_t start, intmax_t end)
/*
* list Delete String
* return list without elements from start and end in list
* negative indexes are allowed
* \param
* list
* start index, must be in the list
* end index, must be in the list
* \return
* sliced list
* list copy when start=end or when start and end are not set correctly
* NULL when list is empty
* NULL when list is NULL or when end is under start
* NULL error
*/
char **iListDelS(char ***list, intmax_t start, intmax_t end)
/*
* list Delete Element String
* return new list without the element at index
* negative indexes are allowed
* \param
* list
* \param
* index must be in the list
* \return
* new list without the element at index
* NULL when list is empty
* NULL when list is NULL
*/
char **listDelElemS(char **list, intmax_t index)
/*
* list Delete Element String
* return list without the element at index
* negative indexes are allowed
* \param
* list
* \param
* index must be in the list
* \return
* new list without the element at index
* NULL when list is empty
* NULL when list is NULL
* NULL error
*/
char **iListDelElemS(char ***list, intmax_t index)
/*
* print list elements
* to stdout
* when list is NULL, returns directly without doing anything
* \param
* list
* \return
* nothing
* 0 success
* -1 error
*/
int listPrintS(char **list)
/*
* list Sort String Compare function
* in:
* a
* b
* out:
* test result
*/
internal int listSortSCmp(const void * a, const void * b)
/*
* list Sort String
* duplicate list and sort
* \param
* list
* \return
* new sorted list
* empty list when list is empty
* NULL when list is NULL
*/
char **listSortS(char **list)
/*
* list Sort String
* \param
* list
* \return
* sorted list
* empty list when list is empty
* unchanged list when list is NULL
* NULL error
*/
char **iListSortS(char ***list)
/*
* list Sort String
* duplicate list and sort
* \param
* list
* compareFunction
* \return
* new sorted list
* empty list when list is empty
* NULL when list is NULL
*/
char **listSortFS(char **list, shCmpt compareFunction)
/*
* list Sort String
* \param
* list
* compareFunction
* \return
* sorted list
* empty list when list is empty
* unchanged list when list is NULL
* NULL error
*/
char **iListSortFS(char ***list, shCmpt compareFunction)
/*
* ignore case list Sort String Compare function
* in:
* a
* b
* out:
* test result
*/
internal int icListSortSCmp(const void * a, const void * b)
/*
* ignore case list Sort String
* duplicate list and sort
* \param
* list
* \return
* new sorted list
* empty list when list is empty
* NULL when list is NULL
*/
char **icListSortS(char **list)
/*
* ignore case list Sort String
* \param
* list
* \return
* sorted list
* empty list when list is empty
* unchanged list when list is NULL
* NULL error
*/
char **iicListSortS(char ***list)
/*
* return text from filePath in a list
* new line characters are removed
* \param
* filePath: file path
* \return
* lines in list
* empty list when the file is empty
* NULL on failure
*/
/* this readText has the same performance as the original and takes twice the amount of RAM */
/*
* return text from stream fp in a list
* new line characters are removed
* \param
* fp: file stream
* \return
* lines in list
* empty list when there is no data in the stream
* NULL on failure
*/
char **readStream(FILE *fp)
/*
* write list to filePath
* \param
* filePath
* list
* \return
* true success
* false failed, filePath or list are NULL
*/
bool writeText(const char *filePath, char **list)
/*
* write list to stream
* \param
* fp: file stream
* list
* \return
* true success
* false failed, fp or list are NULL
*/
bool writeStream(FILE *fp, char **list)
/*
* append list to filePath
* \param
* filePath
* list
* \return
* true success
* false failed, filePath or list are NULL
*/
bool appendText(const char *filePath, char **list)
/*
* execute command
* return stdout from cmd
* \param
* cmd: command
* \return
* stdout from command in a list
* empty list when command didnt produce any output
* NULL when cmd is NULL
*/
char **execOut(const char *cmd)
/*
* execute system command with formatting
* \param
* formatting
* \return
* stdout from command in a list
* empty list when command didnt produce any output
* NULL when cmd is NULL
*/
char **systemOutf(const char *fmt, ...)
/*
* execute system command with formatting
* \param
* formatting
* \return
* system return code
*/
int systemf(const char *fmt, ...)
/*
* list Equal String
* compare each element of list1 and list2
* \param
* 2 lists
* \return
* true the lists have identical elements
* false they differ
*/
bool listEqS(char **list1, char **list2)
/*
* return true when list has string
* \param
* list
* string
* \return
* true when list has string
* false when the string is not found
* false when list or string are NULL
*/
bool listHasS(char **list, const char *string)
/*
* return index of string in list
* \param
* list
* string
* \return
* index
* -1 when the string is not found
* -1 when list or string are NULL
*/
ssize_t listIndexOfS(char **list, const char *string)
/*
* list binary search string
* efficiently finds the index of string in list
* the list has be sorted with for example listSortS
* \param
* list
* string to search
* \return
* index of string
* -1 string not found or NULL input pointers
*/
ssize_t listBinarySearchS(char **list, const char *string) {
ssize_t first = 0, middle, last;;
if (!list || !string) {
return(-1);
}
last = listLengthS(list) - 1;
while (first <= last) {
middle = (first+last)/2;
if (strcmp(list[middle], string) < 0) {
first = middle + 1;
}
else if (strcmp(list[middle], string) == 0) {
return(middle);
}
else {
last = middle -1;
}
}
return(-1);
}
ssize_t listBinarySearchCharS(char **list, char c) {
charToS(s, c);
return(listBinarySearchS(list, s));
}
/*
* Uniquify elements of list
* duplicate list
* each elements are unique in the new list
* \param
* list
* \return
* new list with unique elements
* empty list when list is empty
* NULL when list is NULL
*/
char **listUniqS(char **list)
/*
* Uniquify elements of list
* each elements are unique in the list
* \param
* list
* \return
* list with unique elements
* empty list when list is empty
* unchanged list when list is NULL
* NULL error
*/
char **iListUniqS(char ***list)
/*
* ignore case list Equal String
* compare each element of list1 and list2
* \param
* 2 lists
* \return
* true the lists have identical elements
* false they differ
*/
bool icListEqS(char **list1, char **list2)
/*
* ignore case and return true when list has string
* \param
* list
* string
* \return
* true when list has string
* false when the string is not found
* false when list or string are NULL
*/
bool icListHasS(char **list, const char *string)
/*
* ignore case and return index of string in list
* \param
* list
* string
* \return
* index
* -1 when the string is not found
* -1 when list or string are NULL
*/
ssize_t icListIndexOfS(char **list, const char *string)
/*
* ignore case list binary search string
* efficiently finds the index of string in list
* the list has be sorted with for example listSortS
* \param
* list
* string to search
* \return
* index of string
* -1 string not found or NULL input pointers
*/
ssize_t icListBinarySearchS(char **list, const char *string) {
ssize_t first = 0, middle, last;;
if (!list || !string) {
return(-1);
}
last = listLengthS(list) - 1;
while (first <= last) {
middle = (first+last)/2;
if (strcasecmp(list[middle], string) < 0) {
first = middle + 1;
}
else if (strcasecmp(list[middle], string) == 0) {
return(middle);
}
else {
last = middle -1;
}
}
return(-1);
}
ssize_t icListBinarySearchCharS(char **list, char c) {
charToS(s, c);
return(icListBinarySearchS(list, s));
}
/*
* ignore case and uniquify elements of list
* duplicate list
* each elements are unique in the new list
* \param
* list
* \return
* new list with unique elements
* empty list when list is empty
* NULL when list is NULL
*/
char **icListUniqS(char **list)
/*
* ignore case and uniquify elements of list
* each elements are unique in the list
* \param
* list
* \return
* list with unique elements
* empty list when list is empty
* unchanged list when list is NULL
* NULL error
*/
char **iicListUniqS(char ***list)
/*
* remove empty strings from list
* \param
* list
* \return
* list without empty strings
* empty list when list is empty
* NULL when list is NULL
*/
char **listCompactS(char **list)
/*
* remove empty strings from list
* \param
* list
* \return
* list without empty strings
* empty list when list is empty
* unchanged list when list is NULL
* NULL error
*/
char **iListCompactS(char ***list)
/*
* generate backtrace
* the program has to be linked the -rdynamic option for btrace to work
* btrace can backtrace 50 functions at most.
* \return
* list of functions in the backtrace, the line format is: function name: source path:line number
*/
#if (__FreeBSD__ || __TERMUX__)
/*
* list Empty Function
* \return
* new empty list
*/
void **listEmptyF(void)
/*
* list Empty Function
* \return
* empty list
* NULL error
*/
void **iListEmptyF(void ***list)
/*
* list Is Empty
* \param
* list
* \return
* false when there are elements in the list
* true when list is empty
* true when list is NULL
*/
bool listIsEmpty(void **list)
/*
* list Create Function
* create a list from the list of parameters
* used from the listCreate(...) macro
* \param
* list of elements seperated with commas
* \return
* list
* NULL when first element if NULL
*/
void **listCreateF(void *paramType, ...)
/*
* list From Array
* copy array of 'size' to a new list
* NULL elements are not copied to the list
* \param
* array
* size - number of elements in the array
* \return
* list
* empty list when size is 0
* NULL when array is NULL
*/
void **listFromArray(void **array, size_t size)
/*
* list Push
* (like iListPushS)
* append s pointer at the end of the list
* when list is NULL, a new list with one element is returned
* when list and s are NULL return list with 2 NULL elements
* when s is NULL, NULL is pushed at the end of the list
* the list is reallocated to add extra space
* \param
* pointer to list - becomes NULL when realloc fails
* s: element to push
* \return
* list success
* NULL error
*/
void **listPush(void ***list, void *s)
/*
* list Pop
* return last element from list and remove last element from the list
* \param
* pointer to list
* \return
* last element
* NULL when the list is NULL or empty (first element is NULL)
*/
void *listPop(void ***list)
/*
* list Prepend
* (like iListPrependS)
* append s pointer at the beginning of the list
* when list is NULL, a new list with one element is returned
* when list and s are NULL return list with 2 NULL elements
* when s is NULL, NULL is pushed at the end of the list
* the list is reallocated to add extra space
* \param
* pointer to list - becomes NULL when realloc fails
* s: element to prepend
* \return
* list success
* NULL error
*/
void **listPrepend(void ***list, void *s)
/*
* list Dequeue
* return first element from list and remove last element from the list
* \param
* pointer to list
* \return
* first element
* NULL when the list is NULL or empty (first element is NULL)
*/
void *listDequeue(void ***list)
/*
* list Free
* \param
* list
* \return
* nothing
*/
void listFree(void **list)
/*
* list free many
* free variable list of pointers
* listFreeManyS(l1, l2, ...);
*/
void listFreeManyF(void **paramType, ...)
/*
* list Length
* return number of elements until the first NULL element
* \param
* list
* \return
* number of element until first NULL element
* 0 when list is NULL
*/
size_t listLength(void **list)
/*
* list Get
* (like iListGetS)
* index can be negative
* \param
* list
* index: index in list, must be inside the list
* \return
* element
* NULL when list is NULL or index is not set correctly
*/
void *listGet(void **list, intmax_t index)
/*
* list Set
* (like iListSetS)
* store element at given index
* previous element at index has to be freed before hand
* index can be negative
* \param
* list
* index: index in list, must be inside the list
* element
* \return
* list success
* NULL error
* Does nothing when:
* when list is NULL, index is not set correctly or s is NULL
*/
void **listSet(void **list, intmax_t index, void *s)
/*
* list Duplicate
* (like iListDupS)
* copy pointers to new list
* After this function, free list with free instead of listFreeS
* Note: this function creates a new list, so void *** is not needed.
* Unlike iList functions.
* \param
* list
* \return
* new list pointing to the same elements as list
* NULL when list is NULL
*/
void **listDup(void **list)
/*
* list Reverse
* create index list and reverse list, the last element is the first element of the new list
* \param
* list
* \return
* reversed list
* NULL when list is NULL
*/
void **listReverse(void **list)
/*
* list Reverse
* reverse list, the last element is the first element of the list
* \param
* list
* \return
* reversed list
* nothing when list is NULL
* NULL error
*/
void **iListReverse(void ***list)
/*
* list Cat
* \param
* arbitrary list of lists seperated by commas
* \return
* new list with input lists concatenated
*/
void **listCatF(void **paramType, ...)
/*
* list Append
* (like iListAppendS)
* Append list2 at the end of list1 by copying the pointers
* from list2 to list1.
* After this function, free list2 with free instead of listFreeS
* list1 is reallocated to add extra space
* \param
* list1
* list2
* \return
* list1 and list2
* list1 not modified when list1 and list2 are NULL
* or when list1 is identical to list2 (same pointers)
* NULL error
*/
void **listAppend(void ***list1, void **list2)
/*
* list Add
* add list1 and list2 in a new list
* \param
* list1
* list2
* \return
* new list with list1 and list2
* NULL when list1 and list2 are NULL
*/
void **listAdd(void **list1, void **list2)
/*
* list Slice
* (like iListCopyS)
* return new list with element pointers from start and end in list
* negative indexes are allowed
* Note: this function creates a new list, so void *** is not needed.
* Unlike iList functions.
* \param
* list
* start index, must be in the list
* end index, must be in the list
* \return
* new list pointing to the same elements as list
* empty list when start=end
* NULL when list is empty
* NULL when list is NULL or when start and end are not set correctly
*/
void **listSlice(void **list, intmax_t start, intmax_t end)
/*
* list Slice
* return list with elements from start and end in list
* negative indexes are allowed
* \param
* list
* start index, must be in the list
* end index, must be in the list
* \return
* sliced list
* empty list when start=end
* unchanged when list is empty
* unchanged when list is NULL or when start and end are not set correctly
* NULL error
*/
void **iListSlice(void ***list, intmax_t start, intmax_t end)
/*
* list Insert
* insert list in list at index
* return new list with toInsert at index
* negative indexes are allowed
* index -1 is the end of the array and is equivalent to index len
* \param
* list
* index in list
* toInsert list
* \return
* new list
* NULL when list is NULL or invalid index
*/
void **listInsert(void **list, intmax_t index, void **toInsert)
/*
* list Insert
* insert list in list at index
* After this function, free toInsert with free instead of listFreeS
* return list with toInsert at index
* negative indexes are allowed
* index -1 is the end of the array and is equivalent to index len