OSSP CVS Repository

ossp - Check-in [2216]
Not logged in
[Honeypot]  [Browse]  [Home]  [Login]  [Reports
[Search]  [Ticket]  [Timeline
  [Patchset]  [Tagging/Branching

Check-in Number: 2216
Date: 2002-Jul-03 15:25:34 (local)
2002-Jul-03 13:25:34 (UTC)
User:rse
Branch:
Comment: Add this first cut for the forthcoming OSSP cfg library to CVS. This is work in progress and still not ready for use anywhere.
Tickets:
Inspections:
Files:
ossp-pkg/cfg/.cvsignore      added-> 1.1
ossp-pkg/cfg/00TODO      added-> 1.1
ossp-pkg/cfg/Makefile      added-> 1.1
ossp-pkg/cfg/cfg.h      added-> 1.1
ossp-pkg/cfg/cfg.pod      added-> 1.1
ossp-pkg/cfg/cfg_fmt.c      added-> 1.1
ossp-pkg/cfg/cfg_fmt.h      added-> 1.1
ossp-pkg/cfg/cfg_grid.c      added-> 1.1
ossp-pkg/cfg/cfg_grid.h      added-> 1.1
ossp-pkg/cfg/cfg_node.c      added-> 1.1
ossp-pkg/cfg/cfg_node.h      added-> 1.1
ossp-pkg/cfg/cfg_syn.c      added-> 1.1
ossp-pkg/cfg/cfg_syn.h      added-> 1.1
ossp-pkg/cfg/cfg_syn_parse.y      added-> 1.1
ossp-pkg/cfg/cfg_syn_scan.l      added-> 1.1
ossp-pkg/cfg/cfg_test.c      added-> 1.1
ossp-pkg/cfg/cfg_util.c      added-> 1.1
ossp-pkg/cfg/cfg_util.h      added-> 1.1
ossp-pkg/cfg/sample.cfg      added-> 1.1

ossp-pkg/cfg/.cvsignore -> 1.1

*** /dev/null    Mon Apr 29 13:15:42 2024
--- -    Mon Apr 29 13:17:36 2024
***************
*** 0 ****
--- 1,6 ----
+ cfg_syn_parse.c
+ cfg_syn_parse.h
+ cfg_syn_scan.c
+ cfg_test
+ *.o
+ *.a


ossp-pkg/cfg/00TODO -> 1.1

*** /dev/null    Mon Apr 29 13:15:42 2024
--- -    Mon Apr 29 13:17:36 2024
***************
*** 0 ****
--- 1,4 ----
+ - cfg_t
+ - cfg_data.c
+ - cfg_node_dump()
+ - cfg_node_destroy() for whole tree


ossp-pkg/cfg/Makefile -> 1.1

*** /dev/null    Mon Apr 29 13:15:42 2024
--- -    Mon Apr 29 13:17:36 2024
***************
*** 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
+ 


ossp-pkg/cfg/cfg.h -> 1.1

*** /dev/null    Mon Apr 29 13:15:42 2024
--- -    Mon Apr 29 13:17:36 2024
***************
*** 0 ****
--- 1,99 ----
+ /*
+ **  OSSP cfg - Configuration Parsing
+ **  Copyright (c) 1999-2002 Ralf S. Engelschall <rse@engelschall.com>
+ **  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 <stdarg.h>
+ 
+ /* ============================================================ */
+ 
+ /* 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__ */
+ 


ossp-pkg/cfg/cfg.pod -> 1.1

*** /dev/null    Mon Apr 29 13:15:42 2024
--- -    Mon Apr 29 13:17:36 2024
***************
*** 0 ****
--- 1,160 ----
+ ##
+ ##  OSSP cfg - Configuration Parsing
+ ##  Copyright (c) 1999-2002 Ralf S. Engelschall <rse@engelschall.com>
+ ##  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<OSSP cfg> - Configuration Parsing
+ 
+ =head1 SYNOPSIS
+ 
+ ...
+ 
+ =head1 DESCRIPTION
+ 
+ B<OSSP cfg> 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<sequence>      ::= I<empty>
+                 | B<directive>
+                 | B<directive> B<SEP> B<sequence>
+ 
+ B<directive>     ::= B<token> 
+                 | B<token> B<directive>
+ 
+ B<token>         ::= B<OPEN> B<sequence> B<CLOSE>
+                 | B<string>
+ 
+ B<string>        ::= B<DQ_STRING>   # double quoted string
+                 | B<SQ_STRING>   # single quoted string
+                 | B<PT_STRING>   # 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<regex>/"):
+ 
+ B<SEP>           ::= /;/
+ 
+ B<OPEN>          ::= /{/
+ 
+ B<CLOSE>         ::= /}/
+ 
+ B<DQ_STRING>     ::= /"/ B<DQ_CHARS> /"/
+ 
+ B<DQ_CHARS>      ::= I<empty>
+                 | B<DQ_CHAR> B<DQ_CHARS>
+ 
+ B<DQ_CHAR>       ::= /\\"/               # 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<SQ_STRING>     ::= /'/ B<SQ_CHARS> /'/
+ 
+ B<SQ_CHARS>      ::= I<empty>
+                 | B<SQ_CHAR> B<SQ_CHARS>
+ 
+ B<SQ_CHAR>       ::= /\\'/               # escaped quote
+                 | /\\\n[ \t]*/        # line contination
+                 | /\\\\/              # escaped escape
+                 | /./                 # any other char
+ 
+ B<PT_STRING>     ::= B<PT_CHAR> B<PT_CHARS>
+ 
+ B<PT_CHARS>      ::= I<empty>
+                 | B<PT_CHAR> B<PT_STRING>
+ 
+ B<PT_CHAR>       ::= /[^ \t\n;{}"']/     # none of specials
+ 
+ Additionally, white-space B<WS> and comment B<CO> tokens are allowed at
+ any position in the above productions of the previous grammar part.
+ 
+ B<WS>            ::= /[ \t\n]+/
+ 
+ B<CO>            ::= B<CO_C>                # style of C
+                 | B<CO_CXX>              # style of C++
+                 | B<CO_SH>               # style of /bin/sh
+ 
+ B<CO_C>          ::= /\/\*([^*]|\*(?!\/))*\*\//
+ 
+ B<CO_CXX>        ::= /\/\/[^\n]*/
+ 
+ B<CO_SH>         ::= /#[^\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<OSSP cfg> 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<OSSP> project.
+ 
+ =head1 AUTHOR
+ 
+  Ralf S. Engelschall
+  rse@engelschall.com
+  www.engelschall.com
+ 
+ =cut
+ 


ossp-pkg/cfg/cfg_fmt.c -> 1.1

*** /dev/null    Mon Apr 29 13:15:42 2024
--- -    Mon Apr 29 13:17:36 2024
***************
*** 0 ****
--- 1,1167 ----
+ /*
+ **  OSSP cfg - Configuration Parsing
+ **  Copyright (c) 1999-2002 Ralf S. Engelschall <rse@engelschall.com>
+ **  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 <panos@alumni.cs.colorado.edu> 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 <stdio.h>
+ #include <stdlib.h>
+ #include <stdarg.h>
+ #include <string.h>
+ #include <ctype.h>
+ #include <math.h>
+ 
+ #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 %<unknown> */
+ 
+     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
+                  * %<char> 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 %<char>
+                  * (like syslog). Note that we can't point s inside fmt
+                  * because the unknown <char> 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;
+ }
+ 


ossp-pkg/cfg/cfg_fmt.h -> 1.1

*** /dev/null    Mon Apr 29 13:15:42 2024
--- -    Mon Apr 29 13:17:36 2024
***************
*** 0 ****
--- 1,76 ----
+ /*
+ **  OSSP cfg - Configuration Parsing
+ **  Copyright (c) 1999-2002 Ralf S. Engelschall <rse@engelschall.com>
+ **  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__ */
+ 


ossp-pkg/cfg/cfg_grid.c -> 1.1

*** /dev/null    Mon Apr 29 13:15:42 2024
--- -    Mon Apr 29 13:17:36 2024
***************
*** 0 ****
--- 1,511 ----
+ /*
+ **  OSSP cfg - Configuration Parsing
+ **  Copyright (c) 1999-2002 Ralf S. Engelschall <rse@engelschall.com>
+ **  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;
+ }
+ 


ossp-pkg/cfg/cfg_grid.h -> 1.1

*** /dev/null    Mon Apr 29 13:15:42 2024
--- -    Mon Apr 29 13:17:36 2024
***************
*** 0 ****
--- 1,50 ----
+ /*
+ **  OSSP cfg - Configuration Parsing
+ **  Copyright (c) 1999-2002 Ralf S. Engelschall <rse@engelschall.com>
+ **  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 <stdlib.h>
+ #include <string.h>
+ 
+ #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__ */
+ 


ossp-pkg/cfg/cfg_node.c -> 1.1

*** /dev/null    Mon Apr 29 13:15:42 2024
--- -    Mon Apr 29 13:17:36 2024
***************
*** 0 ****
--- 1,233 ----
+ /*
+ **  OSSP cfg - Configuration Parsing
+ **  Copyright (c) 1999-2002 Ralf S. Engelschall <rse@engelschall.com>
+ **  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 <stdio.h>
+ #include <stdlib.h>
+ #include <stdarg.h>
+ #include <unistd.h>
+ 
+ #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;
+ }
+ 


ossp-pkg/cfg/cfg_node.h -> 1.1

*** /dev/null    Mon Apr 29 13:15:42 2024
--- -    Mon Apr 29 13:17:36 2024
***************
*** 0 ****
--- 1,73 ----
+ /*
+ **  OSSP cfg - Configuration Parsing
+ **  Copyright (c) 1999-2002 Ralf S. Engelschall <rse@engelschall.com>
+ **  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__ */
+ 


ossp-pkg/cfg/cfg_syn.c -> 1.1

*** /dev/null    Mon Apr 29 13:15:42 2024
--- -    Mon Apr 29 13:17:36 2024
***************
*** 0 ****
--- 1,149 ----
+ /*
+ **  OSSP cfg - Configuration Parsing
+ **  Copyright (c) 1999-2002 Ralf S. Engelschall <rse@engelschall.com>
+ **  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;
+ }
+ 


ossp-pkg/cfg/cfg_syn.h -> 1.1

*** /dev/null    Mon Apr 29 13:15:42 2024
--- -    Mon Apr 29 13:17:36 2024
***************
*** 0 ****
--- 1,74 ----
+ /*
+ **  OSSP cfg - Configuration Parsing
+ **  Copyright (c) 1999-2002 Ralf S. Engelschall <rse@engelschall.com>
+ **  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 <string.h>
+ #include <stdarg.h>
+ 
+ #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__ */
+ 


ossp-pkg/cfg/cfg_syn_parse.y -> 1.1

*** /dev/null    Mon Apr 29 13:15:42 2024
--- -    Mon Apr 29 13:17:36 2024
***************
*** 0 ****
--- 1,166 ----
+ %{
+ /*
+ **  OSSP cfg - Configuration Parsing
+ **  Copyright (c) 1999-2002 Ralf S. Engelschall <rse@engelschall.com>
+ **  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 <stdio.h>
+ #include <stdlib.h>
+ 
+ #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  <npNode>   sequence
+ %type  <npNode>   directives
+ %type  <npNode>   directive
+ %type  <npNode>   tokens
+ %type  <npNode>   token
+ %type  <npNode>   string
+ 
+ /* list of scanner tokens */
+ %token            T_SEP
+ %token            T_OPEN
+ %token            T_CLOSE
+ %token <cpString> 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; 
+       }
+     ;
+ 
+ %%
+ 


ossp-pkg/cfg/cfg_syn_scan.l -> 1.1

*** /dev/null    Mon Apr 29 13:15:42 2024
--- -    Mon Apr 29 13:17:36 2024
***************
*** 0 ****
--- 1,220 ----
+ %{
+ /*
+ **  OSSP cfg - Configuration Parsing
+ **  Copyright (c) 1999-2002 Ralf S. Engelschall <rse@engelschall.com>
+ **  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 <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+ 
+ #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);
+ }
+ <SS_CO_C>"*/" {
+     BEGIN(INITIAL);
+ }
+ <SS_CO_C>(.|\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);
+ }
+ <SS_DQ>\" {
+     *cpStr = '\0';
+     yylval->cpString = strdup(caStr);
+     BEGIN(INITIAL);
+     return T_STRING;
+ }
+ <SS_DQ>\\[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;
+ }
+ <SS_DQ>\\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;
+ }
+ <SS_DQ>\\n { *cpStr++ = '\n'; }
+ <SS_DQ>\\r { *cpStr++ = '\r'; }
+ <SS_DQ>\\t { *cpStr++ = '\t'; }
+ <SS_DQ>\\b { *cpStr++ = '\b'; }
+ <SS_DQ>\\f { *cpStr++ = '\f'; }
+ <SS_DQ>\\(.|\n) {
+     *cpStr++ = yytext[1];
+ }
+ <SS_DQ>[^\\\"]+ {
+     char *cp = yytext;
+     while (*cp != '\0')
+         *cpStr++ = *cp++;
+ }
+ <SS_DQ>(.|\n) {
+     *cpStr++ = yytext[1];
+ }
+ 
+     /* single-quoted word ('...') */
+ \' {
+     cpStr = caStr;
+     BEGIN(SS_SQ);
+ }
+ <SS_SQ>\' {
+     *cpStr = '\0';
+     yylval->cpString = strdup(caStr);
+     BEGIN(INITIAL);
+     return T_STRING;
+ }
+ <SS_SQ>\\(.|\n) {
+     *cpStr++ = yytext[1];
+ }
+ <SS_SQ>[^\\\']+ {
+     char *cp = yytext;
+     while (*cp != '\0')
+         *cpStr++ = *cp++;
+ }
+ <SS_SQ>(.|\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;
+ }
+ 


