📄 sflxmll.c
字号:
/* ----------------------------------------------------------------<Prolog>-
Name: sflxmll.c
Title: XML serialisation functions
Package: Standard Function Library (SFL)
Written: 1996/06/08 iMatix SFL project team <sfl@imatix.com>
Revised: 2000/02/02
Synopsis: Loads XML file into memory, to/from disk files.
Copyright: Copyright (c) 1991-2000 iMatix Corporation
License: This is free software; you can redistribute it and/or modify
it under the terms of the SFL License Agreement as provided
in the file LICENSE.TXT. This software is distributed in
the hope that it will be useful, but without any warranty.
------------------------------------------------------------------</Prolog>-*/
#include "prelude.h" /* Universal include file */
#include "sfldate.h" /* Date and time functions */
#include "sflfile.h" /* File access functions */
#include "sfllist.h" /* List access functions */
#include "sflmem.h" /* Memory allocation functions */
#include "sflstr.h" /* String access functions */
#include "sflxml.h" /* XML definitions */
#include "sflsymb.h"
#include "sflhttp.h" /* Meta-char encoding/decoding */
#include "sflxmll.h" /* Include prototype data */
#include "sflxmll.d" /* Include dialog data */
/* Function prototypes */
static int xml_save_file_item (FILE *xmlfile, XML_ITEM *item,
int generation);
static void xml_save_string_item (char *xml_string, XML_ITEM *item);
static size_t xml_item_size (XML_ITEM *item);
static void init_charmaps (void);
static void build_charmap (byte flag, char *chars);
static int xml_start_dialog (void);
static void expect_token (char expect);
static char get_next_char (void);
static char get_next_non_white_char (void);
static int collect_name (void);
static char *collect_literal (char terminator);
static void error_exception (char *format, ...);
/*- Global variables used in this source file only --------------------------*/
static int
feedback, /* Feedback for calling program */
char_nbr, /* Current read position in line */
line_nbr, /* Input line nbr from file */
generation; /* How many levels of children */
static const char
*ppath, /* XML file path as specified */
*pname; /* XML file name as specified */
static char
*fname, /* Full file name of XML file */
*literal, /* String of any length */
*xmltext, /* Pointer to XML string */
*xmlline, /* Current line w/space for EOL */
token [LINE_MAX + 1], /* Token from input stream */
name [LINE_MAX + 1], /* Saved name */
error_message [LINE_MAX + 1]; /* Saved name */
static FILE
*xmlfile;
static XML_ITEM
*item, /* Current XML item */
*top_item, /* Current top-level XML item */
*root; /* Root XML item */
static Bool
extended; /* Extended or normal load? */
/* Character classification tables and macros */
static byte
cmap [256]; /* Character classification tables */
#define CMAP_NAME 1 /* Normal name character */
#define CMAP_NAME_OPEN 2 /* Valid character to start name */
#define CMAP_QUOTE 4 /* Possible string delimiters */
#define CMAP_PRINTABLE 8 /* Valid characters in literal */
#define CMAP_DECIMAL 16 /* Decimal digits */
#define CMAP_HEX 32 /* Hexadecimal digits */
/* Macros for character mapping: */
#define is_name(ch) (cmap [(byte) (ch)] & CMAP_NAME)
#define is_name_open(ch) (cmap [(byte) (ch)] & CMAP_NAME_OPEN)
#define is_quote(ch) (cmap [(byte) (ch)] & CMAP_QUOTE)
#define is_printable(ch) (cmap [(byte) (ch)] & CMAP_PRINTABLE)
#define is_decimal(ch) (cmap [(byte) (ch)] & CMAP_DECIMAL)
#define is_hex(ch) (cmap [(byte) (ch)] & CMAP_HEX)
/* ---------------------------------------------------------------------[<]-
Function: xml_save_file
Synopsis: Saves an XML tree to the specified file. Returns XML_NOERROR
or XML_FILEERROR.
---------------------------------------------------------------------[>]-*/
int
xml_save_file (
XML_ITEM *item,
const char *filename)
{
FILE
*xmlfile; /* XML output stream */
int
count; /* How many symbols did we save? */
ASSERT (item);
ASSERT (filename);
init_charmaps (); /* Initialise character maps */
if ((xmlfile = file_open (filename, 'w')) == NULL)
return XML_FILEERROR; /* No permission to write file */
/* Write XML file header */
fprintf (xmlfile, "<?xml version=\"1.0\"?>\n");
/* Output XML root */
count = xml_save_file_item (xmlfile, item, 0);
/* Output a final carriage return */
fprintf (xmlfile, "\n");
file_close (xmlfile);
return XML_NOERROR;
}
/* -------------------------------------------------------------------------
* init_charmaps
*
* Initialise character map bit tables. These are used to speed-up
* token recognition and collection.
*/
static void
init_charmaps (void)
{
memset (cmap, 0, sizeof (cmap)); /* Clear all bitmaps */
/* Name ::= (Letter | '_' | ':') (NameChar)* */
/* NameChar ::= Letter | Digit | MiscName */
/* Map fixed character sets to various bitmaps */
build_charmap (CMAP_NAME, "abcdefghijklmnopqrstuvwxyz");
build_charmap (CMAP_NAME, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
build_charmap (CMAP_NAME, "0123456789");
build_charmap (CMAP_NAME, "_:.-");
build_charmap (CMAP_NAME_OPEN, "abcdefghijklmnopqrstuvwxyz");
build_charmap (CMAP_NAME_OPEN, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
build_charmap (CMAP_NAME_OPEN, "_:");
build_charmap (CMAP_QUOTE, "\"'");
/* Printable characters. ??? */
build_charmap (CMAP_PRINTABLE, "abcdefghijklmnopqrstuvwxyz");
build_charmap (CMAP_PRINTABLE, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
build_charmap (CMAP_PRINTABLE, "0123456789");
build_charmap (CMAP_PRINTABLE, "!@#$%^&*()-_=+[]{}\\|;:'\"<>,./?`~ ");
build_charmap (CMAP_DECIMAL, "0123456789");
build_charmap (CMAP_HEX, "abcdefghijklmnopqrstuvwxyz");
build_charmap (CMAP_HEX, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
build_charmap (CMAP_HEX, "0123456789");
}
/* -------------------------------------------------------------------------
* build_charmap
*
* Encode character string and flag into character map table. Flag should
* be a 1-bit value from 1 to 128 (character map is 8 bits wide).
*/
static void
build_charmap (byte flag, char *string)
{
for (; *string; string++)
cmap [(byte) *string] |= flag;
}
static int
xml_save_file_item (FILE *xmlfile, XML_ITEM *item, int generation)
{
int
count = 1; /* Count 1 for current item */
XML_ITEM
*child,
*sibling;
XML_ATTR
*attr;
char
*item_name,
*attr_name,
*ptr;
Bool
pretty;
/* First output item name and attributes */
item_name = xml_item_name (item);
if (item_name)
{
fprintf (xmlfile, "<%s", item_name);
FORATTRIBUTES (attr, item)
{
attr_name = xml_attr_name (attr);
ptr = xml_attr_value (attr);
http_encode_meta (token, &ptr, LINE_MAX, FALSE);
fprintf (xmlfile, "\n%*s%s = \"%s", (generation + 1) * 4, "",
attr_name, token);
while (*ptr)
{
http_encode_meta (token, &ptr, LINE_MAX, FALSE);
fprintf (xmlfile, "\n%s", token);
}
fprintf (xmlfile, "\"");
}
/* If value or children exist, use long form, otherwise short form */
if ((child = xml_first_child (item)))
{
fprintf (xmlfile, ">");
pretty = TRUE;
for (sibling = child ;
sibling != NULL ;
sibling = xml_next_sibling (sibling))
if (! xml_item_name (sibling))
pretty = FALSE;
else
break;
for ( ; child != NULL; child = xml_next_sibling (child))
{
if (pretty)
fprintf (xmlfile, "\n%*s", (generation + 1) * 4, "");
count += xml_save_file_item (xmlfile, child,
generation + 1);
if (xml_item_name (child))
{
pretty = TRUE;
for (sibling = xml_next_sibling (child) ;
sibling != NULL ;
sibling = xml_next_sibling (sibling))
if (! xml_item_name (sibling))
pretty = FALSE;
else
break;
}
}
if (pretty)
fprintf (xmlfile, "\n%*s", generation * 4, "");
fprintf (xmlfile, "</%s>", item_name);
}
else
fprintf (xmlfile, "/>");
}
else /* Not name => this is a value node */
{
ptr = xml_item_value (item);
if (ptr)
while (*ptr)
{
http_encode_meta (token, &ptr, LINE_MAX, FALSE);
fprintf (xmlfile, "%s", token);
}
}
return (count);
}
/* ---------------------------------------------------------------------[<]-
Function: xml_save_string
Synopsis: Saves an XML tree to a string. Returns a freshly-allocated
string containing the XML tree, or NULL if there was insufficient memory
to allocate a new string.
---------------------------------------------------------------------[>]-*/
char *
xml_save_string (
XML_ITEM *item)
{
size_t
xml_size;
char
*xml_string;
ASSERT (item);
init_charmaps (); /* Initialise character maps */
xml_size = xml_item_size (item);
xml_string = mem_alloc (xml_size + 1000);
if (xml_string)
xml_save_string_item (xml_string, item);
return (xml_string);
}
/* Return string size of XML item and all its children */
static size_t
xml_item_size (XML_ITEM *item)
{
size_t
item_size = 0;
XML_ITEM
*child = NULL;
XML_ATTR
*attr;
char
*item_name,
*attr_name,
*ptr;
/* First output item name and attributes */
item_name = xml_item_name (item);
if (item_name)
{
/* Count '<name' */
item_size += strlen (item_name) + 1;
FORATTRIBUTES (attr, item)
{
attr_name = xml_attr_name (attr);
ptr = xml_attr_value (attr);
/* Count ' name="value"' */
item_size += strlen (attr_name) + 4;
while (*ptr)
{
http_encode_meta (token, &ptr, LINE_MAX, FALSE);
item_size += strlen (token);
}
}
/* If value or children exist, use long form, otherwise short form */
if ((child = xml_first_child (item)))
{
/* Count '>' and '</name>' */
item_size += strlen (name) + 4;
for (child = xml_first_child (item);
child != NULL;
child = xml_next_sibling (child))
item_size += xml_item_size (child);
}
else
/* Count '/>' */
item_size += 2;
}
else /* No name => this is a value node */
{
ptr = xml_item_value (item);
while (*ptr)
{
http_encode_meta (token, &ptr, LINE_MAX, FALSE);
item_size += strlen (token);
}
}
return (item_size);
}
static void
xml_save_string_item (char *xml_string, XML_ITEM *item)
{
XML_ITEM
*child = NULL;
XML_ATTR
*attr;
char
*item_name,
*attr_name,
*ptr;
/* First output item name and attributes */
xml_string [0] = 0;
item_name = xml_item_name (item);
if (item_name)
{
xstrcat (xml_string, "<", item_name, NULL);
FORATTRIBUTES (attr, item)
{
attr_name = xml_attr_name (attr);
ptr = xml_attr_value (attr);
xstrcat (xml_string, " ", attr_name, "=\"", NULL);
while (*ptr)
{
http_encode_meta (token, &ptr, LINE_MAX, FALSE);
strcat (xml_string, token);
}
strcat (xml_string, "\"");
}
/* If value or children exist, use long form, otherwise short form */
if ((child = xml_first_child (item)))
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -