# HG changeset patch # User Matti Hamalainen # Date 1206499318 -7200 # Node ID bd61a80a6c54ae513c4314ae265e9aae0a95a7d7 Initial import into Mercurial repository. Discarding old cvs/svn history here, because it's cluttered and commit messages are mostly crap. diff -r 000000000000 -r bd61a80a6c54 th_args.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/th_args.c Wed Mar 26 04:41:58 2008 +0200 @@ -0,0 +1,387 @@ +/* + * Simple commandline argument processing + * Programmed and designed by Matti 'ccr' Hamalainen + * (C) Copyright 2002-2008 Tecnic Software productions (TNSP) + * + * Please read file 'COPYING' for information on license and distribution. + */ +/* +Description +=========== +Structures and functions for simple commandline argument processing, +option argument handling (short and long forms supported). + +Output function for printing out short on-line help for said options +and program commandline usage. + + +Format for typical commandline: + +$ program -a -b -c --long-d -e argument-for-e --long-f="argument for f" + +where -a, -b and -c are short options without required arguments; +--long-d is a long option without argument; -e is short option with +argument and finally --long-f is long option with argument. + + +Introduction +============ +Handling of commandline options in th_args_process() has various +options, which effect how an option is handled. Also the error +situations (unknown option/no required argument) can be handled +in different ways. + +Typically th_args_process() is called as follows: + +BOOL optionHandlerCallback(int optionNumber, char *optionArgument, char *optionName) +{ + if (option is OK) + return TRUE; + else + return FALSE; +} + +BOOL nonoptionHandlerCallback(char *argumentString) +{ + // return value same as in optionHandlerCallback +} + + +int main(int argc, char *argv[]) +{ + if (th_args_process(argc, argv, optList, optListN, + optionHandlerCallback, nonoptionHandlerCallback)) { + ... arguments OK ... + } else { + ... arguments invalid or required arguments missing ... + } +} + + +NOTICE! +------- +The return value from handler callbacks affects the return value of +th_args_process(). Additionally, a failure in callback (returns FALSE) +effects the argument processing if bailOut argument of th_args_process() +is TRUE! + +If bailOut is TRUE, any error/failure in argument processing (including +callbacks) immediately stops the argument processing and FALSE is +returned from th_args_process(). + +If bailOut is FALSE, most errors are "ignored", but FALSE is still returned +if any errors occured. + + +NOTICE #2! +---------- +A small temporary buffer of N*sizeof(BOOL) (where N is number of +options in optList[]) is allocated for processing required options. +If this allocation fails, the program is immediately exited with +code 128. + + +Examples +======== +Example of different options, in a fictional optionlist struct: + +optarg_t optList[] = { + // Option without arguments + { 0, '?', "help", "Show this help", OPT_NONE }, + + // Option with a required argument + { 1, 'o', "output", "Output file name", OPT_ARGREQ }, + + // Option with optional argument + { 2, 'f', "foobar", "Use foobar, with optional string", OPT_ARGOPT }, + + // This option is required to be given, though without other flags + // it may not make much sense. + { 4, 'S', "stupid", "You must give this option", OPT_REQUIRED }, + + // The flags can be combined with OR operator: this option is both + // required to be specified, and also requires argument (the filename) + { 5, 'i', "input", "Input file name", OPT_REQUIRED | OPT_ARGREQ }, + + + // Option with only long form + { 0, 0, "only-long", "Long option", OPT_NONE }, + + // Option with only short form + { 0, 's', NULL, "Short option", OPT_NONE }, + +}; + +const DINT optListN = (sizeof(optList) / sizeof(t_opt)); + + +*/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "th_util.h" +#include "th_args.h" +#include "th_string.h" + + +/* Check if option requires an argument + */ +static BOOL th_args_check_arg(optarg_t *o, char *optArg) +{ + if ((o->optFlags & OPT_ARGMASK) == OPT_ARGREQ && optArg == NULL) { + if (o->optShort != 0 && o->optLong != NULL) { + THERR("Option '-%c ARG' (--%s=ARG) requires an argument!\n", + o->optShort, o->optLong); + } else if (o->optShort != 0) { + THERR("Option '-%c ARG' requires an argument!\n", o->optShort); + } else if (o->optLong != NULL) { + THERR("Option --%s=ARG requires an argument!\n", o->optLong); + } + + return FALSE; + } else + return TRUE; + +} + + +/* Handle short options + */ +static BOOL th_args_process_short(char *currArg, int *newArgIndex, + BOOL *wasGiven, int argc, char *argv[], + optarg_t optList[], int optListN, + BOOL (*handleOpt)(int, char *, char *)) +{ + char *tmpArg = currArg, *optArg; + int optN; + BOOL isFound; + + /* Short options can be combined: -a -b -c == -abc */ + while (*tmpArg) { + + for (optN = 0, isFound = FALSE; (optN < optListN) && !isFound; optN++) + if (*tmpArg == optList[optN].optShort) { + /* Get possible option argument, if needed */ + if ((optList[optN].optFlags & OPT_ARGMASK) != 0 && (++(*newArgIndex) < argc)) + optArg = argv[*newArgIndex]; + else + optArg = NULL; + + /* Check if option argument is required */ + if (!th_args_check_arg(&optList[optN], optArg)) + return FALSE; + else { + char tmpStr[2] = { 0, 0 }; + + /* Option was given succesfully, try to handle it */ + wasGiven[optN] = TRUE; + + tmpStr[0] = *tmpArg; + + if (!handleOpt(optList[optN].optID, optArg, tmpStr)) + return FALSE; + } + + isFound = TRUE; + } + + if (!isFound) { + THERR("Unknown short option '%c' in argument '-%s'\n", + *tmpArg, currArg); + return FALSE; + } + + tmpArg++; + } + + return TRUE; +} + + +/* Handle long options + */ +static BOOL th_args_process_long(char *currArg, int *newArgIndex, + BOOL *wasGiven, int argc, char *argv[], + optarg_t optList[], int optListN, + BOOL (*handleOpt)(int, char *, char *)) +{ + int optN, optLen, i; + char *optArg; + + (void) argc; (void) argv; (void) newArgIndex; + + /* Long option */ + for (optN = -1, optLen = i = 0; (i < optListN) && (optN < 0); i++) + if (optList[i].optLong) { + optLen = strlen(optList[i].optLong); + if (strncmp(currArg, optList[i].optLong, optLen) == 0) + optN = i; + } + + /* Get possible option argument, if needed */ + if (optN >= 0) { + if ((optList[optN].optFlags & OPT_ARGMASK) != 0) { + if (currArg[optLen] == '=') + optArg = &currArg[optLen + 1]; + else + optArg = NULL; + } else + optArg = NULL; + + /* Check if option argument is required */ + if (!th_args_check_arg(&optList[optN], optArg)) + return FALSE; + else { + /* Option was given succesfully, try to handle it */ + wasGiven[optN] = TRUE; + if (!handleOpt(optList[optN].optID, optArg, currArg)) + return FALSE; + } + } else { + THERR("Unknown long option '--%s'\n", currArg); + return FALSE; + } + + return TRUE; +} + + +/* Process arguments, handling short and long options by + * calling the given callback functions. + */ +BOOL th_args_process(int argc, char *argv[], + optarg_t optList[], int optListN, + BOOL (*handleOpt) (int, char *, char *), + BOOL (*handleNonOption) (char *), BOOL bailOut) +{ + BOOL endOptions, optionsOK; + int argIndex, newArgIndex, i; + char *currArg; + BOOL *wasGiven; + + /* Allocate wasGiven */ + wasGiven = (BOOL *) th_calloc(optListN, sizeof(BOOL)); + if (!wasGiven) { + THERR("FATAL ERROR! Could not allocate wasGiven in th_args_process()!\n"); + exit(128); + } + + /* Parse arguments */ + argIndex = 1; + optionsOK = TRUE; + endOptions = FALSE; + while (argIndex < argc) { + currArg = argv[argIndex]; + if ((currArg[0] == '-') && !endOptions) { + newArgIndex = argIndex; + currArg++; + if (*currArg == '-') { + /* Check for "--", which ends the options-list */ + currArg++; + if (*currArg == 0) { + endOptions = TRUE; + continue; + } + + /* Long options */ + if (!th_args_process_long(currArg, &newArgIndex, + wasGiven, argc, argv, optList, optListN, + handleOpt)) + optionsOK = FALSE; + } else { + /* Short options */ + if (!th_args_process_short(currArg, &newArgIndex, + wasGiven, argc, argv, optList, optListN, + handleOpt)) + optionsOK = FALSE; + } + + argIndex = newArgIndex; + } else { + /* Was not option argument */ + if (!handleNonOption || (handleNonOption && !handleNonOption(currArg))) { + THERR("Invalid argument '%s'\n", currArg); + optionsOK = FALSE; + } + } + + /* Check if we bail out on invalid argument */ + if (!optionsOK && bailOut) { + th_free(wasGiven); + return FALSE; + } + + argIndex++; + } + + /* Check wasGiven by isRequired */ + for (i = 0; i < optListN; i++) + if ((optList[i].optFlags & OPT_REQUIRED) != 0 && !wasGiven[i]) { + THERR("Option -%s (--%s) is required.\n", + optList[i].optShort, optList[i].optLong); + + optionsOK = FALSE; + if (bailOut) break; + } + + th_free(wasGiven); + return optionsOK; +} + + +/* Print help for commandline arguments/options + */ +void th_args_help(FILE * outFile, + optarg_t optList[], int optListN, + char * progName, char * progUsage) +{ + int i, nrequired; + + fprintf(outFile, + "\n%s v%s (%s)\n" + "%s\n" + "%s\n" + "Usage: %s %s\n", + th_prog_name, th_prog_version, th_prog_fullname, + th_prog_author, th_prog_license, progName, progUsage); + + + for (i = nrequired = 0; i < optListN; i++) { + optarg_t *o = &optList[i]; + + /* Print short option */ + if (o->optShort != 0) + fprintf(outFile, " -%c, ", o->optShort); + else + fprintf(outFile, " "); + + /* Print long option */ + if (o->optLong) { + char tmpStr[64], *p; + + if ((o->optFlags & OPT_ARGMASK) == OPT_ARGOPT) { + snprintf(tmpStr, sizeof(tmpStr), "%s[=ARG]", optList[i].optLong); + p = tmpStr; + } else if ((o->optFlags & OPT_ARGMASK) == OPT_ARGREQ) { + snprintf(tmpStr, sizeof(tmpStr), "%s=ARG", optList[i].optLong); + p = tmpStr; + } else + p = o->optLong; + + fprintf(outFile, "--%-15s", p); + } else + fprintf(outFile, " "); + + fprintf(outFile, " %s.", optList[i].optDesc); + + if (o->optFlags & OPT_REQUIRED) { + fprintf(outFile, " [*]\n"); + nrequired++; + } else + fprintf(outFile, "\n"); + } + + if (nrequired > 0) + fprintf(outFile, "(Options marked with [*] are required)\n"); +} + diff -r 000000000000 -r bd61a80a6c54 th_args.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/th_args.h Wed Mar 26 04:41:58 2008 +0200 @@ -0,0 +1,50 @@ +/* + * Simple commandline argument processing function + * Programmed and designed by Matti 'ccr' Hamalainen + * (C) Copyright 2002-2008 Tecnic Software productions (TNSP) + * + * Please read file 'COPYING' for information on license and distribution. + */ +#ifndef _TH_ARGS +#define _TH_ARGS + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "th_util.h" + + +/* Option flags + */ +#define OPT_NONE (0) /* Simple option with no arguments */ + +#define OPT_ARGREQ (1) /* Option's argument is required */ +#define OPT_ARGOPT (3) /* Option's argument is optional */ +#define OPT_ARGMASK (3) /* Mask for option argument flags */ + +#define OPT_REQUIRED (4) /* This option is required to be given */ + + +typedef struct { + int optID; + char optShort; + char *optLong; + char *optDesc; + int optFlags; +} optarg_t; + + +BOOL th_args_process(int argc, char *argv[], + optarg_t argList[], int argListN, + BOOL (*handleOpt)(int, char *, char *), + BOOL (*handleFile)(char *), BOOL); + +void th_args_help(FILE *, optarg_t optList[], int optListN, + char *, char *); + +#ifdef __cplusplus +} +#endif +#endif /* _TH_ARGS */ diff -r 000000000000 -r bd61a80a6c54 th_config.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/th_config.c Wed Mar 26 04:41:58 2008 +0200 @@ -0,0 +1,575 @@ +/* + * Very simple configuration handling functions + * Programmed and designed by Matti 'ccr' Hamalainen + * (C) Copyright 2004-2007 Tecnic Software productions (TNSP) + * + * Please read file 'COPYING' for information on license and distribution. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +#include +#include "th_config.h" +#include "th_util.h" +#include "th_string.h" + +#define LPREV (pNode->pPrev) +#define LNEXT (pNode->pNext) + + +void th_config_error(char_t * pcFilename, size_t lineNum, + const char_t * pcFormat, ...) +{ + va_list ap; + va_start(ap, pcFormat); + fprintf(stderr, "%s: '%s', line #%d: ", th_prog_name, pcFilename, lineNum); + vfprintf(stderr, pcFormat, ap); + va_end(ap); +} + + +/* Create a new configuration + */ +t_config *th_config_new(void) +{ + t_config *cfg; + + cfg = (t_config *) th_calloc(1, sizeof(t_config)); + if (!cfg) + return NULL; + + return cfg; +} + + +/* Free a given configuration (the values are not free'd) + */ +void th_config_free(t_config * cfg) +{ + t_config_item *pCurr, *pNext; + + if (!cfg) + return; + + pCurr = cfg->pItems; + while (pCurr) { + pNext = pCurr->pNext; + th_free(pCurr->itemName); + th_free(pCurr); + pCurr = pNext; + } +} + + +/* Allocate and add new item to configuration + */ +t_config_item *th_config_add(t_config * cfg, char_t * itemName, int itemType, + BOOL(*itemValidate) (t_config_item *), void *itemData) +{ + t_config_item *pNode; + + if (!cfg) + return NULL; + + /* Allocate new item */ + pNode = (t_config_item *) th_calloc(1, sizeof(t_config_item)); + if (!pNode) + return NULL; + + /* Set values */ + pNode->itemType = itemType; + pNode->itemData = itemData; + pNode->itemValidate = itemValidate; + th_pstrcpy(&pNode->itemName, itemName); + + /* Insert into linked list */ + if (cfg->pItems) { + /* The first node's pPrev points to last node */ + LPREV = cfg->pItems->pPrev; /* New node's prev = Previous last node */ + cfg->pItems->pPrev->pNext = pNode; /* Previous last node's next = New node */ + cfg->pItems->pPrev = pNode; /* New last node = New node */ + LNEXT = NULL; /* But next is NULL! */ + } else { + cfg->pItems = pNode; /* First node ... */ + LPREV = pNode; /* ... it's also last */ + LNEXT = NULL; /* But next is NULL! */ + } + + return pNode; +} + + +/* Add integer type setting into give configuration + */ +int th_config_add_int(t_config * cfg, char_t * itemName, BOOL(*itemValidate) (t_config_item *), + int *itemData, int itemDef) +{ + t_config_item *pNode; + + pNode = th_config_add(cfg, itemName, ITEM_INT, itemValidate, (void *) itemData); + if (!pNode) + return -1; + + *itemData = itemDef; + + return 0; +} + + +/* Add unsigned integer type setting into give configuration + */ +int th_config_add_uint(t_config * cfg, char_t * itemName, BOOL(*itemValidate) (t_config_item *), + unsigned int * itemData, unsigned int itemDef) +{ + t_config_item *pNode; + + pNode = th_config_add(cfg, itemName, ITEM_UINT, itemValidate, (void *) itemData); + if (!pNode) + return -1; + + *itemData = itemDef; + + return 0; +} + + +/* Add strint type setting into given configuration + */ +int th_config_add_str(t_config * cfg, char_t * itemName, BOOL(*itemValidate) (t_config_item *), + char_t ** itemData, char_t * itemDef) +{ + t_config_item *pNode; + + pNode = th_config_add(cfg, itemName, ITEM_STRING, itemValidate, (void *) itemData); + if (!pNode) + return -1; + + if (itemDef != NULL) + *itemData = th_strdup(itemDef); + else + *itemData = NULL; + + return 0; +} + + +/* Add boolean type setting into given configuration + */ +int th_config_add_bool(t_config * cfg, char_t * itemName, BOOL(*itemValidate) (t_config_item *), + BOOL * itemData, BOOL itemDef) +{ + t_config_item *pNode; + + pNode = th_config_add(cfg, itemName, ITEM_BOOL, itemValidate, (void *) itemData); + if (!pNode) + return -1; + + *itemData = itemDef; + + return 0; +} + + +/* Read a given file into configuration structure and variables + */ +enum +{ + PM_EOF, + PM_ERROR, + PM_NORMAL, + PM_COMMENT, + PM_NEXT, + PM_KEYNAME, + PM_KEYSET, + PM_STRING, + PM_INT, + PM_BOOL +}; + +#define VADDCH(ch) if (strPos < SET_MAX_BUF) { tmpStr[strPos++] = ch; } +#define VISEND(ch) (ch == '\r' || ch == '\n' || ch == ';' || th_isspace(c)) + +int th_config_read(char_t * pcFilename, t_config * cfg) +{ + FILE *inFile; + t_config_item *pItem; + char_t tmpStr[SET_MAX_BUF + 1]; + size_t lineNum, strPos; + int c, parseMode, prevMode, nextMode, tmpCh; + BOOL isFound, isStart, tmpBool, isError, validError; + + assert(cfg); + + /* Open the file */ + if ((inFile = fopen(pcFilename, "rb")) == NULL) + return -1; + + /* Initialize values */ + pItem = NULL; + tmpCh = 0; + strPos = 0; + lineNum = 1; + c = -1; + isFound = isStart = tmpBool = isError = validError = FALSE; + nextMode = prevMode = parseMode = PM_NORMAL; + + /* Parse the configuration */ + while ((parseMode != PM_EOF) && (parseMode != PM_ERROR)) { + if (c == -1) { + /* Get next character */ + switch (c = fgetc(inFile)) { + case EOF: + if (parseMode != PM_NORMAL) { + th_config_error(pcFilename, lineNum, + "Unexpected end of file.\n"); + parseMode = PM_ERROR; + } else + parseMode = PM_EOF; + break; + + case '\n': + lineNum++; + } + } + + switch (parseMode) { + case PM_COMMENT: + /* Comment parsing mode */ + if (c == '\n') { + /* End of line, end of comment */ + parseMode = prevMode; + prevMode = PM_COMMENT; + } + c = -1; + break; + + case PM_NORMAL: + /* Normal parsing mode */ + if (c == '#') { + prevMode = parseMode; + parseMode = PM_COMMENT; + c = -1; + } else if (VISEND(c)) { + c = -1; + } else if (th_isalpha(c)) { + /* Start of key name found */ + prevMode = parseMode; + parseMode = PM_KEYNAME; + strPos = 0; + } else { + /* Error! Invalid character found */ + th_config_error(pcFilename, lineNum, + "Unexpected character '%c'\n", c); + parseMode = PM_ERROR; + } + break; + + case PM_KEYNAME: + /* Configuration KEY name parsing mode */ + if (c == '#') { + /* Start of comment */ + prevMode = parseMode; + parseMode = PM_COMMENT; + c = -1; + } else if (th_iscrlf(c) || th_isspace(c) || c == '=') { + /* End of key name */ + prevMode = parseMode; + parseMode = PM_NEXT; + nextMode = PM_KEYSET; + } else if (th_isalnum(c) || (c == '_')) { + /* Add to key name string */ + VADDCH(c) + else + { + /* Error! Key name string too long! */ + th_config_error(pcFilename, lineNum, + "Config key name too long!"); + parseMode = PM_ERROR; + } + c = -1; + } else { + /* Error! Invalid character found */ + th_config_error(pcFilename, lineNum, + "Unexpected character '%c'\n", c); + parseMode = PM_ERROR; + } + break; + + case PM_KEYSET: + if (c == '=') { + /* Find key from configuration */ + tmpStr[strPos] = 0; + isFound = FALSE; + pItem = cfg->pItems; + while (pItem && !isFound) { + if (strcmp(pItem->itemName, tmpStr) == 0) + isFound = TRUE; + else + pItem = pItem->pNext; + } + + /* Check if key was found */ + if (isFound) { + /* Okay, set next mode */ + switch (pItem->itemType) { + case ITEM_STRING: + nextMode = PM_STRING; + break; + + case ITEM_INT: + case ITEM_UINT: + nextMode = PM_INT; + break; + + case ITEM_BOOL: + nextMode = PM_BOOL; + break; + } + + prevMode = parseMode; + parseMode = PM_NEXT; + isStart = TRUE; + strPos = 0; + } else { + /* Error! No configuration key by this name found */ + th_config_error(pcFilename, lineNum, + "No such configuration setting ('%s')\n", + tmpStr); + parseMode = PM_ERROR; + } + + c = -1; + } else { + /* Error! '=' expected! */ + th_config_error(pcFilename, lineNum, + "Unexpected character '%c', '=' expected.\n", c); + parseMode = PM_ERROR; + } + break; + + case PM_NEXT: + /* Search next item parsing mode */ + if (c == '#') { + /* Start of comment */ + prevMode = parseMode; + parseMode = PM_COMMENT; + } else if (th_isspace(c) || th_iscrlf(c)) { + /* Ignore whitespaces and linechanges */ + c = -1; + } else { + /* Next item found */ + prevMode = parseMode; + parseMode = nextMode; + } + break; + + case PM_STRING: + /* String parsing mode */ + if (isStart) { + /* Start of string, get delimiter */ + tmpCh = c; + isStart = FALSE; + strPos = 0; + } else if (c == tmpCh) { + /* End of string, set the value */ + tmpStr[strPos] = 0; + th_pstrcpy((char_t **) pItem->itemData, tmpStr); + if (pItem->itemValidate) { + if (!pItem->itemValidate(pItem)) + validError = TRUE; + } + + prevMode = parseMode; + parseMode = PM_NORMAL; + } else { + /* Add character to string */ + VADDCH(c) + else + { + /* Error! String too long! */ + th_config_error(pcFilename, lineNum, + "String too long! Maximum is %d characters.", + SET_MAX_BUF); + parseMode = PM_ERROR; + } + } + + c = -1; + break; + + case PM_INT: + /* Integer parsing mode */ + if (isStart && (pItem->itemType == ITEM_UINT) && (c == '-')) { + /* Error! Negative values not allowed for unsigned ints */ + th_config_error(pcFilename, lineNum, + "Negative value specified, unsigned value expected."); + parseMode = PM_ERROR; + } else if (isStart && (c == '-' || c == '+')) { + VADDCH(c) + else + isError = TRUE; + } else if (th_isdigit(c)) { + VADDCH(c) + else + isError = TRUE; + } else if (VISEND(c)) { + /* End of integer parsing mode */ + tmpStr[strPos] = 0; + switch (pItem->itemType) { + case ITEM_INT: + *((int *) pItem->itemData) = atoi(tmpStr); + break; + + case ITEM_UINT: + *((unsigned int *) pItem->itemData) = atol(tmpStr); + break; + } + if (pItem->itemValidate) { + if (!pItem->itemValidate(pItem)) + validError = TRUE; + } + + prevMode = parseMode; + parseMode = PM_NORMAL; + } else { + /* Error! Unexpected character. */ + th_config_error(pcFilename, lineNum, + "Unexpected character, ", SET_MAX_BUF); + parseMode = PM_ERROR; + } + + if (isError) { + /* Error! String too long! */ + th_config_error(pcFilename, lineNum, + "String too long! Maximum is %d characters.", + SET_MAX_BUF); + parseMode = PM_ERROR; + } + + isStart = FALSE; + c = -1; + break; + + case PM_BOOL: + /* Boolean parsing mode */ + if (isStart) { + tmpCh = c; + isStart = FALSE; + } else if (VISEND(c)) { + /* End of boolean parsing */ + switch (tmpCh) { + case 'Y': + case 'y': + case 'T': + case 't': + case '1': + tmpBool = TRUE; + break; + + default: + tmpBool = FALSE; + break; + } + + /* Set the value */ + *((BOOL *) pItem->itemData) = tmpBool; + if (pItem->itemValidate) { + if (!pItem->itemValidate(pItem)) + validError = TRUE; + } + + prevMode = parseMode; + parseMode = PM_NORMAL; + } + + c = -1; + break; + } + } + + + /* Close files */ + fclose(inFile); + + /* Check for validation errors */ + if (validError) + return 1; + + /* Return result */ + if (parseMode == PM_ERROR) + return -2; + else + return 0; +} + + +/* Write a configuration into file + */ +int th_config_write(FILE * outFile, t_config * cfg) +{ + t_config_item *pItem; + + if (!cfg) + return -1; + + fprintf(outFile, "# Configuration written by %s %s\n\n", + th_prog_fullname, th_prog_version); + + pItem = cfg->pItems; + while (pItem) { + if (!pItem->itemData || ((pItem->itemType == ITEM_STRING) && + *(char_t **) pItem->itemData == NULL)) { + + fprintf(outFile, "#%s = ", pItem->itemName); + + switch (pItem->itemType) { + case ITEM_STRING: + fprintf(outFile, "\"string\""); + break; + + case ITEM_INT: + fprintf(outFile, "int"); + break; + + case ITEM_UINT: + fprintf(outFile, "uint"); + break; + + case ITEM_BOOL: + fprintf(outFile, "boolean"); + break; + } + + } else { + fprintf(outFile, "%s = ", pItem->itemName); + + switch (pItem->itemType) { + case ITEM_STRING: + fprintf(outFile, "\"%s\"", + *((char_t **) pItem->itemData)); + break; + + case ITEM_INT: + fprintf(outFile, "%i", + *((int *) pItem->itemData)); + break; + + case ITEM_UINT: + fprintf(outFile, "%d", + *((unsigned int *) pItem->itemData)); + break; + + case ITEM_BOOL: + fprintf(outFile, "%s", + *((BOOL *) pItem->itemData) ? "yes" : "no"); + break; + } + } + + fprintf(outFile, "\n\n"); + pItem = pItem->pNext; + } + + return 0; +} diff -r 000000000000 -r bd61a80a6c54 th_config.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/th_config.h Wed Mar 26 04:41:58 2008 +0200 @@ -0,0 +1,62 @@ +/* + * Very simple configuration file parsing functions + * Programmed and designed by Matti 'ccr' Hamalainen + * (C) Copyright 2004-2007 Tecnic Software productions (TNSP) + * + * Please read file 'COPYING' for information on license and distribution. + */ +#ifndef _TH_CONFIG_H +#define _TH_CONFIG_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "th_util.h" +#include + +/* + * Type definations + */ +enum ITEM_TYPE { + ITEM_BLOCK = 1, + ITEM_STRING, + ITEM_INT, + ITEM_UINT, + ITEM_BOOL +}; + + +typedef struct tconfignode { + char *itemName; /* Config item name */ + int itemType; /* Type of the item */ + void *itemData; /* Data / value */ + + BOOL (*itemValidate)(struct tconfignode *); + + struct tconfignode *pNext, *pPrev; +} t_config_item; + + +typedef struct { + t_config_item *pItems; +} t_config; + + +/* + * Functions + */ +t_config * th_config_new(void); +int th_config_read(char *, t_config *); +void th_config_free(t_config *); +int th_config_write(FILE *, t_config *); + +int th_config_add_int(t_config *cfg, char *itemName, BOOL (*itemValidate)(t_config_item *), int *itemData, int itemDef); +int th_config_add_uint(t_config *cfg, char *itemName, BOOL (*itemValidate)(t_config_item *), unsigned int *itemData, unsigned int itemDef); +int th_config_add_str(t_config *cfg, char *itemName, BOOL (*itemValidate)(t_config_item *), char **itemData, char *itemDef); +int th_config_add_bool(t_config *cfg, char *itemName, BOOL (*itemValidate)(t_config_item *), BOOL *itemData, BOOL itemDef); + +#ifdef __cplusplus +} +#endif +#endif /* _TH_CONFIG_H */ diff -r 000000000000 -r bd61a80a6c54 th_endian.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/th_endian.c Wed Mar 26 04:41:58 2008 +0200 @@ -0,0 +1,96 @@ +/* + * Endianess handling + * Programmed and designed by Matti 'ccr' Hamalainen + * (C) Copyright 2002-2007 Tecnic Software productions (TNSP) + * + * Please read file 'COPYING' for information on license and distribution. + */ +#include "th_endian.h" +#include + + +/* + * Endianess conversion routines + */ +#ifdef TH_BIGENDIAN +/* Convert to from Small Endian + */ +void TH_NE16(uint16_t * iVal) +{ + uint16_t r = *iVal; + *iVal = ((r & 0xff) << 8) | ((r >> 8) & 0xff); +} + + +void TH_NE32(uint32_t * iVal) +{ + uint32_t r = *iVal; + *iVal = ((r & 0xff) << 8) | ((r >> 8) & 0xff) | + ((r & 0x00ff0000L) << 8) | ((r >> 8) & 0x00ff0000L); +} + + +/* Convert to Small/Little Endian + */ +uint16_t TH_LE16(uint16_t iVal) +{ + return ((iVal & 0xff) << 8) | ((iVal >> 8) & 0xff); +} + + +uint32_t TH_LE32(uint32_t iVal) +{ + return ((iVal & 0xff) << 8) | ((iVal >> 8) & 0xff) | + ((iVal & 0x00ff0000L) << 8) | ((iVal >> 8) & 0x00ff0000L); +} +#endif /* TH_BIGENDIAN */ + + +/* + * File routines for endian-dependant data + */ +#define TH_FILE FILE +#define TH_FREAD fread +#define TH_FGETC fgetc +#define TH_RNAME(X) TH_READ_##X +#define TH_CODE_ENDIAN2 +#include "th_endian2.h" +#undef TH_CODE_ENDIAN2 + + +BOOL TH_WRITE_STR(FILE * f, uint8_t * s, size_t l) +{ + return (fwrite(s, sizeof(uint8_t), l, f) == l); +} + + +void TH_WRITE_BE16(FILE * f, uint16_t v) +{ + fputc((v >> 8) & 0xFF, f); + fputc(v & 0xFF, f); +} + + +void TH_WRITE_BE32(FILE * f, uint32_t v) +{ + fputc((v >> 24) & 0xFF, f); + fputc((v >> 16) & 0xFF, f); + fputc((v >> 8) & 0xFF, f); + fputc(v & 0xFF, f); +} + + +void TH_WRITE_LE16(FILE * f, uint16_t v) +{ + fputc(v & 0xFF, f); + fputc((v >> 8) & 0xFF, f); +} + + +void TH_WRITE_LE32(FILE * f, uint32_t v) +{ + fputc(v & 0xFF, f); + fputc((v >> 8) & 0xFF, f); + fputc((v >> 16) & 0xFF, f); + fputc((v >> 24) & 0xFF, f); +} diff -r 000000000000 -r bd61a80a6c54 th_endian.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/th_endian.h Wed Mar 26 04:41:58 2008 +0200 @@ -0,0 +1,55 @@ +/* + * Endianess handling + * Programmed and designed by Matti 'ccr' Hamalainen + * (C) Copyright 2002-2007 Tecnic Software productions (TNSP) + * + * Please read file 'COPYING' for information on license and distribution. + */ +#ifndef _TH_ENDIAN_H +#define _TH_ENDIAN_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +#include "th_types.h" + +/* + * Data endianess conversion routines + */ +#ifdef TH_BIGENDIAN +void TH_NE16(uint16_t *); +void TH_NE32(uint32_t *); +uint16_t TH_LE16(uint16_t); +uint32_t TH_LE32(uint32_t); +#else +#define TH_NE16(X) +#define TH_NE32(X) +#define TH_LE16(X) X +#define TH_LE32(X) X +#endif + + +/* + * Endian-handling file read/write routines + */ +BOOL TH_READ_STR(FILE *f, uint8_t *s, size_t l); +uint16_t TH_READ_BE16(FILE *f); +uint32_t TH_READ_BE32(FILE *f); +uint16_t TH_READ_LE16(FILE *f); +uint32_t TH_READ_LE32(FILE *f); + +BOOL TH_WRITE_STR(FILE *f, uint8_t *s, size_t l); +void TH_WRITE_BE16(FILE *f, uint16_t v); +void TH_WRITE_BE32(FILE *f, uint32_t v); +void TH_WRITE_LE16(FILE *f, uint16_t v); +void TH_WRITE_LE32(FILE *f, uint32_t v); + +#ifdef __cplusplus +} +#endif +#endif /* _TH_ENDIAN_H */ diff -r 000000000000 -r bd61a80a6c54 th_endian2.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/th_endian2.h Wed Mar 26 04:41:58 2008 +0200 @@ -0,0 +1,49 @@ +/* + * Endianess handling + * Programmed and designed by Matti 'ccr' Hamalainen + * (C) Copyright 2002-2007 Tecnic Software productions (TNSP) + * + * Please read file 'COPYING' for information on license and distribution. + */ +#if (!defined(TH_RNAME) || !defined(TH_FILE) || !defined(TH_FREAD) || !defined(TH_FGETC)) +#error Some required preprocessor macros NOT defined, but th_endian2.h included! +#endif + +#ifdef TH_CODE_ENDIAN2 +BOOL TH_RNAME(STR) (TH_FILE *f, uint8_t *s, size_t l) +{ + return (TH_FREAD(s, sizeof(uint8_t), l, f) == l); +} + + +uint16_t TH_RNAME(BE16) (TH_FILE *f) +{ + return (((uint16_t) TH_FGETC(f)) << 8) | + ((uint16_t) TH_FGETC(f)); +} + + +uint32_t TH_RNAME(BE32) (TH_FILE *f) +{ + return (((uint32_t) TH_FGETC(f)) << 24) | + (((uint32_t) TH_FGETC(f)) << 16) | + (((uint32_t) TH_FGETC(f)) << 8) | + ((uint32_t) TH_FGETC(f)); +} + + +uint16_t TH_RNAME(LE16) (TH_FILE *f) +{ + return ((uint16_t) TH_FGETC(f)) | + (((uint16_t) TH_FGETC(f)) << 8); +} + + +uint32_t TH_RNAME(LE32) (TH_FILE *f) +{ + return ((uint32_t) TH_FGETC(f)) | + (((uint32_t) TH_FGETC(f)) << 8) | + (((uint32_t) TH_FGETC(f)) << 16) | + (((uint32_t) TH_FGETC(f)) << 24); +} +#endif diff -r 000000000000 -r bd61a80a6c54 th_string.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/th_string.c Wed Mar 26 04:41:58 2008 +0200 @@ -0,0 +1,462 @@ +/* + * Miscellaneous string-handling related utility-functions + * Programmed and designed by Matti 'ccr' Hamalainen + * (C) Copyright 2002-2008 Tecnic Software productions (TNSP) + * + * Please read file 'COPYING' for information on license and distribution. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "th_string.h" + +#define LPREV (pNode->pPrev) +#define LNEXT (pNode->pNext) + +/* Allocate memory for a string with given length + */ +char *th_stralloc(const size_t l) +{ + assert(l > 0); + return th_malloc(sizeof(char) * l); +} + + +char *th_strrealloc(char * s, const size_t l) +{ + assert(l > 0); + return th_realloc(s, sizeof(char) * l); +} + + +/* Duplicate a string [strdup] + */ +char *th_strdup(char * str) +{ + char *result, *s, *d; + + if (!str) return NULL; + + /* Allocate memory for destination */ + result = th_stralloc(strlen(str) + 1); + if (!result) + return NULL; + + /* Copy to the destination */ + s = str; + d = result; + while (*s) { + *(d++) = *(s++); + } + *d = 0; + + return result; +} + + +char *th_strncpy(char * dst, char * src, size_t n) +{ + char *s, *d; + size_t i; + assert(src); + assert(dst); + + /* Copy to the destination */ + i = n; + s = src; + d = dst; + while (*s && (i > 0)) { + *(d++) = *(s++); + i--; + } + + /* Fill rest of space with zeros */ + while (i > 0) { + *(d++) = 0; + i--; + } + + /* Ensure that last is always zero */ + dst[n - 1] = 0; + + return dst; +} + + +int th_strncmp(char * str1, char * str2, size_t n) +{ + char *s1, *s2; + assert(str1); + assert(str2); + + /* Check the string pointers */ + if (str1 == str2) + return 0; + + /* Go through the string */ + s1 = str1; + s2 = str2; + while ((n > 0) && *s1 && *s2 && (*s1 == *s2)) { + s1++; + s2++; + n--; + } + + if (n > 0) + return ((*s1) - (*s2)); + else + return 0; +} + + +/* Compare two strings ignoring case [strcasecmp, strncasecmp] + */ +int th_strcasecmp(char * str1, char * str2) +{ + char *s1 = str1, *s2 = str2; + assert(str1); + assert(str2); + + /* Check the string pointers */ + if (str1 == str2) + return 0; + + /* Go through the string */ + while (*s1 && *s2 && (th_tolower(*s1) == th_tolower(*s2))) { + s1++; + s2++; + } + + return (th_tolower(*s1) - th_tolower(*s2)); +} + + +int th_strncasecmp(char * str1, char * str2, size_t n) +{ + char *s1 = str1, *s2 = str2; + assert(str1); + assert(str2); + + /* Check the string pointers */ + if (str1 == str2) + return 0; + + /* Go through the string */ + while ((n > 0) && *s1 && *s2 && (th_tolower(*s1) == th_tolower(*s2))) { + s1++; + s2++; + n--; + } + + if (n > 0) + return (th_tolower(*s1) - th_tolower(*s2)); + else + return 0; +} + + +/* Remove all occurences of control characters, in-place. + * Resulting string is always shorter or same length than original. + */ +void th_strip_ctrlchars(char * str) +{ + char *i, *j; + assert(str); + + i = str; + j = str; + while (*i) { + if (!th_iscntrl(*i)) + *(j++) = *i; + i++; + } + + *j = 0; +} + + +/* Copy a given string over in *result. + */ +int th_pstrcpy(char ** result, char * str) +{ + assert(result); + + /* Check the string pointers */ + if (!str) + return -1; + + /* Allocate memory for destination */ + th_free(*result); + *result = th_stralloc(strlen(str) + 1); + if (!*result) + return -2; + + /* Copy to the destination */ + strcpy(*result, str); + + return 0; +} + + +/* Concatenates a given string into string pointed by *result. + */ +int th_pstrcat(char ** result, char * str) +{ + assert(result); + + /* Check the string pointers */ + if (!str) + return -1; + + if (*result != NULL) { + *result = th_strrealloc(*result, strlen(*result) + strlen(str) + 1); + if (*result == NULL) + return -1; + + strcat(*result, str); + } else { + *result = th_stralloc(strlen(str) + 1); + if (*result == NULL) + return -1; + + strcpy(*result, str); + } + + return 0; +} + + +/* Find next non-whitespace character in string. + * Updates iPos into the position of such character and + * returns pointer to the string. + */ +char *th_findnext(char * str, size_t * iPos) +{ + assert(str); + + /* Terminating NULL-character is not whitespace! */ + while (th_isspace(str[*iPos])) + (*iPos)++; + return &str[*iPos]; +} + + +/* Find next chSep-character from string + */ +char *th_findsep(char * str, size_t * iPos, char chSep) +{ + assert(str); + + /* Terminating NULL-character is not digit! */ + while (str[*iPos] && (str[*iPos] != chSep)) + (*iPos)++; + return &str[*iPos]; +} + + +/* Find next chSep- or whitespace from string + */ +char *th_findseporspace(char * str, size_t * iPos, char chSep) +{ + assert(str); + + /* Terminating NULL-character is not digit! */ + while (!th_isspace(str[*iPos]) && (str[*iPos] != chSep)) + (*iPos)++; + return &str[*iPos]; +} + + +/* Compare a string to a pattern. Case-SENSITIVE version. + * The matching pattern can consist of any normal characters plus + * wildcards ? and *. "?" matches any character and "*" matches + * any number of characters. + */ +BOOL th_strmatch(char * str, char * pattern) +{ + BOOL didMatch, isAnyMode, isEnd; + char *tmpPattern; + + /* Check given pattern and string */ + if (!str) + return FALSE; + if (!pattern) + return FALSE; + + /* Initialize */ + tmpPattern = NULL; + didMatch = TRUE; + isEnd = FALSE; + isAnyMode = FALSE; + + /* Start comparision */ + do { + didMatch = FALSE; + switch (*pattern) { + case '?': + /* Any single character matches */ + if (*str) { + didMatch = TRUE; + pattern++; + str++; + } + break; + + case '*': + didMatch = TRUE; + pattern++; + if (!*pattern) + isEnd = TRUE; + isAnyMode = TRUE; + tmpPattern = pattern; + break; + + case 0: + if (isAnyMode) { + if (*str) + str++; + else + isEnd = TRUE; + } else { + if (*str) { + if (tmpPattern) { + isAnyMode = TRUE; + pattern = tmpPattern; + } else + didMatch = FALSE; + } else + isEnd = TRUE; + } + break; + default: + if (isAnyMode) { + if ((*pattern) == (*str)) { + isAnyMode = FALSE; + didMatch = TRUE; + } else { + if (*str) { + didMatch = TRUE; + str++; + } + } + } else { + if ((*pattern) == (*str)) { + didMatch = TRUE; + if (*pattern) + pattern++; + if (*str) + str++; + } else { + if (tmpPattern) { + didMatch = TRUE; + isAnyMode = TRUE; + pattern = tmpPattern; + } + } + } + + if (!*str && !*pattern) + isEnd = TRUE; + break; + + } /* switch */ + + } while ((didMatch) && (!isEnd)); + + return didMatch; +} + + +/* Compare a string to a pattern. Case-INSENSITIVE version. + */ +BOOL th_strcasematch(char * str, char * pattern) +{ + BOOL didMatch, isAnyMode, isEnd; + char *tmpPattern; + + /* Check given pattern and string */ + if (!str) + return FALSE; + if (!pattern) + return FALSE; + + /* Initialize */ + tmpPattern = NULL; + didMatch = TRUE; + isEnd = FALSE; + isAnyMode = FALSE; + + /* Start comparision */ + do { + switch (*pattern) { + case '?': + /* Any single character matches */ + if (*str) { + pattern++; + str++; + } else + didMatch = FALSE; + break; + + case '*': + pattern++; + if (!*pattern || (*pattern == '?')) + isEnd = TRUE; + isAnyMode = TRUE; + tmpPattern = pattern; + break; + + case 0: + if (isAnyMode) { + if (*str) + str++; + else + isEnd = TRUE; + } else { + if (*str) { + if (tmpPattern) { + isAnyMode = TRUE; + pattern = tmpPattern; + } else + didMatch = FALSE; + } else + isEnd = TRUE; + } + break; + + default: + if (isAnyMode) { + if (th_tolower(*pattern) == th_tolower(*str)) { + isAnyMode = FALSE; + } else { + if (*str) + str++; + else + didMatch = FALSE; + } + } else { + if (th_tolower(*pattern) == th_tolower(*str)) { + if (*pattern) + pattern++; + if (*str) + str++; + } else { + if (tmpPattern) { + isAnyMode = TRUE; + pattern = tmpPattern; + } else + didMatch = FALSE; + } + } + + if (!*str && !*pattern) + isEnd = TRUE; + break; + + } /* switch */ + + } while ((didMatch) && (!isEnd)); + + return didMatch; +} + diff -r 000000000000 -r bd61a80a6c54 th_string.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/th_string.h Wed Mar 26 04:41:58 2008 +0200 @@ -0,0 +1,66 @@ +/* + * Miscellaneous string-handling related utility-functions + * Programmed and designed by Matti 'ccr' Hamalainen + * (C) Copyright 2002-2008 Tecnic Software productions (TNSP) + * + * Please read file 'COPYING' for information on license and distribution. + */ +#ifndef _TH_STRING_H +#define _TH_STRING_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "th_util.h" +#include +#include + +/* Macros + */ +#define th_isalnum(c) isalnum((int)(unsigned char) c) +#define th_isalpha(c) isalpha((int)(unsigned char) c) +#define th_isascii(c) isascii((int)(unsigned char) c) +#define th_isblank(c) isblank((int)(unsigned char) c) +#define th_iscntrl(c) iscntrl((int)(unsigned char) c) +#define th_isdigit(c) isdigit((int)(unsigned char) c) +#define th_isgraph(c) isgraph((int)(unsigned char) c) +#define th_islower(c) islower((int)(unsigned char) c) +#define th_isprint(c) isprint((int)(unsigned char) c) +#define th_ispunct(c) ispunct((int)(unsigned char) c) +#define th_isspace(c) isspace((int)(unsigned char) c) +#define th_isupper(c) isupper((int)(unsigned char) c) +#define th_isxdigit(c) isxdigit((int)(unsigned char) c) +#define th_iscrlf(c) ((c=='\r')||(c=='\n')) + +#define th_isspecial(q) (((q >= 0x5b) && (q <= 0x60)) || ((q >= 0x7b) && (q <= 0x7d))) + +#define th_tolower(c) tolower((int)(unsigned char) c) +#define th_toupper(c) toupper((int)(unsigned char) c) + + +/* Normal NUL-terminated string functions + */ +char *th_stralloc(size_t); +char *th_strrealloc(char *, size_t); +char *th_strdup(char *); +char *th_strncpy(char *, char *, size_t); +int th_strcasecmp(char *, char *); +int th_strncasecmp(char *, char *, size_t); +void th_strip_ctrlchars(char *); + +int th_pstrcpy(char **, char *); +int th_pstrcat(char **, char *); + +char *th_findnext(char *, size_t *); +char *th_findsep(char *, size_t *, char); +char *th_findseporspace(char *, size_t *, char); + +BOOL th_strmatch(char *, char *); +BOOL th_strcasematch(char *, char *); + + +#ifdef __cplusplus +} +#endif +#endif /* _TH_STRING_H */ diff -r 000000000000 -r bd61a80a6c54 th_types.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/th_types.h Wed Mar 26 04:41:58 2008 +0200 @@ -0,0 +1,104 @@ +/* + * Type definations + * Programmed and designed by Matti 'ccr' Hamalainen + * (C) Copyright 2002-2008 Tecnic Software productions (TNSP) + * + * Please read file 'COPYING' for information on license and distribution. + */ +/* If your code uses "config.h", you need to #include + * it before including this header. + */ +#ifndef _TH_TYPES_H +#define _TH_TYPES_H + +#ifdef HAVE_STDINT_H +#include +#ifndef HAVE_INT_TYPES +#define HAVE_INT_TYPES 1 +#endif +#endif + +#ifdef HAVE_SYS_TYPES_H +#include +#ifndef HAVE_INT_TYPES +#define HAVE_INT_TYPES 1 +#endif +#endif + +/* Shorthand types */ +typedef unsigned long int ulint_t; +typedef signed long int lint_t; +#ifndef HAVE_UINT_T +typedef unsigned int uint_t; +#endif + +/* Default assumptions for these types should be ok for most 32bit platforms... + * feel free to define TH_TYPE_* if necessary to remedy + */ +#ifdef TH_TYPE_I8 +typedef unsigned TH_TYPE_I8 uint8_t; /* 8 bits, unsigned */ +typedef signed TH_TYPE_I8 int8_t; /* 8 bits, signed */ +#else +#ifndef HAVE_INT_TYPES +typedef unsigned char uint8_t; +typedef signed char int8_t; +#endif +#endif + + +#ifdef TH_TYPE_I16 +typedef unsigned TH_TYPE_I16 uint16_t; /* 16 bits, unsigned == 2 BYTEs */ +typedef signed TH_TYPE_I16 int16_t; /* 16 bits, signed */ +#else +#ifndef HAVE_INT_TYPES +typedef unsigned short int uint16_t; +typedef signed short int int16_t; +#endif +#endif + +#ifdef TH_TYPE_I32 +typedef unsigned TH_TYPE_I32 uint32_t; /* 32 bits, unsigned == 4 BYTES == 2 WORDs */ +typedef signed TH_TYPE_I32 int32_t; /* 32 bits, signed */ +#else +#ifndef HAVE_INT_TYPES +typedef unsigned int uint32_t; +typedef signed int int32_t; +#endif +#endif + +#ifdef TH_TYPE_I64 +typedef unsigned TH_TYPE_I64 uint64_t; /* 64 bits, unsigned == 8 BYTES == 2 DWORDs */ +typedef signed TH_TYPE_I64 int64_t; /* 64 bits, signed */ +#else +#ifndef HAVE_INT_TYPES +typedef unsigned long long uint64_t; +typedef signed long long int64_t; +#endif +#endif + + +/* This is the character type used in all string-related routines of + * th_libs. Currently it is set to be equivalent of basetype "char", + * but under some platforms it may be necessary to use + * "unsigned char" instead. + * + * Also in future this type may be changed to hold 32-bit UNICODE + */ +typedef char char_t; + + +/* Define a boolean type + */ +#if ((!defined(FALSE)) && (!defined(TRUE)) && (!defined(BOOL))) +typedef enum { FALSE=0, TRUE=1 } BOOL; +#endif + +#ifndef BOOL +#ifdef bool +#define BOOL bool +#else +#define BOOL int +#endif +#endif + +#endif /* _TH_TYPES_H */ diff -r 000000000000 -r bd61a80a6c54 th_util.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/th_util.c Wed Mar 26 04:41:58 2008 +0200 @@ -0,0 +1,140 @@ +/* + * Generic utility-functions, macros and defaults + * Programmed and designed by Matti 'ccr' Hamalainen + * (C) Copyright 2002-2008 Tecnic Software productions (TNSP) + * + * Please read file 'COPYING' for information on license and distribution. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "th_util.h" +#include + +/* + * Default settings + */ +#ifdef TH_NO_DEFAULTS +#define TH_PROG_AUTHOR "" +#define TH_PROG_LICENSE "" +#else +#define TH_PROG_AUTHOR "By Matti 'ccr' Hämäläinen (C) Copyright 2008 TNSP" +#define TH_PROG_LICENSE "This software is licensed under GNU GPL version 2" +#endif + +BOOL th_isInitialized = FALSE; +int th_verbosityLevel = 2; +char *th_prog_name = NULL, + *th_prog_fullname = NULL, + *th_prog_version = NULL, + *th_prog_author = NULL, + *th_prog_license = NULL; + + +/* Initialize th_util-library and global variables + */ +void th_init(char *progName, char *progFullName, char *progVersion, + char *progAuthor, char *progLicense) +{ + th_prog_name = progName; + th_prog_fullname = progFullName; + th_prog_version = progVersion; + + if (progAuthor) + th_prog_author = progAuthor; + else + th_prog_author = TH_PROG_AUTHOR; + + if (progLicense) + th_prog_license = progLicense; + else + th_prog_license = TH_PROG_LICENSE; + + th_isInitialized = TRUE; +} + + +/* Print formatted error, warning and information messages + * TODO: Implement th_vfprintf() and friends? + */ +void THERR(const char *pcFormat, ...) +{ + va_list ap; + assert(th_isInitialized); + + va_start(ap, pcFormat); + fprintf(stderr, "%s: ", th_prog_name); + vfprintf(stderr, pcFormat, ap); + va_end(ap); +} + + +void THMSG(int verbLevel, const char *pcFormat, ...) +{ + va_list ap; + assert(th_isInitialized); + + /* Check if the current verbosity level is enough */ + if (th_verbosityLevel >= verbLevel) { + va_start(ap, pcFormat); + fprintf(stderr, "%s: ", th_prog_name); + vfprintf(stderr, pcFormat, ap); + va_end(ap); + } +} + + +void THPRINT(int verbLevel, const char *pcFormat, ...) +{ + va_list ap; + assert(th_isInitialized); + + /* Check if the current verbosity level is enough */ + if (th_verbosityLevel >= verbLevel) { + va_start(ap, pcFormat); + vfprintf(stderr, pcFormat, ap); + va_end(ap); + } +} + + +/* Memory handling routines + */ +void *th_malloc(size_t l) +{ + return malloc(l); +} + + +void *th_calloc(size_t n, size_t l) +{ + return calloc(n, l); +} + + +void *th_realloc(void *p, size_t l) +{ + return realloc(p, l); +} + + +void th_free(void *p) +{ + /* Check for NULL pointers for portability due to some libc + * implementations not handling free(NULL) too well. + */ + if (p) free(p); +} + + +#ifndef HAVE_MEMSET +void *th_memset(void *p, int c, size_t n) +{ + unsigned char *dp = (unsigned char *) p; + + while (n--) + *(dp++) = c; + + return p; +} +#endif diff -r 000000000000 -r bd61a80a6c54 th_util.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/th_util.h Wed Mar 26 04:41:58 2008 +0200 @@ -0,0 +1,76 @@ +/* + * Generic utility-functions, macros and defaults + * Programmed and designed by Matti 'ccr' Hamalainen + * (C) Copyright 2002-2008 Tecnic Software productions (TNSP) + * + * Please read file 'COPYING' for information on license and distribution. + */ +#ifndef _TH_UTIL_H +#define _TH_UTIL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "th_types.h" +#include +#include +#ifndef HAVE_NO_ASSERT +#include +#endif + +#ifdef HAVE_STRING_H +#include +#define HAVE_MEMSET 1 +#else +#ifdef HAVE_STRINGS_H +#include +#endif +#endif + +#ifdef HAVE_MEMORY_H +#include +#endif + + +/* Replacement for assert() */ +#ifdef HAVE_NO_ASSERT +# ifdef NDEBUG +# define assert(NEXPR) /* stub */ +# else +# define assert(NEXPR) do { if (!(NEXPR)) { fprintf(stderr, "[%s:%d] assert(" # NEXPR ") failed!\n", __FILE__, __LINE__); abort(); } } while (0) +# endif +#endif + +/* Global variables + */ +extern int th_verbosityLevel; +extern char *th_prog_name, + *th_prog_fullname, + *th_prog_version, + *th_prog_author, + *th_prog_license; + +/* Functions + */ +void th_init(char *progName, char *progFullName, char *progVersion, + char *progAuthor, char *progLicense); +void THERR(const char *, ...); +void THMSG(int, const char *, ...); +void THPRINT(int, const char *, ...); + +void * th_malloc(size_t); +void * th_calloc(size_t, size_t); +void * th_realloc(void *, size_t); +void th_free(void *); + +#ifdef HAVE_MEMSET +#define th_memset memset +#else +void *th_memset(void *, int, size_t); +#endif + +#ifdef __cplusplus +} +#endif +#endif /* _TH_UTIL_H */