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)
BUCKETS(count, divider)
setMax(result, a, b)
setMin(result, a, b)
maxV(a, b)
minV(a, b)
cast(type, casted, toCast)
freen(ptr)
EVA(var, func)
loopBreaker(breakCount)
UNIQVAR(name)
logVar(var, format)
logMVar(mask, var, format)
logPtr(pointer)
logMPtr(mask, 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(...)
logSI(format, string)
logSW(format, string)
logSE(format, string)
logSC(format, string)
uint64_t logMask
pLogMask(mask, level, ...)
logMI(mask, ...)
logMW(mask, ...)
logME(mask, ...)
logMC(mask, ...)
logSMI(mask, format, string)
logSMW(mask, format, string)
logSME(mask, format, string)
logSMC(mask, format, string)
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 *toHexS(const void *buf, size_t len)
char *toHexSepS(const void *buf, size_t len, const char *separator)
char *toHexHeadSepS(const void *buf, size_t len, const char *head, const char *separator)
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 *bFormatS(char *string, const char *fmt, ...)
char *bLFormatS(char *string, size_t stringSize, 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 listStrLengthS(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)
ssize_t joinLength(char **list, const 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)
reallocArray(name, count)
sliceT(typeName, elementType)
createSlice(typeName, name)
createSliceCount(typeName, name, count)
createSliceClearCount(typeName, name, count)
createAllocateSlice(typeName, name)
createAllocateSliceCount(typeName, name, count)
createAllocateSliceClearCount(typeName, name, count)
sliceInit(name)
sliceInitCount(name, countInt)
sliceCalloc(name, countInt)
sliceResize(name, countInt)
sliceClearResize(name, countInt)
sliceFree(name)
sliceDup(name)
sliceCreateNDup(name, dest)
sliceBDup(name, dest)
sliceData(name)
sliceFrom(name, array, countInt)
sliceMirror(name, start, end)
sliceBMirror(name, dest, start, end)
sliceMirrorFrom(name, array, countInt)
sliceClearRange(name, start, end)
sliceFit(name)
sliceClearElem(name, index)
slicePush(name)
sliceAppend(name, v)
slicePop(name)
sliceSet(name, index, v)
sliceAt(name, index)
slicePtr(name, index)
sliceLast(name)
sliceWriteFilename(name, filename)
sliceReadFilename(name, filename)
forEachSc(name, index)
sliceInject(name, index)
slicePrepend(name, v)
sliceDelElem(name, index)
sliceDel(name, start, end)
sliceAppendFrom(name, array, countInt)
slicePrependFrom(name, array, countInt)
sliceInsert(name, index, slice)
sliceInsertFrom(name, index, array, countInt)
sliceSlice(name, start, end)
sliceCopy(name, start, end)
sliceBCopy(name, dest, start, end)
sliceSort(name, compareFunction)
sliceEq(name, slice, eqFunction)
sliceHas(name, value, eqFunction)
sliceIndexOf(name, value, eqFunction)
sliceBinarySearch(name, value, less, equal)
sliceUniq(name, eqFunction)
staticSliceT(typeName, elementType, MAXCOUNT)
createStaticSlice(typeName, name)
staticSliceBDup(name, dest)
staticSliceFrom(name, array, countInt)
staticSliceClearRange(name, start, end)
staticSliceReadFilename(name, filename)
staticSliceInject(name, index)
staticSliceVAppend(name, staticSlice)
staticSliceAppendFrom(name, array, countInt)
staticSliceVPrepend(name, staticSlice)
staticSlicePrependFrom(name, array, countInt)
staticSliceInsert(name, index, staticSlice)
staticSliceInsertFrom(name, index, array, countInt)
staticSliceBCopy(name, dest, start, end)
vectorT(typeName, elementType)
createVector(typeName, name)
createVectorCount(typeName, name, count)
createVectorClearCount(typeName, name, count)
createAllocateVector(typeName, name)
createAllocateVectorCount(typeName, name, count)
createAllocateVectorClearCount(typeName, name, count)
vectorInitCount(name, countInt)
vectorCalloc(name, countInt)
vectorResize(name, countInt)
vectorClearResize(name, countInt)
vectorDup(name)
vectorCreateNDup(name, dest)
vectorBDup(name, dest)
vectorFrom(name, array, countInt)
vectorFit(name)
vectorAppend(name, v)
vectorSet(name, index, v)
vectorReadFilename(name, filename)
vectorInject(name, index)
vectorPrepend(name, v)
vectorVAppend(name, vector)
vectorAppendFrom(name, array, countInt)
vectorVPrepend(name, vector)
vectorPrependFrom(name, array, countInt)
vectorInsert(name, index, vector)
vectorInsertFrom(name, index, array, countInt)
vectorCopy(name, start, end)
vectorBCopy(name, dest, start, end)
dVectorT(typeName, elementType)
createDVector(typeName, name)
createDVectorCount(typeName, name, count)
dVectorResize(a, count)
dVectorAt(a, index)
dVectorPtr(a, index)
dVectorReadFilename(a, filename)
typedef struct {
staticArrayT(typeName, element, MAXCOUNT)
createStaticArray(typeName, name)
staticArrayGet(name, index)
staticArrayGetIndex(name, index)
staticArrayRef(name, index)
staticArrayRefIndex(name, index)
staticArrayWriteFilename(name, filename)
staticArrayReadFilename(name, filename)
indexerT(typeName, INT_TYPE)
createIndexer(typeName, name, maxCount)
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)
createDArray(typeName, name)
createDArrayCount(typeName, name, count)
dArrayInitCount(a, count)
dArrayResize(a, count)
dArrayAt(a, index)
dArrayPtr(a, index)
dArrayWriteFilename(a, filename)
dArrayReadFilename(a, filename)
slabT(typeName, elementType)
createSlab(typeName, name)
createSlabCount(typeName, name, count)
slabInitCount(a, count)
slabResize(a, count)
slabEmpty(name)
slabCount(name)
slabWriteFilename(a, filename)
slabReadFilename(a, filename)
staticBitsetT(typeName, containerType, count)
staticBitsetBucket(name, index)
staticBitset0(name, index)
staticBitset1(name, index)
staticBitsetSet(name, index, value)
staticBitsetInv(name, index)
staticBitsetGet(name, index)
bitsetBucket(name, index)
bitset0(name, at, index)
bitset1(name, at, index)
bitsetSet(name, at, index, value)
bitsetInv(name, at, index)
bitsetGet(name, at, index)
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))
/*
* divide count by divider and add one when remainder is not zero
* this is used in segmented arrays to count the number of buckets from the element count
* For example, bucket have 64 elements and there are 66 elements in the array
* 66/64 = 1
* and there are 2 buckets, so BUCKETS returns 2
*/
#define BUCKETS(count, divider) ((count)/(divider) + (((count) % (divider)) ? 1 : 0))
#define setMax(result, a, b) do{\
#define setMin(result, a, b) do{\
#define maxV(a, b) ({\
#define minV(a, b) ({\
/*
* 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);
/*
* free pointer and set it to NULL
*/
#define freen(ptr) do {\
/*
* 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 logMVar(mask, var, format) logMI(mask, "%s=%" format, stringifyExpr(var), var);
#define logBoolVar(var) logVar(var, "b");
#define logMBoolVar(mask, var) logMVar(mask, var, "b");
/*
* log pointer
*/
#define logPtr(pointer) logI("%s=%p", stringifyExpr(pointer), pointer);
#define logMPtr(mask, pointer) logMI(mask, "%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__)
/*
* log string and free
* Example:
* logSI("The list: %s", catS("1", "2"));
*/
#define logSI(format, string) do {\
/*
* log string and free
* Example:
* logSW("The list: %s", catS("1", "2"));
*/
#define logSW(format, string) do {\
/*
* log string and free
* Example:
* logSE("The list: %s", catS("1", "2"));
*/
#define logSE(format, string) do {\
/*
* log string and free
* Example:
* logSC("The list: %s", catS("1", "2"));
*/
#define logSC(format, string) do {\
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__)
/*
* log and mask string and then free
* Example:
* logSMI("The list: %s", catS("1", "2"));
*/
#define logSMI(mask, format, string) do {\
/*
* log and mask string and then free
* Example:
* logSMW("The list: %s", catS("1", "2"));
*/
#define logSMW(mask, format, string) do {\
/*
* log and mask string and then free
* Example:
* logSME("The list: %s", catS("1", "2"));
*/
#define logSME(mask, format, string) do {\
/*
* log and mask string and then free
* Example:
* logSMI("The list: %s", catS("1", "2"));
*/
#define logSMC(mask, format, string) do {\
// 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);
// create a string with bytes in buf converted to hex strings: 0xff,
char *toHexS(const void *buf, size_t len);
// create a string with bytes in buf converted to hex strings separated by separator: 0xffSEP
char *toHexSepS(const void *buf, size_t len, const char *separator);
// create a string with bytes in buf converted to hex strings separated by separator and with head string in front of earch byte: HEADffSEP
char *toHexHeadSepS(const void *buf, size_t len, const char *head, const char *separator);
// 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, ...);
char *bFormatS(char *string, const char *fmt, ...);
char *bLFormatS(char *string, size_t stringSize, const char *fmt, ...);
// 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);
// list length as a single string
ssize_t listStrLengthS(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);
// list length after joined with delimiter
ssize_t joinLength(char **list, const 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);
// create name variable and allocate array of type on heap
#define newArray(name, type, count)\
// allocate array
#define allocArray (name, count) malloc((count) * sizeof(*(name)))
// calloc array
#define callocArray (name, count) calloc(count, sizeof(*(name)))
// realloc array
#define reallocArray(name, count) realloc(name, (count) * sizeof(*(name)))
/*
* slice - dynamic array in one chunk of memory (similar to vector and slab below)
* This is a simple dynamic array holding element count and the data
* this type of array has a dynamic element count
* pushing elements into the array increases the element count
* poping elements only decreases the element count, call sliceFit to realoc the slice
* no sanity checks are done
* the prefix is slice
* Usage:
* to declare a slice:
* sliceT(typeName, type);
* typeName slce;
* sliceInit(&slce);
* or
* sliceInitCount(&slce, 17);
* sliceAppend(&slce, value);
* // get an element
* int a = sliceAt(&slce, 0);
* set
* sliceAt(&slce, 1) = 3;
* sliceFree(&slce);
* Slice variables:
* slce.array: elements
* slce.count: current element count
* Note: some functions are macros to be able to have structs as element and
* access the struct members directly, for example:
* sliceLast(chan).a = 0;
*/
#define sliceSz 1
/*
* declares type for slice
* \param
* typeName slice type name
* \param
* element type of elements (int, struct, pointer...)
*/
#define sliceT(typeName, elementType)\
#define createSlice(typeName, name) ;typeName name; sliceInit(&name)
#define createSliceCount(typeName, name, count) ;typeName name; sliceInitCount(&name, count)
#define createSliceClearCount(typeName, name, count) ;typeName name; sliceCalloc(&name, count)
#define createAllocateSlice(typeName, name) ;typeName *name = calloc(1, sizeof(typeName))
#define createAllocateSliceCount(typeName, name, count) ;typeName *name = calloc(1, sizeof(typeName)); sliceInitCount(name, count)
#define createAllocateSliceClearCount(typeName, name, count) ;typeName *name = calloc(1, sizeof(typeName)); sliceCalloc(name, count)
#define sliceTerminate(name) if (name) sliceFree(name);free(name)
/*
* initialize empty slice
* \param
* name variable name for slice
*/
#define sliceInit(name) do{\
/*
* initialize slice and count
* \param
* name variable name for slice
* \param
* count initial element count for name type
*/
#define sliceInitCount(name, countInt) do{\
/*
* initialize slice and count and set slice data to 0
* \param
* name variable name for slice
* \param
* count initial element count for name type
*/
#define sliceCalloc(name, countInt) do{\
/*
* resize slice (even empty slices)
*/
#define sliceResize(name, countInt) do{\
/*
* resize slice and clear the new elements with memset
* even empty slices can be resized and cleared
*/
#define sliceClearResize(name, countInt) do{\
/*
* free the internal buffers
* \param
* name slice
*/
#define sliceFree(name) free((name)->array)
/*
* duplicate slice
*/
#define sliceDup(name) ({\
/*
* declare dest slice and duplicate slice
*/
#define sliceCreateNDup(name, dest) ;typeof(*(name)) dest; sliceInitCount(dest, (name)->count); if ((name)->array) { memcpy(dest->array, (name)->array, (name)->count * sizeof (name)->array[0]); dest->count = (name)->count;}
/*
* duplicate slice to already declared dest slice
*/
#define sliceBDup(name, dest) do{\
/*
* direct access to underlying array
*/
#define sliceData(name) (name)->array
/*
* copy data from array to slice
*/
#define sliceFrom(name, array, countInt) do{\
/*
* mirror a range in a slice
* the data is not copied to dest slice, to copy data see sliceCopy or sliceBCopy
*/
#define sliceMirror(name, start, end) ({\
/*
* mirror a range in a slice
* the data is not copied to dest slice, to copy data see sliceCopy or sliceBCopy
* name can be slice, vector or slab
* dest must be slice
*/
#define sliceBMirror(name, dest, start, end) do{\
/*
* mirror from array to slice
* the data is not copied to dest slice, to copy data see sliceCopy or sliceBCopy
*/
#define sliceMirrorFrom(name, array, countInt) do{\
/*
* set 0 in slice elements
* count is unchanged
*/
#define sliceClear(name) do{\
#define sliceClearRange(name, start, end) do{\
/*
* Empty slice
* Set count to 0
* Allocated buffers in the slice must be freed before running sliceEmpty
*/
#define sliceEmpty(name) (name)->count = 0
/*
* is slice Empty
*/
#define sliceIsEmpty(name) ((name)->count == 0 || !(name)->array)
/*
* realloc slice to count
*/
#define sliceFit(name) do{\
/*
* return element count
*/
#define sliceCount(name) (name)->count
/*
* size of slice element
*/
#define sliceElemSize(name) sizeof((name)->array[0])
/*
* allocate an element
* only when the slice is full
*/
#define sliceAlloc(name) do{\
/*
* clear (set 0) in element at index
*/
#define sliceClearElem(name, index) memset(&(name)->array[index], 0, sizeof (name)->array[0])
/*
* push element and expand the slice
* no data (random) is set in the new element
* \param
* name slice
*/
#define slicePush(name) do {\
/*
* append element and expand the slice
* \param
* name slice
* \param
* v element to push
*/
#define sliceAppend(name, v) do{\
/*
* push element and expand the slice
* the new element is cleared
* \param
* name slice
*/
#define sliceClearPush(name) do{\
/*
* pop element
* the element count is decreased
* NOTE: using comma operator to avoid warning
* warning: operation on ‘b.head’ may be undefined [-Wsequence-point]
* \param
* name slice
*/
#define slicePop(name) ((name)->count--, (name)->array[(name)->count])
/*
* 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 sliceDelLast(name) ((name)->count--)
/*
* set value at index and clearResize slice when index is outside slice count
*/
#define sliceSet(name, index, v) do{\
/*
* get / set element at index
* \param
* name slice
* \param
* index index in array
*/
#define sliceAt(name, index) ((name)->array[index])
/*
* get pointer to element at index
* \param
* name slice
* \param
* index index in array
*/
#define slicePtr(name, index) ((name)->array + index)
/*
* last element
* \param
* name slice
*/
#define sliceLast(name) ((name)->array[(name)->count-1])
/*
* pointer to last element
* \param
* name slice
*/
#define sliceLastPtr(name) ((name)->array + (name)->count - 1)
/*
* index of last element
*/
#define sliceLastIndex(name) ((name)->count - 1)
/*
* first element
* \param
* name slice
*/
#define sliceFirst(name) ((name)->array[0])
/*
* write the slice content to filename file
* No NULL checks are done on the parameters
* \param
* filename file name string
*/
#define sliceWriteFilename(name, filename) do {\
/*
* write the slice content to disk
* No NULL checks are done on the parameters
* \param
* file already opened file
*/
#define sliceWrite(name, file) fwrite((name)->array, sizeof((name)->array[0]), sliceCount(name), file)
/*
* read a slice from filename file
* No NULL checks are done on the parameters
* \param
* filename file name string
*/
#define sliceReadFilename(name, filename) do {\
/*
* read a slice from disk
* No NULL checks are done on the parameters
* \param
* file already opened file
*/
#define sliceRead(name, file) do {\
/*
* loop index on slice elements
* For example:
* forEachV(vec, i) {
* sliceAt(vec, i) = 0;
* }
*/
#define forEachSc(name, index) range(index, (name)->count)
/*
* insert an element at index
* the data is moved to create space for the new element
* to set data at the new element, use sliceAt(name, index) = value;
*/
#define sliceInject(name, index) do {\
/*
* prepend element
* \param
* name slice
* \param
* v element to prepend
*/
#define slicePrepend(name, v) do {\
/*
* dequeue element
* \param
* name slice
*/
#define sliceDequeue(name) ({\
/*
* delete first element in slice
* the data is moved when count > 1
*/
#define sliceDelFirst(name) do {\
/*
* delete an element in slice
* the data is moved when index < (count-1)
* when index = count -1, the last element is deleted and no data is moved
*/
#define sliceDelElem(name, index) do {\
/*
* delete range in slice
* start must be between 0 and last index
* end must be between 1 and count
*/
#define sliceDel(name, start, end) do {\
/*
* append slice to slice name
* the data is copied
*/
#define sliceVAppend(name, slice) do {\
/*
* append array to slice
* the data is copied
*/
#define sliceAppendFrom(name, array, countInt) do {\
/*
* prepend slice to slice name
* the data in slice name is moved and
* the data in slice is copied to slice name
*/
#define sliceVPrepend(name, slice) do {\
/*
* prepend array to slice
* the data in slice is moved and
* the data in array is copied to slice
*/
#define slicePrependFrom(name, array, countInt) do {\
/*
* insert slice at position index
* the data in slice name is moved and
* the data in slice is copied to slice name
*/
#define sliceInsert(name, index, slice) do {\
/*
* insert array at position index
* the data in slice is moved and
* the data in array is copied to slice
*/
#define sliceInsertFrom(name, index, array, countInt) do {\
/*
* slice slice, keep only elements between start and end
* start must be between 0 and last index
* end must be between 1 and count
* the slice is returned
*/
#define sliceSlice(name, start, end) ({\
/*
* copy slice elements between start and end to a new slice
* start must be between 0 and last index
* end must be between 1 and count
* the new slice is returned and must be freed with sliceTerminate
*/
#define sliceCopy(name, start, end) ({\
/*
* copy slice elements between start and end to the dest slice
* start must be between 0 and last index
* end must be between 1 and count
*/
#define sliceBCopy(name, dest, start, end) do{\
/*
* sort the slice
* the compareFunction must prototype of type:
* int cmp(const void * a, const void * b);
* the results of the compareFunction should be:
* <0 when a < b
* 0 when a = b
* >0 when a > b
*/
#define sliceSort(name, compareFunction) do{ \
/*
* return true when slice name is equal to slice
* eqFunction should return true when the elements are equal
* eqFunction can be either a macro or a function
*/
#define sliceEq(name, slice, eqFunction) ({\
/*
* return true when slice has value
* eqFunction should return true when the elements are equal
* eqFunction can be either a macro or a function
*/
#define sliceHas(name, value, eqFunction) ({\
/*
* return index (ssize_t) of value in slice
* eqFunction should return true when the elements are equal
* eqFunction can be either a macro or a function
* return value is -1 when value is not found
*/
#define sliceIndexOf(name, value, eqFunction) ({\
/*
* binary search value in slice
* efficiently finds the index of value in slice
* the slice has to be sorted before calling sliceBinarySearch
* less is a macro taking an index and the search value returning 1 when sliceAt(name,index) is less than value:
* #define less(index, value) sliceAt(name, index) < value
* equal is a macro returning 1 when sliceAt(name,index) is equal to value:
* #define equal(index, value) sliceAt(name,index) == value
* return value is -1 when value is not found
*/
#define sliceBinarySearch(name, value, less, equal) ({\
/*
* Uniquify elements in slice
* each elements are unique in the slice
* eqFunction should return true when the elements are equal
* eqFunction can be either a macro or a function
*/
#define sliceUniq(name, eqFunction) do{\
/*
* end slice
*/
/*
* staticSlice - static array with element count
* pushing elements into the array increases the element count
* poping elements only decreases the element count
* no sanity checks are done
* the prefix is staticSlice
* Usage:
* to declare a staticSlice:
* staticSliceT(typeName, type, 10);
* typeName slce;
* staticSliceInit(&slce);
* staticSliceAppend(&slce, value);
* // get an element
* int a = staticSliceAt(&slce, 0);
* set
* staticSliceAt(&slce, 1) = 3;
* staticSliceFree(&slce);
* StaticSlice variables:
* slce.array: elements
* slce.count: current element count
* Note: some functions are macros to be able to have structs as element and
* access the struct members directly, for example:
* staticSliceLast(chan).a = 0;
*/
/*
* declares type for staticSlice
* \param
* typeName staticSlice type name
* \param
* element type of elements (int, struct, pointer...)
* \param
* MAXCOUNT array/ring buffer size
*/
#define staticSliceT(typeName, elementType, MAXCOUNT)\
#define createStaticSlice(typeName, name) ;typeName name; staticSliceInit(&name)
/*
* initialize empty staticSlice
* \param
* name variable name for staticSlice
*/
#define staticSliceInit(name) do{\
/*
* duplicate staticSlice to already declared dest staticSlice
*/
#define staticSliceBDup(name, dest) do{\
/*
* direct access to underlying array
*/
#define staticSliceData sliceData
/*
* copy data from array to staticSlice
*/
#define staticSliceFrom(name, array, countInt) do{\
/*
* set 0 in staticSlice elements
* count is unchanged
*/
#define staticSliceClear(name) memset((name)->array, 0, (name)->count * sizeof (name)->array[0])
#define staticSliceClearRange(name, start, end) memset((name)->array + start, 0, (end-start) * sizeof (name)->array[0])
/*
* Empty staticSlice
* Set count to 0
* Allocated buffers in the staticSlice must be freed before running staticSliceEmpty
*/
#define staticSliceEmpty sliceEmpty
/*
* is staticSlice Empty
*/
#define staticSliceIsEmpty(name) ((name)->count == 0)
/*
* return element count
*/
#define staticSliceCount sliceCount
/*
* size of staticSlice element
*/
#define staticSliceElemSize sliceElemSize
/*
* clear (set 0) in element at index
*/
#define staticSliceClearElem sliceClearElem
/*
* push element and expand the staticSlice
* no data (random) is set in the new element
* \param
* name staticSlice
*/
#define staticSlicePush(name) (name)->count++
/*
* append element and expand the staticSlice
* \param
* name staticSlice
* \param
* v element to push
*/
#define staticSliceAppend(name, v) do{\
/*
* push element and expand the staticSlice
* the new element is cleared
* \param
* name staticSlice
*/
#define staticSliceClearPush(name) do{\
/*
* pop element
* the element count is decreased
* NOTE: using comma operator to avoid warning
* warning: operation on ‘b.head’ may be undefined [-Wsequence-point]
* \param
* name staticSlice
*/
#define staticSlicePop slicePop
/*
* 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 staticSliceDelLast sliceDelLast
/*
* get / set element at index
* \param
* name staticSlice
* \param
* index index in array
*/
#define staticSliceAt sliceAt
/*
* get pointer to element at index
* \param
* name staticSlice
* \param
* index index in array
*/
#define staticSlicePtr slicePtr
/*
* last element
* \param
* name staticSlice
*/
#define staticSliceLast sliceLast
/*
* pointer to last element
* \param
* name staticSlice
*/
#define staticSliceLastPtr sliceLastPtr
/*
* index of last element
*/
#define staticSliceLastIndex sliceLastIndex
/*
* first element
* \param
* name staticSlice
*/
#define staticSliceFirst sliceFirst
/*
* write the staticSlice content to filename file
* No NULL checks are done on the parameters
* \param
* filename file name string
*/
#define staticSliceWriteFilename sliceWriteFilename
/*
* write the staticSlice content to disk
* No NULL checks are done on the parameters
* \param
* file already opened file
*/
#define staticSliceWrite sliceWrite
/*
* read a staticSlice from filename file
* No NULL checks are done on the parameters
* \param
* filename file name string
*/
#define staticSliceReadFilename(name, filename) do {\
/*
* read a staticSlice from disk
* No NULL checks are done on the parameters
* \param
* file already opened file
*/
#define staticSliceRead(name, file) do {\
/*
* loop index on staticSlice elements
* For example:
* forEachV(vec, i) {
* staticSliceAt(vec, i) = 0;
* }
*/
#define forEachSSc forEachSc
/*
* insert an element at index
* the data is moved to create space for the new element
* to set data at the new element, use staticSliceAt(name, index) = value;
*/
#define staticSliceInject(name, index) do {\
/*
* prepend element
* \param
* name staticSlice
* \param
* v element to prepend
*/
#define staticSlicePrepend(name, v) do {\
/*
* dequeue element
* \param
* name staticSlice
*/
#define staticSliceDequeue sliceDequeue
/*
* delete first element in staticSlice
* the data is moved when count > 1
*/
#define staticSliceDelFirst sliceDelFirst
/*
* delete an element in staticSlice
* the data is moved when index < (count-1)
* when index = count -1, the last element is deleted and no data is moved
*/
#define staticSliceDelElem sliceDelElem
/*
* delete range in staticSlice
* start must be between 0 and last index
* end must be between 1 and count
*/
#define staticSliceDel sliceDel
/*
* append staticSlice to staticSlice name
* the data is copied
*/
#define staticSliceVAppend(name, staticSlice) do {\
/*
* append array to staticSlice
* the data is copied
*/
#define staticSliceAppendFrom(name, array, countInt) do {\
/*
* prepend staticSlice to staticSlice name
* the data in staticSlice name is moved and
* the data in staticSlice is copied to staticSlice name
*/
#define staticSliceVPrepend(name, staticSlice) do {\
/*
* prepend array to staticSlice
* the data in staticSlice is moved and
* the data in array is copied to staticSlice
*/
#define staticSlicePrependFrom(name, array, countInt) do {\
/*
* insert staticSlice at position index
* the data in staticSlice name is moved and
* the data in staticSlice is copied to staticSlice name
*/
#define staticSliceInsert(name, index, staticSlice) do {\
/*
* insert array at position index
* the data in staticSlice is moved and
* the data in array is copied to staticSlice
*/
#define staticSliceInsertFrom(name, index, array, countInt) do {\
/*
* staticSlice staticSlice, keep only elements between start and end
* start must be between 0 and last index
* end must be between 1 and count
* the staticSlice is returned
*/
#define staticSliceSlice sliceSlice
/*
* copy staticSlice elements between start and end to the dest staticSlice
* start must be between 0 and last index
* end must be between 1 and count
*/
#define staticSliceBCopy(name, dest, start, end) do{\
/*
* sort the staticSlice
* the compareFunction must prototype of type:
* int cmp(const void * a, const void * b);
* the results of the compareFunction should be:
* <0 when a < b
* 0 when a = b
* >0 when a > b
*/
#define staticSliceSort sliceSort
/*
* return true when staticSlice name is equal to staticSlice
* eqFunction should return true when the elements are equal
* eqFunction can be either a macro or a function
*/
#define staticSliceEq sliceEq
/*
* return true when staticSlice has value
* eqFunction should return true when the elements are equal
* eqFunction can be either a macro or a function
*/
#define staticSliceHas sliceHas
/*
* return index (ssize_t) of value in staticSlice
* eqFunction should return true when the elements are equal
* eqFunction can be either a macro or a function
* return value is -1 when value is not found
*/
#define staticSliceIndexOf sliceIndexOf
/*
* binary search value in staticSlice
* efficiently finds the index of value in staticSlice
* the staticSlice has to be sorted before calling staticSliceBinarySearch
* less is a macro taking an index and the search value returning 1 when staticSliceAt(name,index) is less than value:
* #define less(index, value) staticSliceAt(name, index) < value
* equal is a macro returning 1 when staticSliceAt(name,index) is equal to value:
* #define equal(index, value) staticSliceAt(name,index) == value
* return value is -1 when value is not found
*/
#define staticSliceBinarySearch sliceBinarySearch
/*
* Uniquify elements in staticSlice
* each elements are unique in the staticSlice
* eqFunction should return true when the elements are equal
* eqFunction can be either a macro or a function
*/
#define staticSliceUniq sliceUniq
/*
* end staticSlice
*/
/*
* vector - dynamic array in one chunk of memory (similar to slab below)
* This is a simple dynamic array holding element count, maximum element count and the data
* vector supports shrinking through vectorResize
* this type of array has a dynamic element count
* pushing elements into the array increases the element count
* poping elements only decreases the element count, call vectorFit to resize the vector
* no sanity checks are done
* the prefix is vector
* Usage:
* to declare a vector:
* vectorT(typeName, type);
* typeName vectr;
* vectorInit(&vectr);
* or
* vectorInitCount(&vectr, 17);
* vectorAppend(&vectr, value);
* // get an element
* int a = vectorAt(&vectr, 0);
* set
* vectorAt(&vectr, 1) = 3;
* vectorFree(&vectr);
* Vector variables:
* vectr.array: elements
* vectr.count: current element count
* vectr.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:
* vectorLast(chan).a = 0;
*/
#define vectorSz 1
/*
* declares type for vector
* \param
* typeName vector type name
* \param
* element type of elements (int, struct, pointer...)
*/
#define vectorT(typeName, elementType)\
#define createVector(typeName, name) ;typeName name; vectorInit(&name)
#define createVectorCount(typeName, name, count) ;typeName name; vectorInitCount(&name, count)
#define createVectorClearCount(typeName, name, count) ;typeName name; vectorCalloc(&name, count)
#define createAllocateVector(typeName, name) ;typeName *name = calloc(1, sizeof(typeName))
#define createAllocateVectorCount(typeName, name, count) ;typeName *name = calloc(1, sizeof(typeName)); vectorInitCount(name, count)
#define createAllocateVectorClearCount(typeName, name, count) ;typeName *name = calloc(1, sizeof(typeName)); vectorCalloc(name, count)
#define vectorTerminate(name) if (name) vectorFree(name);free(name)
/*
* initialize empty vector
* \param
* name variable name for vector
*/
#define vectorInit(name) do{\
/*
* initialize vector and count
* \param
* name variable name for vector
* \param
* count initial element count for name type
*/
#define vectorInitCount(name, countInt) do{\
/*
* initialize vector and count and set vector data to 0
* \param
* name variable name for vector
* \param
* count initial element count for name type
*/
#define vectorCalloc(name, countInt) do{\
/*
* resize vector (even empty vectors)
*/
#define vectorResize(name, countInt) do{\
/*
* resize vector and clear the new elements with memset
* even empty vectors can be resized and cleared
*/
#define vectorClearResize(name, countInt) do{\
/*
* free the internal buffers
* \param
* name vector
*/
#define vectorFree sliceFree
/*
* duplicate vector
*/
#define vectorDup(name) ({\
/*
* declare dest vector and duplicate vector
*/
#define vectorCreateNDup(name, dest) ;typeof(*(name)) dest; vectorInitCount(dest, (name)->count); if ((name)->array) { memcpy(dest->array, (name)->array, (name)->count * sizeof (name)->array[0]); dest->count = (name)->count;}
/*
* duplicate vector to already declared dest vector
*/
#define vectorBDup(name, dest) do{\
/*
* direct access to underlying array
*/
#define vectorData sliceData
/*
* copy data from array to vector
*/
#define vectorFrom(name, array, countInt) do{\
/*
* set 0 in vector elements
* count is unchanged
*/
#define vectorClear sliceClear
#define vectorClearRange sliceClearRange
/*
* Empty vector
* Set count to 0
* Allocated buffers in the vector must be freed before running vectorEmpty
*/
#define vectorEmpty sliceEmpty
/*
* is vector Empty
*/
#define vectorIsEmpty sliceIsEmpty
/*
* resize vector from maxCount to count
*/
#define vectorFit(name) do{\
/*
* return element count
*/
#define vectorCount sliceCount
/*
* return max element count
*/
#define vectorMaxCount(name) (name)->maxCount
/*
* size of vector element
*/
#define vectorElemSize sliceElemSize
/*
* allocate an element
* only when the vector is full
*/
#define vectorAlloc(name) do{\
/*
* clear (set 0) in element at index
*/
#define vectorClearElem sliceClearElem
/*
* push element and expand the vector
* no data (random) is set in the new element
* \param
* name vector
*/
#define vectorPush(name) do {\
/*
* append element and expand the vector
* \param
* name vector
* \param
* v element to push
*/
#define vectorAppend(name, v) do{\
/*
* push element and expand the vector
* the new element is cleared
* \param
* name vector
*/
#define vectorClearPush(name) do{\
/*
* pop element
* the element count is decreased
* NOTE: using comma operator to avoid warning
* warning: operation on ‘b.head’ may be undefined [-Wsequence-point]
* \param
* name vector
*/
#define vectorPop slicePop
/*
* 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 vectorDelLast sliceDelLast
/*
* set value at index and clearResize vector when index is outside vector maxCount
*/
#define vectorSet(name, index, v) do{\
/*
* get / set element at index
* \param
* name vector
* \param
* index index in array
*/
#define vectorAt sliceAt
/*
* get pointer to element at index
* \param
* name vector
* \param
* index index in array
*/
#define vectorPtr slicePtr
/*
* last element
* \param
* name vector
*/
#define vectorLast sliceLast
/*
* pointer to last element
* \param
* name vector
*/
#define vectorLastPtr sliceLastPtr
/*
* index of last element
*/
#define vectorLastIndex sliceLastIndex
/*
* first element
* \param
* name vector
*/
#define vectorFirst sliceFirst
/*
* write the vector content to filename file
* No NULL checks are done on the parameters
* \param
* filename file name string
*/
#define vectorWriteFilename sliceWriteFilename
/*
* write the vector content to disk
* No NULL checks are done on the parameters
* \param
* file already opened file
*/
#define vectorWrite sliceWrite
/*
* read a vector from filename file
* No NULL checks are done on the parameters
* \param
* filename file name string
*/
#define vectorReadFilename(name, filename) do {\
/*
* read a vector from disk
* No NULL checks are done on the parameters
* \param
* file already opened file
*/
#define vectorRead(name, file) do {\
/*
* loop index on vector elements
* For example:
* forEachV(vec, i) {
* vectorAt(vec, i) = 0;
* }
*/
#define forEachV forEachSc
/*
* insert an element at index
* the data is moved to create space for the new element
* to set data at the new element, use vectorAt(name, index) = value;
*/
#define vectorInject(name, index) do {\
/*
* prepend element
* \param
* name vector
* \param
* v element to prepend
*/
#define vectorPrepend(name, v) do {\
/*
* dequeue element
* \param
* name vector
*/
#define vectorDequeue sliceDequeue
/*
* delete first element in vector
* the data is moved when count > 1
*/
#define vectorDelFirst sliceDelFirst
/*
* delete an element in vector
* the data is moved when index < (count-1)
* when index = count -1, the last element is deleted and no data is moved
*/
#define vectorDelElem sliceDelElem
/*
* delete range in vector
* start must be between 0 and last index
* end must be between 1 and count
*/
#define vectorDel sliceDel
/*
* append vector to vector name
* the data is copied
*/
#define vectorVAppend(name, vector) do {\
/*
* append array to vector
* the data is copied
*/
#define vectorAppendFrom(name, array, countInt) do {\
/*
* prepend vector to vector name
* the data in vector name is moved and
* the data in vector is copied to vector name
*/
#define vectorVPrepend(name, vector) do {\
/*
* prepend array to vector
* the data in vector is moved and
* the data in array is copied to vector
*/
#define vectorPrependFrom(name, array, countInt) do {\
/*
* insert vector at position index
* the data in vector name is moved and
* the data in vector is copied to vector name
*/
#define vectorInsert(name, index, vector) do {\
/*
* insert array at position index
* the data in vector is moved and
* the data in array is copied to vector
*/
#define vectorInsertFrom(name, index, array, countInt) do {\
/*
* slice vector, keep only elements between start and end
* start must be between 0 and last index
* end must be between 1 and count
* the vector is returned
*/
#define vectorSlice sliceSlice
/*
* copy vector elements between start and end to a new vector
* start must be between 0 and last index
* end must be between 1 and count
* the new vector is returned and must be freed with vectorTerminate
*/
#define vectorCopy(name, start, end) ({\
/*
* copy vector elements between start and end to the dest vector
* start must be between 0 and last index
* end must be between 1 and count
*/
#define vectorBCopy(name, dest, start, end) do{\
/*
* sort the vector
* the compareFunction must prototype of type:
* int cmp(const void * a, const void * b);
* the results of the compareFunction should be:
* <0 when a < b
* 0 when a = b
* >0 when a > b
*/
#define vectorSort sliceSort
/*
* return true when vector name is equal to vector
* eqFunction should return true when the elements are equal
* eqFunction can be either a macro or a function
*/
#define vectorEq sliceEq
/*
* return true when vector has value
* eqFunction should return true when the elements are equal
* eqFunction can be either a macro or a function
*/
#define vectorHas sliceHas
/*
* return index (ssize_t) of value in vector
* eqFunction should return true when the elements are equal
* eqFunction can be either a macro or a function
* return value is -1 when value is not found
*/
#define vectorIndexOf sliceIndexOf
/*
* binary search value in vector
* efficiently finds the index of value in vector
* the vector has to be sorted before calling vectorBinarySearch
* less is a macro taking an index and the search value returning 1 when vectorAt(name,index) is less than value:
* #define less(index, value) vectorAt(name, index) < value
* equal is a macro returning 1 when vectorAt(name,index) is equal to value:
* #define equal(index, value) vectorAt(name,index) == value
* return value is -1 when value is not found
*/
#define vectorBinarySearch sliceBinarySearch
/*
* Uniquify elements in vector
* each elements are unique in the vector
* eqFunction should return true when the elements are equal
* eqFunction can be either a macro or a function
*/
#define vectorUniq sliceUniq
/*
* end vector
*/
/*
* dynamic segmented vector
* this type of array is faster than vector when there are many elements and has a dynamic element count
* pushing elements into the array increases the element count
* the data is stored in static array segments
* no sanity checks are done
* usage examples: regular array, stack
* the prefix is dVector
* Usage:
* to declare an array:
* dVectorT(typeName, type);
* typeName dvector;
* dVectorInit(&dvector);
* or
* dVectorInitCount(&dvector, 17);
* dVectorAppend(&dvector, value);
* // get an element
* int a = dVectorAt(&dvector, 0);
* set
* dVectorAt(&dvector, 1) = 3;
* dVectorFree(&dvector);
* dVector variables:
* dvector.maxCount: maximum element count allowed
* Note: dont combine the macros, it gives wrong results:
* a = dVectorAt(&dvector, dVectorPop(&dvector2));
* dVectorPop 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:
* dVectorLast(chan).a = 0;
*/
// user parameters
/*
* chunk size: 2^dVectorBits elements
*/
#define dVectorBits 6
// user parameters end
#define dVectorSz (1<<dVectorBits)
#define dVectorMask (dVectorSz-1)
/*
* declares type for dynamic array
* \param
* typeName dVector type name
* \param
* element type of elements (int, struct, pointer...)
*/
#define dVectorT(typeName, elementType)\
#define createDVector(typeName, name) ;typeName name; dVectorInit(&name)
#define createDVectorCount(typeName, name, count) ;typeName name; dVectorInitCount(&name, count)
/*
* initialize dynamic array with minimum element count
* \param
* a variable name for dVector
*/
#define dVectorInit(a) do{\
/*
* initialize dynamic array and count
* \param
* a variable name for dVector
* \param
* count initial element count for name type
*/
#define dVectorInitCount(a, count) do{\
#define dVectorResize(a, count) do{\
/*
* free the internal buffers
* \param
* a dynamic array
*/
#define dVectorFree(a) do{\
/*
* Empty Array
* Allocated buffers in the array must be freed before running dVectorEmpty
*/
#define dVectorEmpty(name) (name)->count = 0
/*
* is Array Empty
*/
#define dVectorIsEmpty(name) ((name)->count == 0)
/*
* return element count
*/
#define dVectorCount(name) (name)->count
/*
* return max element count
*/
#define dVectorMaxCount(name) ((name)->maxCount * dVectorSz)
/*
* allocate buffer for new elements
* only when the array is full
* \param
* a dynamic array
*/
#define dVectorAlloc(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 dVectorPush(a) do{\
/*
* append element and expand the dynamic array
* \param
* a dynamic array
* \param
* v element to push
*/
#define dVectorAppend(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 dVectorPop(a) ((a)->count--, *((typeof((a)->element)*)((a)->buffers[((a)->count)>>dVectorBits])+(((a)->count)&dVectorMask)))
/*
* 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 dVectorDelLast(a) ((a)->count--)
// TODO poor perfomance #define dVectorPrepend(a, v)
// TODO poor perfomance #define dVectorDequeue(a)
// TODO poor perfomance #define dVectorDelFirst(a)
/*
* get / set element at index
* \param
* a dynamic array
* \param
* index index in array
*/
#define dVectorAt(a, index) (*((typeof((a)->element)*)((a)->buffers[(index)>>dVectorBits])+((index)&dVectorMask)))
/*
* get pointer to element at index
* \param
* a dynamic array
* \param
* index index in array
*/
#define dVectorPtr(a, index) ((typeof((a)->element)*)((a)->buffers[(index)>>dVectorBits])+((index)&dVectorMask))
/*
* last element
* \param
* a dynamic array
*/
#define dVectorLast(a) (*((typeof((a)->element)*)((a)->buffers[((a)->count-1)>>dVectorBits])+(((a)->count-1)&dVectorMask)))
/*
* pointer to last element
* \param
* a dynamic array
*/
#define dVectorLastPtr(a) ((typeof((a)->element)*)((a)->buffers[((a)->count-1)>>dVectorBits])+(((a)->count-1)&dVectorMask))
/*
* index of last element
*/
#define dVectorLastIndex(a) ((a)->count-1)
/*
* first element
* \param
* a dynamic array
*/
#define dVectorFirst(a) (*((typeof((a)->element)*)((a)->buffers[0])))
/*
* write the dVector content to filename file
* No NULL checks are done on the parameters
* \param
* filename file name string
*/
#define dVectorWriteFilename(a, filename) do {\
/*
* write the dVector content to disk
* No NULL checks are done on the parameters
* \param
* file already opened file
*/
#define dVectorWrite(a, file) do {\
/*
* read a dVector from filename file
* No NULL checks are done on the parameters
* \param
* filename file name string
*/
#define dVectorReadFilename(a, filename) do {\
/*
* read a dVector from disk
* No NULL checks are done on the parameters
* \param
* file already opened file
*/
#define dVectorRead(a, file) do {\
/*
* end dynamic segmented vector
*/
/*
* staticArray type definition
* this type of array has a static maximum element count (fixed)
* staticArray has head and last indexes, this allows dequeuing from head elements fast
* 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...)
* \param
* MAXCOUNT array/ring buffer size
*/
#define staticArrayT(typeName, element, MAXCOUNT)\
#define createStaticArray(typeName, name) ;typeName name; staticArrayInit(name)
/*
* 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) )]
#define staticArrayAt staticArrayGet
/*
* 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)\
#define createIndexer(typeName, name, maxCount) ;typeName name; indexerInit(name, maxCount)
/*
* 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 segmented array
* this type of array is faster than slab when there are many elements and has a dynamic element count
* pushing elements into the array increases the element count
* the data is stored in static array segments
* dArray has head and last indexes, this allows dequeuing from head elements fast
* no sanity checks are done
* usage examples: regular array, stack, lifo, fifo
* the prefix is dArray
* Usage:
* 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);
* dArray variables:
* darray.maxCount: maximum element count allowed
* 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)\
#define createDArray(typeName, name) ;typeName name; dArrayInit(&name)
#define createDArrayCount(typeName, name, count) ;typeName name; dArrayInitCount(&name, count)
/*
* 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 dVectorFree
/*
* 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
* slab supports shrinking through slabResize, the slab is reset when head or last are outside the new size
* slab has head and last indexes, this allows dequeuing from head elements fast
* 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
* Usage:
* 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);
* Slab variables:
* slab.array: elements
* slab.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:
* 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)\
#define createSlab(typeName, name) ;typeName name; slabInit(&name)
#define createSlabCount(typeName, name, count) ;typeName name; slabInitCount(&name, count)
/*
* 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 sliceFree
/*
* 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 vectorMaxCount
/*
* 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
*/
#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 sliceAt
/*
* get pointer to element at index
* \param
* a slab
* \param
* index index in array
*/
#define slabPtr slicePtr
/*
* 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
*/
/*
* static bitset
* no sanity checks are done
* Usage:
* staticBitsetT(typeName, u64 , 8);
* typeName bits;
* staticBitsetClear(&bits);
* staticBitset1(&bits, index);
* bool bit = staticBitsetGet(&bits, index);
*/
/*
* typedef for staticBitset
* \param
* typeName typedef name
* \param
* containerType element type in array: u8, u16, u32, u64...
* \param
* count bit count in array
*/
#define staticBitsetT(typeName, containerType, count)\
#define staticBitsetCount(name) (sizeof((name)->map) * 8)
#define staticBitsetClear(name) memset(name, 0, sizeof(*(name)));
#define staticBitsetBucket(name, index) (name)->map[index / (8 * sizeof((name)->map[0]))]
#define staticBitset0(name, index) do{\
#define staticBitset1(name, index) do{\
#define staticBitsetSet(name, index, value) do{\
#define staticBitsetInv(name, index) do{\
#define staticBitsetGet(name, index) ({\
/*
* end static bitset
*/
/*
* bitset
* the underlying array is defined in the provided at macro or function
* no sanity checks are done
* a dynamic bitset can be created using slice and sliceAt
*/
#define bitsetModulo 8
#define bitsetBucket(name, index) (name)->map[index / (bitsetModulo)]
#define bitset0(name, at, index) do{\
#define bitset1(name, at, index) do{\
#define bitsetSet(name, at, index, value) do{\
#define bitsetInv(name, at, index) do{\
/*
* get bit at index
* at must be macro or function taking 2 parameters:
* at(name, intIndex)
* and return the value at intIndex
*/
#define bitsetGet(name, at, index) ({\
/*
* end bitset
*/
// 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__ || __OpenBSD__ || __DragonFly__))
/*
* 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__ || __OpenBSD__ || __DragonFly__))
/*
* 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 (do not free this pointer)
*/
const char *getProgPath(void)
/*
* get real program path
* The first call allocates libSheepyRealProgPath, it is freed with freeRealProgPath
* \return
* real program path (do not free this pointer)
*/
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
* this function is called from the systemNFree macro
* \param
* command command to run in the shell
* \return
* 0 success
* command error code
*/
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 in ctime format (Wed Dec 12 11:44:08 2018), you must free the pointer
*/
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, you must free the pointer
*/
char *timeToYMDS(const time_t t)
/*
* get current date in ctime format (Wed Dec 12 11:44:08 2018)
* you must free the pointer
*/
char *getCurrentDate(void)
/*
* get current date in Y-m-d H:M:S format
* you must free the pointer
*/
char *getCurrentDateYMD(void)
/*
* sheepy dirname
* the returned string has to be freed
* \param
* path
* \return
* path without basename (last item in the path, you must free the pointer)
* "./" 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 (you must free the pointer)
*/
char *expandHome(const char* path)
/*
* expands ~/ ($HOME) or ~USER\n
* duplicate and expand path. The original remains unchanged.
* \param
* path string
* \return
* new string path or NULL (you must free the pointer)
*/
char *expandHome(const char* path)
/*
* expands ~/ ($HOME) or ~USER\n
* expand path.
* \param
* path: string (this parameter is reallocated)
* \return
* path modified path\n
* NULL error
*/
char *iExpandHome(char **path)
/*
* expands ~/ ($HOME) or ~USER\n
* duplicate and expand path.
* \param
* path: string (this parameter is reallocated)
* \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 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)
/*
* 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 (you must free the pointer)
* 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 (this parameter is reallocated)
* \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 (you must free the pointer)
*/
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 (you must free the pointer)
*/
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 (you must free the pointer)
* 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 (you must free the pointer)
* 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
* fp 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 (you must free the pointer)
* NULL an error occured
*/
void *readFileToS(const char *filePath)
/*
* read file to string
* 0 is added at the end to terminate the string
* \param
* fp file pointer
* \return
* data in file (you must free the pointer)
* 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
* fp 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
* fp 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 (you must free the pointer)
* 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
* fp file pointer
* string
* \return
* 1 success
* 0 error
*/
int writeStreamS(FILE *fp, const char *string)
/*
* write buffer to file
* \param
* fp file pointer
* 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 path to file
* string
* \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 (you must free the pointer with listFreeS)
* 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 (you must free the pointer with listFreeS)
* 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 (you must free the pointer with listFreeS)
* 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 (you must free the pointer with listFreeS)
* 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 (you must free the pointer with listFreeS)
* 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 (you must free the pointer with listFreeS)
* 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
* \param
* 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 (you must free the pointer)
* 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 (you must free the pointer)
* NULL error opening /dev/urandom, malloc failed, fread /dev/urandom failed, length is 0
*/
char *randomAlphaNumS(uint64_t length)
/*
* buffer 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
* there is no size limit and the buffer expands as needed
* \return
* line from the user (you must free the pointer)
* 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 (you must free the pointer)
*/
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 (you must free the pointer)
* 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 (you must free the pointer)
* 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)
/*
* create a string with bytes in buf converted to hex strings
* \param
* buf buffer to convert to hexstring
* \param
* len buffer size in bytes
* \return
* string representing the buffer in hexadecimal "0x01, 0x02,..." (you must free the pointer)
*/
char *toHexS(const void *buf, size_t len)
/*
* create a string with bytes in buf converted to hex strings separated by separator
* \param
* buf buffer to convert to hexstring
* \param
* len buffer size in bytes
* \param
* separator separator between the hexadecimal numbers
* \return
* string representing the buffer in hexadecimal "0x01SEP0x02SEP..." (you must free the pointer)
*/
char *toHexSepS(const void *buf, size_t len, const char *separator)
/*
* create a string with bytes in buf converted to hex strings separated by separator and with head string in front of earch byte: HEADffSEP
* \param
* buf buffer to convert to hexstring
* \param
* len buffer size in bytes
* \param
* head separator before each hexadecimal numbers
* \param
* separator separator after each hexadecimal numbers
* \return
* string representing the buffer in hexadecimal "HEAD0x01SEPHEAD0x02SEP..." (you must free the pointer)
*/
char *toHexHeadSepS(const void *buf, size_t len, const char *head, const char *separator)
/*
* 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 (you must free the pointer)
*/
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 (you must free the pointer)
* NULL when fmt is NULL or asprintf fails
*/
char *formatS(const char *fmt, ...)
/*
* format string
* \param
* format string and other parameters
* \return
* formated string
* NULL when string, fmt are NULL or sprintf fails
*/
char *bFormatS(char *string, const char *fmt, ...)
/*
* format string
* \param
* format string and other parameters
* \return
* formated string
* NULL when string, fmt is NULL or snprintf fails
*/
char *bLFormatS(char *string, size_t stringSize, const char *fmt, ...)
/*
* append strings
* \param
* string1 string
* string2 string to append at the end of string1
* \return
* new string string1+string2 (you must free the pointer)
* 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 (you must free the pointer)
* 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 (you must free the pointer)
* 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 (you must free the pointer)
* 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 (you must free the pointer)
* 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 (you must free the pointer)
* 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 (you must free the pointer)
* 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 (you must free the pointer)
* 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 (you must free the pointer)
* 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 (you must free the pointer)
* 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 (you must free the pointer)
* 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 (you must free the pointer)
* 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 (you must free the pointer)
* 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 (you must free the pointer)
* "" 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 (that is allocated with malloc)
* 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 (you must free the pointer)
* 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 (you must free the pointer)
* "" 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 (this parameter is reallocated)
* olds: old string to be replaced in s
* news: new string replacing olds in s
* ...
* \return
* modified string (you must free the pointer)
* 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 (you must free the pointer)
* "" 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 (this parameter is reallocated)
* 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 (you must free the pointer)
* 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 (you must free the pointer)
* "" 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 (this parameter is reallocated)
* olds: old string to be replaced in s
* news: new string replacing olds in s
* ...
* \return
* modified string (you must free the pointer)
* 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 (you must free the pointer)
*/
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 (you must free the pointer)
*/
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 (you must free the pointer)
*/
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 (you must free the pointer)
*/
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 (you must free the pointer)
*/
char *trimS(const char *string)
/*
* trim String
* \param
* string (this parameter is reallocated)
* \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 (you must free the pointer)
*/
char *lTrimS(const char *string)
/*
* left trim String
* \param
* string (this parameter is reallocated)
* \return
* string without leading spaces (you must free the pointer)
* NULL error
*/
char *iLTrimS(char **string)
/*
* buffer left trim 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 (you must free the pointer)
*/
char *rTrimS(const char *string)
/*
* right trim String
* \param
* string
* \return
* string without trailing spaces
* NULL error
*/
char *iRTrimS(char **string)
/*
* buffer right trim 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 (you must free the pointer)
*/
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 (you must free the pointer)
*/
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 (you must free the pointer)
* "" 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 (this parameter is reallocated)
* start: start index, must be in the string
* end: end index, must be in the string after start
* \return
* sliced string (you must free the pointer)
* "" 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
* \param
* index in string
* \param
* toInsert string
* \return
* new string (you must free the pointer)
* 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
* \param
* index in string
* \param
* toInsert string
* \return
* new string (you must free the pointer)
* 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 (this parameter is reallocated)
* \param
* index in string
* \param
* toInsert string
* \return
* modified string (you must free the pointer)
* 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 (this parameter is reallocated)
* \param
* index in string
* \param
* toInsert string
* \return
* modified string (you must free the pointer)
* 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
* \param
* index in string
* \param
* 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
* \param
* index in string
* \param
* 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
* \param
* index in string
* \param
* toInject char
* \return
* new string (you must free the pointer)
* 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 (this parameter is reallocated)
* \param
* index in string
* \param
* toInject char
* \return
* modified string (you must free the pointer)
* 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
* \param
* index in string
* \param
* 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
* \param
* index in string
* \param
* 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
* \param
* start: start index, must be in the string
* \param
* end: end index, must be in the string after start
* \return
* new sliced string (you must free the pointer)
* 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 (this parameter is reallocated)
* \param
* start: start index, must be in the string
* \param
* end: end index, must be in the string after start
* \return
* sliced string (you must free the pointer)
* 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
* \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 *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
* \param
* index: must be in the string, -1 is the last character in the string
* \return
* new string (you must free the pointer)
* 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 (this parameter is reallocated)
* \param
* index: must be in the string, -1 is the last character in the string
* \return
* new string (you must free the pointer)
* 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
* \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 *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
* \param
* 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
* \param
* 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
* \param
* 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
* \param
* 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
* \param
* 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
* \param
* 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
* \param
* 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
* \param
* 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 (you must free the pointer)
* 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 (you must free the pointer)
* 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 (you must free the pointer)
* "" 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
* \param
* olds: old string to be replaced in s
* \param
* news: new string replacing olds in s
* \param
* 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
* \param
* olds: old string to be replaced in s
* \param
* news: new string replacing olds in s
* \param
* 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
* \param
* olds: old string to be replaced in s
* \param
* 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
* \param
* olds: old string to be replaced in s
* \param
* 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
* \param
* olds: old string to be replaced in s
* \param
* 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
* \param
* olds: old string to be replaced in s
* \param
* 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)
/*
* upper case UTF-8 encoded string
* duplicate string
* \param
* string UTF-8 encoded string
* \return
* new upper case string (you must free the pointer)
*/
char *upperUTF8(const char *utf8)
/*
* upper case UTF-8 encoded string
* \param
* string (this parameter is reallocated)
* \return
* upper case string (you must free the pointer)
* 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
*/
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 (you must free the pointer)
*/
char *lowerUTF8(const char *utf8)
/*
* lower case String
* \param
* string (this parameter is reallocated)
* \return
* lower case string (you must free the pointer)
* 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 (you must free the pointer)
* 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
* \param
* c character to remove
* \return
* new string without successive repetitions of char c (you must free the pointer)
*/
char *uniqUTF8(const char *string,