registry.c
来自「《jsp编程起步》里面的所有源代码」· C语言 代码 · 共 424 行
C
424 行
/* * Copyright (c) 1999 Caucho Technology. All rights reserved. * * Caucho Technology permits redistribution, modification and use * of this file in source and binary form ("the Software") under the * Caucho Developer Source License ("the License"). In particular, the following * conditions must be met: * * 1. Each copy or derived work of the Software must preserve the copyright * notice and this notice unmodified. * * 2. Redistributions of the Software in source or binary form must include * an unmodified copy of the License, normally in a plain ASCII text * * 3. The names "Resin" or "Caucho" are trademarks of Caucho Technology and * may not be used to endorse products derived from this software. * "Resin" or "Caucho" may not appear in the names of products derived * from this software. * * 4. Caucho Technology requests that attribution be given to Resin * in any manner possible. We suggest using the "Resin Powered" * button or creating a "powered by Resin(tm)" link to * http://www.caucho.com for each page served by Resin. * * This Software is provided "AS IS," without a warranty of any kind. * ALL EXPRESS OR IMPLIED REPRESENTATIONS AND WARRANTIES, INCLUDING ANY * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. * Caucho Technology AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES * SUFFERED BY LICENSEE OR ANY THIRD PARTY AS A RESULT OF USING OR * DISTRIBUTING SOFTWARE. IN NO EVENT WILL Caucho OR ITS LICENSORS BE LIABLE * FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR * INABILITY TO USE SOFTWARE, EVEN IF HE HAS BEEN ADVISED OF THE POSSIBILITY * OF SUCH DAMAGES. */#include <stdio.h>#include <ctype.h>#include <string.h>#include <time.h>#include "cse.h"/* * stream_t is a convenience class containing the parse state. */typedef struct rstream_t { config_t *config; // configuration we're reading into FILE *file; // input stream to read char *path; // file name int line; // current line char *buf; // expandable buffer for reading tokens int length; // current length of the token in the buffer int capacity; // total buffer capacity} rstream_t;/* * Read a byte from the input stream, counting lines. */static intbuf_read(rstream_t *is){ int ch = fgetc(is->file); if (ch == '\n') is->line++; return ch;}/* * append a character to the token, expanding if necessary */static voidbuf_append(rstream_t *is, int ch){ if (is->length + 2 >= is->capacity) { char *old = is->buf; is->capacity *= 2; is->buf = cse_alloc(is->config, 2 * is->capacity); cse_free(is->config, old); } is->buf[is->length++] = ch;}/* * Add a child to the current registry node. */static registry_t *registry_add(rstream_t *is, registry_t *node, char *key){ registry_t *child = (registry_t *) cse_alloc(is->config, sizeof(registry_t)); memset(child, 0, sizeof(registry_t)); child->parent = node; child->key = key; if (node->last) { node->last->next = child; node->last = child; } else { node->first = child; node->last = child; } return child;}/* * Parse an attribute. * * The 'id' attribute is equivalent to a value of the parent node. * * entity references are not handled, i.e. ', " and &. */static int parse_attribute(rstream_t *is, registry_t *node, int ch){ registry_t *attr; for (; isspace(ch); ch = buf_read(is)) { } is->length = 0; for (; ch >= 0 && ! isspace(ch) && ch != '=' && ch != '/' && ch != '>'; ch = buf_read(is)) { buf_append(is, ch); } if (is->length == 0) { ungetc(ch, is->file); return 0; } is->buf[is->length] = 0; if (! strcmp(is->buf, "id")) attr = node; else attr = registry_add(is, node, cse_strdup(is->config, is->buf)); for (; isspace(ch); ch = buf_read(is)) { } if (ch != '=') { ungetc(ch, is->file); return 0; } for (ch = buf_read(is); isspace(ch); ch = buf_read(is)) { } if (ch < 0 || ch == '/' || ch == '>') { cse_error(is->config, "%s:%d: expected attribute at '%c'\n", is->path, is->line, ch); return -1; } if (ch == '\'' || ch == '\"') { int end = ch; is->length = 0; for (ch = buf_read(is); ch >= 0 && ch != end; ch = buf_read(is)) buf_append(is, ch); if (ch != end) { cse_error(is->config, "%s:%d: expected '%c' at '%c'\n", is->path, is->line, end, ch); return -1; } is->buf[is->length] = 0; attr->value = cse_strdup(is->config, is->buf); return ' '; } else { is->length = 0; for (; ch >= 0 && ! isspace(ch) && ch != '/' && ch != '>'; ch = buf_read(is)) { buf_append(is, ch); } is->buf[is->length] = 0; attr->value = cse_strdup(is->config, is->buf); return ch; }}/* * parses an open tag, including the attributes. */static intparse_tag(rstream_t *is, registry_t **p_node, int ch){ registry_t *node = *p_node; registry_t *child = 0; is->length = 0; for (; ch >= 0 && ! isspace(ch) && ch != '/' && ch != '>'; ch = buf_read(is)) { buf_append(is, ch); } if (is->length == 0) { cse_error(is->config, "%s:%d: unexpected char at '%c'\n", is->path, is->line, ch); return -1; } is->buf[is->length] = 0; child = registry_add(is, node, cse_strdup(is->config, is->buf)); while ((ch = parse_attribute(is, child, ch)) > 0) { } if (ch < 0) { cse_error(is->config, "%s:%d: unexpected end of file\n", is->path, is->line); return ch; } else if (ch == 0) ch = buf_read(is); for (; isspace(ch); ch = buf_read(is)) { } if (ch == '>') { *p_node = child; return 0; } else if (ch != '/') { cse_error(is->config, "%s:%d: expected '/' at '%c'\n", is->path, is->line, ch); return -1; } ch = buf_read(is); if (ch == '>') return 1; else { cse_error(is->config, "%s:%d: expected '>' at '%c'\n", is->path, is->line, ch); return -1; }}/* * parses a close tag */static intparse_end_tag(rstream_t *is, registry_t **node){ int ch; is->length = 0; for (ch = buf_read(is); ch >= 0 && ! isspace(ch) && ch != '/' && ch != '>'; ch = buf_read(is)) { buf_append(is, ch); } if (is->length == 0) { cse_error(is->config, "%s:%d: expected end tag at '%c'\n", is->path, is->line, ch); return -1; } for (; ch >= 0 && isspace(ch); ch = buf_read(is)) { } if (ch != '>') { cse_error(is->config, "%s:%d: expected '>' at '%c'\n", is->path, is->line, ch); return -1; } is->buf[is->length] = 0; // XXX: need to check *node = (*node)->parent; return 1;}/* * skips to the end of the comment */static voidskip_comment(rstream_t *is){ int ch; while ((ch = buf_read(is)) >= 0) { while (ch == '-') { ch = buf_read(is); while (ch == '-') { if ((ch = buf_read(is)) == '>') return; } } } cse_error(is->config, "%s:%d: expected comment end at end of file\n", is->path, is->line);}/* * Parses the configuration file. */registry_t *cse_parse(FILE *file, config_t *config){ int ch; rstream_t is; int spaceOnly = 1; registry_t *root; registry_t *node; is.file = file; is.path = config->path; is.line = 1; is.config = config; is.length = 0; is.capacity = 1024; is.buf = cse_alloc(config, is.capacity); root = (registry_t *) cse_alloc(config, sizeof(registry_t)); memset(root, 0, sizeof(registry_t)); root->key = ""; node = root; while ((ch = buf_read(&is)) >= 0) { switch (ch) { case ' ': case '\t': case '\n': case '\f': buf_append(&is, ch); break; case '<': if (spaceOnly) is.length = 0; else if (! node->value && ! node->first) { is.buf[is.length] = 0; node->value = cse_strdup(config, is.buf); } ch = buf_read(&is); if (ch == '!') { if ((ch = buf_read(&is)) != '-') cse_error(config, "%s:%d: expected comment start at '%c'\n", ch); if ((ch = buf_read(&is)) != '-') cse_error(config, "%s:%d: expected comment start at '%c'\n", ch); skip_comment(&is); } else if (ch != '/') { if (parse_tag(&is, &node, ch) < 0) return 0; } else { if (parse_end_tag(&is, &node) < 0) return 0; } break; default: spaceOnly = 0; buf_append(&is, ch); break; } } return root;}/* * Returns the next matching node. * * e.g. to iterate through all foo * for (node = cse_next_link(root->first, "foo"); * node; * node = cse_next_line(node->next, "foo")) { * } * */registry_t *cse_next_link(registry_t *node, char *key){ for (; node; node = node->next) { if (! strcmp(node->key, key)) return node; } return 0;}voidcse_print_registry(registry_t *registry){ if (! registry) return; for (; registry; registry = registry->next) { if (registry->first) { cse_log("<%s id=%s>\n", registry->key, registry->value ? registry->value : ""); cse_print_registry(registry->first); cse_log("</%s>\n", registry->key); } else cse_log("%s=%s\n", registry->key, registry->value ? registry->value : ""); }}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?