silcconfig.c
- Author: Johnny Mnemonic <johnny@themnemonic.org>
+ Author: Giovanni Giacobbi <giovanni@giacobbi.net>
- Copyright (C) 1997 - 2002 Pekka Riikonen
+ Copyright (C) 2002 - 2006 Giovanni Giacobbi
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
*/
/* $Id$ */
-#include "silcincludes.h"
+#include "silc.h"
/* limit debug logging verbosity */
#if 0
#define SILC_CONFIG_DEBUG(fmt)
#endif
+#define BUF_SIZE 255
+
/* this is the option struct and currently it is only used internally to
* the module and other structs. */
typedef struct SilcConfigOptionStruct {
/* unique for each config file (and included ones) */
struct SilcConfigFileObject {
- char *filename; /* the original filename opened */
- int level; /* parsing level, how many nested silc_config_main we have */
- char *base; /* this is a fixed pointer to the base location */
- char *p; /* the Parser poitner */
- uint32 len; /* fixed length of the whole file */
- uint32 line; /* current parsing line, strictly linked to p */
- bool included; /* wether this file is main or included */
+ char *filename; /* the original filename opened */
+ int level; /* parsing level, how many nested
+ silc_config_main we have */
+ char *base; /* this is a fixed pointer to the base location */
+ char *p; /* the Parser poitner */
+ SilcUInt32 len; /* fixed length of the whole file */
+ SilcUInt32 line; /* current parsing line, strictly linked to p */
+ SilcBool included; /* wether this file is main or included */
};
/* We need the entity to base our block-style parsing on */
/* access error descriptions only with silc_config_strerror() */
static char *errorstrs[] = {
- "-OK", /* SILC_CONFIG_OK */
- "-SILENT", /* SILC_CONFIG_ESILENT */
- "Invalid syntax", /* SILC_CONFIG_EGENERIC */
- "Internal error! Please report this bug", /* SILC_CONFIG_EINTERNAL */
- "Can't open specified file", /* SILC_CONFIG_ECANTOPEN */
- "Expected open-brace '{'", /* SILC_CONFIG_EOPENBRACE */
- "Missing close-brace '}'", /* SILC_CONFIG_ECLOSEBRACE */
- "Invalid data type", /* SILC_CONFIG_ETYPE */
- "Unknown option", /* SILC_CONFIG_EBADOPTION */
- "Invalid text", /* SILC_CONFIG_EINVALIDTEXT */
- "Double option specification", /* SILC_CONFIG_EDOUBLE */
- "Expected data but not found", /* SILC_CONFIG_EEXPECTED */
- "Expected '='", /* SILC_CONFIG_EEXPECTEDEQUAL */
- "Unexpected data", /* SILC_CONFIG_EUNEXPECTED */
- "Missing mandatory fields", /* SILC_CONFIG_EMISSFIELDS */
- "Missing ';'", /* SILC_CONFIG_EMISSCOLON */
+ "-OK", /* SILC_CONFIG_OK */
+ "-SILENT", /* SILC_CONFIG_ESILENT */
+ "-PRINTLINE", /* SILC_CONFIG_EPRINTLINE */
+ "Invalid syntax", /* SILC_CONFIG_EGENERIC */
+ "Internal error! Please report this bug", /* SILC_CONFIG_EINTERNAL */
+ "Can't open specified file", /* SILC_CONFIG_ECANTOPEN */
+ "Expected open-brace '{'", /* SILC_CONFIG_EOPENBRACE */
+ "Missing close-brace '}'", /* SILC_CONFIG_ECLOSEBRACE */
+ "Invalid data type", /* SILC_CONFIG_ETYPE */
+ "Unknown option", /* SILC_CONFIG_EBADOPTION */
+ "Invalid text", /* SILC_CONFIG_EINVALIDTEXT */
+ "Double option specification", /* SILC_CONFIG_EDOUBLE */
+ "Expected data but not found", /* SILC_CONFIG_EEXPECTED */
+ "Expected '='", /* SILC_CONFIG_EEXPECTEDEQUAL */
+ "Unexpected data", /* SILC_CONFIG_EUNEXPECTED */
+ "Missing mandatory fields", /* SILC_CONFIG_EMISSFIELDS */
+ "Missing ';'", /* SILC_CONFIG_EMISSCOLON */
};
/* return string describing SilcConfig's error code */
static void my_trim_spaces(SilcConfigFile *file)
{
register char *r = file->p;
- while (isspace(*r))
+ while ((*r != '\0' && *r != EOF) && isspace((int)*r))
if (*r++ == '\n') file->line++;
file->p = r;
}
+
/* Skips the current line until newline (lf or cr) */
static void my_skip_line(SilcConfigFile *file)
{
register char *r = file->p;
- while (*r && (*r != '\n') && (*r != '\r')) r++;
- file->p = (*r ? r + 1 : r);
+ while ((*r != '\0' && *r != EOF) && (*r != '\n') && (*r != '\r')) r++;
+ file->p = ((*r != '\0' && *r != EOF) ? r + 1 : r);
file->line++;
}
+
/* Obtains a text token from the current position until first separator.
* a separator is any non alphanumeric character nor "_" or "-" */
static char *my_next_token(SilcConfigFile *file, char *to)
{
+ unsigned int count = 0;
register char *o;
my_trim_spaces(file);
o = file->p;
- while (isalnum(*o) || (*o == '_') || (*o == '-'))
+ while ((isalnum((int)*o) || (*o == '_') || (*o == '-')) && count < BUF_SIZE) {
+ count++;
*to++ = *o++;
+ }
*to = '\0';
file->p = o;
return to;
}
+
/* Obtains a string from the current position. The only difference from
* next_token() is that quoted-strings are also accepted */
static char *my_get_string(SilcConfigFile *file, char *to)
my_trim_spaces(file);
o = file->p;
if (*o == '"') {
- char *quot = strchr(++o, '"');
- int len = quot - o;
- if (!quot) { /* XXX FIXME: gotta do something here */
- printf("Bullshit, missing matching \"");
- exit(1);
+ unsigned int count = 0;
+ char *d = to;
+ while (count < BUF_SIZE) {
+ o++;
+ if (*o == '"') {
+ break;
+ }
+ if (*o == '\\') {
+ o++;
+ }
+ count++;
+ *d++ = *o;
}
- if (len <= 0)
- *to = '\0';
- else {
- strncpy(to, o, len);
- to[len] = '\0';
+ if (count >= BUF_SIZE) { /* XXX FIXME: gotta do something here */
+ fprintf(stderr, "Bullshit, missing matching \"");
+ exit(1);
}
+ *d = '\0';
/* update stream pointer */
- file->p = quot + 1;
- return to;
+ file->p = o + 1;
+ } else {
+ /* we don't need quote parsing, fall-back to token extractor */
+ my_next_token(file, to);
}
- /* we don't need quote parsing, fall-back to token extractor */
- my_next_token(file, to);
return to;
-};
+}
+
/* Skips all comment lines and spaces lines until first useful character */
static void my_skip_comments(SilcConfigFile *file)
{
}
return NULL;
}
-/* ... */
+
+/* Converts a string in the type specified. returns a dynamically
+ * allocated pointer. */
static void *silc_config_marshall(SilcConfigType type, const char *val)
{
void *pt;
int val_int;
- bool val_bool;
+ SilcBool val_boolean;
char *val_tmp;
- uint32 val_size;
+ SilcUInt32 val_size;
switch (type) {
case SILC_CONFIG_ARG_TOGGLE:
if (!strcasecmp(val, "yes") || !strcasecmp(val, "true") ||
!strcasecmp(val, "on") || !strcasecmp(val, "1")) {
- val_bool = TRUE;
+ val_boolean = TRUE;
}
else if (!strcasecmp(val, "no") || !strcasecmp(val, "false") ||
!strcasecmp(val, "off") || !strcasecmp(val, "0")) {
- val_bool = FALSE;
+ val_boolean = FALSE;
}
else
return NULL;
- pt = silc_calloc(1, sizeof(val_bool));
- *(bool *)pt = (bool) val_bool;
+ pt = silc_calloc(1, sizeof(val_boolean));
+ *(SilcBool *)pt = (SilcBool) val_boolean;
return pt;
case SILC_CONFIG_ARG_INT:
val_int = (int) strtol(val, &val_tmp, 0);
*(int *)pt = val_int;
return pt;
case SILC_CONFIG_ARG_SIZE:
- val_size = (uint32) strtol(val, &val_tmp, 0);
+ val_size = (SilcUInt32) strtol(val, &val_tmp, 0);
if (val == val_tmp)
return NULL; /* really wrong, there must be at least one digit */
/* Search for a designator */
- switch (tolower(val_tmp[0])) {
+ switch (tolower((int)val_tmp[0])) {
case '\0': /* None */
break;
case 'k': /* Kilobytes */
- val_size *= (uint32) 1024;
+ val_size *= (SilcUInt32) 1024;
break;
case 'm': /* Megabytes */
- val_size *= (uint32) (1024 * 1024);
+ val_size *= (SilcUInt32) (1024 * 1024);
break;
case 'g':
- val_size *= (uint32) (1024 * 1024 * 1024);
+ val_size *= (SilcUInt32) (1024 * 1024 * 1024);
break;
default:
return NULL;
if (val_tmp[1])
return NULL;
pt = silc_calloc(1, sizeof(val_size));
- *(uint32 *)pt = val_size;
+ *(SilcUInt32 *)pt = val_size;
return pt;
case SILC_CONFIG_ARG_STR: /* the only difference between STR and STRE is */
if (!val[0]) /* that STR cannot be empty, while STRE can. */
/* Tries to open the config file and returns a valid SilcConfigFile object
* or NULL if failed */
-SilcConfigFile *silc_config_open(char *configfile)
+SilcConfigFile *silc_config_open(const char *configfile)
{
char *buffer;
- uint32 filelen;
+ SilcUInt32 filelen;
SilcConfigFile *ret;
if (!(buffer = silc_file_readfile(configfile, &filelen)))
void silc_config_close(SilcConfigFile *file)
{
if (file) {
- /* XXX FIXME: this check could probably be removed later */
- uint32 my_len = (uint32) (strchr(file->base, EOF) - file->base);
- SILC_CONFIG_DEBUG(("file=0x%x name=\"%s\" level=%d line=%lu", (uint32) file,
- file->filename, file->level, file->line));
- if (my_len != file->len) {
- fprintf(stderr, "FATAL ERROR: saved len and current len does not match!\n");
- abort();
- }
silc_free(file->filename);
memset(file->base, 'F', file->len);
silc_free(file->base);
ret = silc_calloc(1, sizeof(*ret));
ret->file = file;
return ret;
-};
+}
/* Returns the original filename of the object file */
/* Returns the current line that file parsing arrived at */
-uint32 silc_config_get_line(SilcConfigFile *file)
+SilcUInt32 silc_config_get_line(SilcConfigFile *file)
{
if (file)
return file->line;
/* Returns a pointer to the beginning of the requested line. If the line
* was not found, NULL is returned */
-char *silc_config_read_line(SilcConfigFile *file, uint32 line)
+char *silc_config_read_line(SilcConfigFile *file, SilcUInt32 line)
{
register char *p;
int len;
- char *ret, *endbuf;
+ char *ret = NULL, *endbuf;
if (!file || (line <= 0))
return NULL;
found:
if ((endbuf = strchr(p, '\n'))) {
len = endbuf - p;
- ret = silc_calloc(len, sizeof(*ret));
- strncpy(ret, p, len);
- ret[len] = '\0';
- }
- else {
- ret = silc_calloc(strlen(p), sizeof(*ret));
- strcpy(ret, p);
+ if (len > 0)
+ ret = silc_memdup(p, len);
+ } else {
+ ret = silc_memdup(p, strlen(p));
}
return ret;
}
/* (Private) destroy a SilcConfigEntity */
-static void silc_config_destroy(SilcConfigEntity ent)
+static void silc_config_destroy(SilcConfigEntity ent, SilcBool destroy_opts)
{
SilcConfigOption *oldopt, *nextopt;
SILC_CONFIG_DEBUG(("Freeing config entity [ent=0x%x] [opts=0x%x]",
- (uint32) ent, (uint32) ent->opts));
+ (SilcUInt32) ent, (SilcUInt32) ent->opts));
+
+ /* if she wants to preserve options just free the object struct */
+ if (!destroy_opts)
+ goto skip_sect;
+
for (oldopt = ent->opts; oldopt; oldopt = nextopt) {
nextopt = oldopt->next;
memset(oldopt->name, 'F', strlen(oldopt->name) + 1);
memset(oldopt, 'F', sizeof(*oldopt));
silc_free(oldopt);
}
+
+ skip_sect:
memset(ent, 'F', sizeof(*ent));
silc_free(ent);
}
/* Registers a new option in the specified entity.
* Returns TRUE on success, FALSE if already registered. */
-bool silc_config_register(SilcConfigEntity ent, const char *name,
+SilcBool silc_config_register(SilcConfigEntity ent, const char *name,
SilcConfigType type, SilcConfigCallback cb,
const SilcConfigTable *subtable, void *context)
{
SilcConfigOption *newopt;
- SILC_CONFIG_DEBUG(("Register new option=\"%s\" type=%u cb=0x%08x context=0x%08x",
- name, type, (uint32) cb, (uint32) context));
+ SILC_CONFIG_DEBUG(("Register new option=\"%s\" "
+ "type=%u cb=0x%08x context=0x%08x",
+ name, type, (SilcUInt32) cb, (SilcUInt32) context));
/* if we are registering a block, make sure there is a specified sub-table */
if (!ent || !name || ((type == SILC_CONFIG_ARG_BLOCK) && !subtable))
/* Register a new option table in the specified config entity */
-bool silc_config_register_table(SilcConfigEntity ent,
+SilcBool silc_config_register_table(SilcConfigEntity ent,
const SilcConfigTable table[], void *context)
{
int i;
/* loop throught statements */
while (1) {
- char buf[255];
+ char buf[BUF_SIZE];
SilcConfigOption *thisopt;
/* makes it pointing to the next interesting char */
/* obtain the keyword */
my_next_token(file, buf);
- SILC_CONFIG_DEBUG(("Looking up keyword=\"%s\" [line=%lu]", buf, file->line));
+ SILC_CONFIG_DEBUG(("Looking up keyword=\"%s\" [line=%lu]",
+ buf, file->line));
/* handle special directive */
if (!strcasecmp(buf, "include")) {
}
else {
void *pt;
- int ret;
+ int ret = 0; /* very important in case of no cb */
if (*(*p)++ != '=')
return SILC_CONFIG_EEXPECTEDEQUAL;
pt = silc_config_marshall(thisopt->type, buf);
if (!pt)
return SILC_CONFIG_EINVALIDTEXT;
- if (thisopt->cb) {
+ if (thisopt->cb)
ret = thisopt->cb(thisopt->type, thisopt->name, file->line,
pt, thisopt->context);
- if (ret) {
- SILC_CONFIG_DEBUG(("Callback refused the value [ret=%d]", ret));
- return ret;
- }
- }
+
+ /* since we have to free "pt" both on failure and on success, we
+ assume that ret == 0 if we didn't actually call any cb. */
silc_free(pt);
+ if (ret) {
+ SILC_CONFIG_DEBUG(("Callback refused the value [ret=%d]", ret));
+ return ret;
+ }
}
continue;
* destroyed. */
main_cleanup:
if ((file->level != 0) || (file->included != TRUE))
- silc_config_destroy(ent);
+ silc_config_destroy(ent, TRUE);
+ else
+ silc_config_destroy(ent, FALSE);
main_end:
return ret;