ossp-pkg/cfg/cfg_test.c -> 1.1

*** /dev/null    Mon Apr 29 13:15:42 2024
--- -    Mon Apr 29 13:17:36 2024
***************
*** 0 ****
--- 1,97 ----
+ 
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+ 
+ #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 <file>\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;
+ }
+ 


ossp-pkg/cfg/cfg_util.c -> 1.1

*** /dev/null    Mon Apr 29 13:15:42 2024
--- -    Mon Apr 29 13:17:36 2024
***************
*** 0 ****
--- 1,93 ----
+ /*
+ **  OSSP cfg - Configuration Parsing
+ **  Copyright (c) 1999-2002 Ralf S. Engelschall <rse@engelschall.com>
+ **  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 <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+ #include <unistd.h>
+ 
+ #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;
+ }
+ 


ossp-pkg/cfg/cfg_util.h -> 1.1

*** /dev/null    Mon Apr 29 13:15:42 2024
--- -    Mon Apr 29 13:17:36 2024
***************
*** 0 ****
--- 1,39 ----
+ /*
+ **  OSSP cfg - Configuration Parsing
+ **  Copyright (c) 1999-2002 Ralf S. Engelschall <rse@engelschall.com>
+ **  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__ */
+ 


ossp-pkg/cfg/sample.cfg -> 1.1

*** /dev/null    Mon Apr 29 13:15:42 2024
--- -    Mon Apr 29 13:17:36 2024
***************
*** 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;
+ };
+ 

CVSTrac 2.0.1