Index: ossp-pkg/cfg/.cvsignore RCS File: /v/ossp/cvs/ossp-pkg/cfg/.cvsignore,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/cfg/.cvsignore,v' | diff -u /dev/null - -L'ossp-pkg/cfg/.cvsignore' 2>/dev/null --- ossp-pkg/cfg/.cvsignore +++ - 2024-05-15 10:58:11.027849828 +0200 @@ -0,0 +1,6 @@ +cfg_syn_parse.c +cfg_syn_parse.h +cfg_syn_scan.c +cfg_test +*.o +*.a Index: ossp-pkg/cfg/00TODO RCS File: /v/ossp/cvs/ossp-pkg/cfg/Attic/00TODO,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/cfg/Attic/00TODO,v' | diff -u /dev/null - -L'ossp-pkg/cfg/00TODO' 2>/dev/null --- ossp-pkg/cfg/00TODO +++ - 2024-05-15 10:58:11.030502999 +0200 @@ -0,0 +1,4 @@ +- cfg_t +- cfg_data.c +- cfg_node_dump() +- cfg_node_destroy() for whole tree Index: ossp-pkg/cfg/Makefile RCS File: /v/ossp/cvs/ossp-pkg/cfg/Attic/Makefile,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/cfg/Attic/Makefile,v' | diff -u /dev/null - -L'ossp-pkg/cfg/Makefile' 2>/dev/null --- ossp-pkg/cfg/Makefile +++ - 2024-05-15 10:58:11.033095933 +0200 @@ -0,0 +1,51 @@ + +CC = /usr/opkg/bin/gcc +CFLAGS = -pipe -O2 -g -ggdb3 \ + -ansi -pedantic -Wall \ + -Wmultichar -Wno-system-headers -Wtraditional \ + -Wshadow -Wpointer-arith \ + -Wbad-function-cast -Wcast-align \ + -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations \ + -Wredundant-decls -Wnested-externs -Winline +#CFLAGS = -Wundef -W -Wconversion -Wfloat-equal -Wunreachable-code -Wwrite-strings +AR = ar +RANLIB = ranlib +RM = rm -f +BISON = bison +FLEX = flex-beta + +LIB = libcfg.a +OBJ = cfg_grid.o cfg_node.o cfg_fmt.o cfg_syn.o cfg_syn_parse.o cfg_syn_scan.o cfg_util.o +TST = cfg_test + +all: $(LIB) $(TST) + +.c.o: + $(CC) $(CFLAGS) -c $< + +cfg_syn.c: cfg_syn.h cfg_syn_parse.h +cfg_syn_scan.o: cfg_syn_scan.c cfg_syn_parse.h +cfg_syn_scan.c: cfg_syn_scan.l + $(FLEX) -Pcfg_syn_ -s -8 -B -ocfg_syn_scan.c cfg_syn_scan.l +cfg_syn_parse.c cfg_syn_parse.h: cfg_syn_parse.y + $(BISON) -d -k -pcfg_syn_ -ocfg_syn_parse.c cfg_syn_parse.y + +$(LIB): $(OBJ) + $(AR) rc $(LIB) $(OBJ) + $(RANLIB) $(LIB) + +$(TST): $(TST).o $(LIB) + $(CC) -o $(TST) $(TST).o $(LIB) + +clean: + $(RM) $(LIB) + $(RM) $(OBJ) + $(RM) $(TST).o $(TST) + $(RM) core *.core *.aux *.log + $(RM) cfg_syn_parse.c cfg_syn_parse.h + $(RM) cfg_syn_scan.c + +check: test +test: $(TST) + ./$(TST) sample.cfg + Index: ossp-pkg/cfg/cfg.h RCS File: /v/ossp/cvs/ossp-pkg/cfg/cfg.h,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/cfg/cfg.h,v' | diff -u /dev/null - -L'ossp-pkg/cfg/cfg.h' 2>/dev/null --- ossp-pkg/cfg/cfg.h +++ - 2024-05-15 10:58:11.035692109 +0200 @@ -0,0 +1,99 @@ +/* +** OSSP cfg - Configuration Parsing +** Copyright (c) 1999-2002 Ralf S. Engelschall +** Copyright (c) 1999-2002 The OSSP Project (http://www.ossp.org/) +** Copyright (c) 2001-2002 Cable & Wireless Deutschland (http://www.cw.com/de/) +** +** This file is part of OSSP cfg, a configuration parsing +** library which can be found at http://www.ossp.org/pkg/lib/cfg/. +** +** Permission to use, copy, modify, and distribute this software for +** any purpose with or without fee is hereby granted, provided that +** the above copyright notice and this permission notice appear in all +** copies. +** +** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR +** CONTRIBUTORS 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 CONTRCFG, 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 DAMAGE. +** +** cfg.h: master API +*/ + +#ifndef __CFG_H__ +#define __CFG_H__ + +#include + +/* ============================================================ */ + +/* general return codes */ +typedef enum { + CFG_OK = 0, + CFG_ERR_ARG, + CFG_ERR_INT, + CFG_ERR_SYS, + CFG_ERR_SYN +} cfg_rc_t; + +/* ============================================================ */ + +/* configuration handle */ +struct cfg_st; +typedef struct cfg_st cfg_t; + +/* configuration API */ +cfg_rc_t cfg_create (cfg_t **cfg); +cfg_rc_t cfg_destroy (cfg_t *cfg); + +/* ============================================================ */ + +/* list of node types */ +typedef enum { + CFG_NODE_TYPE_NN = 0, /* node unknown */ + CFG_NODE_TYPE_SEQ, /* node represents a sequence */ + CFG_NODE_TYPE_DIR, /* node represents a directive */ + CFG_NODE_TYPE_TOK /* node represents a token */ +} cfg_node_type_t; + +/* list of node attributes */ +typedef enum { + CFG_NODE_ATTR_TYPE, /* type of node */ + CFG_NODE_ATTR_PARENT, /* pointer to parent node */ + CFG_NODE_ATTR_RBROTH, /* pointer to right brother node */ + CFG_NODE_ATTR_CHILD1, /* pointer to first child node */ + CFG_NODE_ATTR_TOKEN, /* pointer to the node token string */ + CFG_NODE_ATTR_DATA /* pointer to the node annotation data */ +} cfg_node_attr_t; + +/* list of node linking variants */ +typedef enum { + CFG_NODE_LINK_PARENT, + CFG_NODE_LINK_RBROTH, + CFG_NODE_LINK_CHILD1 +} cfg_node_link_t; + +/* configuration node type */ +struct cfg_node_st; +typedef struct cfg_node_st cfg_node_t; + +cfg_rc_t cfg_node_create (cfg_node_t **node); +cfg_rc_t cfg_node_set (cfg_node_t *node, cfg_node_attr_t attr, ...); +cfg_rc_t cfg_node_get (cfg_node_t *node, cfg_node_attr_t attr, ...); +cfg_rc_t cfg_node_link (cfg_node_t *node, cfg_node_link_t id, cfg_node_t *node2); +cfg_rc_t cfg_node_unlink (cfg_node_t *node); +cfg_rc_t cfg_node_apply (cfg_node_t *node, void (*cb_fct)(void *, cfg_node_t *), void *cb_ctx); +cfg_rc_t cfg_node_destroy (cfg_node_t *node); + +/* ============================================================ */ + +#endif /* __CFG_H__ */ + Index: ossp-pkg/cfg/cfg.pod RCS File: /v/ossp/cvs/ossp-pkg/cfg/cfg.pod,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/cfg/cfg.pod,v' | diff -u /dev/null - -L'ossp-pkg/cfg/cfg.pod' 2>/dev/null --- ossp-pkg/cfg/cfg.pod +++ - 2024-05-15 10:58:11.038371882 +0200 @@ -0,0 +1,160 @@ +## +## OSSP cfg - Configuration Parsing +## Copyright (c) 1999-2002 Ralf S. Engelschall +## Copyright (c) 1999-2002 The OSSP Project (http://www.ossp.org/) +## Copyright (c) 2001-2002 Cable & Wireless Deutschland (http://www.cw.com/de/) +## +## This file is part of OSSP cfg, a configuration parsing +## library which can be found at http://www.ossp.org/pkg/lib/cfg/. +## +## Permission to use, copy, modify, and distribute this software for +## any purpose with or without fee is hereby granted, provided that +## the above copyright notice and this permission notice appear in all +## copies. +## +## THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR +## CONTRIBUTORS 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 DAMAGE. +## +## cfg.pod: manual page +## + +=pod + +=head1 NAME + +B - Configuration Parsing + +=head1 SYNOPSIS + +... + +=head1 DESCRIPTION + +B is a ISO-C library for parsing arbitrary C/C++-style +configuration files. A configuration is sequence of directives. Each +directive consists of zero or more tokens. Each token can be either a +string or again a complete sequence. This means the configuration syntax +has a recursive structure and this way allows to configure structures +which require arbitrarily nested sections. + +=head2 CONFIGURATION SYNTAX + +The configuration syntax is described by the following context-free +(Chomsky-2) grammar: + +B ::= I + | B + | B B B + +B ::= B + | B B + +B ::= B B B + | B + +B ::= B # double quoted string + | B # single quoted string + | B # plain text string + +The other contained terminal symbols are defined itself by the following +set of grammars production (regular sub-grammars for character +sequences given as Perl-style regular expressions "/I/"): + +B ::= /;/ + +B ::= /{/ + +B ::= /}/ + +B ::= /"/ B /"/ + +B ::= I + | B B + +B ::= /\\"/ # escaped quote + | /\\x[0-9a-zA-Z]{2}/ # hexadecimal char + | /\\[0-7]{1,3}/ # octal character + | /\\[trn]/ # TAB, CR, NL + | /\\\n[ \t]*/ # line continuation + | /\\\\/ # escaped escape + | /./ # any other char + +B ::= /'/ B /'/ + +B ::= I + | B B + +B ::= /\\'/ # escaped quote + | /\\\n[ \t]*/ # line contination + | /\\\\/ # escaped escape + | /./ # any other char + +B ::= B B + +B ::= I + | B B + +B ::= /[^ \t\n;{}"']/ # none of specials + +Additionally, white-space B and comment B tokens are allowed at +any position in the above productions of the previous grammar part. + +B ::= /[ \t\n]+/ + +B ::= B # style of C + | B # style of C++ + | B # style of /bin/sh + +B ::= /\/\*([^*]|\*(?!\/))*\*\// + +B ::= /\/\/[^\n]*/ + +B ::= /#[^\n]*/ + +=head2 CONFIGURATION EXAMPLE + +A more intuitive description of the configuration syntax is perhaps given by +the following example which shows all features at once: + + /* single word */ + foo; + + /* multi word */ + foo bar quux; + + /* nested structure */ + foo { bar; baz } quux; + + /* quoted strings */ + 'foo bar' + "foo\x0a\t\n\ + bar" + +=head1 APPLICATION PROGRAMMING INTERFACE (API) + +=head1 HISTORY + +B was implemented in lots of small steps over a very +long time. The first ideas date back to the year 1995 when Ralf S. +Engelschall attended his first compiler construction lessons at +university. But it was first time finished in 2002 by him for use in the +B project. + +=head1 AUTHOR + + Ralf S. Engelschall + rse@engelschall.com + www.engelschall.com + +=cut + Index: ossp-pkg/cfg/cfg_fmt.c RCS File: /v/ossp/cvs/ossp-pkg/cfg/cfg_fmt.c,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/cfg/cfg_fmt.c,v' | diff -u /dev/null - -L'ossp-pkg/cfg/cfg_fmt.c' 2>/dev/null --- ossp-pkg/cfg/cfg_fmt.c +++ - 2024-05-15 10:58:11.041067383 +0200 @@ -0,0 +1,1167 @@ +/* +** OSSP cfg - Configuration Parsing +** Copyright (c) 1999-2002 Ralf S. Engelschall +** Copyright (c) 1999-2002 The OSSP Project (http://www.ossp.org/) +** Copyright (c) 2001-2002 Cable & Wireless Deutschland (http://www.cw.com/de/) +** +** This file is part of OSSP cfg, a configuration parsing +** library which can be found at http://www.ossp.org/pkg/lib/cfg/. +** +** Permission to use, copy, modify, and distribute this software for +** any purpose with or without fee is hereby granted, provided that +** the above copyright notice and this permission notice appear in all +** copies. +** +** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR +** CONTRIBUTORS 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 CONTRCFG, 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 DAMAGE. +** +** cfg_fmt.c: printf(3)-style formatting +*/ + +/* + * This is a generic printf-style formatting code which is based on + * Apache's ap_snprintf which it turn is based on and used with the + * permission of, the SIO stdio-replacement strx_* functions by Panos + * Tsirigotis for xinetd. The IEEE + * floating point formatting routines are derived from an anchient + * FreeBSD version which took it from GNU libc-4.6.27 and modified it + * to be thread safe. The whole code was finally cleaned up, stripped + * and extended by Ralf S. Engelschall for use inside the Str library. + * Especially any Apache and network specific kludges were removed again + * and instead the formatting engine now can be extended by the caller + * on-the-fly. It was then finally adjusted to be stand-alone for use + * inside OSSP. + */ + +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2000-2002 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Apache" and "Apache Software Foundation" must + * not be used to endorse or promote products derived from this + * software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * nor may "Apache" appear in their name, without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS 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 DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +#include "cfg_fmt.h" + +/* types which are locally use */ +typedef long long_int; +typedef unsigned long u_long_int; +#if defined(SIZEOF_LONG_LONG) && (SIZEOF_LONG_LONG > 0) +typedef long long quad_int; +typedef unsigned long long u_quad_int; +#else +typedef long quad_int; +typedef unsigned long u_quad_int; +#endif + +/* a few handy defines */ +#ifndef NUL +#define NUL '\0' +#endif +#ifndef NULL +#define NULL ((void *)0) +#endif +#ifndef FALSE +#define FALSE (0) +#endif +#ifndef TRUE +#define TRUE (!FALSE) +#endif +#define S_NULL "(NULL)" +#define S_NULL_LEN 6 +#define FLOAT_DIGITS 6 +#define EXPONENT_LENGTH 10 + +/* NUM_BUF_SIZE is the size of the buffer used for arithmetic + conversions. This is a magic number; do NOT decrease it! */ +#define NUM_BUF_SIZE 512 +#define NDIG 80 + +/* compatibility */ +#if !defined(HAVE_ISNAN) +#define isnan(d) (0) +#endif +#if !defined(HAVE_ISINF) +#define isinf(d) (0) +#endif + +/* explicit support for unsigned char based ctype stuff */ +#define cfg_fmt_isalpha(c) (isalpha(((unsigned char)(c)))) +#define cfg_fmt_isdigit(c) (isdigit(((unsigned char)(c)))) +#define cfg_fmt_isxdigit(c) (isxdigit(((unsigned char)(c)))) +#define cfg_fmt_islower(c) (islower(((unsigned char)(c)))) +#define cfg_fmt_tolower(c) (tolower((unsigned char)(c))) + +/* + * Convert decimal number to its string representation. The number of + * digits is specified by ndigit decpt is set to the position of the + * decimal point sign is set to 0 for positive, 1 for negative. buf must + * have at least NDIG bytes. + */ + +#define cfg_fmt_ecvt(arg,ndigits,decpt,sign,buf) \ + cfg_fmt_cvt((arg), (ndigits), (decpt), (sign), 1, (buf)) + +#define cfg_fmt_fcvt(arg,ndigits,decpt,sign,buf) \ + cfg_fmt_cvt((arg), (ndigits), (decpt), (sign), 0, (buf)) + +static char * +cfg_fmt_cvt( + double arg, + int ndigits, + int *decpt, + int *sign, + int eflag, + char *buf) +{ + register int r2; + double fi, fj; + register char *p, *p1; + + if (ndigits >= NDIG - 1) + ndigits = NDIG - 2; + r2 = 0; + *sign = FALSE; + p = &buf[0]; + if (arg < 0) { + *sign = TRUE; + arg = -arg; + } + arg = modf(arg, &fi); + p1 = &buf[NDIG]; + + /* Do integer part */ + if (fi != 0) { + p1 = &buf[NDIG]; + while (fi != 0 && p1 > &buf[0]) { + fj = modf(fi / 10, &fi); + *--p1 = (int)((fj + .03) * 10) + '0'; + r2++; + } + while (p1 < &buf[NDIG]) + *p++ = *p1++; + } + else if (arg > 0) { + while ((fj = arg * 10) < 1) { + arg = fj; + r2--; + } + } + p1 = &buf[ndigits]; + if (eflag == 0) + p1 += r2; + *decpt = r2; + if (p1 < &buf[0]) { + buf[0] = NUL; + return (buf); + } + while (p <= p1 && p < &buf[NDIG]) { + arg *= 10; + arg = modf(arg, &fj); + *p++ = (int) fj + '0'; + } + if (p1 >= &buf[NDIG]) { + buf[NDIG - 1] = NUL; + return (buf); + } + p = p1; + *p1 += 5; + while (*p1 > '9') { + *p1 = '0'; + if (p1 > buf) + ++ * --p1; + else { + *p1 = '1'; + (*decpt)++; + if (eflag == 0) { + if (p > buf) + *p = '0'; + p++; + } + } + } + *p = NUL; + return buf; +} + +static char * +cfg_fmt_gcvt( + double number, + int ndigit, + char *buf, + int altform) +{ + int sign; + int decpt; + register char *p1, *p2; + register int i; + char buf1[NDIG]; + + p1 = cfg_fmt_ecvt(number, ndigit, &decpt, &sign, buf1); + p2 = buf; + if (sign) + *p2++ = '-'; + for (i = ndigit - 1; i > 0 && p1[i] == '0'; i--) + ndigit--; + if ((decpt >= 0 && decpt - ndigit > 4) + || (decpt < 0 && decpt < -3)) { /* use E-style */ + decpt--; + *p2++ = *p1++; + *p2++ = '.'; + for (i = 1; i < ndigit; i++) + *p2++ = *p1++; + *p2++ = 'e'; + if (decpt < 0) { + decpt = -decpt; + *p2++ = '-'; + } + else + *p2++ = '+'; + if (decpt / 100 > 0) + *p2++ = decpt / 100 + '0'; + if (decpt / 10 > 0) + *p2++ = (decpt % 100) / 10 + '0'; + *p2++ = decpt % 10 + '0'; + } + else { + if (decpt <= 0) { + if (*p1 != '0') + *p2++ = '.'; + while (decpt < 0) { + decpt++; + *p2++ = '0'; + } + } + for (i = 1; i <= ndigit; i++) { + *p2++ = *p1++; + if (i == decpt) + *p2++ = '.'; + } + if (ndigit < decpt) { + while (ndigit++ < decpt) + *p2++ = '0'; + *p2++ = '.'; + } + } + if (p2[-1] == '.' && !altform) + p2--; + *p2 = NUL; + return buf; +} + +/* + * The INS_CHAR macro inserts a character in the buffer and flushes the + * buffer if necessary. It uses the char pointers sp and bep: sp points + * to the next available character in the buffer, bep points to the + * end-of-buffer+1. While using this macro, note that the nextb pointer + * is NOT updated. NOTE: Evaluation of the c argument should not have + * any side-effects + */ +#define INS_CHAR(c, sp, bep, cc) { \ + if (sp >= bep) { \ + vbuff->curpos = sp; \ + if (vbuff->flush(vbuff)) \ + return -1; \ + sp = vbuff->curpos; \ + bep = vbuff->endpos; \ + } \ + *sp++ = (c); \ + cc++; \ +} + +/* + * Convert a string to decimal value + */ +#define NUM(c) ((c) - '0') +#define STR_TO_DEC(str, num) { \ + num = NUM(*str++); \ + while (cfg_fmt_isdigit(*(str))) { \ + num *= 10 ; \ + num += NUM(*str++) ; \ + } \ +} + +/* + * This macro does zero padding so that the precision requirement is + * satisfied. The padding is done by adding '0's to the left of the + * string that is going to be printed. + */ +#define FIX_PRECISION(adjust, precision, s, s_len) \ + if (adjust) { \ + while (s_len < precision) { \ + *--s = '0'; \ + s_len++; \ + } \ + } + +/* + * This macro does padding. + * The padding is done by printing the character ch. + */ +#define PAD(width, len, ch) \ + do { \ + INS_CHAR(ch, sp, bep, cc); \ + width--; \ + } while (width > len) + +/* + * Prefix the character ch to the string str + * Increase length. Set the has_prefix flag. + */ +#define PREFIX(str, length, ch) \ + *--str = ch; \ + length++; \ + has_prefix = TRUE + +/* + * Convert num to its decimal format. + * Return value: + * - a pointer to a string containing the number (no sign) + * - len contains the length of the string + * - is_negative is set to TRUE or FALSE depending on the sign + * of the number (always set to FALSE if is_unsigned is TRUE) + * The caller provides a buffer for the string: that is the buf_end argument + * which is a pointer to the END of the buffer + 1 (i.e. if the buffer + * is declared as buf[ 100 ], buf_end should be &buf[ 100 ]) + * Note: we have 2 versions. One is used when we need to use quads + * (conv_10_quad), the other when we don't (conv_10). We're assuming the + * latter is faster. + */ +static char * +conv_10( + register long_int num, + register int is_unsigned, + register int *is_negative, + char *buf_end, + register size_t *len) +{ + register char *p = buf_end; + register u_long_int magnitude; + + if (is_unsigned) { + magnitude = (u_long_int)num; + *is_negative = FALSE; + } + else { + *is_negative = (num < 0); + /* On a 2's complement machine, negating the most negative integer + results in a number that cannot be represented as a signed integer. + Here is what we do to obtain the number's magnitude: + a. add 1 to the number + b. negate it (becomes positive) + c. convert it to unsigned + d. add 1 */ + if (*is_negative) { + long_int t = num + 1; + + magnitude = ((u_long_int) - t) + 1; + } + else + magnitude = (u_long_int)num; + } + /* We use a do-while loop so that we write at least 1 digit */ + do { + register u_long_int new_magnitude = magnitude / 10; + *--p = (char) (magnitude - new_magnitude * 10 + '0'); + magnitude = new_magnitude; + } while (magnitude); + *len = (int)(buf_end - p); + return p; +} + +static char * +conv_10_quad( + quad_int num, + register int is_unsigned, + register int *is_negative, + char *buf_end, + register size_t *len) +{ + register char *p = buf_end; + u_quad_int magnitude; + + if (is_unsigned) { + magnitude = (u_quad_int)num; + *is_negative = FALSE; + } + else { + *is_negative = (num < 0); + /* On a 2's complement machine, negating the most negative integer + result in a number that cannot be represented as a signed integer. + Here is what we do to obtain the number's magnitude: + a. add 1 to the number + b. negate it (becomes positive) + c. convert it to unsigned + d. add 1 */ + if (*is_negative) { + quad_int t = num + 1; + magnitude = ((u_quad_int) - t) + 1; + } + else + magnitude = (u_quad_int)num; + } + /* We use a do-while loop so that we write at least 1 digit */ + do { + u_quad_int new_magnitude = magnitude / 10; + *--p = (char)(magnitude - new_magnitude * 10 + '0'); + magnitude = new_magnitude; + } while (magnitude); + *len = (int)(buf_end - p); + return p; +} + +/* + * Convert a floating point number to a string formats 'f', 'e' or 'E'. + * The result is placed in buf, and len denotes the length of the string + * The sign is returned in the is_negative argument (and is not placed + * in buf). + */ +static char * +conv_fp( + register char format, + register double num, + int add_dp, + int precision, + int *is_negative, + char *buf, + size_t *len) +{ + register char *s = buf; + register char *p; + int decimal_point; + char buf1[NDIG]; + + if (format == 'f') + p = cfg_fmt_fcvt(num, precision, &decimal_point, is_negative, buf1); + else /* either e or E format */ + p = cfg_fmt_ecvt(num, precision + 1, &decimal_point, is_negative, buf1); + + /* Check for Infinity and NaN */ + if (cfg_fmt_isalpha(*p)) { + *len = strlen(strcpy(buf, p)); + *is_negative = FALSE; + return (buf); + } + + if (format == 'f') { + if (decimal_point <= 0) { + *s++ = '0'; + if (precision > 0) { + *s++ = '.'; + while (decimal_point++ < 0) + *s++ = '0'; + } + else if (add_dp) + *s++ = '.'; + } + else { + while (decimal_point-- > 0) + *s++ = *p++; + if (precision > 0 || add_dp) + *s++ = '.'; + } + } + else { + *s++ = *p++; + if (precision > 0 || add_dp) + *s++ = '.'; + } + + /* copy the rest of p, the NUL is NOT copied */ + while (*p) + *s++ = *p++; + + if (format != 'f') { + char temp[EXPONENT_LENGTH]; /* for exponent conversion */ + size_t t_len; + int exponent_is_negative; + + *s++ = format; /* either e or E */ + decimal_point--; + if (decimal_point != 0) { + p = conv_10((long_int) decimal_point, FALSE, &exponent_is_negative, + &temp[EXPONENT_LENGTH], &t_len); + *s++ = exponent_is_negative ? '-' : '+'; + /* Make sure the exponent has at least 2 digits */ + if (t_len == 1) + *s++ = '0'; + while (t_len--) + *s++ = *p++; + } + else { + *s++ = '+'; + *s++ = '0'; + *s++ = '0'; + } + } + + *len = (int)(s - buf); + return buf; +} + +/* + * Convert num to a base X number where X is a power of 2. nbits determines X. + * For example, if nbits is 3, we do base 8 conversion + * Return value: + * a pointer to a string containing the number + * The caller provides a buffer for the string: that is the buf_end + * argument which is a pointer to the END of the buffer + 1 (i.e. if the + * buffer is declared as buf[100], buf_end should be &buf[100]) As with + * conv_10, we have a faster version which is used when the number isn't + * quad size. + */ + +static const char low_digits[] = "0123456789abcdef"; +static const char upper_digits[] = "0123456789ABCDEF"; + +static char * +conv_p2( + register u_long_int num, + register int nbits, + char format, + char *buf_end, + register size_t *len) +{ + register int mask = (1 << nbits) - 1; + register char *p = buf_end; + register const char *digits = (format == 'X') ? upper_digits : low_digits; + + do { + *--p = digits[num & mask]; + num >>= nbits; + } while (num); + *len = (int)(buf_end - p); + return p; +} + +static char * +conv_p2_quad( + u_quad_int num, + register int nbits, + char format, + char *buf_end, + register size_t *len) +{ + register int mask = (1 << nbits) - 1; + register char *p = buf_end; + register const char *digits = (format == 'X') ? upper_digits : low_digits; + + do { + *--p = digits[num & mask]; + num >>= nbits; + } while (num); + *len = (size_t)(buf_end - p); + return p; +} + +/* + * cfg_fmt_format(), the generic printf-style formatting routine + * and heart of this piece of source. + */ +int +cfg_fmt_format( + cfg_fmt_format_t *vbuff, + const char *fmt, + va_list ap) +{ + register char *sp; + register char *bep; + register int cc = 0; + register unsigned int i; + + char *s = NULL; + char *q; + size_t s_len; + + register int min_width = 0; + int precision = 0; + enum { LEFT, RIGHT } adjust; + char pad_char; + char prefix_char; + + double fp_num; + quad_int i_quad = (quad_int)0; + u_quad_int ui_quad; + long_int i_num = (long_int)0; + u_long_int ui_num; + + char num_buf[NUM_BUF_SIZE]; + char char_buf[2]; /* for printing %% and % */ + + enum var_type_enum { IS_QUAD, IS_LONG, IS_SHORT, IS_INT }; + enum var_type_enum var_type = IS_INT; + + int alternate_form; + int print_sign; + int print_blank; + int adjust_precision; + int adjust_width; + int is_negative; + + char extinfo[20]; + + sp = vbuff->curpos; + bep = vbuff->endpos; + + while (*fmt != NUL) { + if (*fmt != '%') { + INS_CHAR(*fmt, sp, bep, cc); + } + else { + /* + * Default variable settings + */ + adjust = RIGHT; + alternate_form = print_sign = print_blank = FALSE; + pad_char = ' '; + prefix_char = NUL; + extinfo[0] = NUL; + + fmt++; + + /* + * Try to avoid checking for flags, width or precision + */ + if (!cfg_fmt_islower(*fmt)) { + /* + * Recognize flags: -, #, BLANK, + + */ + for (;; fmt++) { + if (*fmt == '{') { + i = 0; + for (fmt++; *fmt != '}' && *fmt != NUL; fmt++) { + if (i < sizeof(extinfo)-1) + extinfo[i++] = *fmt; + } + extinfo[i] = NUL; + } + else if (*fmt == '-') + adjust = LEFT; + else if (*fmt == '+') + print_sign = TRUE; + else if (*fmt == '#') + alternate_form = TRUE; + else if (*fmt == ' ') + print_blank = TRUE; + else if (*fmt == '0') + pad_char = '0'; + else + break; + } + + /* + * Check if a width was specified + */ + if (cfg_fmt_isdigit(*fmt)) { + STR_TO_DEC(fmt, min_width); + adjust_width = TRUE; + } + else if (*fmt == '*') { + min_width = va_arg(ap, int); + fmt++; + adjust_width = TRUE; + if (min_width < 0) { + adjust = LEFT; + min_width = -min_width; + } + } + else + adjust_width = FALSE; + + /* + * Check if a precision was specified + * + * XXX: an unreasonable amount of precision may be specified + * resulting in overflow of num_buf. Currently we + * ignore this possibility. + */ + if (*fmt == '.') { + adjust_precision = TRUE; + fmt++; + if (cfg_fmt_isdigit(*fmt)) { + STR_TO_DEC(fmt, precision); + } + else if (*fmt == '*') { + precision = va_arg(ap, int); + fmt++; + if (precision < 0) + precision = 0; + } + else + precision = 0; + } + else + adjust_precision = FALSE; + } + else + adjust_precision = adjust_width = FALSE; + + /* + * Modifier check + */ + if (*fmt == 'q') { + var_type = IS_QUAD; + fmt++; + } + else if (*fmt == 'l') { + var_type = IS_LONG; + fmt++; + } + else if (*fmt == 'h') { + var_type = IS_SHORT; + fmt++; + } + else { + var_type = IS_INT; + } + + /* + * Argument extraction and printing. + * First we determine the argument type. + * Then, we convert the argument to a string. + * On exit from the switch, s points to the string that + * must be printed, s_len has the length of the string + * The precision requirements, if any, are reflected in s_len. + * + * NOTE: pad_char may be set to '0' because of the 0 flag. + * It is reset to ' ' by non-numeric formats + */ + switch (*fmt) { + + /* Unsigned Decimal Integer */ + case 'u': + if (var_type == IS_QUAD) { + i_quad = va_arg(ap, u_quad_int); + s = conv_10_quad(i_quad, 1, &is_negative, + &num_buf[NUM_BUF_SIZE], &s_len); + } + else { + if (var_type == IS_LONG) + i_num = (long_int)va_arg(ap, u_long_int); + else if (var_type == IS_SHORT) + i_num = (long_int)(unsigned short)va_arg(ap, unsigned int); + else + i_num = (long_int)va_arg(ap, unsigned int); + s = conv_10(i_num, 1, &is_negative, + &num_buf[NUM_BUF_SIZE], &s_len); + } + FIX_PRECISION(adjust_precision, precision, s, s_len); + break; + + /* Signed Decimal Integer */ + case 'd': + case 'i': + if (var_type == IS_QUAD) { + i_quad = va_arg(ap, quad_int); + s = conv_10_quad(i_quad, 0, &is_negative, + &num_buf[NUM_BUF_SIZE], &s_len); + } + else { + if (var_type == IS_LONG) + i_num = (long_int)va_arg(ap, long_int); + else if (var_type == IS_SHORT) + i_num = (long_int)(short)va_arg(ap, int); + else + i_num = (long_int)va_arg(ap, int); + s = conv_10(i_num, 0, &is_negative, + &num_buf[NUM_BUF_SIZE], &s_len); + } + FIX_PRECISION(adjust_precision, precision, s, s_len); + + if (is_negative) + prefix_char = '-'; + else if (print_sign) + prefix_char = '+'; + else if (print_blank) + prefix_char = ' '; + break; + + /* Unsigned Octal Integer */ + case 'o': + if (var_type == IS_QUAD) { + ui_quad = va_arg(ap, u_quad_int); + s = conv_p2_quad(ui_quad, 3, *fmt, + &num_buf[NUM_BUF_SIZE], &s_len); + } + else { + if (var_type == IS_LONG) + ui_num = (u_long_int) va_arg(ap, u_long_int); + else if (var_type == IS_SHORT) + ui_num = (u_long_int)(unsigned short)va_arg(ap, unsigned int); + else + ui_num = (u_long_int)va_arg(ap, unsigned int); + s = conv_p2(ui_num, 3, *fmt, &num_buf[NUM_BUF_SIZE], &s_len); + } + FIX_PRECISION(adjust_precision, precision, s, s_len); + if (alternate_form && *s != '0') { + *--s = '0'; + s_len++; + } + break; + + /* Unsigned Hexadecimal Integer */ + case 'x': + case 'X': + if (var_type == IS_QUAD) { + ui_quad = va_arg(ap, u_quad_int); + s = conv_p2_quad(ui_quad, 4, *fmt, + &num_buf[NUM_BUF_SIZE], &s_len); + } + else { + if (var_type == IS_LONG) + ui_num = (u_long_int)va_arg(ap, u_long_int); + else if (var_type == IS_SHORT) + ui_num = (u_long_int)(unsigned short)va_arg(ap, unsigned int); + else + ui_num = (u_long_int)va_arg(ap, unsigned int); + s = conv_p2(ui_num, 4, *fmt, &num_buf[NUM_BUF_SIZE], &s_len); + } + FIX_PRECISION(adjust_precision, precision, s, s_len); + if (alternate_form && i_num != 0) { + *--s = *fmt; /* 'x' or 'X' */ + *--s = '0'; + s_len += 2; + } + break; + + /* String */ + case 's': + s = va_arg(ap, char *); + if (s != NULL) { + s_len = strlen(s); + if (adjust_precision && precision < s_len) + s_len = precision; + } + else { + s = S_NULL; + s_len = S_NULL_LEN; + } + pad_char = ' '; + break; + + /* Double Floating Point (style 1) */ + case 'f': + case 'e': + case 'E': + fp_num = va_arg(ap, double); + if (isnan(fp_num)) { + s = "NaN"; + s_len = 3; + } + else if (isinf(fp_num)) { + s = "Inf"; + s_len = 3; + } + else { + /* use &num_buf[1], so that we have room for the sign */ + s = conv_fp(*fmt, fp_num, alternate_form, + (adjust_precision == FALSE) ? FLOAT_DIGITS : precision, + &is_negative, &num_buf[1], &s_len); + if (is_negative) + prefix_char = '-'; + else if (print_sign) + prefix_char = '+'; + else if (print_blank) + prefix_char = ' '; + } + break; + + /* Double Floating Point (style 2) */ + case 'g': + case 'G': + fp_num = va_arg(ap, double); + if (isnan(fp_num)) { + s = "NaN"; + s_len = 3; + } + else if (isinf(fp_num)) { + s = "Inf"; + s_len = 3; + } + else { + if (adjust_precision == FALSE) + precision = FLOAT_DIGITS; + else if (precision == 0) + precision = 1; + /* use &num_buf[1], so that we have room for the sign */ + s = cfg_fmt_gcvt(fp_num, precision, &num_buf[1], alternate_form); + if (*s == '-') + prefix_char = *s++; + else if (print_sign) + prefix_char = '+'; + else if (print_blank) + prefix_char = ' '; + s_len = strlen(s); + if (alternate_form && (q = strchr(s, '.')) == NULL) { + s[s_len++] = '.'; + s[s_len] = NUL; /* delimit for following strchr() */ + } + if (*fmt == 'G' && (q = strchr(s, 'e')) != NULL) + *q = 'E'; + } + break; + + /* Single Character */ + case 'c': + char_buf[0] = (char) (va_arg(ap, int)); + s = &char_buf[0]; + s_len = 1; + pad_char = ' '; + break; + + /* The '%' Character */ + case '%': + char_buf[0] = '%'; + s = &char_buf[0]; + s_len = 1; + pad_char = ' '; + break; + + /* Special: Number of already written characters */ + case 'n': + if (var_type == IS_QUAD) + *(va_arg(ap, quad_int *)) = cc; + else if (var_type == IS_LONG) + *(va_arg(ap, long *)) = cc; + else if (var_type == IS_SHORT) + *(va_arg(ap, short *)) = cc; + else + *(va_arg(ap, int *)) = cc; + break; + + /* + * Pointer argument type. + */ + case 'p': +#if defined(SIZEOF_LONG_LONG) && (SIZEOF_LONG_LONG == SIZEOF_VOID_P) + ui_quad = (u_quad_int) va_arg(ap, void *); + s = conv_p2_quad(ui_quad, 4, 'x', &num_buf[NUM_BUF_SIZE], &s_len); +#else + ui_num = (u_long_int) va_arg(ap, void *); + s = conv_p2(ui_num, 4, 'x', &num_buf[NUM_BUF_SIZE], &s_len); +#endif + pad_char = ' '; + break; + + case NUL: + /* + * The last character of the format string was %. + * We ignore it. + */ + continue; + + /* + * The default case is for unrecognized %'s. We print + * % to help the user identify what option is not + * understood. This is also useful in case the user + * wants to pass the output of format_converter to + * another function that understands some other % + * (like syslog). Note that we can't point s inside fmt + * because the unknown could be preceded by width + * etc. + */ + default: + s = NULL; + if (vbuff->format != NULL) { + vbuff->format(vbuff, + &prefix_char, &pad_char, &s, &s_len, + num_buf, NUM_BUF_SIZE, extinfo, *fmt, &ap); + if (s == NULL) + return -1; + } + if (s == NULL) { + char_buf[0] = '%'; + char_buf[1] = *fmt; + s = char_buf; + s_len = 2; + pad_char = ' '; + } + break; + } + + if (prefix_char != NUL && s != S_NULL && s != char_buf) { + *--s = prefix_char; + s_len++; + } + + if (adjust_width && adjust == RIGHT && min_width > s_len) { + if (pad_char == '0' && prefix_char != NUL) { + INS_CHAR(*s, sp, bep, cc); + s++; + s_len--; + min_width--; + } + PAD(min_width, s_len, pad_char); + } + + /* + * Print the string s. + */ + for (i = s_len; i != 0; i--) { + INS_CHAR(*s, sp, bep, cc); + s++; + } + + if (adjust_width && adjust == LEFT && min_width > s_len) + PAD(min_width, s_len, pad_char); + } + fmt++; + } + vbuff->curpos = sp; + return cc; +} + +/* + * cfg_fmt_format -- format a new string. + * This is inspired by POSIX sprintf(3), but mainly provides the + * following differences: first it is actually a snprintf(3) style, i.e. + * it allows one to specify the maximum number of characters which are + * allowed to write. Second, it allows one to just count the number of + * characters which have to be written. + */ + +#define STR_FORMAT_BUFLEN 20 + +static int cfg_fmt_flush_fake(cfg_fmt_format_t *out_handle) +{ + out_handle->data[1].i += out_handle->data[2].i; + out_handle->curpos = (char *)out_handle->data[0].vp; + return 0; +} + +static int cfg_fmt_flush_real(cfg_fmt_format_t *out_handle) +{ + return -1; +} + +int cfg_fmt_vsprintf(char *s, size_t n, const char *fmt, va_list ap) +{ + cfg_fmt_format_t handle; + char buf[STR_FORMAT_BUFLEN]; + int rv; + + if (n == 0) + return 0; + if (s == NULL) { + /* fake formatting, i.e., calculate output length only */ + handle.curpos = buf; + handle.endpos = buf + sizeof(buf) - 1; + handle.flush = cfg_fmt_flush_fake; + handle.format = NULL; + handle.data[0].vp = buf; + handle.data[1].i = 0; + handle.data[2].i = sizeof(buf); + rv = cfg_fmt_format(&handle, fmt, ap); + if (rv == -1) + rv = (int)n; + } + else { + /* real formatting, i.e., create output */ + handle.curpos = s; + handle.endpos = s + n - 1; + handle.flush = cfg_fmt_flush_real; + handle.format = NULL; + rv = cfg_fmt_format(&handle, fmt, ap); + *(handle.curpos) = NUL; + if (rv == -1) + rv = (int)n; + } + return rv; +} + +char *cfg_fmt_vasprintf(const char *fmt, va_list ap) +{ + va_list apbak; + char *s; + int rv; + + apbak = ap; + if ((rv = cfg_fmt_vsprintf(NULL, -1, fmt, ap)) == -1) + return NULL; + if ((s = malloc(rv+1)) == NULL) + return NULL; + ap = apbak; + if ((rv = cfg_fmt_vsprintf(s, rv+1, fmt, ap)) == -1) + return NULL; + return s; +} + +int cfg_fmt_sprintf(char *s, size_t n, const char *fmt, ...) +{ + va_list ap; + int rv; + + va_start(ap, fmt); + rv = cfg_fmt_vsprintf(s, n, fmt, ap); + va_end(ap); + return rv; +} + +char *cfg_fmt_asprintf(const char *fmt, ...) +{ + va_list ap; + char *rv; + + va_start(ap, fmt); + rv = cfg_fmt_vasprintf(fmt, ap); + va_end(ap); + return rv; +} + Index: ossp-pkg/cfg/cfg_fmt.h RCS File: /v/ossp/cvs/ossp-pkg/cfg/cfg_fmt.h,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/cfg/cfg_fmt.h,v' | diff -u /dev/null - -L'ossp-pkg/cfg/cfg_fmt.h' 2>/dev/null --- ossp-pkg/cfg/cfg_fmt.h +++ - 2024-05-15 10:58:11.044294640 +0200 @@ -0,0 +1,76 @@ +/* +** OSSP cfg - Configuration Parsing +** Copyright (c) 1999-2002 Ralf S. Engelschall +** Copyright (c) 1999-2002 The OSSP Project (http://www.ossp.org/) +** Copyright (c) 2001-2002 Cable & Wireless Deutschland (http://www.cw.com/de/) +** +** This file is part of OSSP cfg, a configuration parsing +** library which can be found at http://www.ossp.org/pkg/lib/cfg/. +** +** Permission to use, copy, modify, and distribute this software for +** any purpose with or without fee is hereby granted, provided that +** the above copyright notice and this permission notice appear in all +** copies. +** +** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR +** CONTRIBUTORS 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 CONTRCFG, 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 DAMAGE. +** +** cfg_fmt.h: printf(3)-style formatting API +*/ + +#ifndef __CFG_FMT_H__ +#define __CFG_FMT_H__ + +struct cfg_fmt_format_st { + /* the output buffer */ + char *curpos; /* start of output buffer (first pos) */ + char *endpos; /* end of output buffer (last pos) */ + + /* callback for flushing the output buffer */ + int (*flush)( + struct cfg_fmt_format_st *spec /* this cfg_fmt_format_t specification */ + ); + + /* callback for formatting unknown %-constructs */ + void (*format)( + struct cfg_fmt_format_st *spec, /* this cfg_fmt_format_t specification */ + char *prefix_char, /* output arg: prefix character */ + char *pad_char, /* output arg: padding character */ + char **s_buf, /* output arg: string buffer */ + size_t *s_len, /* output arg: string len */ + char *num_buf, /* input arg: temporary buffer */ + int num_buf_size, /* input arg: temporary buffer len */ + char *extinfo, /* input arg: extension information */ + char fmt_char, /* input arg: current formatting character */ + va_list *ap /* in/out arg: variable argument pointer */ + ); + + /* arbitrary passed-through application data */ + union { + int i; + long l; + double d; + void *vp; + } data[6]; +}; + +typedef struct cfg_fmt_format_st cfg_fmt_format_t; + +int cfg_fmt_format (cfg_fmt_format_t *vbuff, const char *fmt, va_list ap); +int cfg_fmt_vsprintf (char *s, size_t n, const char *fmt, va_list ap); +char *cfg_fmt_vasprintf (const char *fmt, va_list ap); +int cfg_fmt_sprintf (char *s, size_t n, const char *fmt, ...); +char *cfg_fmt_asprintf (const char *fmt, ...); + +#endif /* __CFG_FMT_H__ */ + Index: ossp-pkg/cfg/cfg_grid.c RCS File: /v/ossp/cvs/ossp-pkg/cfg/cfg_grid.c,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/cfg/cfg_grid.c,v' | diff -u /dev/null - -L'ossp-pkg/cfg/cfg_grid.c' 2>/dev/null --- ossp-pkg/cfg/cfg_grid.c +++ - 2024-05-15 10:58:11.046875358 +0200 @@ -0,0 +1,511 @@ +/* +** OSSP cfg - Configuration Parsing +** Copyright (c) 1999-2002 Ralf S. Engelschall +** Copyright (c) 1999-2002 The OSSP Project (http://www.ossp.org/) +** Copyright (c) 2001-2002 Cable & Wireless Deutschland (http://www.cw.com/de/) +** +** This file is part of OSSP cfg, a configuration parsing +** library which can be found at http://www.ossp.org/pkg/lib/cfg/. +** +** Permission to use, copy, modify, and distribute this software for +** any purpose with or without fee is hereby granted, provided that +** the above copyright notice and this permission notice appear in all +** copies. +** +** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR +** CONTRIBUTORS 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 CONTRCFG, 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 DAMAGE. +** +** cfg_grid.c: grid memory allocator (implementation) +*/ + +/* + * This is a special-case memory management library dedicated to the + * speed- and memory-optimized allocation and deallocation of fixed + * size objects. Inside OSSP cfg we have lots of those objects and + * if we would manage them directly through malloc(3) it would be to + * run-time expensive and waste too much total memory. + * + * It works by collecting together larger segments (cfg_grid_seg_t) of + * those fixed size objects (cfg_grid_tile_t) and linking them into + * a top-level grid structure (cfg_grid_t). The number of tiles in a + * segment grows with the Fibonacci numbers f(n) = f(n-1)+f(n-2) in + * order to dynamically scale better to the allocation requests without + * having to waste too much memory (in contrast to the usual "double to + * twice of size" approach). Inside a grid segment, the tiles are just + * arranged as a linear array after a heading linkage structure. The + * free tiles are remembered in a single linked list. So the grid in + * memory looks like this: + * + * -----BEGIN EMBEDDED OBJECT----- + * Content-type: application/fig + * Description: grid memory allocator memory architecture + * Version: eo/1.0 + * H4sIAOT/mDwCA61aTW/cNhA9R79CQM82+DUUdS7QIkBuvfYSJAvXQLIoYv9/VOKI + * b0itg/i5RhD6rcX5nqFm6P3tj49/zvE+TJ8+X78+ffn872X6/XJ9vvyYPl6//HN5 + * mj5dnrdP8zx55+6dm/56vD58u0x3YfLBuTlMefbiZu+2ZdlB2TaFOcwb3P6HdZb6 + * 0807+bZu/5a6yvRBSXc+ywA2HvoIIIxcyyzuF1yhEEDomGHPxtUfXBdleuc7pvuH + * XdDGNbqDtAI185WkqUlNwpLmJjXTUquJsVkfhSWVFg6hpeYmNQsRt+rYXeEkPZDm + * c4DIcM3uZAs000cA4lhdc1MRoHT5gT1k5t7am8WZX9ue6S5vxbe6I8Xrbq76VmfF + * MKBd+XUAVP2ddDIUOnbYRaSWQ/U6upCUzhaOOEJypCWvIBPHFuKKmIhjK3HtUodO + * RNdKsLPaEuQUXKoeO1eclgyZhqiiVG0ydDVU+qSxfWROv2T7LgOebru0NlX+viuE + * fUmULSNxh06mZfpNpj6AXw69Xku8QvIqLHHwTXJFpGRkhfqBe6OhEJRYeMkZkrlS + * KiigVQaEs7ZDVCmpOwejTMPjqSGhOjMkmCUdsvjgmvpEZB0iN6fTsRQ3oDcEqkDr + * whOviPJK55cmdTgQSxz6hXUndO9QcbcLl7orPOJdj04fsY/U+iU2CFyPvGOrYvRm + * l7o4eGyfntYRY0PcG8St8XLtt3W7/fbVRXQiHtnoU0PcYRhjM6OiQ6/XEidok4Qm + * zpCcecnVUmlO3hFLvMCdCy+5QHKhJpPq7ap2kgEtLQIdEop1dmejTMPjqaHF0VoX + * 6AqkSdfyxvYRrP3PjK9CzNdt315jHHcrxQ6FVi0d4qZ4G+Mj3YFEDPKoILJulDjz + * kjHMR36ajzZW8vN8xOAZ3zDRY6SPmOmjDfU25fJjfcRcD6NMw+OpIaGPbY3UMiA9 + * 9fyAuN6nM9mCYh7GtI99bKAKtC488Yoor/y57OElz5/LAedy4PMrI6sMFWSVIS51 + * EzySXY/U0CQ94nofPXleYKNuiG5AVO+jGg7e7FN3fHVb76P9UMILgepyTsQjm/MD + * cl4UtG1CNyr1paTEC92o1LeXEhde8qAx2eWMGpNdzqgx+VJXb0t7s3fo9FGE7XLU + * nYNRpuHNQnU5qg34nyUNUWAdkn5m/Jgd2Ed1OTo/u6Zfh0JL3A5RXU5VUomFv6RZ + * IHnhK7ZAcuElJ7QLjr4qVWJpgedennaXocSZrhu9mFrcgKRFoEORrpvRKNPweGpI + * 6GO7/UGrR3ae28J1OZ3JCEp3byQyoDcEqkDrwhOviPLKn8seXvL8uRxwFgU+vzKy + * ylBBVhniUnfBvUuRHunlyOJ6xHU5evK8wEbvYkQGxN3wFDl7s0/d0+Ec6PnQpuIU + * 6PlQiXdEEmdIzrxk34ZtvV/ydP+uhi8HYokTJCe6E+44GIrudvH0fDgaZRoeTw1F + * eojrVD8ZEd3ZCNabGbpmnnjpF5Z4heSVlpxwTZMcnwRJbhcLoaFED3HwZI9WyDS0 + * 8Fq/wEbdUA8PoMObTOqO3jxQ6E8H20debeghswwo4T7N0Gno2eJ9mwRLfZSmD34D + * /r5+UeVeG4b960LHd1/c8f2IEkQ/AJz62rfJ6L4TsKPKvPTgfaSszZSKdub13QXw + * LlL0TevaK35nXlMI4F2kRIQltrikFpd0+PD/mxI3bvWiYQdHvuGnHxM3ul//USd2 + * A50CXMjkrjmbkpLti8+bIOW46Tof19Hb1kVqRj78ePz6t3P+RJONZKl+V5X9ZsfT + * 5eH75fr8KiLNFpqqvEWWpiBLFTm7crVpzruWcQPPj98uleI/a7orF0koAAA= + * -----END EMBEDDED OBJECT----- + */ + +#include "cfg_grid.h" + +/* macro set for implementing single-linked lists */ +#define CFG_LIST_HEAD(type)\ + struct { type *first; } +#define CFG_LIST_ELEM(type) \ + struct { type *next; } +#define CFG_LIST_INIT(hp) \ + CFG_LIST_FIRST((hp)) = NULL +#define CFG_LIST_ELEM_INIT(ep, field) \ + CFG_LIST_NEXT((ep), field) = NULL +#define CFG_LIST_FIRST(hp) \ + ((hp)->first) +#define CFG_LIST_NEXT(ep, field) \ + ((ep)->field.next) +#define CFG_LIST_INSERT_HEAD(hp, ep, field) \ + do { CFG_LIST_NEXT((ep), field) = CFG_LIST_FIRST((hp)); \ + CFG_LIST_FIRST((hp)) = (ep); } while (0) +#define CFG_LIST_REMOVE_HEAD(hp, field) \ + CFG_LIST_FIRST((hp)) = \ + CFG_LIST_NEXT(CFG_LIST_FIRST((hp)), field) + +/* macro set for implementing double-linked rings */ +#define CFG_RING_HEAD(type) \ + struct { type *next; type *prev; } +#define CFG_RING_ELEM(type) \ + struct { type *next; type *prev; } +#define CFG_RING_SENTINEL(hp, type, field) \ + (type *)((char *)(hp) - ((size_t)(&((type *)0)->field))) +#define CFG_RING_INIT(hp, type, field) \ + do { CFG_RING_FIRST((hp)) = CFG_RING_SENTINEL((hp), type, field); \ + CFG_RING_LAST((hp)) = CFG_RING_SENTINEL((hp), type, field); } while (0) +#define CFG_RING_ELEM_INIT(ep, field) \ + do { CFG_RING_NEXT((ep), field) = (ep); \ + CFG_RING_PREV((ep), field) = (ep); } while (0) +#define CFG_RING_FIRST(hp) \ + ((hp)->next) +#define CFG_RING_LAST(hp) \ + ((hp)->prev) +#define CFG_RING_NEXT(ep, field) \ + ((ep)->field.next) +#define CFG_RING_PREV(ep, field) \ + ((ep)->field.prev) +#define CFG_RING_SPLICE_BEFORE(lep, ep1, epN, field) \ + do { \ + CFG_RING_NEXT((epN), field) = (lep); \ + CFG_RING_PREV((ep1), field) = CFG_RING_PREV((lep), field); \ + CFG_RING_NEXT(CFG_RING_PREV((lep), field), field) = (ep1); \ + CFG_RING_PREV((lep), field) = (epN); \ + } while (0) +#define CFG_RING_SPLICE_AFTER(lep, ep1, epN, field) \ + do { \ + CFG_RING_PREV((ep1), field) = (lep); \ + CFG_RING_NEXT((epN), field) = CFG_RING_NEXT((lep), field); \ + CFG_RING_PREV(CFG_RING_NEXT((lep), field), field) = (epN); \ + CFG_RING_NEXT((lep), field) = (ep1); \ + } while (0) +#define CFG_RING_SPLICE_HEAD(hp, ep1, epN, type, field) \ + CFG_RING_SPLICE_AFTER(CFG_RING_SENTINEL((hp), type, field), (ep1), (epN), field) +#define CFG_RING_SPLICE_TAIL(hp, ep1, epN, type, field) \ + CFG_RING_SPLICE_BEFORE(CFG_RING_SENTINEL((hp), type, field), (ep1), (epN), field) +#define CFG_RING_INSERT_BEFORE(lep, nep, field) \ + CFG_RING_SPLICE_BEFORE((lep), (nep), (nep), field) +#define CFG_RING_INSERT_AFTER(lep, nep, field) \ + CFG_RING_SPLICE_AFTER((lep), (nep), (nep), field) +#define CFG_RING_INSERT_HEAD(hp, nep, type, field) \ + CFG_RING_SPLICE_HEAD((hp), (nep), (nep), type, field) +#define CFG_RING_INSERT_TAIL(hp, nep, type, field) \ + CFG_RING_SPLICE_TAIL((hp), (nep), (nep), type, field) +#define CFG_RING_UNSPLICE(ep1, epN, field) \ + do { \ + CFG_RING_NEXT(CFG_RING_PREV((ep1), field), field) = \ + CFG_RING_NEXT((epN), field); \ + CFG_RING_PREV(CFG_RING_NEXT((epN), field), field) = \ + CFG_RING_PREV((ep1), field); \ + } while (0) +#define CFG_RING_REMOVE(ep, field) \ + CFG_RING_UNSPLICE((ep), (ep), field) +#define CFG_RING_FOREACH(ep, hp, type, field) \ + for ((ep) = CFG_RING_FIRST((hp)); \ + (ep) != CFG_RING_SENTINEL((hp), type, field); \ + (ep) = CFG_RING_NEXT((ep), field)) +#define CFG_RING_FOREACH_REVERSE(ep, hp, type, field) \ + for ((ep) = CFG_RING_LAST((hp)); \ + (ep) != CFG_RING_SENTINEL((hp), type, field); \ + (ep) = CFG_RING_PREV((ep), field)) + +/* forward declarations */ +struct cfg_grid_tile_st; +struct cfg_grid_seg_st; + +/* corresponding types */ +typedef struct cfg_grid_tile_st cfg_grid_tile_t; +typedef struct cfg_grid_seg_st cfg_grid_seg_t; + +/* the structure of a grid tile */ +struct cfg_grid_tile_st { + CFG_LIST_ELEM(cfg_grid_tile_t) gt_link; /* linkage to next tile */ +}; + +/* the structure of a grid segment */ +struct cfg_grid_seg_st { + CFG_RING_ELEM(cfg_grid_seg_t) gs_link; /* linkage to next+prev segments */ + cfg_grid_tile_t *gs_tile_base; /* pointer to tile base */ + int gs_tile_num; /* number of tiles */ + CFG_LIST_HEAD(cfg_grid_tile_t) gs_tile_free_list; /* list of free tiles */ + int gs_tile_free_num; /* number of free tiles */ +}; + +/* the structure of a grid */ +struct cfg_grid_st { + CFG_RING_HEAD(cfg_grid_seg_t) g_seg; /* ring of segments */ + int g_seg_num; /* number of segments */ + size_t g_tile_size; /* size of a tile */ + int g_tile_num_first; /* number of tiles in first segment */ +}; + +/* + * Align a size to the next larger or equal size which is likely to have the + * longest *relevant* CPU-specific memory word alignment restrictions. + */ +static size_t cfg_mem_align(size_t size) +{ + union mem_word { + void *mw_vp; + void (*mw_fp)(void); + char *mw_cp; + long mw_l; + double mw_d; + }; + return ((1+((size-1) / sizeof(union mem_word))) * sizeof(union mem_word)); +} + +/* create a grid segment [INTERNAL] */ +static cfg_rc_t +cfg_grid_seg_create( + cfg_grid_seg_t **pseg, + size_t tile_size, + int tile_num) +{ + size_t seg_top_size; + size_t seg_size; + cfg_grid_seg_t *seg; + cfg_grid_tile_t *tile; + int i; + + /* determine (aligned) sizes */ + seg_top_size = cfg_mem_align(sizeof(cfg_grid_seg_t)); + seg_size = seg_top_size + (tile_size * tile_num); + + /* allocate first segment */ + if ((seg = (cfg_grid_seg_t *)malloc(seg_size)) == NULL) + return CFG_ERR_SYS; + + /* initialize first segment */ + CFG_RING_ELEM_INIT(seg, gs_link); + seg->gs_tile_base = (cfg_grid_tile_t *)((char *)seg + seg_top_size); + seg->gs_tile_num = tile_num; + CFG_LIST_ELEM_INIT(seg->gs_tile_base, gt_link); + CFG_LIST_INIT(&seg->gs_tile_free_list); + CFG_LIST_INSERT_HEAD(&seg->gs_tile_free_list, seg->gs_tile_base, gt_link); + seg->gs_tile_free_num = seg->gs_tile_num; + + /* initialize free tile list in first segment */ + tile = CFG_LIST_FIRST(&seg->gs_tile_free_list); + for (i = 0; i < seg->gs_tile_free_num-1; i++) { + CFG_LIST_NEXT(tile, gt_link) = (cfg_grid_tile_t *)((char *)tile+tile_size); + tile = CFG_LIST_NEXT(tile, gt_link); + } + CFG_LIST_NEXT(tile, gt_link) = NULL; + + /* pass segment to caller */ + *pseg = seg; + + return CFG_OK; +} + +/* create a grid */ +cfg_rc_t +cfg_grid_create( + cfg_grid_t **pgrid, + size_t tile_size, + int tile_num) +{ + cfg_grid_t *grid; + cfg_grid_seg_t *seg; + cfg_rc_t rc; + + /* consistency checks */ + if (tile_size < 1) + return CFG_ERR_ARG; + if (tile_num < 1) + return CFG_ERR_ARG; + + /* determine (aligned) sizes */ + tile_size = cfg_mem_align(tile_size); + + /* allocate top-level grid structure */ + if ((grid = (cfg_grid_t *)malloc(sizeof(cfg_grid_t))) == NULL) + return CFG_ERR_SYS; + + /* allocate first segment */ + if ((rc = cfg_grid_seg_create(&seg, tile_size, tile_num)) != CFG_OK) { + free(grid); + return rc; + } + + /* initialize top-level structure */ + CFG_RING_INIT(&grid->g_seg, cfg_grid_seg_t, gs_link); + CFG_RING_INSERT_HEAD(&grid->g_seg, seg, cfg_grid_seg_t, gs_link); + grid->g_seg_num = 1; + grid->g_tile_size = tile_size; + grid->g_tile_num_first = tile_num; + + /* pass grid to caller */ + *pgrid = grid; + + return CFG_OK; +} + +/* destroy a grid */ +cfg_rc_t +cfg_grid_destroy( + cfg_grid_t *grid) +{ + cfg_grid_seg_t *seg; + cfg_grid_seg_t *seg_last; + + /* consistency checks */ + if (grid == NULL) + return CFG_ERR_ARG; + + /* destroy grid segments */ + seg_last = CFG_RING_FIRST(&grid->g_seg); + while (seg_last != CFG_RING_SENTINEL(&grid->g_seg, cfg_grid_seg_t, gs_link)) { + seg = CFG_RING_NEXT(seg_last, gs_link); + free(seg_last); + } + + /* destroy top-level grid structure */ + free(grid); + + return CFG_OK; +} + +/* allocate a tile from a grid */ +cfg_rc_t +cfg_grid_alloc( + cfg_grid_t *grid, + void **ptile) +{ + cfg_grid_seg_t *seg; + cfg_grid_seg_t *seg_l1; + cfg_grid_seg_t *seg_l2; + cfg_grid_tile_t *tile; + cfg_rc_t rc; + int tile_num; + + /* consistency checks */ + if (grid == NULL || ptile == NULL) + return CFG_ERR_ARG; + + /* find segment with first free tile */ + seg_l2 = NULL; + seg_l1 = NULL; + seg = CFG_RING_FIRST(&grid->g_seg); + while (seg != CFG_RING_SENTINEL(&grid->g_seg, cfg_grid_seg_t, gs_link)) { + if (seg->gs_tile_free_num > 0) + break; + seg_l2 = seg_l1; + seg_l1 = seg; + seg = CFG_RING_NEXT(seg, gs_link); + } + + /* if no more segment with a free tile exists, add new segment */ + if (seg == CFG_RING_SENTINEL(&grid->g_seg, cfg_grid_seg_t, gs_link)) { + /* tile_num increases with Fibonacci behaviour, i.e, + tile_num(seg) = tile_num(seg_l1) + tile_num(seg_l2). This way + the segments grow in size exponentially but not as fast as + twith he usual "double the size" approach. */ + if (seg_l2 == NULL) + tile_num = grid->g_tile_num_first; + else + tile_num = seg_l1->gs_tile_num + seg_l2->gs_tile_num; + if ((rc = cfg_grid_seg_create(&seg, grid->g_tile_size, tile_num)) != CFG_OK) + return rc; + CFG_RING_INSERT_TAIL(&grid->g_seg, seg, cfg_grid_seg_t, gs_link); + grid->g_seg_num++; + } + + /* allocate tile from segment */ + tile = CFG_LIST_FIRST(&seg->gs_tile_free_list); + CFG_LIST_REMOVE_HEAD(&seg->gs_tile_free_list, gt_link); + seg->gs_tile_free_num--; + + /* pass tile to caller */ + *ptile = tile; + + return CFG_OK; +} + +/* find grid segment where tile is stored [INTERNAL] */ +static cfg_rc_t +cfg_grid_seg_find( + cfg_grid_t *grid, + cfg_grid_seg_t **pseg, + cfg_grid_tile_t *tile) +{ + cfg_grid_seg_t *seg; + + seg = CFG_RING_FIRST(&grid->g_seg); + while (seg != CFG_RING_SENTINEL(&grid->g_seg, cfg_grid_seg_t, gs_link)) { + if ( seg->gs_tile_base <= tile + && tile < (seg->gs_tile_base+(grid->g_tile_size*seg->gs_tile_num))) { + if (pseg != NULL) + *pseg = seg; + return CFG_OK; + } + seg = CFG_RING_NEXT(seg, gs_link); + } + return CFG_ERR_INT; +} + +/* free a tile to a grid */ +cfg_rc_t +cfg_grid_free( + cfg_grid_t *grid, + void *_tile) +{ + cfg_grid_seg_t *seg; + cfg_grid_tile_t *tile; + cfg_rc_t rc; + + /* cast to internal structure */ + tile = (cfg_grid_tile_t *)_tile; + + /* consistency checks */ + if (grid == NULL || tile == NULL) + return CFG_ERR_ARG; + + /* find segment of tile */ + if ((rc = cfg_grid_seg_find(grid, &seg, tile)) != CFG_OK) + return rc; + + /* move into list of free tiles */ + CFG_LIST_INSERT_HEAD(&seg->gs_tile_free_list, tile, gt_link); + seg->gs_tile_free_num++; + + /* free segment if it is now empty */ + if ( grid->g_seg_num > 1 + && seg->gs_tile_num == seg->gs_tile_free_num) { + CFG_RING_REMOVE(seg, gs_link); + grid->g_seg_num--; + free(seg); + } + + return CFG_OK; +} + +/* test whether a tile is inside a grid */ +cfg_rc_t +cfg_grid_inside( + cfg_grid_t *grid, + void *_tile) +{ + cfg_grid_tile_t *tile; + + /* cast to internal structure */ + tile = (cfg_grid_tile_t *)_tile; + + /* consistency checks */ + if (grid == NULL || tile == NULL) + return CFG_ERR_ARG; + + /* just try to find a segment */ + return cfg_grid_seg_find(grid, NULL, tile); +} + +/* determine grid statistics */ +cfg_rc_t +cfg_grid_stat( + cfg_grid_t *grid, + int *pchunks, + int *pbytes_mgmt, int *pbytes_used, int *pbytes_free, + int *ptiles_used, int *ptiles_free) +{ + cfg_grid_seg_t *seg; + int chunks = 0; + int bytes_mgmt = 0; + int bytes_used = 0; + int bytes_free = 0; + int tiles_used = 0; + int tiles_free = 0; + + /* consistency checks */ + if (grid == NULL) + return CFG_ERR_ARG; + + /* determine statistic information */ + bytes_mgmt += sizeof(cfg_grid_t); + chunks += 1; + CFG_RING_FOREACH(seg, &grid->g_seg, cfg_grid_seg_t, gs_link) { + chunks++; + bytes_mgmt += sizeof(cfg_grid_seg_t); + bytes_used += ((seg->gs_tile_num - seg->gs_tile_free_num) * grid->g_tile_size); + bytes_free += (seg->gs_tile_free_num * grid->g_tile_size); + tiles_used += (seg->gs_tile_num - seg->gs_tile_free_num); + tiles_free += seg->gs_tile_free_num; + } + + /* pass statistic information to caller */ + if (pchunks != NULL) + *pchunks = chunks; + if (pbytes_mgmt != NULL) + *pbytes_mgmt = bytes_mgmt; + if (pbytes_used != NULL) + *pbytes_used = bytes_used; + if (pbytes_free != NULL) + *pbytes_free = bytes_free; + if (ptiles_used != NULL) + *ptiles_used = tiles_used; + if (ptiles_free != NULL) + *ptiles_free = tiles_free; + + return CFG_OK; +} + Index: ossp-pkg/cfg/cfg_grid.h RCS File: /v/ossp/cvs/ossp-pkg/cfg/cfg_grid.h,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/cfg/cfg_grid.h,v' | diff -u /dev/null - -L'ossp-pkg/cfg/cfg_grid.h' 2>/dev/null --- ossp-pkg/cfg/cfg_grid.h +++ - 2024-05-15 10:58:11.049729988 +0200 @@ -0,0 +1,50 @@ +/* +** OSSP cfg - Configuration Parsing +** Copyright (c) 1999-2002 Ralf S. Engelschall +** Copyright (c) 1999-2002 The OSSP Project (http://www.ossp.org/) +** Copyright (c) 2001-2002 Cable & Wireless Deutschland (http://www.cw.com/de/) +** +** This file is part of OSSP cfg, a configuration parsing +** library which can be found at http://www.ossp.org/pkg/lib/cfg/. +** +** Permission to use, copy, modify, and distribute this software for +** any purpose with or without fee is hereby granted, provided that +** the above copyright notice and this permission notice appear in all +** copies. +** +** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR +** CONTRIBUTORS 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 CONTRCFG, 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 DAMAGE. +** +** cfg_grid.h: grid memory allocator (declaration) +*/ + +#ifndef __CFG_GRID_H__ +#define __CFG_GRID_H__ + +#include +#include + +#include "cfg.h" + +struct cfg_grid_st; +typedef struct cfg_grid_st cfg_grid_t; + +extern cfg_rc_t cfg_grid_create (cfg_grid_t **grid, size_t tile_size, int tile_num); +extern cfg_rc_t cfg_grid_alloc (cfg_grid_t *grid, void **tile); +extern cfg_rc_t cfg_grid_inside (cfg_grid_t *grid, void *tile); +extern cfg_rc_t cfg_grid_free (cfg_grid_t *grid, void *tile); +extern cfg_rc_t cfg_grid_stat (cfg_grid_t *grid, int *chunks, int *bytes_mgmt, int *bytes_used, int *bytes_free, int *tiles_used, int *tiles_free); +extern cfg_rc_t cfg_grid_destroy(cfg_grid_t *grid); + +#endif /* __CFG_GRID_H__ */ + Index: ossp-pkg/cfg/cfg_node.c RCS File: /v/ossp/cvs/ossp-pkg/cfg/cfg_node.c,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/cfg/cfg_node.c,v' | diff -u /dev/null - -L'ossp-pkg/cfg/cfg_node.c' 2>/dev/null --- ossp-pkg/cfg/cfg_node.c +++ - 2024-05-15 10:58:11.052284966 +0200 @@ -0,0 +1,233 @@ +/* +** OSSP cfg - Configuration Parsing +** Copyright (c) 1999-2002 Ralf S. Engelschall +** Copyright (c) 1999-2002 The OSSP Project (http://www.ossp.org/) +** Copyright (c) 2001-2002 Cable & Wireless Deutschland (http://www.cw.com/de/) +** +** This file is part of OSSP cfg, a configuration parsing +** library which can be found at http://www.ossp.org/pkg/lib/cfg/. +** +** Permission to use, copy, modify, and distribute this software for +** any purpose with or without fee is hereby granted, provided that +** the above copyright notice and this permission notice appear in all +** copies. +** +** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR +** CONTRIBUTORS 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 CONTRCFG, 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 DAMAGE. +** +** cfg_node.c: configuration nodes +*/ + +#include +#include +#include +#include + +#include "cfg_node.h" + +cfg_rc_t cfg_node_create(cfg_node_t **node) +{ + cfg_node_t *n; + + if ((n = malloc(sizeof(cfg_node_t))) == NULL) + return CFG_ERR_SYS; + n->type = CFG_NODE_TYPE_NN; + n->parent = NULL; + n->rbroth = NULL; + n->child1 = NULL; + n->token = NULL; + n->data.t = CFG_DATA_TYPE_LONG; + n->data.u.l = 0; + *node = n; + return CFG_OK; +} + +cfg_rc_t cfg_node_set(cfg_node_t *node, cfg_node_attr_t attr, ...) +{ + va_list ap; + + if (node == NULL) + return CFG_ERR_ARG; + va_start(ap, attr); + switch (attr) { + case CFG_NODE_ATTR_TYPE: { + node->type = (cfg_node_type_t)va_arg(ap, cfg_node_type_t); + break; + } + case CFG_NODE_ATTR_PARENT: { + node->parent = (cfg_node_t *)va_arg(ap, cfg_node_t *); + break; + } + case CFG_NODE_ATTR_RBROTH: { + node->rbroth = (cfg_node_t *)va_arg(ap, cfg_node_t *); + break; + } + case CFG_NODE_ATTR_CHILD1: { + node->child1 = (cfg_node_t *)va_arg(ap, cfg_node_t *); + break; + } + case CFG_NODE_ATTR_TOKEN: { + node->token = (char *)va_arg(ap, char *); + break; + } + case CFG_NODE_ATTR_DATA: { + node->data.t = (cfg_data_type_t)va_arg(ap, cfg_data_type_t); + switch (node->data.t) { + case CFG_DATA_TYPE_PTR: node->data.u.p = (void *)va_arg(ap, void *); break; + case CFG_DATA_TYPE_CHAR: node->data.u.c = (char )va_arg(ap, int ); break; + case CFG_DATA_TYPE_INT: node->data.u.i = (int )va_arg(ap, int ); break; + case CFG_DATA_TYPE_LONG: node->data.u.l = (long )va_arg(ap, long ); break; + case CFG_DATA_TYPE_FLOAT: node->data.u.f = (float )va_arg(ap, double); break; + case CFG_DATA_TYPE_DOUBLE: node->data.u.d = (double)va_arg(ap, double); break; + default: return CFG_ERR_ARG; + } + } + default: + return CFG_ERR_ARG; + } + va_end(ap); + return CFG_OK; +} + +cfg_rc_t cfg_node_get(cfg_node_t *node, cfg_node_attr_t attr, ...) +{ + va_list ap; + + if (node == NULL) + return CFG_ERR_ARG; + va_start(ap, attr); + switch (attr) { + case CFG_NODE_ATTR_TYPE: { + cfg_node_type_t *type = (cfg_node_type_t *)va_arg(ap, cfg_node_type_t *); + *type = node->type; + break; + } + case CFG_NODE_ATTR_PARENT: { + cfg_node_t **n = (cfg_node_t **)va_arg(ap, cfg_node_t **); + *n = node->parent; + break; + } + case CFG_NODE_ATTR_RBROTH: { + cfg_node_t **n = (cfg_node_t **)va_arg(ap, cfg_node_t **); + *n = node->rbroth; + break; + } + case CFG_NODE_ATTR_CHILD1: { + cfg_node_t **n = (cfg_node_t **)va_arg(ap, cfg_node_t **); + *n = node->child1; + break; + } + case CFG_NODE_ATTR_TOKEN: { + char **token = (char **)va_arg(ap, char **); + *token = node->token; + break; + } + case CFG_NODE_ATTR_DATA: { + cfg_data_type_t *type = (cfg_data_type_t *)va_arg(ap, cfg_data_type_t *); + *type = node->data.t; + switch (node->data.t) { + case CFG_DATA_TYPE_PTR: *((void **)va_arg(ap, void **)) = node->data.u.p; break; + case CFG_DATA_TYPE_CHAR: *((char *)va_arg(ap, int *)) = node->data.u.c; break; + case CFG_DATA_TYPE_INT: *((int *)va_arg(ap, int *)) = node->data.u.i; break; + case CFG_DATA_TYPE_LONG: *((long *)va_arg(ap, long *)) = node->data.u.l; break; + case CFG_DATA_TYPE_DOUBLE: *((double *)va_arg(ap, double *)) = node->data.u.d; break; + case CFG_DATA_TYPE_FLOAT: *((float *)va_arg(ap, double *)) = node->data.u.f; break; + default: return CFG_ERR_ARG; + } + } + default: + return CFG_ERR_ARG; + } + va_end(ap); + return CFG_OK; +} + +cfg_rc_t cfg_node_link(cfg_node_t *node, cfg_node_link_t id, cfg_node_t *node2) +{ + cfg_node_t *n; + + if (node == NULL || node2 == NULL) + return CFG_ERR_ARG; + if (id == CFG_NODE_LINK_RBROTH) { + /* make node a rbroth */ + n = node2; + n->parent = node->parent; + while (n->rbroth != NULL) { + n->parent = node->parent; + n = n->rbroth; + } + n->rbroth = node->rbroth; + node->rbroth = node2; + } + else if (id == CFG_NODE_LINK_CHILD1) { + /* make node a child1 */ + n = node2; + n->parent = node; + while (n->rbroth != NULL) { + n->parent = node; + n = n->rbroth; + } + n->rbroth = node->child1; + node->child1 = node2; + } + return CFG_OK; +} + +cfg_rc_t cfg_node_unlink(cfg_node_t *node) +{ + cfg_node_t *n; + + if (node == NULL) + return CFG_ERR_ARG; + if (node->parent == NULL) + return CFG_OK; + if (node->parent->child1 == node) { + /* node was a child1 */ + node->parent->child1 = node->rbroth; + } + else { + /* node was a rbroth */ + n = node->parent->child1; + while (n->rbroth != node) + n = n->rbroth; + n->rbroth = node->rbroth; + } + return CFG_OK; +} + +cfg_rc_t cfg_node_apply(cfg_node_t *node, void (*cb_fct)(void *, cfg_node_t *), void *cb_ctx) +{ + cfg_rc_t rc; + + if (cb_fct == NULL) + return CFG_ERR_ARG; + if (node != NULL) { + cb_fct(cb_ctx, node); + if (node->child1 != NULL) + if ((rc = cfg_node_apply(node->child1, cb_fct, cb_ctx)) != CFG_OK) + return rc; + if (node->rbroth != NULL) + if ((rc = cfg_node_apply(node->rbroth, cb_fct, cb_ctx)) != CFG_OK) + return rc; + } + return CFG_OK; +} + +cfg_rc_t cfg_node_destroy(cfg_node_t *node) +{ + if (node == NULL) + return CFG_ERR_ARG; + free(node); + return CFG_OK; +} + Index: ossp-pkg/cfg/cfg_node.h RCS File: /v/ossp/cvs/ossp-pkg/cfg/cfg_node.h,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/cfg/cfg_node.h,v' | diff -u /dev/null - -L'ossp-pkg/cfg/cfg_node.h' 2>/dev/null --- ossp-pkg/cfg/cfg_node.h +++ - 2024-05-15 10:58:11.055253806 +0200 @@ -0,0 +1,73 @@ +/* +** OSSP cfg - Configuration Parsing +** Copyright (c) 1999-2002 Ralf S. Engelschall +** Copyright (c) 1999-2002 The OSSP Project (http://www.ossp.org/) +** Copyright (c) 2001-2002 Cable & Wireless Deutschland (http://www.cw.com/de/) +** +** This file is part of OSSP cfg, a configuration parsing +** library which can be found at http://www.ossp.org/pkg/lib/cfg/. +** +** Permission to use, copy, modify, and distribute this software for +** any purpose with or without fee is hereby granted, provided that +** the above copyright notice and this permission notice appear in all +** copies. +** +** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR +** CONTRIBUTORS 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 CONTRCFG, 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 DAMAGE. +** +** cfg_node.h: configuration nodes (internals) +*/ + +#ifndef __CFG_NODE_H__ +#define __CFG_NODE_H__ + +#include "cfg.h" + +typedef enum { + CFG_DATA_TYPE_PTR, + CFG_DATA_TYPE_CHAR, + CFG_DATA_TYPE_INT, + CFG_DATA_TYPE_LONG, + CFG_DATA_TYPE_FLOAT, + CFG_DATA_TYPE_DOUBLE +} cfg_data_type_t; + +typedef union { + void *p; + char c; + int i; + long l; + float f; + double d; +} cfg_data_union_t; + +typedef struct { + cfg_data_type_t t; /* data type */ + cfg_data_union_t u; /* data storage */ + void (*d)( /* data destructor */ + cfg_data_type_t t, + cfg_data_union_t *u + ); +} cfg_data_t; + +struct cfg_node_st { + cfg_node_type_t type; /* type of node */ + cfg_node_t *parent; /* pointer to parent node */ + cfg_node_t *rbroth; /* pointer to right brother node */ + cfg_node_t *child1; /* pointer to first child node */ + char *token; /* pointer to corresponding token string */ + cfg_data_t data; /* annotation data */ +}; + +#endif /* __CFG_NODE_H__ */ + Index: ossp-pkg/cfg/cfg_syn.c RCS File: /v/ossp/cvs/ossp-pkg/cfg/cfg_syn.c,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/cfg/cfg_syn.c,v' | diff -u /dev/null - -L'ossp-pkg/cfg/cfg_syn.c' 2>/dev/null --- ossp-pkg/cfg/cfg_syn.c +++ - 2024-05-15 10:58:11.057812378 +0200 @@ -0,0 +1,149 @@ +/* +** OSSP cfg - Configuration Parsing +** Copyright (c) 1999-2002 Ralf S. Engelschall +** Copyright (c) 1999-2002 The OSSP Project (http://www.ossp.org/) +** Copyright (c) 2001-2002 Cable & Wireless Deutschland (http://www.cw.com/de/) +** +** This file is part of OSSP cfg, a configuration parsing +** library which can be found at http://www.ossp.org/pkg/lib/cfg/. +** +** Permission to use, copy, modify, and distribute this software for +** any purpose with or without fee is hereby granted, provided that +** the above copyright notice and this permission notice appear in all +** copies. +** +** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR +** CONTRIBUTORS 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 DAMAGE. +** +** cfg_syn.c: syntax parsing +*/ + +#include "cfg.h" +#include "cfg_grid.h" +#include "cfg_node.h" +#include "cfg_fmt.h" +#include "cfg_syn.h" + +/* prototypes for Flex-generated scanner */ +extern int cfg_syn_lex_init(void *); +extern int cfg_syn_lex_destroy(void *); +extern void cfg_syn_set_extra(void *, void *); + +/* prototypes for Bison-generated parser */ +extern int cfg_syn_parse(void *); + +/* build a node tree according to a textual specification */ +cfg_rc_t cfg_syn(cfg_t *cfg, cfg_node_t **node, char *err_buf, size_t err_len, const char *input) +{ + cfg_syn_ctx_t ctx; + void *yyscan; + + /* initialize scanner */ + cfg_syn_lex_init(&yyscan); + cfg_syn_set_extra(&ctx, yyscan); + + /* establish our own context which is passed + through the parser and scanner */ + ctx.inputptr = input; + ctx.inputbuf = input; + ctx.inputlen = strlen(input); + ctx.cfg = cfg; + ctx.node = NULL; + ctx.rv = CFG_OK; + ctx.err_buf = err_buf; + ctx.err_len = err_len; + ctx.yyscan = yyscan; + + /* start the parser loop */ + if (cfg_syn_parse(&ctx)) + ctx.rv = (ctx.rv == CFG_OK ? CFG_ERR_INT : ctx.rv); + + /* destroy scanner */ + cfg_syn_lex_destroy(yyscan); + + /* provide root/top-level node as result */ + *node = ctx.node; + + return ctx.rv; +} + +/* remember a parsing error (used internally) */ +void cfg_syn_error(cfg_syn_ctx_t *ctx, cfg_rc_t rv, YYLTYPE *loc, const char *fmt, ...) +{ + va_list ap; + const char *cpF, *cpL; + const char *cpP, *cpE; + int line, column; + char *cpBuf; + char *cp; + size_t n; + + /* remember error code */ + ctx->rv = rv; + + /* short circuit processing if no error buffer exists */ + if (ctx->err_buf == NULL || ctx->err_len <= 0) + return; + + /* determine first and last positions of token */ + cpF = ctx->inputbuf+loc->first; + cpL = ctx->inputbuf+loc->last; + + /* determine epilog and prolog of token */ + cpP = cpF-4; + if (cpP < ctx->inputbuf) + cpP = ctx->inputbuf; + cpE = cpL+4; + if (cpE > ctx->inputbuf+ctx->inputlen) + cpE = ctx->inputbuf+ctx->inputlen; + + /* calculate line and column of token */ + line = 1; + column = 1; + for (cp = (char *)ctx->inputbuf; cp < (ctx->inputbuf+ctx->inputlen) && cp != cpF; cp++) { + column++; + if (*cp == '\n') { + column = 1; + line++; + } + } + + /* extract token context with mark token borders */ + if ((cpBuf = malloc((size_t)((cpE-cpP)+2+1))) == NULL) + return; + cp = cpBuf; + n = cpF-cpP; + memcpy(cp, cpP, n); cp += n; + *cp++ = '<'; + n = cpL-cpF; + memcpy(cp, cpF, n); cp += n; + *cp++ = '>'; + n = cpE-cpL; + memcpy(cp, cpL, n); cp += n; + *cp++ = '\0'; + + /* remember parsing error: part I (context part) */ + cfg_fmt_sprintf(ctx->err_buf, sizeof(ctx->err_len), + "line %d, column %d: `%s'; %s", + line, column, cpBuf); + free(cpBuf); + + /* remember parsing error: part II (parsing part) */ + n = strlen(ctx->err_buf); + va_start(ap, fmt); + cfg_fmt_vsprintf(ctx->err_buf+n, sizeof(ctx->err_len)-n, fmt, ap); + va_end(ap); + + return; +} + Index: ossp-pkg/cfg/cfg_syn.h RCS File: /v/ossp/cvs/ossp-pkg/cfg/cfg_syn.h,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/cfg/cfg_syn.h,v' | diff -u /dev/null - -L'ossp-pkg/cfg/cfg_syn.h' 2>/dev/null --- ossp-pkg/cfg/cfg_syn.h +++ - 2024-05-15 10:58:11.060505496 +0200 @@ -0,0 +1,74 @@ +/* +** OSSP cfg - Configuration Parsing +** Copyright (c) 1999-2002 Ralf S. Engelschall +** Copyright (c) 1999-2002 The OSSP Project (http://www.ossp.org/) +** Copyright (c) 2001-2002 Cable & Wireless Deutschland (http://www.cw.com/de/) +** +** This file is part of OSSP cfg, a configuration parsing +** library which can be found at http://www.ossp.org/pkg/lib/cfg/. +** +** Permission to use, copy, modify, and distribute this software for +** any purpose with or without fee is hereby granted, provided that +** the above copyright notice and this permission notice appear in all +** copies. +** +** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR +** CONTRIBUTORS 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 DAMAGE. +** +** cfg_syn.h: syntax parsing header +*/ + +#ifndef __CFG_SYN_H__ +#define __CFG_SYN_H__ + +#include +#include + +#include "cfg.h" +#include "cfg_grid.h" +#include "cfg_node.h" + +/* internal specification scanner/parser context */ +typedef struct { + const char *inputptr; /* input buffer: current reading pointer */ + const char *inputbuf; /* input buffer: begin of buffer */ + size_t inputlen; /* input buffer: size of buffer */ + cfg_t *cfg; /* the configuration object */ + cfg_node_t *node; /* top-level/root/result channel */ + cfg_rc_t rv; /* return value */ + char *err_buf; /* error buffer pointer */ + size_t err_len; /* error buffer length */ + void *yyscan; /* Flex scanner context */ +} cfg_syn_ctx_t; + +/* internal scanner/parser token location */ +typedef struct { + int first; + int last; +} cfg_syn_loc_t; +#define YYLTYPE cfg_syn_loc_t + +/* support for automatic location tracking by Bison */ +#define first_line first +#define first_column first +#define last_line last +#define last_column last + +/* internal API */ +extern cfg_rc_t cfg_syn(cfg_t *cfg, cfg_node_t **node, char *err_buf, size_t err_len, const char *input); + +/* error reporting function */ +extern void cfg_syn_error(cfg_syn_ctx_t *ctx, cfg_rc_t rv, YYLTYPE *loc, const char *fmt, ...); + +#endif /* __CFG_SYN_H__ */ + Index: ossp-pkg/cfg/cfg_syn_parse.y RCS File: /v/ossp/cvs/ossp-pkg/cfg/cfg_syn_parse.y,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/cfg/cfg_syn_parse.y,v' | diff -u /dev/null - -L'ossp-pkg/cfg/cfg_syn_parse.y' 2>/dev/null --- ossp-pkg/cfg/cfg_syn_parse.y +++ - 2024-05-15 10:58:11.063072832 +0200 @@ -0,0 +1,166 @@ +%{ +/* +** OSSP cfg - Configuration Parsing +** Copyright (c) 1999-2002 Ralf S. Engelschall +** Copyright (c) 1999-2002 The OSSP Project (http://www.ossp.org/) +** Copyright (c) 2001-2002 Cable & Wireless Deutschland (http://www.cw.com/de/) +** +** This file is part of OSSP cfg, a configuration parsing +** library which can be found at http://www.ossp.org/pkg/lib/cfg/. +** +** Permission to use, copy, modify, and distribute this software for +** any purpose with or without fee is hereby granted, provided that +** the above copyright notice and this permission notice appear in all +** copies. +** +** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR +** CONTRIBUTORS 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 DAMAGE. +** +** cfg_syn_parse.y: context free grammar specification for GNU Bison +** +** ATTENTION: This requires GNU Bison 1.30 or newer! +*/ + +#include +#include + +#include "cfg.h" +#include "cfg_syn.h" + +/* make sure yyparse() accepts a context pointer and + passes through its inlined scanner context to yylex() */ +#define CTX ((cfg_syn_ctx_t *)ctx) +#define YYPARSE_PARAM ctx +#define YYLEX_PARAM CTX->yyscan + +/* provide an explicit prototype for the yylex() function but use + "void *" instead of correct type because at this point in the + generation process we have the types still not available */ +extern int yylex(/*YYSTYPE*/ void *lvalp, + /*YYLTYPE*/ void *llocp, cfg_syn_ctx_t *ctx); + +/* generate verbose error messages and remember them inside the context */ +#undef yyerror +#define yyerror(msg) \ + cfg_syn_error(CTX, CFG_ERR_SYN, &yylloc, msg) +#define YYERROR_VERBOSE + +/* scanner state transition */ +extern void cfg_syn_scan_push(cfg_syn_ctx_t *, const char *state); +extern void cfg_syn_scan_pop(cfg_syn_ctx_t *); +%} + +/* parser options */ +%pure_parser +%locations +%defines + +/* the YYSTYPE: parser token value */ +%union { + char *cpString; + cfg_node_t *npNode; +} + +/* assign YYSTYPE elements to parser rules */ +%type sequence +%type directives +%type directive +%type tokens +%type token +%type string + +/* list of scanner tokens */ +%token T_SEP +%token T_OPEN +%token T_CLOSE +%token T_STRING + +/* operator association */ +%right T_SEP +%right T_OPEN +%right T_CLOSE + +/* grammar start rule + (technically redundant but explicit to be sure) */ +%start configuration + +%% + +configuration + : sequence { + CTX->node = $1; + } + ; + +sequence + : directives { + cfg_node_t *n; + cfg_node_create(&n); + cfg_node_set(n, CFG_NODE_ATTR_TYPE, CFG_NODE_TYPE_SEQ); + cfg_node_set(n, CFG_NODE_ATTR_CHILD1, $1); + } + ; + +directives + : /* empty */ { + $$ = NULL; + } + | directive { + $$ = $1; + } + | directive T_SEP directives { + cfg_node_set($1, CFG_NODE_ATTR_RBROTH, $3); + $$ = $1; + } + ; + +directive + : tokens { + cfg_node_t *n; + cfg_node_create(&n); + cfg_node_set(n, CFG_NODE_ATTR_TYPE, CFG_NODE_TYPE_DIR); + cfg_node_set(n, CFG_NODE_ATTR_CHILD1, $1); + } + ; + +tokens + : token { + $$ = $1; + } + | token tokens { + cfg_node_set($1, CFG_NODE_ATTR_RBROTH, $2); + $$ = $1; + } + ; + +token + : T_OPEN sequence T_CLOSE { + $$ = $2; + } + | string { + $$ = $1; + } + ; + +string + : T_STRING { + cfg_node_t *n; + cfg_node_create(&n); + cfg_node_set(n, CFG_NODE_ATTR_TYPE, CFG_NODE_TYPE_TOK); + cfg_node_set(n, CFG_NODE_ATTR_TOKEN, $1); + $$ = n; + } + ; + +%% + Index: ossp-pkg/cfg/cfg_syn_scan.l RCS File: /v/ossp/cvs/ossp-pkg/cfg/cfg_syn_scan.l,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/cfg/cfg_syn_scan.l,v' | diff -u /dev/null - -L'ossp-pkg/cfg/cfg_syn_scan.l' 2>/dev/null --- ossp-pkg/cfg/cfg_syn_scan.l +++ - 2024-05-15 10:58:11.065708168 +0200 @@ -0,0 +1,220 @@ +%{ +/* +** OSSP cfg - Configuration Parsing +** Copyright (c) 1999-2002 Ralf S. Engelschall +** Copyright (c) 1999-2002 The OSSP Project (http://www.ossp.org/) +** Copyright (c) 2001-2002 Cable & Wireless Deutschland (http://www.cw.com/de/) +** +** This file is part of OSSP cfg, a configuration parsing +** library which can be found at http://www.ossp.org/pkg/lib/cfg/. +** +** Permission to use, copy, modify, and distribute this software for +** any purpose with or without fee is hereby granted, provided that +** the above copyright notice and this permission notice appear in all +** copies. +** +** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR +** CONTRIBUTORS 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 DAMAGE. +** +** cfg_syn_scan.l: regular grammar specification for GNU Flex +** +** ATTENTION: This requires GNU Flex 2.5.6 or newer! +*/ + +#include +#include +#include + +#include "cfg.h" +#include "cfg_syn.h" +#include "cfg_syn_parse.h" + +/* how to find our own context */ +#define CTX ((cfg_syn_ctx_t *)yyget_extra(yy_globals)) + +/* provide own input handling */ +#define YY_NO_UNPUT 1 +#undef YY_INPUT +#define YY_INPUT(buf,result,max_size) (result = yyinput(CTX, buf, max_size)) +static int yyinput(cfg_syn_ctx_t *ctx, char *buf, int max_size); + +/* location tracking */ +#define YY_USER_INIT \ + yylloc->first = 0; \ + yylloc->last = 0; +#define YY_USER_ACTION \ + yylloc->first = yylloc->last; \ + yylloc->last += yyleng; +#define YY_USER_ACTION_ROLLBACK \ + yylloc->last = yylloc->first +%} + +/* scanner options */ +%pointer +%option stack +%option reentrant-bison +%option never-interactive +%option noyywrap + +/* scanner states */ +%x SS_DQ +%x SS_SQ +%x SS_CO_C + +%% + + /* local variables */ + char caStr[1024]; + char *cpStr = NULL; + + /* whitespaces */ +[ \t\n]+ { + /* no-op */ +} + + /* C-style block comment */ +"/*" { + BEGIN(SS_CO_C); +} +"*/" { + BEGIN(INITIAL); +} +(.|\n) { + /* no-op */ +} + + /* C++-style EOL comment */ +"//"[^\n]* { + /* no-op */ +} + + /* Shell-style EOL comment */ +"#"[^\n]* { + /* no-op */ +} + + /* double-quoted word ("...") */ +\" { + cpStr = caStr; + BEGIN(SS_DQ); +} +\" { + *cpStr = '\0'; + yylval->cpString = strdup(caStr); + BEGIN(INITIAL); + return T_STRING; +} +\\[0-7]{1,3} { + unsigned int result; + (void)sscanf(yytext+1, "%o", &result); + if (result > 0xff) { + cfg_syn_error(CTX, CFG_ERR_SYN, yylloc, "escape sequence out of bound"); + return 0; + } + *cpStr++ = result; +} +\\x[0-9a-fA-F]{2} { + unsigned int result; + (void)sscanf(yytext+1, "%x", &result); + if (result > 0xff) { + cfg_syn_error(CTX, CFG_ERR_SYN, yylloc, "escape sequence out of bound"); + return 0; + } + *cpStr++ = result; +} +\\n { *cpStr++ = '\n'; } +\\r { *cpStr++ = '\r'; } +\\t { *cpStr++ = '\t'; } +\\b { *cpStr++ = '\b'; } +\\f { *cpStr++ = '\f'; } +\\(.|\n) { + *cpStr++ = yytext[1]; +} +[^\\\"]+ { + char *cp = yytext; + while (*cp != '\0') + *cpStr++ = *cp++; +} +(.|\n) { + *cpStr++ = yytext[1]; +} + + /* single-quoted word ('...') */ +\' { + cpStr = caStr; + BEGIN(SS_SQ); +} +\' { + *cpStr = '\0'; + yylval->cpString = strdup(caStr); + BEGIN(INITIAL); + return T_STRING; +} +\\(.|\n) { + *cpStr++ = yytext[1]; +} +[^\\\']+ { + char *cp = yytext; + while (*cp != '\0') + *cpStr++ = *cp++; +} +(.|\n) { + *cpStr++ = yytext[1]; +} + + /* plain text word */ +[^ \t\n;{}"']+ { + yylval->cpString = strdup(yytext); + return T_STRING; +} + + /* special tokens */ +";" { return T_SEP; } +"{" { return T_OPEN; } +"}" { return T_CLOSE; } + + /* anything else is returned as is... */ +.|\n { + return yytext[0]; +} + +%% + +/* external scanner state transitions */ +void cfg_syn_scan_push(cfg_syn_ctx_t *ctx, const char *state); +void cfg_syn_scan_push(cfg_syn_ctx_t *ctx, const char *state) +{ + if (strcmp(state, "SS_SQ") == 0) + yy_push_state(SS_SQ, ctx->yyscan); +} +void cfg_syn_scan_pop(cfg_syn_ctx_t *ctx); +void cfg_syn_scan_pop(cfg_syn_ctx_t *ctx) +{ + yy_pop_state(ctx->yyscan); +} + +/* buffer-based input routine */ +static int yyinput(cfg_syn_ctx_t *ctx, char *buf, int max_size) +{ + int n; + + n = (ctx->inputbuf + ctx->inputlen - ctx->inputptr); + if (n > max_size) + n = max_size; + if (n <= 0) + return YY_NULL; + memcpy(buf, ctx->inputptr, n); + ctx->inputptr += n; + return n; +} + Index: ossp-pkg/cfg/cfg_test.c RCS File: /v/ossp/cvs/ossp-pkg/cfg/cfg_test.c,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/cfg/cfg_test.c,v' | diff -u /dev/null - -L'ossp-pkg/cfg/cfg_test.c' 2>/dev/null --- ossp-pkg/cfg/cfg_test.c +++ - 2024-05-15 10:58:11.068441251 +0200 @@ -0,0 +1,97 @@ + +#include +#include +#include + +#include "cfg.h" +#include "cfg_util.h" +#include "cfg_node.h" +#include "cfg_syn.h" + +typedef struct { + int line; + int col; + FILE *fp; +} cb_ctx_t; + +static void cb_out(cb_ctx_t *ctx, char *str) +{ + int i; + + fprintf(stderr, "cb_out <%s>\n", str); + fprintf(ctx->fp, "%s", str); + for (i = 0; str[i] != '\0'; i++) { + if (str[i] == '\n') { + ctx->line++; + ctx->col = 0; + } + else { + ctx->col++; + } + } +} + +static void cb_fct(void *_ctx, cfg_node_t *node) +{ + cb_ctx_t *ctx = (cb_ctx_t *)_ctx; + cfg_node_type_t type; + cfg_node_t *node2; + cfg_rc_t rc; + char *token; + + fprintf(stderr, "cb_fct enter\n"); + rc = cfg_node_get(node, CFG_NODE_ATTR_TYPE, &type); + fprintf(stderr, "rc=%d type=%d\n", rc, type); + if (type == CFG_NODE_TYPE_SEQ) { + cb_out(ctx, " {\n"); + } + else if (type == CFG_NODE_TYPE_DIR) { + cb_out(ctx, ";\n"); + cfg_node_get(node, CFG_NODE_ATTR_RBROTH, &node2); + if (node2 == NULL) + cb_out(ctx, "};\n"); + } + else if (type == CFG_NODE_TYPE_TOK) { + cfg_node_get(node, CFG_NODE_ATTR_TOKEN, &token); + if (token != NULL) { + cb_out(ctx, token); + cfg_node_get(node, CFG_NODE_ATTR_RBROTH, &node2); + if (node2 != NULL) + cb_out(ctx, " "); + } + } + fprintf(stderr, "cb_fct leave\n"); +} + +int main(int argc, char *argv[]) +{ + cfg_rc_t rc; + char *buf_ptr; + size_t buf_size; + cfg_node_t *node; + char err_buf[1024]; + + if (argc != 2) { + fprintf(stderr, "USAGE: %s \n", argv[0]); + exit(1); + } + if ((rc = cfg_util_readfile(argv[1], &buf_ptr, &buf_size)) != CFG_OK) { + fprintf(stderr, "ERROR: reading file \"%s\"\n", argv[1]); + exit(1); + } + if ((rc = cfg_syn(NULL, &node, err_buf, sizeof(err_buf), buf_ptr)) != CFG_OK) { + fprintf(stderr, "ERROR: %s\n", err_buf); + } + else { + cb_ctx_t ctx; + + ctx.line = 0; + ctx.col = 0; + ctx.fp = stdout; + cfg_node_apply(node, cb_fct, &ctx); + } + free(buf_ptr); + + return 0; +} + Index: ossp-pkg/cfg/cfg_util.c RCS File: /v/ossp/cvs/ossp-pkg/cfg/cfg_util.c,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/cfg/cfg_util.c,v' | diff -u /dev/null - -L'ossp-pkg/cfg/cfg_util.c' 2>/dev/null --- ossp-pkg/cfg/cfg_util.c +++ - 2024-05-15 10:58:11.071054111 +0200 @@ -0,0 +1,93 @@ +/* +** OSSP cfg - Configuration Parsing +** Copyright (c) 1999-2002 Ralf S. Engelschall +** Copyright (c) 1999-2002 The OSSP Project (http://www.ossp.org/) +** Copyright (c) 2001-2002 Cable & Wireless Deutschland (http://www.cw.com/de/) +** +** This file is part of OSSP cfg, a configuration parsing +** library which can be found at http://www.ossp.org/pkg/lib/cfg/. +** +** Permission to use, copy, modify, and distribute this software for +** any purpose with or without fee is hereby granted, provided that +** the above copyright notice and this permission notice appear in all +** copies. +** +** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR +** CONTRIBUTORS 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 DAMAGE. +** +** cfg_util.c: utility functions +*/ + +#include +#include +#include +#include + +#include "cfg.h" +#include "cfg_util.h" + +cfg_rc_t cfg_util_readfile(const char *filename, char **buf_ptr, size_t *buf_len) +{ + FILE *fp = NULL; + size_t n; + char *cp; + + if (strcmp(filename, "-") == 0) { + /* file is given on stdin */ + (*buf_len) = 32; + if ((*buf_ptr = (char *)malloc(*buf_len)) == NULL) + return CFG_ERR_SYS; + cp = *buf_ptr; + while ((n = fread(cp, 1, (*buf_len)-(cp-(*buf_ptr)), stdin)) > 0) { + cp += n; + if (((*buf_ptr)+(*buf_len))-cp < (*buf_len)/8) { + (*buf_len) *= 2; + n = cp-(*buf_ptr); + if ((cp = (char *)realloc(*buf_ptr, *buf_len)) == NULL) { + free(*buf_ptr); + return CFG_ERR_SYS; + } + *buf_ptr = cp; + cp += n; + } + } + *cp = '\0'; + } + else { + /* file is given on filesystem */ + if ((fp = fopen(filename, "r")) == NULL) + return CFG_ERR_SYS; + fseek(fp, 0, SEEK_END); + if ((n = ftell(fp)) > 0) { + if ((*buf_ptr = (char *)malloc(n+1)) == NULL) { + fclose(fp); + return CFG_ERR_SYS; + } + fseek(fp, 0, SEEK_SET); + if ((n = fread(*buf_ptr, 1, n, fp)) == 0) { + free(*buf_ptr); + fclose(fp); + return CFG_ERR_SYS; + } + (*buf_ptr)[n] = '\0'; + (*buf_len) = n+1; + } + else { + (*buf_ptr) = strdup(""); + (*buf_len) = 1; + } + fclose(fp); + } + return CFG_OK; +} + Index: ossp-pkg/cfg/cfg_util.h RCS File: /v/ossp/cvs/ossp-pkg/cfg/cfg_util.h,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/cfg/cfg_util.h,v' | diff -u /dev/null - -L'ossp-pkg/cfg/cfg_util.h' 2>/dev/null --- ossp-pkg/cfg/cfg_util.h +++ - 2024-05-15 10:58:11.073645373 +0200 @@ -0,0 +1,39 @@ +/* +** OSSP cfg - Configuration Parsing +** Copyright (c) 1999-2002 Ralf S. Engelschall +** Copyright (c) 1999-2002 The OSSP Project (http://www.ossp.org/) +** Copyright (c) 2001-2002 Cable & Wireless Deutschland (http://www.cw.com/de/) +** +** This file is part of OSSP cfg, a configuration parsing +** library which can be found at http://www.ossp.org/pkg/lib/cfg/. +** +** Permission to use, copy, modify, and distribute this software for +** any purpose with or without fee is hereby granted, provided that +** the above copyright notice and this permission notice appear in all +** copies. +** +** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR +** CONTRIBUTORS 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 CONTRCFG, 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 DAMAGE. +** +** cfg_util.h: utility functions (internals) +*/ + +#ifndef __CFG_UTIL_H__ +#define __CFG_UTIL_H__ + +#include "cfg.h" + +cfg_rc_t cfg_util_readfile(const char *filename, char **buf_ptr, size_t *buf_len); + +#endif /* __CFG_UTIL_H__ */ + Index: ossp-pkg/cfg/sample.cfg RCS File: /v/ossp/cvs/ossp-pkg/cfg/Attic/sample.cfg,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/cfg/Attic/sample.cfg,v' | diff -u /dev/null - -L'ossp-pkg/cfg/sample.cfg' 2>/dev/null --- ossp-pkg/cfg/sample.cfg +++ - 2024-05-15 10:58:11.076191799 +0200 @@ -0,0 +1,26 @@ +## +## sample.cfg +## + +/* now comes + a C/C++ style block comment ** quux */ + +foo -b --bar -qX --quux=X baz +rootdir /; // C++ style EOL comment +tmpdir /tmp; + +directory /foo { + deny from all; + allow from { 1.2.3.4; 6.7.8.9 }; + fuck; + foobar { baz } quux; +}; + +directory /foo2 { + deny from all; # shell-style EOL comment + allow from { 1.2.3.4; 6.7.8.9 } butnot { 1; 2; 3; }; + fuck; + foobar { baz } quux "multiline string,\ + without blanks" baz; +}; +