X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=lib%2Fsilcutil%2Fsilcconfig.c;h=93e27d2d3560ac655a6300e1c34662e444124ef6;hb=40f8443d8d3a6577336ee66d18e04d9ac4d956bb;hp=188ffa2b66a46e171b703db2a92162281b537d72;hpb=d47a87b03b846e2333ef57b2c0d81f1644992964;p=silc.git diff --git a/lib/silcutil/silcconfig.c b/lib/silcutil/silcconfig.c index 188ffa2b..93e27d2d 100644 --- a/lib/silcutil/silcconfig.c +++ b/lib/silcutil/silcconfig.c @@ -2,14 +2,13 @@ silcconfig.c - Author: Johnny Mnemonic + Author: Giovanni Giacobbi - Copyright (C) 1997 - 2002 Pekka Riikonen + Copyright (C) 2002 - 2003 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 @@ -19,7 +18,7 @@ */ /* $Id$ */ -#include "silcincludes.h" +#include "silc.h" /* limit debug logging verbosity */ #if 0 @@ -41,13 +40,14 @@ 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 */ @@ -58,22 +58,23 @@ struct SilcConfigEntityObject { /* 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 needed 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 */ @@ -93,7 +94,7 @@ char *silc_config_strerror(int errnum) static void my_trim_spaces(SilcConfigFile *file) { register char *r = file->p; - while (isspace(*r)) + while ((*r != '\0' && *r != EOF) && isspace(*r)) if (*r++ == '\n') file->line++; file->p = r; } @@ -101,8 +102,8 @@ static void my_trim_spaces(SilcConfigFile *file) 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. @@ -170,29 +171,30 @@ static SilcConfigOption *silc_config_find_option(SilcConfigEntity ent, } 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); @@ -202,7 +204,7 @@ static void *silc_config_marshall(SilcConfigType type, const char *val) *(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 */ @@ -210,13 +212,13 @@ static void *silc_config_marshall(SilcConfigType type, const char *val) 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; @@ -225,7 +227,7 @@ static void *silc_config_marshall(SilcConfigType type, const char *val) 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. */ @@ -250,16 +252,16 @@ static void *silc_config_marshall(SilcConfigType type, const char *val) /* 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))) return NULL; - ret = (SilcConfigFile *) silc_calloc(1, sizeof(*ret)); + ret = silc_calloc(1, sizeof(*ret)); ret->filename = strdup(configfile); ret->base = ret->p = buffer; ret->len = filelen; @@ -272,14 +274,6 @@ SilcConfigFile *silc_config_open(char *configfile) 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); @@ -293,10 +287,12 @@ void silc_config_close(SilcConfigFile *file) SilcConfigEntity silc_config_init(SilcConfigFile *file) { SilcConfigEntity ret; + if (!file) return NULL; + SILC_CONFIG_DEBUG(("Allocating new config entity")); - ret = (SilcConfigEntity) silc_calloc(1, sizeof(*ret)); + ret = silc_calloc(1, sizeof(*ret)); ret->file = file; return ret; }; @@ -312,7 +308,7 @@ char *silc_config_get_filename(SilcConfigFile *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; @@ -322,11 +318,11 @@ uint32 silc_config_get_line(SilcConfigFile *file) /* 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; @@ -341,13 +337,10 @@ char *silc_config_read_line(SilcConfigFile *file, uint32 line) 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; } @@ -361,11 +354,16 @@ char *silc_config_read_current_line(SilcConfigFile *file) /* (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); @@ -373,41 +371,47 @@ static void silc_config_destroy(SilcConfigEntity ent) 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 */ +/* Registers a new option in the specified entity. + * Returns TRUE on success, FALSE if already registered. */ -void 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 (!ent || !name) - return; /* if we are registering a block, make sure there is a specified sub-table */ - if ((type == SILC_CONFIG_ARG_BLOCK) && !subtable) - return; - /* refuse special tag */ + if (!ent || !name || ((type == SILC_CONFIG_ARG_BLOCK) && !subtable)) + return FALSE; + + /* don't register a reserved tag */ if (!strcasecmp(name, "include")) - return; + return FALSE; + + /* check if an option was previously registered */ if (silc_config_find_option(ent, name)) { - fprintf(stderr, "Internal Error: Option double registered\n"); - abort(); + SILC_LOG_DEBUG(("Error: Can't register \"%s\" twice.", name)); + return FALSE; } /* allocate and append the new option */ - newopt = (SilcConfigOption *) silc_calloc(1, sizeof(*newopt)); + newopt = silc_calloc(1, sizeof(*newopt)); newopt->name = strdup(name); newopt->type = type; newopt->cb = cb; newopt->subtable = subtable; newopt->context = context; + /* append this option to the list */ if (!ent->opts) ent->opts = newopt; else { @@ -415,21 +419,25 @@ void silc_config_register(SilcConfigEntity ent, const char *name, for (tmp = ent->opts; tmp->next; tmp = tmp->next); tmp->next = newopt; } + return TRUE; } /* Register a new option table in the specified config entity */ -void silc_config_register_table(SilcConfigEntity ent, +SilcBool silc_config_register_table(SilcConfigEntity ent, const SilcConfigTable table[], void *context) { int i; - if (!ent || !table) return; + if (!ent || !table) + return FALSE; SILC_CONFIG_DEBUG(("Registering table")); - /* FIXME: some potability checks needed */ + /* XXX FIXME: some potability checks needed - really? */ for (i = 0; table[i].name; i++) { - silc_config_register(ent, table[i].name, table[i].type, - table[i].callback, table[i].subtable, context); + if (!silc_config_register(ent, table[i].name, table[i].type, + table[i].callback, table[i].subtable, context)) + return FALSE; } + return TRUE; } /* ... */ @@ -464,7 +472,8 @@ static int silc_config_main_internal(SilcConfigEntity ent) /* 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")) { @@ -544,9 +553,14 @@ static int silc_config_main_internal(SilcConfigEntity ent) /* now call block clean-up callback (if any) */ if (thisopt->cb) { - SILC_CONFIG_DEBUG(("Now calling clean-up callback (if any)")); - thisopt->cb(thisopt->type, thisopt->name, file->line, - NULL, thisopt->context); + int ret; + SILC_CONFIG_DEBUG(("Now calling clean-up callback")); + ret = thisopt->cb(thisopt->type, thisopt->name, file->line, NULL, + thisopt->context); + if (ret) { + SILC_CONFIG_DEBUG(("Callback refused the value [ret=%d]", ret)); + return ret; + } } /* Do we want ';' to be mandatory after close brace? */ if (*(*p)++ != ';') @@ -564,7 +578,7 @@ static int silc_config_main_internal(SilcConfigEntity ent) } else { void *pt; - int ret; + int ret = 0; /* very important in case of no cb */ if (*(*p)++ != '=') return SILC_CONFIG_EEXPECTEDEQUAL; @@ -580,15 +594,17 @@ static int silc_config_main_internal(SilcConfigEntity ent) 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; @@ -627,7 +643,9 @@ int silc_config_main(SilcConfigEntity ent) * 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;