Files
bind9/contrib/idn/mdnkit/lib/resconf.c
2001-06-09 00:30:55 +00:00

1436 lines
36 KiB
C

#ifndef lint
static char *rcsid = "$Id: resconf.c,v 1.25 2001/04/16 02:25:17 m-kasahr Exp $";
#endif
/*
* Copyright (c) 2000 Japan Network Information Center. All rights reserved.
*
* By using this file, you agree to the terms and conditions set forth bellow.
*
* LICENSE TERMS AND CONDITIONS
*
* The following License Terms and Conditions apply, unless a different
* license is obtained from Japan Network Information Center ("JPNIC"),
* a Japanese association, Fuundo Bldg., 1-2 Kanda Ogawamachi, Chiyoda-ku,
* Tokyo, Japan.
*
* 1. Use, Modification and Redistribution (including distribution of any
* modified or derived work) in source and/or binary forms is permitted
* under this License Terms and Conditions.
*
* 2. Redistribution of source code must retain the copyright notices as they
* appear in each source code file, this License Terms and Conditions.
*
* 3. Redistribution in binary form must reproduce the Copyright Notice,
* this License Terms and Conditions, in the documentation and/or other
* materials provided with the distribution. For the purposes of binary
* distribution the "Copyright Notice" refers to the following language:
* "Copyright (c) Japan Network Information Center. All rights reserved."
*
* 4. Neither the name of JPNIC may be used to endorse or promote products
* derived from this Software without specific prior written approval of
* JPNIC.
*
* 5. Disclaimer/Limitation of Liability: THIS SOFTWARE IS PROVIDED BY JPNIC
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JPNIC BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*
* 6. Indemnification by Licensee
* Any person or entities using and/or redistributing this Software under
* this License Terms and Conditions shall defend indemnify and hold
* harmless JPNIC from and against any and all judgements damages,
* expenses, settlement liabilities, cost and other liabilities of any
* kind as a result of use and redistribution of this Software or any
* claim, suite, action, litigation or proceeding by any third party
* arising out of or relates to this License Terms and Conditions.
*
* 7. Governing Law, Jurisdiction and Venue
* This License Terms and Conditions shall be governed by and and
* construed in accordance with the law of Japan. Any person or entities
* using and/or redistributing this Software under this License Terms and
* Conditions hereby agrees and consent to the personal and exclusive
* jurisdiction and venue of Tokyo District Court of Japan.
*/
#include <config.h>
#include <stddef.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <mdn/result.h>
#include <mdn/assert.h>
#include <mdn/logmacro.h>
#include <mdn/converter.h>
#include <mdn/normalizer.h>
#include <mdn/checker.h>
#include <mdn/mapper.h>
#include <mdn/mapselector.h>
#include <mdn/delimitermap.h>
#include <mdn/localencoding.h>
#include <mdn/resconf.h>
#include <mdn/debug.h>
#ifndef MDN_RESCONF_DIR
#define MDN_RESCONF_DIR "/etc"
#endif
#define MDN_RESCONF_FILE MDN_RESCONF_DIR "/mdn.conf"
#define MAX_CONF_LINE_LENGTH 255
#define MAX_CONF_LINE_ARGS 63
struct mdn_resconf {
char *local_encoding;
mdn_converter_t local_converter;
mdn_converter_t idn_converter;
mdn_converter_t alternate_converter;
mdn_normalizer_t normalizer;
mdn_checker_t prohibit_checker;
mdn_checker_t unassigned_checker;
mdn_mapper_t mapper;
mdn_mapselector_t local_mapper;
mdn_delimitermap_t delimiter_mapper;
int reference_count;
};
static mdn_result_t parse_conf(mdn_resconf_t ctx, FILE *fp);
static mdn_result_t parse_alternate_encoding(mdn_resconf_t ctx,
char *args, int lineno);
static mdn_result_t parse_delimiter_map(mdn_resconf_t ctx, char *args,
int lineno);
static mdn_result_t parse_encoding_alias_file(mdn_resconf_t ctx,
char *args, int lineno);
static mdn_result_t parse_idn_encoding(mdn_resconf_t ctx, char *args,
int lineno);
static mdn_result_t parse_local_map(mdn_resconf_t ctx, char *args,
int lineno);
static mdn_result_t parse_nameprep(mdn_resconf_t ctx, char *args,
int lineno, char **nameprep);
static mdn_result_t parse_map(mdn_resconf_t ctx, char *args, int lineno);
static mdn_result_t parse_normalize(mdn_resconf_t ctx, char *args,
int lineno);
static mdn_result_t parse_prohibit(mdn_resconf_t ctx, char *args,
int lineno);
static mdn_result_t parse_unassigned(mdn_resconf_t ctx, char *args,
int lineno);
static int split_args(char *s, char **av, int max_ac);
static void resetconf(mdn_resconf_t ctx);
static mdn_result_t update_local_converter(mdn_resconf_t ctx);
static mdn_result_t mystrdup(const char *from, char **top);
static const char * get_ucs(const char *p, unsigned long *vp);
mdn_result_t
mdn_resconf_initialize(void) {
mdn_result_t r;
TRACE(("mdn_resconf_initialize()\n"));
/*
* Initialize sub modules.
*/
if ((r = mdn_converter_initialize()) != mdn_success)
return (r);
if ((r = mdn_normalizer_initialize()) != mdn_success)
return (r);
if ((r = mdn_checker_initialize()) != mdn_success)
return (r);
if ((r = mdn_mapselector_initialize()) != mdn_success)
return (r);
if ((r = mdn_mapper_initialize()) != mdn_success)
return (r);
return (mdn_success);
}
mdn_result_t
mdn_resconf_create(mdn_resconf_t *ctxp) {
mdn_resconf_t ctx = NULL;
assert(ctxp != NULL);
TRACE(("mdn_resconf_create()\n"));
if ((ctx = malloc(sizeof(*ctx))) == NULL)
return (mdn_nomemory);
ctx->local_encoding = NULL;
ctx->local_converter = NULL;
ctx->idn_converter = NULL;
ctx->alternate_converter = NULL;
ctx->normalizer = NULL;
ctx->prohibit_checker = NULL;
ctx->unassigned_checker = NULL;
ctx->mapper = NULL;
ctx->local_mapper = NULL;
ctx->delimiter_mapper = NULL;
ctx->reference_count = 1;
*ctxp = ctx;
return (mdn_success);
}
char *
mdn_resconf_defaultfile() {
return MDN_RESCONF_FILE;
}
mdn_result_t
mdn_resconf_loadfile(mdn_resconf_t ctx, const char *file) {
FILE *fp;
mdn_result_t r;
assert(ctx != NULL);
TRACE(("mdn_resconf_loadfile(file=%s)\n",
file == NULL ? "<null>" : file));
if ((r = mdn_converter_resetalias()) != mdn_success)
return (r);
resetconf(ctx);
if (file == NULL)
file = mdn_resconf_defaultfile();
if ((fp = fopen(file, "r")) == NULL) {
TRACE(("mdn_resconf_loadfile: cannot open %-.40s\n", file));
return (mdn_nofile);
}
r = parse_conf(ctx, fp);
fclose(fp);
return (r);
}
void
mdn_resconf_destroy(mdn_resconf_t ctx) {
TRACE(("mdn_resconf_destroy()\n"));
TRACE(("mdn_resconf_destroy: update reference count (%d->%d)\n",
ctx->reference_count, ctx->reference_count - 1));
ctx->reference_count--;
if (ctx->reference_count <= 0) {
TRACE(("mdn_converter_destroy: the object is destroyed\n"));
resetconf(ctx);
free(ctx);
}
}
void
mdn_resconf_incrref(mdn_resconf_t ctx) {
assert(ctx != NULL);
TRACE(("mdn_resconf_incrref()\n"));
TRACE(("mdn_resconf_incrref: update reference count (%d->%d)\n",
ctx->reference_count, ctx->reference_count + 1));
ctx->reference_count++;
}
mdn_converter_t
mdn_resconf_getalternateconverter(mdn_resconf_t ctx) {
TRACE(("mdn_resconf_alternateconverter()\n"));
if (ctx->alternate_converter != NULL)
mdn_converter_incrref(ctx->alternate_converter);
return (ctx->alternate_converter);
}
mdn_delimitermap_t
mdn_resconf_getdelimitermap(mdn_resconf_t ctx) {
TRACE(("mdn_resconf_getdelimitermap()\n"));
if (ctx->delimiter_mapper != NULL)
mdn_delimitermap_incrref(ctx->delimiter_mapper);
return (ctx->delimiter_mapper);
}
mdn_converter_t
mdn_resconf_getidnconverter(mdn_resconf_t ctx) {
TRACE(("mdn_resconf_getidnconverter()\n"));
if (ctx->idn_converter != NULL)
mdn_converter_incrref(ctx->idn_converter);
return (ctx->idn_converter);
}
mdn_converter_t
mdn_resconf_getlocalconverter(mdn_resconf_t ctx) {
TRACE(("mdn_resconf_getlocalconverter()\n"));
if (update_local_converter(ctx) != mdn_success)
return (NULL);
mdn_converter_incrref(ctx->local_converter);
return (ctx->local_converter);
}
mdn_mapselector_t
mdn_resconf_getlocalmapselector(mdn_resconf_t ctx) {
TRACE(("mdn_resconf_getlocalmapselector()\n"));
if (ctx->local_mapper != NULL)
mdn_mapselector_incrref(ctx->local_mapper);
return (ctx->local_mapper);
}
mdn_mapper_t
mdn_resconf_getmapper(mdn_resconf_t ctx) {
TRACE(("mdn_resconf_getmapper()\n"));
if (ctx->mapper != NULL)
mdn_mapper_incrref(ctx->mapper);
return (ctx->mapper);
}
mdn_normalizer_t
mdn_resconf_getnormalizer(mdn_resconf_t ctx) {
TRACE(("mdn_resconf_getnormalizer()\n"));
if (ctx->normalizer != NULL)
mdn_normalizer_incrref(ctx->normalizer);
return (ctx->normalizer);
}
mdn_checker_t
mdn_resconf_getprohibitchecker(mdn_resconf_t ctx) {
TRACE(("mdn_resconf_getprohibitchecker()\n"));
if (ctx->prohibit_checker != NULL)
mdn_checker_incrref(ctx->prohibit_checker);
return (ctx->prohibit_checker);
}
mdn_checker_t
mdn_resconf_getunassignedchecker(mdn_resconf_t ctx) {
TRACE(("mdn_resconf_getunassignedchecker()\n"));
if (ctx->unassigned_checker != NULL)
mdn_checker_incrref(ctx->unassigned_checker);
return (ctx->unassigned_checker);
}
void
mdn_resconf_setalternateconverter(mdn_resconf_t ctx,
mdn_converter_t alternate_converter) {
TRACE(("mdn_resconf_setalternateconverter()\n"));
if (ctx->alternate_converter != NULL)
mdn_converter_destroy(ctx->alternate_converter);
ctx->alternate_converter = alternate_converter;
mdn_converter_incrref(ctx->alternate_converter);
}
void
mdn_resconf_setdelimitermap(mdn_resconf_t ctx,
mdn_delimitermap_t delimiter_mapper) {
TRACE(("mdn_resconf_setdelimitermap()\n"));
if (ctx->delimiter_mapper != NULL)
mdn_delimitermap_destroy(ctx->delimiter_mapper);
ctx->delimiter_mapper = delimiter_mapper;
mdn_delimitermap_incrref(ctx->delimiter_mapper);
}
void
mdn_resconf_setidnconverter(mdn_resconf_t ctx,
mdn_converter_t idn_converter) {
TRACE(("mdn_resconf_setidnconverter()\n"));
if (ctx->idn_converter != NULL)
mdn_converter_destroy(ctx->idn_converter);
ctx->idn_converter = idn_converter;
mdn_converter_incrref(ctx->idn_converter);
}
void
mdn_resconf_setlocalconverter(mdn_resconf_t ctx,
mdn_converter_t local_converter) {
TRACE(("mdn_resconf_setlocalconverter()\n"));
if (ctx->local_converter != NULL)
mdn_converter_destroy(ctx->local_converter);
free(ctx->local_encoding);
ctx->local_encoding = NULL; /* See update_local_converter(). */
ctx->local_converter = local_converter;
if (local_converter != NULL)
mdn_converter_incrref(local_converter);
}
void
mdn_resconf_setlocalmapselector(mdn_resconf_t ctx,
mdn_mapselector_t local_mapper) {
TRACE(("mdn_resconf_setlocalmapselector()\n"));
if (ctx->local_mapper != NULL)
mdn_mapselector_destroy(ctx->local_mapper);
ctx->local_mapper = local_mapper;
mdn_mapselector_incrref(ctx->local_mapper);
}
void
mdn_resconf_setmapper(mdn_resconf_t ctx, mdn_mapper_t mapper) {
TRACE(("mdn_resconf_setmapper()\n"));
if (ctx->mapper != NULL)
mdn_mapper_destroy(ctx->mapper);
ctx->mapper = mapper;
mdn_mapper_incrref(ctx->mapper);
}
void
mdn_resconf_setnormalizer(mdn_resconf_t ctx, mdn_normalizer_t normalizer) {
TRACE(("mdn_resconf_setnormalizer()\n"));
if (ctx->normalizer != NULL)
mdn_normalizer_destroy(ctx->normalizer);
ctx->normalizer = normalizer;
mdn_normalizer_incrref(ctx->normalizer);
}
void
mdn_resconf_setprohibitchecker(mdn_resconf_t ctx,
mdn_checker_t prohibit_checker) {
TRACE(("mdn_resconf_setprohibitchecker()\n"));
if (ctx->prohibit_checker != NULL)
mdn_checker_destroy(ctx->prohibit_checker);
ctx->prohibit_checker = prohibit_checker;
mdn_checker_incrref(ctx->prohibit_checker);
}
void
mdn_resconf_setunassignedchecker(mdn_resconf_t ctx,
mdn_checker_t unassigned_checker) {
TRACE(("mdn_resconf_setunassignedchecker()\n"));
if (ctx->unassigned_checker != NULL)
mdn_checker_destroy(ctx->unassigned_checker);
ctx->unassigned_checker = unassigned_checker;
mdn_checker_incrref(ctx->unassigned_checker);
}
mdn_result_t
mdn_resconf_setnameprepversion(mdn_resconf_t ctx, const char *version)
{
char prohibit_scheme_name[MAX_CONF_LINE_LENGTH + 1];
char unassigned_scheme_name[MAX_CONF_LINE_LENGTH + 1];
mdn_mapper_t mapper = NULL;
mdn_normalizer_t normalizer = NULL;
mdn_checker_t prohibit_checker = NULL;
mdn_checker_t unassigned_checker = NULL;
mdn_result_t r;
assert(ctx != NULL && version != NULL);
TRACE(("mdn_resconf_setnameprepversion()\n"));
/*
* Set canonical scheme names.
*/
if (strlen(version) + strlen(MDN_CHECKER_PROHIBIT_PREFIX)
> MAX_CONF_LINE_LENGTH) {
r = mdn_invalid_name;
goto failure;
}
sprintf(prohibit_scheme_name, "%s%s",
MDN_CHECKER_PROHIBIT_PREFIX, version);
if (strlen(version) + strlen(MDN_CHECKER_UNASSIGNED_PREFIX)
> MAX_CONF_LINE_LENGTH) {
r = mdn_invalid_name;
goto failure;
}
sprintf(unassigned_scheme_name, "%s%s",
MDN_CHECKER_UNASSIGNED_PREFIX, version);
/*
* Create objects.
*/
r = mdn_mapper_create(&mapper);
if (r != mdn_success)
goto failure;
r = mdn_normalizer_create(&normalizer);
if (r != mdn_success)
goto failure;
r = mdn_checker_create(&prohibit_checker);
if (r != mdn_success)
goto failure;
r = mdn_checker_create(&unassigned_checker);
if (r != mdn_success)
goto failure;
r = mdn_mapper_add(mapper, version);
if (r != mdn_success)
goto failure;
r = mdn_normalizer_add(normalizer, version);
if (r != mdn_success)
goto failure;
r = mdn_checker_add(prohibit_checker, prohibit_scheme_name);
if (r != mdn_success)
goto failure;
r = mdn_checker_add(unassigned_checker, unassigned_scheme_name);
if (r != mdn_success)
goto failure;
/*
* Set the objects.
*/
mdn_resconf_setmapper(ctx, mapper);
mdn_resconf_setnormalizer(ctx, normalizer);
mdn_resconf_setprohibitchecker(ctx, prohibit_checker);
mdn_resconf_setunassignedchecker(ctx, unassigned_checker);
/*
* Destroy the objects.
*/
mdn_mapper_destroy(mapper);
mdn_normalizer_destroy(normalizer);
mdn_checker_destroy(prohibit_checker);
mdn_checker_destroy(unassigned_checker);
return (mdn_success);
failure:
if (mapper != NULL)
mdn_mapper_destroy(mapper);
if (normalizer != NULL)
mdn_normalizer_destroy(normalizer);
if (prohibit_checker != NULL)
mdn_checker_destroy(prohibit_checker);
if (unassigned_checker != NULL)
mdn_checker_destroy(unassigned_checker);
return (r);
}
mdn_result_t
mdn_resconf_setalternateconvertername(mdn_resconf_t ctx, const char *name,
int flags) {
mdn_converter_t alternate_converter;
mdn_result_t r;
assert(ctx != NULL && name != NULL);
TRACE(("mdn_resconf_setalternateconvertername(name=%s, flags=%d)\n",
name, flags));
r = mdn_converter_create(name, &alternate_converter, flags);
if (r != mdn_success)
return (r);
if (!mdn_converter_isasciicompatible(alternate_converter)) {
mdn_converter_destroy(alternate_converter);
return (mdn_invalid_name);
}
if (ctx->alternate_converter != NULL)
mdn_converter_destroy(ctx->alternate_converter);
ctx->alternate_converter = alternate_converter;
return (mdn_success);
}
mdn_result_t
mdn_resconf_setidnconvertername(mdn_resconf_t ctx, const char *name,
int flags) {
mdn_converter_t idn_converter;
mdn_result_t r;
assert(ctx != NULL && name != NULL);
TRACE(("mdn_resconf_setidnconvertername(name=%s, flags=%d)\n",
name, flags));
r = mdn_converter_create(name, &idn_converter, flags);
if (r != mdn_success)
return (r);
if (ctx->idn_converter != NULL)
mdn_converter_destroy(ctx->idn_converter);
ctx->idn_converter = idn_converter;
return (mdn_success);
}
mdn_result_t
mdn_resconf_setlocalconvertername(mdn_resconf_t ctx, const char *name,
int flags) {
mdn_converter_t local_converter;
char *local_encoding = NULL;
mdn_result_t r;
assert(ctx != NULL);
TRACE(("mdn_resconf_setlocalconvertername(mame=%s, flags=%d)\n",
name == NULL ? "<null>" : name, flags));
if (name == NULL) {
local_converter = NULL;
} else {
r = mdn_converter_create(name, &local_converter, flags);
if (r != mdn_success) {
free(local_encoding);
return (r);
}
}
if (ctx->local_converter != NULL)
mdn_converter_destroy(ctx->local_converter);
free(ctx->local_encoding);
ctx->local_converter = local_converter;
ctx->local_encoding = NULL; /* See update_local_converter(). */
return (mdn_success);
}
mdn_result_t
mdn_resconf_addalldelimitermapucs(mdn_resconf_t ctx, unsigned long *v,
int nv) {
mdn_result_t r;
TRACE(("mdn_resconf_addalldelimitermapucs(nv=%d)\n", nv));
if (ctx->delimiter_mapper == NULL) {
r = mdn_delimitermap_create(&(ctx->delimiter_mapper));
if (r != mdn_success)
return (r);
}
r = mdn_delimitermap_addall(ctx->delimiter_mapper, v, nv);
return (r);
}
mdn_result_t
mdn_resconf_addalllocalmapselectornames(mdn_resconf_t ctx, const char *tld,
const char **names, int nnames) {
mdn_result_t r;
assert(ctx != NULL && names != NULL);
TRACE(("mdn_resconf_addalllocalmapselectorname(tld=%s, nnames=%d)\n",
tld, nnames));
if (ctx->local_mapper == NULL) {
r = mdn_mapselector_create(&(ctx->local_mapper));
if (r != mdn_success)
return (r);
}
r = mdn_mapselector_addall(ctx->local_mapper, tld, names, nnames);
return (r);
}
mdn_result_t
mdn_resconf_addallmappernames(mdn_resconf_t ctx, const char **names,
int nnames) {
mdn_result_t r;
assert(ctx != NULL && names != NULL);
TRACE(("mdn_resconf_addallmappername()\n"));
if (ctx->mapper == NULL) {
r = mdn_mapper_create(&(ctx->mapper));
if (r != mdn_success)
return (r);
}
r = mdn_mapper_addall(ctx->mapper, names, nnames);
return (r);
}
mdn_result_t
mdn_resconf_addallnormalizernames(mdn_resconf_t ctx, const char **names,
int nnames) {
mdn_result_t r;
assert(ctx != NULL && names != NULL);
TRACE(("mdn_resconf_addallnormalizername(nnames=%d)\n", nnames));
if (ctx->normalizer == NULL) {
r = mdn_normalizer_create(&(ctx->normalizer));
if (r != mdn_success)
return (r);
}
r = mdn_normalizer_addall(ctx->normalizer, names, nnames);
return (r);
}
mdn_result_t
mdn_resconf_addallprohibitcheckernames(mdn_resconf_t ctx, const char **names,
int nnames) {
char long_name[MAX_CONF_LINE_LENGTH + 1];
mdn_result_t r;
int i;
assert(ctx != NULL && names != NULL);
TRACE(("mdn_resconf_addallprohibitcheckername(nnames=%d)\n", nnames));
if (ctx->prohibit_checker == NULL) {
r = mdn_checker_create(&(ctx->prohibit_checker));
if (r != mdn_success)
return (r);
}
for (i = 0; i < nnames; i++, names++) {
if (strlen(*names) + strlen(MDN_CHECKER_PROHIBIT_PREFIX)
> MAX_CONF_LINE_LENGTH) {
return (mdn_invalid_name);
}
strcpy(long_name, MDN_CHECKER_PROHIBIT_PREFIX);
strcat(long_name, *names);
r = mdn_checker_add(ctx->prohibit_checker, long_name);
if (r != mdn_success)
return (r);
}
return (mdn_success);
}
mdn_result_t
mdn_resconf_addallunassignedcheckernames(mdn_resconf_t ctx, const char **names,
int nnames) {
char long_name[MAX_CONF_LINE_LENGTH + 1];
mdn_result_t r;
int i;
assert(ctx != NULL && names != NULL);
TRACE(("mdn_resconf_addallunassignedcheckername(nnames=%d)\n",
nnames));
if (ctx->unassigned_checker == NULL) {
r = mdn_checker_create(&(ctx->unassigned_checker));
if (r != mdn_success)
return (r);
}
for (i = 0; i < nnames; i++, names++) {
if (strlen(*names) + strlen(MDN_CHECKER_UNASSIGNED_PREFIX)
> MAX_CONF_LINE_LENGTH) {
return (mdn_invalid_name);
}
strcpy(long_name, MDN_CHECKER_UNASSIGNED_PREFIX);
strcat(long_name, *names);
r = mdn_checker_add(ctx->unassigned_checker, long_name);
if (r != mdn_success)
return (r);
}
return (mdn_success);
}
static mdn_result_t
parse_conf(mdn_resconf_t ctx, FILE *fp) {
char line[MAX_CONF_LINE_LENGTH + 1];
int lineno = 0;
char *argv[3];
int argc;
mdn_result_t r;
char *alternate_encoding_args = NULL;
int alternate_encoding_lineno = 0;
char *idn_encoding_args = NULL;
int idn_encoding_lineno = 0;
char *nameprep = NULL;
/*
* Parse config file. parsing of 'alternate-encoding' and
* 'idn-encoding' lines are postponed because
* 'alias-file' line must be processed before them.
*/
while (fgets(line, sizeof(line), fp) != NULL) {
char *newline;
lineno++;
newline = strpbrk(line, "\r\n");
if (newline != NULL)
*newline = '\0';
else if (fgetc(fp) != EOF) {
mdn_log_error("mdnres: too long line \"%-.30s\", "
"line %d", line, lineno);
return (mdn_invalid_syntax);
}
argc = split_args(line, argv, 2);
if (argc == -1) {
mdn_log_error("mdnres: syntax error, line %d\n",
lineno);
return (mdn_invalid_syntax);
} else if (argc == 0 || argv[0][0] == '#') {
continue;
}
if (strcmp(argv[0], "alternate-encoding") == 0) {
r = mystrdup(argv[1], &alternate_encoding_args);
if (r != mdn_success) {
mdn_log_error("mdnres: %s, line %d\n",
mdn_result_tostring(r), lineno);
}
alternate_encoding_lineno = lineno;
} else if (strcmp(argv[0], "delimiter-map") == 0) {
r = parse_delimiter_map(ctx, argv[1], lineno);
} else if (strcmp(argv[0], "encoding-alias-file") == 0) {
r = parse_encoding_alias_file(ctx, argv[1], lineno);
} else if (strcmp(argv[0], "idn-encoding") == 0) {
r = mystrdup(argv[1], &idn_encoding_args);
if (r != mdn_success) {
mdn_log_error("mdnres: %s, line %d\n",
mdn_result_tostring(r), lineno);
}
idn_encoding_lineno = lineno;
} else if (strcmp(argv[0], "local-map") == 0) {
r = parse_local_map(ctx, argv[1], lineno);
} else if (strcmp(argv[0], "nameprep") == 0) {
r = parse_nameprep(ctx, argv[1], lineno, &nameprep);
} else if (strcmp(argv[0], "nameprep-map") == 0) {
r = parse_map(ctx, argv[1], lineno);
} else if (strcmp(argv[0], "nameprep-normalize") == 0) {
r = parse_normalize(ctx, argv[1], lineno);
} else if (strcmp(argv[0], "nameprep-prohibit") == 0) {
r = parse_prohibit(ctx, argv[1], lineno);
} else if (strcmp(argv[0], "nameprep-unassigned") == 0) {
r = parse_unassigned(ctx, argv[1], lineno);
} else if (strcmp(argv[0], "server-zld") == 0 ||
strcmp(argv[0], "alias-file") == 0 ||
strcmp(argv[0], "normalize") == 0 ||
strcmp(argv[0], "server-encoding") == 0) {
mdn_log_warning("mdnres: obsolete command "
"\"%-.30s\", line %d (ignored)\n",
argv[0], lineno);
r = mdn_success;
} else {
mdn_log_error("mdnres: unrecognized command "
"\"%-.30s\", line %d\n",
argv[0], lineno);
r = mdn_invalid_syntax;
}
if (r != mdn_success)
return (r);
}
lineno++;
if (nameprep != NULL) {
if (ctx->mapper == NULL) {
r = parse_map(ctx, nameprep, lineno);
if (r != mdn_success)
return (r);
}
if (ctx->normalizer == NULL) {
r = parse_normalize(ctx, nameprep, lineno);
if (r != mdn_success)
return (r);
}
if (ctx->prohibit_checker == NULL) {
r = parse_prohibit(ctx, nameprep, lineno);
if (r != mdn_success)
return (r);
}
if (ctx->unassigned_checker == NULL) {
r = parse_unassigned(ctx, nameprep, lineno);
if (r != mdn_success)
return (r);
}
}
if (alternate_encoding_args != NULL) {
r = parse_alternate_encoding(ctx, alternate_encoding_args,
alternate_encoding_lineno);
if (r != mdn_success)
return (r);
}
if (idn_encoding_args != NULL) {
r = parse_idn_encoding(ctx, idn_encoding_args,
idn_encoding_lineno);
if (r != mdn_success)
return (r);
}
return (mdn_success);
}
static mdn_result_t
parse_alternate_encoding(mdn_resconf_t ctx, char *args, int lineno) {
mdn_result_t r;
char *argv[MAX_CONF_LINE_ARGS + 1];
int argc;
argc = split_args(args, argv, MAX_CONF_LINE_ARGS + 1);
if (argc != 1) {
mdn_log_error("mdnres: wrong # of args for "
"alternate-encoding, line %d\n", lineno);
return (mdn_invalid_syntax);
}
r = mdn_converter_create(argv[0], &ctx->alternate_converter,
MDN_CONVERTER_DELAYEDOPEN);
if (r != mdn_success) {
mdn_log_error("mdnres: cannot create alternate-encodng "
"converter, %s, line %d\n",
mdn_result_tostring(r), lineno);
return (mdn_invalid_syntax);
}
if (!mdn_converter_isasciicompatible(ctx->alternate_converter)) {
mdn_log_error("mdnres: alternate encoding must be "
"ASCII-compatible, line %d\n", lineno);
mdn_converter_destroy(ctx->alternate_converter);
ctx->alternate_converter = NULL;
return (mdn_invalid_name);
}
return (r);
}
static mdn_result_t
parse_delimiter_map(mdn_resconf_t ctx, char *args, int lineno) {
mdn_result_t r;
char *argv[MAX_CONF_LINE_ARGS + 1];
int argc;
unsigned long ucs;
int i;
argc = split_args(args, argv, MAX_CONF_LINE_ARGS + 1);
if (argc > MAX_CONF_LINE_ARGS) {
mdn_log_error("mdnres: wrong # of args for delimiter-map, "
"line %d\n", lineno);
return (mdn_invalid_syntax);
}
if (ctx->delimiter_mapper == NULL) {
r = mdn_delimitermap_create(&ctx->delimiter_mapper);
if (r != mdn_success) {
mdn_log_error("mdnres: cannot create delimiter "
"mapper, %s, line %d\n",
mdn_result_tostring(r), lineno);
return (r);
}
}
for (i = 0; i < argc; i++) {
if (get_ucs(argv[i], &ucs) == NULL) {
mdn_log_error("mdnres: invalid delimiter "
"\"%-.30s\", line %d\n",
argv[i], lineno);
return (mdn_invalid_syntax);
}
r = mdn_delimitermap_add(ctx->delimiter_mapper, ucs);
if (r == mdn_invalid_codepoint) {
mdn_log_error("mdnres: invalid delimiter "
"\"%-.30s\", line %d\n",
argv[i], lineno);
return (r);
} else if (r != mdn_success) {
return (r);
}
}
return (mdn_success);
}
static mdn_result_t
parse_encoding_alias_file(mdn_resconf_t ctx, char *args, int lineno) {
mdn_result_t r;
char *argv[MAX_CONF_LINE_ARGS + 1];
int argc;
argc = split_args(args, argv, MAX_CONF_LINE_ARGS + 1);
if (argc != 1) {
mdn_log_error("mdnres: wrong # of args for "
"encoding-alias-file, line %d\n", lineno);
return (mdn_invalid_syntax);
}
r = mdn_converter_aliasfile(argv[0]);
if (r != mdn_success) {
mdn_log_error("mdnres: cannot set aliasfile, %s, line %d\n",
mdn_result_tostring(r), lineno);
}
return (r);
}
static mdn_result_t
parse_idn_encoding(mdn_resconf_t ctx, char *args, int lineno) {
mdn_result_t r;
char *argv[MAX_CONF_LINE_ARGS + 1];
int argc;
argc = split_args(args, argv, MAX_CONF_LINE_ARGS + 1);
if (argc != 1) {
mdn_log_error("mdnres: wrong # of args for idn-encoding, "
"line %d\n", lineno);
return (mdn_invalid_syntax);
}
r = mdn_converter_create(argv[0], &ctx->idn_converter,
MDN_CONVERTER_DELAYEDOPEN);
if (r != mdn_success) {
mdn_log_error("mdnres: cannot create idn converter, %s, "
"line %d\n", mdn_result_tostring(r), lineno);
}
return (r);
}
static mdn_result_t
parse_local_map(mdn_resconf_t ctx, char *args, int lineno) {
mdn_result_t r;
char *argv[MAX_CONF_LINE_ARGS + 1];
int argc;
int i;
argc = split_args(args, argv, MAX_CONF_LINE_ARGS + 1);
if (argc < 2 || argc > MAX_CONF_LINE_ARGS) {
mdn_log_error("mdnres: wrong # of args for local-map, "
"line %d\n", lineno);
return (mdn_invalid_syntax);
}
if (ctx->local_mapper == NULL) {
r = mdn_mapselector_create(&ctx->local_mapper);
if (r != mdn_success) {
mdn_log_error("mdnres: cannot create local mapper, "
"%s, line %d\n",
mdn_result_tostring(r), lineno);
return (r);
}
}
for (i = 1; i < argc; i++) {
r = mdn_mapselector_add(ctx->local_mapper, argv[0], argv[i]);
if (r == mdn_invalid_name) {
mdn_log_error("mdnres: map scheme unavailable "
"\"%-.30s\", line %d\n",
argv[i], lineno);
return (r);
} else if (r != mdn_success) {
return (r);
}
}
return (mdn_success);
}
static mdn_result_t
parse_nameprep(mdn_resconf_t ctx, char *args, int lineno, char **nameprep) {
mdn_result_t r;
char *argv[MAX_CONF_LINE_ARGS + 1];
int argc;
argc = split_args(args, argv, MAX_CONF_LINE_ARGS + 1);
if (argc != 1) {
mdn_log_error("mdnres: wrong # of args for nameprep, "
"line %d\n", lineno);
return (mdn_invalid_syntax);
}
r = mystrdup(argv[0], nameprep);
if (r != mdn_success) {
mdn_log_error("mdnres: cannot set nameprep, %s, line %d\n",
mdn_result_tostring(r), lineno);
}
return (r);
}
static mdn_result_t
parse_map(mdn_resconf_t ctx, char *args, int lineno) {
mdn_result_t r;
char *argv[MAX_CONF_LINE_ARGS + 1];
int argc;
int i;
argc = split_args(args, argv, MAX_CONF_LINE_ARGS + 1);
if (argc > MAX_CONF_LINE_ARGS) {
mdn_log_error("mdnres: wrong # of args for map, line %d\n",
lineno);
return (mdn_invalid_syntax);
}
if (ctx->mapper == NULL) {
r = mdn_mapper_create(&ctx->mapper);
if (r != mdn_success) {
mdn_log_error("mdnres: cannot create mapper, %s, "
"line %d\n", mdn_result_tostring(r),
lineno);
return (r);
}
}
for (i = 0; i < argc; i++) {
r = mdn_mapper_add(ctx->mapper, argv[i]);
if (r == mdn_invalid_name) {
mdn_log_error("mdnres: map scheme unavailable "
"\"%-.30s\", line %d\n",
argv[i], lineno);
return (r);
} else if (r != mdn_success) {
return (r);
}
}
return (mdn_success);
}
static mdn_result_t
parse_normalize(mdn_resconf_t ctx, char *args, int lineno) {
mdn_result_t r;
char *argv[MAX_CONF_LINE_ARGS + 1];
int argc;
int i;
argc = split_args(args, argv, MAX_CONF_LINE_ARGS + 1);
if (argc > MAX_CONF_LINE_ARGS) {
mdn_log_error("mdnres: wrong # of args for normalize, "
"line %d\n", lineno);
return (mdn_invalid_syntax);
}
if (ctx->normalizer == NULL) {
r = mdn_normalizer_create(&ctx->normalizer);
if (r != mdn_success) {
mdn_log_error("mdnres: cannot create normalizer, %s, "
"line %d\n", mdn_result_tostring(r),
lineno);
return (r);
}
}
for (i = 0; i < argc; i++) {
r = mdn_normalizer_add(ctx->normalizer, argv[i]);
if (r == mdn_invalid_name) {
mdn_log_error("mdnres: unknown normalization scheme "
"\"%-.30s\", line %d\n",
argv[i], lineno);
return (r);
} else if (r != mdn_success) {
return (r);
}
}
return (mdn_success);
}
static mdn_result_t
parse_prohibit(mdn_resconf_t ctx, char *args, int lineno) {
mdn_result_t r;
char *argv[MAX_CONF_LINE_ARGS + 1];
int argc;
char scheme_name[MAX_CONF_LINE_LENGTH + 1];
int i;
argc = split_args(args, argv, MAX_CONF_LINE_ARGS + 1);
if (argc > MAX_CONF_LINE_ARGS) {
mdn_log_error("mdnres: wrong # of args for prohibit, "
"line %d\n", lineno);
return (mdn_invalid_syntax);
}
if (ctx->prohibit_checker == NULL) {
r = mdn_checker_create(&ctx->prohibit_checker);
if (r != mdn_success) {
mdn_log_error("mdnres: cannot create prohibit "
"checker, %s, line %d\n",
mdn_result_tostring(r), lineno);
return (r);
}
}
for (i = 0; i < argc; i++) {
sprintf(scheme_name, "%s%s", MDN_CHECKER_PROHIBIT_PREFIX,
argv[i]);
r = mdn_checker_add(ctx->prohibit_checker, scheme_name);
if (r == mdn_invalid_name) {
mdn_log_error("mdnres: prohibit scheme unavailable "
"\"%-.30s\", line %d\n",
argv[i], lineno);
return (r);
} else if (r != mdn_success) {
return (r);
}
}
return (mdn_success);
}
static mdn_result_t
parse_unassigned(mdn_resconf_t ctx, char *args, int lineno) {
mdn_result_t r;
char *argv[MAX_CONF_LINE_ARGS + 1];
int argc;
char scheme_name[MAX_CONF_LINE_LENGTH + 1];
int i;
argc = split_args(args, argv, MAX_CONF_LINE_ARGS + 1);
if (argc > MAX_CONF_LINE_ARGS) {
mdn_log_error("mdnres: wrong # of args for unassigned, "
"line %d\n", lineno);
return (mdn_invalid_syntax);
}
if (ctx->unassigned_checker == NULL) {
r = mdn_checker_create(&ctx->unassigned_checker);
if (r != mdn_success) {
mdn_log_error("mdnres: cannot create unassigned "
"checker, %s, line %d\n",
mdn_result_tostring(r), lineno);
return (r);
}
}
for (i = 0; i < argc; i++) {
sprintf(scheme_name, "%s%s", MDN_CHECKER_UNASSIGNED_PREFIX,
argv[i]);
r = mdn_checker_add(ctx->unassigned_checker, scheme_name);
if (r == mdn_invalid_name) {
mdn_log_error("mdnres: unassigned scheme unavailable "
"\"%-.30s\", line %d\n",
argv[i], lineno);
return (r);
} else if (r != mdn_success) {
return (r);
}
}
return (mdn_success);
}
static int
split_args(char *s, char **av, int max_ac) {
int ac;
int i;
for (ac = 0; *s != '\0' && ac < max_ac; ac++) {
if (ac > 0)
*s++ = '\0';
while (isspace((unsigned char)*s))
s++;
if (*s == '\0')
break;
if (*s == '"' || *s == '\'') {
int qc = *s++;
av[ac] = s;
while (*s != qc) {
if (*s == '\0')
return (-1);
s++;
}
} else {
av[ac] = s;
while (*s != '\0' && !isspace((unsigned char)*s))
s++;
}
}
for (i = ac; i < max_ac; i++)
av[i] = NULL;
return (ac);
}
static void
resetconf(mdn_resconf_t ctx) {
free(ctx->local_encoding);
ctx->local_encoding = NULL;
if (ctx->local_converter != NULL) {
mdn_converter_destroy(ctx->local_converter);
ctx->local_converter = NULL;
}
if (ctx->idn_converter != NULL) {
mdn_converter_destroy(ctx->idn_converter);
ctx->idn_converter = NULL;
}
if (ctx->alternate_converter != NULL) {
mdn_converter_destroy(ctx->alternate_converter);
ctx->alternate_converter = NULL;
}
if (ctx->normalizer != NULL) {
mdn_normalizer_destroy(ctx->normalizer);
ctx->normalizer = NULL;
}
if (ctx->prohibit_checker != NULL) {
mdn_checker_destroy(ctx->prohibit_checker);
ctx->prohibit_checker = NULL;
}
if (ctx->unassigned_checker != NULL) {
mdn_checker_destroy(ctx->unassigned_checker);
ctx->unassigned_checker = NULL;
}
if (ctx->mapper != NULL) {
mdn_mapper_destroy(ctx->mapper);
ctx->mapper = NULL;
}
if (ctx->local_mapper != NULL) {
mdn_mapselector_destroy(ctx->local_mapper);
ctx->local_mapper = NULL;
}
if (ctx->delimiter_mapper != NULL) {
mdn_delimitermap_destroy(ctx->delimiter_mapper);
ctx->delimiter_mapper = NULL;
}
}
static mdn_result_t
update_local_converter(mdn_resconf_t ctx) {
mdn_result_t r;
const char *new_local_encoding;
/*
* This condition comes true only when the converter is set by
* mdn_resconf_setlocalconverter(). In this case, we don't
* update the local converter.
*/
if (ctx->local_encoding == NULL && ctx->local_converter != NULL)
return (mdn_success);
/*
* Update the local converer if the local encoding is changed.
*/
new_local_encoding = mdn_localencoding_name();
if (new_local_encoding == NULL) {
mdn_log_error("cannot determine local codeset name\n");
return (mdn_notfound);
}
if (ctx->local_encoding != NULL &&
ctx->local_converter != NULL &&
strcmp(ctx->local_encoding, new_local_encoding) == 0) {
return (mdn_success);
}
free(ctx->local_encoding);
ctx->local_encoding = NULL;
if (ctx->local_converter != NULL) {
mdn_converter_destroy(ctx->local_converter);
ctx->local_converter = NULL;
}
r = mystrdup(new_local_encoding, &ctx->local_encoding);
if (r != mdn_success)
return (r);
r = mdn_converter_create(ctx->local_encoding,
&ctx->local_converter,
MDN_CONVERTER_RTCHECK);
return (r);
}
static mdn_result_t
mystrdup(const char *from, char **top) {
char *s;
if (*top != NULL) {
free(*top);
*top = NULL;
}
if (from == NULL)
from = "";
s = malloc(strlen(from) + 1);
if (s == NULL)
return (mdn_nomemory);
(void)strcpy(s, from);
*top = s;
return (mdn_success);
}
static const char *
get_ucs(const char *p, unsigned long *vp) {
char *end;
/* Skip leading space */
while (isspace((unsigned char)*p))
p++;
/* Skip optional 'U+' */
if (strncmp(p, "U+", 2) == 0)
p += 2;
*vp = strtoul(p, &end, 16);
if (end == p) {
return (NULL);
}
p = end;
/* Skip trailing space */
while (isspace((unsigned char)*p))
p++;
return p;
}
#ifdef TEST
int
main(int argc, char *argv[])
{
mdn_resconf_t resconf;
mdn_result_t r;
char *conf_file;
if (argc == 1)
conf_file = mdn_resconf_defaultfile();
else
conf_file = argv[1];
r = mdn_resconf_initialize();
if (r != mdn_success) {
fprintf(stderr, "%s: %s\n", argv[0], mdn_result_tostring(r));
exit(1);
}
r = mdn_resconf_create(&resconf);
if (r != mdn_success) {
fprintf(stderr, "%s: %s\n", argv[0], mdn_result_tostring(r));
exit(1);
}
r = mdn_resconf_loadfile(resconf, conf_file);
if (r != mdn_success) {
fprintf(stderr, "%s: %s, %s\n", argv[0],
mdn_result_tostring(r), conf_file);
exit(1);
}
mdn_resconf_destroy(resconf);
return 0;
}
#endif /* TEST */