OSSP CVS Repository

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

Check-in Number: 4875
Date: 2004-Nov-28 14:49:11 (local)
2004-Nov-28 13:49:11 (UTC)
User:rse
Branch:
Comment: Escape non-printable characters of input extracts in error messages.
Tickets:
Inspections:
Files:
ossp-pkg/cfg/ChangeLog      1.23 -> 1.24     3 inserted, 0 deleted
ossp-pkg/cfg/cfg_syn.c      added-> 1.21

ossp-pkg/cfg/ChangeLog 1.23 -> 1.24

--- ChangeLog    2004/11/28 12:58:25     1.23
+++ ChangeLog    2004/11/28 13:49:11     1.24
@@ -10,6 +10,9 @@
 
  Changes between 0.9.5 and 0.9.6 (27-Nov-2004 to xx-Dec-2004):
 
+   *) Escape non-printable characters of input extracts in error messages.
+      [Ralf S. Engelschall <rse@engelschall.com>]
+
    *) Cleanup and extend buffer handling sub-library (cfg_buf.[ch])
       [Ralf S. Engelschall <rse@engelschall.com>]
 


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

*** /dev/null    Sun May  5 05:37:11 2024
--- -    Sun May  5 05:41:23 2024
***************
*** 0 ****
--- 1,409 ----
+ /*
+ **  OSSP cfg - Configuration Parsing
+ **  Copyright (c) 2002-2004 Ralf S. Engelschall <rse@engelschall.com>
+ **  Copyright (c) 2002-2004 The OSSP Project (http://www.ossp.org/)
+ **  Copyright (c) 2002-2004 Cable & Wireless (http://www.cw.com/)
+ **
+ **  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 and formatting
+ */
+ 
+ #include <stdio.h>
+ #include <ctype.h>
+ 
+ #include "cfg.h"
+ #include "cfg_global.h"
+ #include "cfg_grid.h"
+ #include "cfg_node.h"
+ #include "cfg_fmt.h"
+ #include "cfg_syn.h"
+ #include "cfg_buf.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_import(
+     cfg_t *cfg,
+     cfg_node_t **node,
+     const char *in_ptr,
+     size_t in_len,
+     char *err_buf,
+     size_t err_len)
+ {
+     cfg_syn_ctx_t ctx;
+     void *yyscan;
+ 
+     /* argument sanity checking */
+     if (node == NULL || in_ptr == NULL)
+         return CFG_ERR_ARG;
+ 
+     /* 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 = in_ptr;
+     ctx.inputbuf = in_ptr;
+     ctx.inputlen = in_len;
+     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;
+ }
+ 
+ /* helper function for copying out input with escaping of characters */
+ static size_t cfg_syn_error_cpyout(char *out_ptr, const char *in_ptr, size_t in_len)
+ {
+     size_t out_len;
+     char c;
+ 
+     out_len = 0;
+     while (in_len-- > 0) {
+         c = *in_ptr++;
+         switch (c) {
+             case '\n': *out_ptr++ = '\\'; *out_ptr++ = 'n'; out_len += 2; break;
+             case '\r': *out_ptr++ = '\\'; *out_ptr++ = 'r'; out_len += 2; break;
+             case '\t': *out_ptr++ = '\\'; *out_ptr++ = 't'; out_len += 2; break;
+             case '\b': *out_ptr++ = '\\'; *out_ptr++ = 'b'; out_len += 2; break;
+             case '\f': *out_ptr++ = '\\'; *out_ptr++ = 'f'; out_len += 2; break;
+             default: {
+                 if (!isprint((int)c)) {
+                     *out_ptr++ = '\\';
+                     *out_ptr++ = '?';
+                     out_len += 2;
+                 }
+                 else {
+                     *out_ptr++ = c;
+                     out_len++;
+                 }
+             }
+         }
+     }
+     return out_len;
+ }
+ 
+ /* 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;
+     if (cpF < ctx->inputbuf)
+         cpF = ctx->inputbuf;
+     if (cpF > ctx->inputbuf+ctx->inputlen)
+         cpF = ctx->inputbuf+ctx->inputlen;
+     cpL = ctx->inputbuf+loc->last;
+     if (cpL < ctx->inputbuf)
+         cpL = ctx->inputbuf;
+     if (cpL > ctx->inputbuf+ctx->inputlen)
+         cpL = ctx->inputbuf+ctx->inputlen;
+ 
+     /* 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)+2+1))) == NULL)
+         return;
+     cp = cpBuf;
+     cp += cfg_syn_error_cpyout(cp, cpP, cpF-cpP);
+     *cp++ = '<';
+     cp += cfg_syn_error_cpyout(cp, cpF, cpL-cpF);
+     *cp++ = '>';
+     cp += cfg_syn_error_cpyout(cp, cpL, cpE-cpL);
+     *cp++ = '\0';
+ 
+     /* remember parsing error: part I (context part) */
+     cfg_fmt_sprintf(ctx->err_buf, ctx->err_len,
+                     "line %d, column %d: `%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;
+ }
+ 
+ /* internal cfg_syn_export structure */
+ typedef struct {
+     cfg_t *cfg;
+     cfg_buf_t *buf;
+     int indent;
+ } export_t;
+ 
+ /* internal cfg_syn_export helper function: sprintf(3) style output formatting */
+ static void export_format(export_t *ctx, char *fmt, ...)
+ {
+     int i;
+     char *cp;
+     char *cp2;
+     va_list ap;
+     char *str;
+ 
+     va_start(ap, fmt);
+     if ((str = cfg_fmt_vasprintf(fmt, ap)) == NULL)
+         return;
+     cp = str;
+     while ((cp2 = strchr(cp, '\n')) != NULL) {
+         cfg_buf_format(ctx->buf, "%.*s", cp2-cp+1, cp);
+         for (i = 0; i < ctx->indent; i++)
+             cfg_buf_format(ctx->buf, "    ");
+         cp = cp2+1;
+     }
+     if (cp[0] != '\0')
+         cfg_buf_format(ctx->buf, "%s", cp);
+     free(str);
+     va_end(ap);
+     return;
+ }
+ 
+ /* internal cfg_syn_export helper function: indentation handling */
+ static void export_indent(export_t *ctx, signed int n)
+ {
+     if (n > 0) {
+         while (n > 0) {
+             n--;
+             ctx->indent++;
+             cfg_buf_format(ctx->buf, "    ");
+         }
+     }
+     else {
+         while (n < 0 && ctx->indent > 0) {
+             n++;
+             ctx->indent--;
+             cfg_buf_resize(ctx->buf, -4);
+         }
+     }
+ }
+ 
+ /* internal cfg_syn_export helper function: token output formatting */
+ static void export_token(export_t *ctx, const char *token)
+ {
+     const char *cp;
+     char *out;
+     int plain;
+     char c;
+ 
+     plain = 1;
+     for (cp = token; *cp != '\0'; cp++) {
+         if (   !isprint((int)(*cp))
+             || strchr(" \n\r\t\b\f;{}\\\"'", (int)(*cp)) != NULL) {
+             plain = 0;
+             break;
+         }
+     }
+     if (plain)
+         export_format(ctx, "%s", token);
+     else {
+         export_format(ctx, "\"");
+         cp = token;
+         while ((c = *cp++) != '\0') {
+             out = NULL;
+             switch (c) {
+                 case '\n': out = "\\n";  break;
+                 case '\r': out = "\\r";  break;
+                 case '\t': out = "\\t";  break;
+                 case '\b': out = "\\b";  break;
+                 case '\f': out = "\\f";  break;
+                 case '\\': out = "\\\\"; break;
+                 case '"' : out = "\\\""; break;
+             }
+             if (out != NULL)
+                 export_format(ctx, "%s", out);
+             else {
+                 if (isprint((int)c))
+                     export_format(ctx, "%c", c);
+                 else
+                     export_format(ctx, "\\x%02x", c);
+             }
+         }
+         export_format(ctx, "\"");
+     }
+     return;
+ }
+ 
+ /* internal cfg_syn_export helper function: recursive node processing */
+ static void export_node(export_t *ctx, cfg_node_t *node)
+ {
+     cfg_node_type_t type;
+     cfg_node_t *node2;
+     cfg_rc_t rc;
+     char *token;
+ 
+     if ((rc = cfg_node_get(ctx->cfg, node, CFG_NODE_ATTR_TYPE, &type)) != CFG_OK)
+         return;
+     if (type == CFG_NODE_TYPE_SEQ) {
+         /* node is a sequence */
+         export_format(ctx, "{\n");
+         export_indent(ctx, 1);
+         cfg_node_get(ctx->cfg, node, CFG_NODE_ATTR_CHILD1, &node2);
+         while (node2 != NULL) {
+             export_node(ctx, node2); /* recursion */
+             cfg_node_get(ctx->cfg, node2, CFG_NODE_ATTR_RBROTH, &node2);
+         }
+         export_indent(ctx, -1);
+         export_format(ctx, "}");
+     }
+     else if (type == CFG_NODE_TYPE_DIR) {
+         /* node is a directive */
+         cfg_node_get(ctx->cfg, node, CFG_NODE_ATTR_CHILD1, &node2);
+         while (node2 != NULL) {
+             export_node(ctx, node2); /* recursion */
+             cfg_node_get(ctx->cfg, node2, CFG_NODE_ATTR_RBROTH, &node2);
+             if (node2 != NULL)
+                 export_format(ctx, " ");
+         }
+         cfg_node_get(ctx->cfg, node, CFG_NODE_ATTR_RBROTH, &node2);
+         if (node2 != NULL)
+             export_format(ctx, ";");
+         export_format(ctx, "\n");
+     }
+     else if (type == CFG_NODE_TYPE_ARG) {
+         /* node is a token */
+         cfg_node_get(ctx->cfg, node, CFG_NODE_ATTR_TOKEN, &token);
+         if (token != NULL)
+             export_token(ctx, token);
+         else
+             export_format(ctx, "<?>");
+     }
+     return;
+ }
+ 
+ /* export configuration node tree into textual OSSP cfg syntax */
+ cfg_rc_t cfg_syn_export(
+     cfg_t *cfg,
+     cfg_node_t *node,
+     char **output)
+ {
+     cfg_buf_t *buf;
+     cfg_rc_t rc;
+     export_t ctx;
+     cfg_node_t *root;
+ 
+     if (node == NULL || output == NULL)
+         return CFG_ERR_ARG;
+     if ((rc = cfg_buf_create(&buf)) != CFG_OK)
+         return rc;
+ 
+     ctx.cfg    = cfg;
+     ctx.buf    = buf;
+     ctx.indent = 0;
+ 
+     if ((rc = cfg_node_root(cfg, NULL, &root)) != CFG_OK)
+         return rc;
+     if (node == root) {
+         /* if we dump the whole configuration, treat the first SEQ node special
+            because of the implicit braces around it. So expand it manually instead
+            of just calling once export_node(&ctx, node); */
+         cfg_node_get(cfg, node, CFG_NODE_ATTR_CHILD1, &node);
+         while (node != NULL) {
+             export_node(&ctx, node);
+             cfg_node_get(cfg, node, CFG_NODE_ATTR_RBROTH, &node);
+         }
+     }
+     else {
+         export_node(&ctx, node);
+     }
+ 
+     cfg_buf_content(buf, output, NULL, NULL);
+     cfg_buf_destroy(buf);
+ 
+     return CFG_OK;
+ }
+ 
+ /* internal cfg_syn_destroy helper function: recursive node destruction */
+ static cfg_rc_t cfg_syn_destroy_node(cfg_t *cfg, cfg_node_t *node)
+ {
+     if (node == NULL)
+         return CFG_ERR_ARG;
+     if (node->child1 != NULL)
+         cfg_syn_destroy_node(cfg, node->child1); /* recursion */
+     if (node->rbroth != NULL)
+         cfg_syn_destroy_node(cfg, node->rbroth); /* recursion */
+     cfg_node_destroy(cfg, node);
+     return CFG_OK;
+ }
+ 
+ /* destroy syntax node tree */
+ cfg_rc_t cfg_syn_destroy(cfg_t *cfg, cfg_node_t *node)
+ {
+     if (node == NULL)
+         return CFG_ERR_ARG;
+     cfg_syn_destroy_node(cfg, node);
+     return CFG_OK;
+ }
+ 

CVSTrac 2.0.1