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. &apos;, &quot; and &amp;. */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 + -
显示快捷键?