opensc/src/scconf/parse.c

427 lines
10 KiB
C
Raw Normal View History

/*
* $Id$
*
* Copyright (C) 2002
* Antti Tapaninen <aet@cc.hut.fi>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#include <errno.h>
#include "scconf.h"
#include "internal.h"
Complete rewrite of OpenSC build system. 1. Build system now supports MinGW (Windows) compilation using msys and cross compilation. 2. Ability to explicitly disable and enable dependencies of the package. 3. openct, pcsc and nsplugins features are disabled by default. 4. Modified pcsc driver to use pcsc dynamically, no compile time dependency is required. 5. --enable-pcsc-lite configuration option renamed to --enable-pcsc. 6. Install opensc.conf file (as opensc.conf.new if opensc.conf exists). 7. Add--enable-doc configuration option, allow installing documentation into target. 8. Add --disable-man configuration option, allow msys mingw32 users to build from svn without extra dependencies. 9. Add export files to each library in order to export only required symbols. Windows native build may use these files instead of scanning objects' symbols. 10. Add opensc-tool --info to display some general information about the build. 11. Create compatibility library to be linked against library instread of recompiling the same source files in different places. 12. Add different win32 version resource to each class of outputs. 13. Make xsl-stylesheets location selectable. 14. Some win32 fixups. 15. Some warning fixups. 16. Many other autoconf/automake cleanups. Alon Bar-Lev svn diff -r 3315:3399 https://www.opensc-project.org/svn/opensc/branches/alonbl/mingw _M . D configure.in _M src _M src/openssh M src/openssh/Makefile.am _M src/tools M src/tools/rutoken-tool.c M src/tools/opensc-tool.c M src/tools/cardos-info.c M src/tools/pkcs15-crypt.c M src/tools/pkcs15-init.c M src/tools/piv-tool.c M src/tools/netkey-tool.c M src/tools/eidenv.c M src/tools/cryptoflex-tool.c M src/tools/util.c M src/tools/pkcs11-tool.c M src/tools/pkcs15-tool.c M src/tools/util.h M src/tools/opensc-explorer.c M src/tools/Makefile.am _M src/pkcs11 M src/pkcs11/pkcs11-global.c M src/pkcs11/framework-pkcs15.c M src/pkcs11/mechanism.c M src/pkcs11/pkcs11-display.c M src/pkcs11/pkcs11-object.c A src/pkcs11/opensc-pkcs11.exports M src/pkcs11/sc-pkcs11.h M src/pkcs11/pkcs11-spy.c M src/pkcs11/openssl.c M src/pkcs11/Makefile.am A src/pkcs11/pkcs11-spy.exports _M src/tests _M src/tests/regression M src/tests/regression/Makefile.am M src/tests/sc-test.c M src/tests/pintest.c M src/tests/Makefile.am _M src/include _M src/include/opensc M src/include/opensc/Makefile.am A src/include/opensc/svnignore M src/include/Makefile.am _M src/signer _M src/signer/npinclude M src/signer/npinclude/Makefile.am M src/signer/Makefile.am A src/signer/signer.exports _M src/common A src/common/compat_dummy.c D src/common/getopt.txt D src/common/strlcpy.c D src/common/LICENSE A src/common/compat_getopt.txt A src/common/compat_strlcpy.c A src/common/LICENSE.compat_getopt A src/common/compat_getopt.c D src/common/strlcpy.h D src/common/ChangeLog D src/common/getpass.c D src/common/my_getopt.c A src/common/compat_strlcpy.h A src/common/compat_getpass.c A src/common/compat_getopt.h A src/common/ChangeLog.compat_getopt D src/common/README.strlcpy D src/common/my_getopt.h A src/common/compat_getpass.h A src/common/README.compat_strlcpy D src/common/strlcpy.3 A src/common/README.compat_getopt D src/common/getopt.3 D src/common/README.my_getopt A src/common/compat_strlcpy.3 A src/common/compat_getopt.3 M src/common/Makefile.am M src/Makefile.am _M src/pkcs15init M src/pkcs15init/pkcs15-oberthur.c M src/pkcs15init/profile.c M src/pkcs15init/pkcs15-lib.c M src/pkcs15init/pkcs15-rutoken.c A src/pkcs15init/pkcs15init.exports M src/pkcs15init/pkcs15-gpk.c M src/pkcs15init/Makefile.am _M src/scconf M src/scconf/Makefile.am M src/scconf/parse.c A src/scconf/scconf.exports _M src/libopensc M src/libopensc/card-rutoken.c M src/libopensc/compression.c M src/libopensc/sc.c M src/libopensc/card-piv.c M src/libopensc/pkcs15-openpgp.c M src/libopensc/pkcs15-postecert.c M src/libopensc/pkcs15-tcos.c M src/libopensc/opensc-config.in M src/libopensc/reader-pcsc.c A src/libopensc/internal-winscard.h M src/libopensc/ctx.c A src/libopensc/libopensc.exports M src/libopensc/pkcs15-piv.c M src/libopensc/pkcs15-infocamere.c M src/libopensc/internal.h M src/libopensc/pkcs15-actalis.c M src/libopensc/pkcs15-starcert.c M src/libopensc/card-oberthur.c M src/libopensc/pkcs15-atrust-acos.c M src/libopensc/p15card-helper.c D src/libopensc/part10.h M src/libopensc/ui.c M src/libopensc/card-gpk.c M src/libopensc/pkcs15-wrap.c M src/libopensc/pkcs15-gemsafeGPK.c M src/libopensc/log.c M src/libopensc/pkcs15-esteid.c M src/libopensc/pkcs15-prkey-rutoken.c M src/libopensc/log.h M src/libopensc/Makefile.am M src/libopensc/reader-openct.c _M aclocal M aclocal/Makefile.am _M win32 M win32/Makefile.am A win32/versioninfo.rc.in A win32/ltrc.inc A configure.ac _M doc _M doc/tools M doc/tools/pkcs15-profile.xml D doc/changelog.sh D doc/export-wiki.xsl _M doc/api _M doc/api/file M doc/api/man.xsl _M doc/api/asn1 _M doc/api/apps _M doc/api/init _M doc/api/types _M doc/api/card M doc/api/html.xsl _M doc/api/misc _M doc/api/util M doc/Makefile.am D doc/export-wiki.sh AM doc/nonpersistent A doc/nonpersistent/export-wiki.xsl A doc/nonpersistent/Makefile.am A doc/nonpersistent/export-wiki.sh A doc/nonpersistent/svn2cl.xsl D doc/generate-man.sh D doc/svn2cl.xsl M Makefile.am A svnignore _M etc M etc/opensc.conf.in M etc/Makefile.am D man _M solaris M solaris/Makefile git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@3405 c6295689-39f2-0310-b995-f0e70906c6a9
2008-03-06 16:06:59 +00:00
#include <compat_strlcpy.h>
#define STATE_NAME 0x01
#define STATE_VALUE 0x02
#define STATE_SET 0x10
static scconf_item *scconf_get_last_item(scconf_block *root)
{
scconf_block *block = root;
scconf_item *item;
for (item = root->items; item; item = item->next) {
if (!item->next) {
return item;
}
}
return block->items;
}
static void scconf_parse_error(scconf_parser * parser, const char *error)
{
/* FIXME: save the error somewhere */
parser->error = 1;
snprintf(parser->emesg, sizeof(parser->emesg), "Line %d: %s\n", parser->line, error);
}
static void scconf_parse_error_not_expect(scconf_parser * parser,
const char *token)
{
/* FIXME: save the error somewhere */
parser->error = 1;
snprintf(parser->emesg, sizeof(parser->emesg), "Line %d: not expecting '%s'\n", parser->line, token);
}
static void scconf_parse_warning_expect(scconf_parser * parser, const char *token)
{
/* FIXME: save the warnings somewhere */
parser->warnings = 1;
snprintf(parser->emesg, sizeof(parser->emesg),
"Line %d: missing '%s', ignoring\n",
parser->line, token);
}
static scconf_item *scconf_item_find(scconf_parser * parser, const char *key)
{
scconf_item *item;
for (item = parser->block->items; item; item = item->next) {
if (item->type == SCCONF_ITEM_TYPE_VALUE &&
strcasecmp(item->key, parser->key) == 0) {
return item;
}
}
return item;
}
static scconf_item *scconf_item_add_internal(scconf_parser * parser, int type)
{
scconf_item *item;
if (type == SCCONF_ITEM_TYPE_VALUE) {
/* if item with same key already exists, use it */
item = scconf_item_find(parser, parser->key);
if (item) {
if (parser->key) {
free(parser->key);
}
parser->key = NULL;
parser->current_item = item;
return item;
}
}
item = (scconf_item *) malloc(sizeof(scconf_item));
if (!item) {
return NULL;
}
memset(item, 0, sizeof(scconf_item));
item->type = type;
item->key = parser->key;
parser->key = NULL;
if (parser->last_item) {
parser->last_item->next = item;
} else {
parser->block->items = item;
}
parser->current_item = parser->last_item = item;
return item;
}
scconf_item *scconf_item_add(scconf_context * config, scconf_block * block, scconf_item * item, int type, const char *key, const void *data)
{
scconf_parser parser;
scconf_block *dst = NULL;
if (!config && !block)
return NULL;
if (!data)
return NULL;
memset(&parser, 0, sizeof(scconf_parser));
parser.config = config ? config : NULL;
parser.key = key ? strdup(key) : NULL;
parser.block = block ? block : config->root;
parser.name = NULL;
parser.last_item = scconf_get_last_item(parser.block);
parser.current_item = item;
if (type == SCCONF_ITEM_TYPE_BLOCK) {
scconf_block_copy((const scconf_block *) data, &dst);
scconf_list_copy(dst->name, &parser.name);
}
scconf_item_add_internal(&parser, type);
switch (parser.current_item->type) {
case SCCONF_ITEM_TYPE_COMMENT:
parser.current_item->value.comment = strdup((const char *) data);
break;
case SCCONF_ITEM_TYPE_BLOCK:
if (!dst)
return NULL;
dst->parent = parser.block;
parser.current_item->value.block = dst;
scconf_list_destroy(parser.name);
break;
case SCCONF_ITEM_TYPE_VALUE:
scconf_list_copy((const scconf_list *) data, &parser.current_item->value.list);
break;
}
return parser.current_item;
}
static void scconf_block_add_internal(scconf_parser * parser)
{
scconf_block *block;
scconf_item *item;
item = scconf_item_add_internal(parser, SCCONF_ITEM_TYPE_BLOCK);
block = (scconf_block *) malloc(sizeof(scconf_block));
if (!block) {
return;
}
memset(block, 0, sizeof(scconf_block));
block->parent = parser->block;
item->value.block = block;
if (!parser->name) {
scconf_list_add(&parser->name, "");
}
block->name = parser->name;
parser->name = NULL;
parser->block = block;
parser->last_item = NULL;
}
scconf_block *scconf_block_add(scconf_context * config, scconf_block * block, const char *key, const scconf_list *name)
{
scconf_parser parser;
if (!config)
return NULL;
memset(&parser, 0, sizeof(scconf_parser));
parser.config = config;
parser.key = key ? strdup(key) : NULL;
parser.block = block ? block : config->root;
scconf_list_copy(name, &parser.name);
parser.last_item = scconf_get_last_item(parser.block);
parser.current_item = parser.block->items;
scconf_block_add_internal(&parser);
return parser.block;
}
static void scconf_parse_parent(scconf_parser * parser)
{
parser->block = parser->block->parent;
parser->last_item = parser->block->items;
if (parser->last_item) {
while (parser->last_item->next) {
parser->last_item = parser->last_item->next;
}
}
}
static void scconf_parse_reset_state(scconf_parser * parser)
{
if (parser) {
if (parser->key) {
free(parser->key);
}
scconf_list_destroy(parser->name);
parser->key = NULL;
parser->name = NULL;
parser->state = 0;
}
}
void scconf_parse_token(scconf_parser * parser, int token_type, const char *token)
{
scconf_item *item;
int len;
if (parser->error) {
/* fatal error */
return;
}
switch (token_type) {
case TOKEN_TYPE_NEWLINE:
parser->line++;
if (parser->last_token_type != TOKEN_TYPE_NEWLINE) {
break;
}
/* fall through - treat empty lines as comments */
case TOKEN_TYPE_COMMENT:
item = scconf_item_add_internal(parser, SCCONF_ITEM_TYPE_COMMENT);
item->value.comment = token ? strdup(token) : NULL;
break;
case TOKEN_TYPE_STRING:
{
char *stoken = NULL;
if ((parser->state & (STATE_VALUE | STATE_SET)) ==
(STATE_VALUE | STATE_SET)) {
scconf_parse_warning_expect(parser, ";");
scconf_parse_reset_state(parser);
}
if (*token == '"') {
/* quoted string, remove them */
token++;
len = strlen(token);
if (len < 1 || token[len - 1] != '"') {
scconf_parse_warning_expect(parser, "\"");
} else {
/* stoken */
stoken = token ? strdup(token) : NULL;
if (stoken) {
stoken[len - 1] = '\0';
}
}
}
if (!stoken) {
stoken = token ? strdup(token) : NULL;
}
if (parser->state == 0) {
/* key */
parser->key = stoken ? strdup(stoken) : NULL;
parser->state = STATE_NAME;
} else if (parser->state == STATE_NAME) {
/* name */
parser->state |= STATE_SET;
scconf_list_add(&parser->name, stoken);
} else if (parser->state == STATE_VALUE) {
/* value */
parser->state |= STATE_SET;
scconf_list_add(&parser->current_item->value.list,
stoken);
} else {
/* error */
scconf_parse_error_not_expect(parser, stoken);
}
if (stoken) {
free(stoken);
}
stoken = NULL;
}
break;
case TOKEN_TYPE_PUNCT:
switch (*token) {
case '{':
if ((parser->state & STATE_NAME) == 0) {
scconf_parse_error_not_expect(parser, "{");
break;
}
scconf_block_add_internal(parser);
scconf_parse_reset_state(parser);
break;
case '}':
if (parser->state != 0) {
if ((parser->state & STATE_VALUE) == 0 ||
(parser->state & STATE_SET) == 0) {
scconf_parse_error_not_expect(parser,
"}");
break;
}
/* foo = bar } */
scconf_parse_warning_expect(parser, ";");
scconf_parse_reset_state(parser);
}
if (!parser->block->parent) {
/* too many '}' */
scconf_parse_error(parser,
"missing matching '{'");
break;
}
scconf_parse_parent(parser);
break;
case ',':
if ((parser->state & (STATE_NAME | STATE_VALUE)) == 0) {
scconf_parse_error_not_expect(parser, ",");
}
parser->state &= ~STATE_SET;
break;
case '=':
if ((parser->state & STATE_NAME) == 0) {
scconf_parse_error_not_expect(parser, "=");
break;
}
scconf_item_add_internal(parser, SCCONF_ITEM_TYPE_VALUE);
parser->state = STATE_VALUE;
break;
case ';':
#if 0
if ((parser->state & STATE_VALUE) == 0 ||
(parser->state & STATE_SET) == 0) {
scconf_parse_error_not_expect(parser, ";");
break;
}
#endif
scconf_parse_reset_state(parser);
break;
default:
snprintf(parser->emesg, sizeof(parser->emesg),
"Line %d: bad token ignoring\n",
parser->line);
}
break;
}
parser->last_token_type = token_type;
}
int scconf_parse(scconf_context * config)
{
static char buffer[256];
scconf_parser p;
int r = 1;
memset(&p, 0, sizeof(p));
p.config = config;
p.block = config->root;
p.line = 1;
if (!scconf_lex_parse(&p, config->filename)) {
snprintf(buffer, sizeof(buffer),
"Unable to open \"%s\": %s",
config->filename, strerror(errno));
r = -1;
} else if (p.error) {
strlcpy(buffer, p.emesg, sizeof(buffer));
r = 0;
} else {
r = 1;
}
if (r <= 0)
config->errmsg = buffer;
return r;
}
int scconf_parse_string(scconf_context * config, const char *string)
{
static char buffer[256];
scconf_parser p;
int r;
memset(&p, 0, sizeof(p));
p.config = config;
p.block = config->root;
p.line = 1;
if (!scconf_lex_parse_string(&p, string)) {
snprintf(buffer, sizeof(buffer),
"Failed to parse configuration string");
r = -1;
} else if (p.error) {
strlcpy(buffer, p.emesg, sizeof(buffer));
r = 0;
} else {
r = 1;
}
if (r <= 0)
config->errmsg = buffer;
return r;
}