Point to the new location of the ZeroXML library that contains xmlgrep
This commit is contained in:
parent
2d267a5782
commit
ecccfeb18a
11 changed files with 3 additions and 3872 deletions
|
@ -1,111 +0,0 @@
|
|||
24-05-2009
|
||||
* Add a node cache that can be enabled at compile time.
|
||||
the node cache prevents recursively walking the xml tree over and over
|
||||
again to find the specified nodes.
|
||||
|
||||
05-05-2009
|
||||
* Various bugfixes, required to get fgrun working
|
||||
* add testxml as sort of a stress test application
|
||||
|
||||
30-04-2009
|
||||
* Add support for CDATA
|
||||
* Fix an off by one problem.
|
||||
|
||||
28-04-2009
|
||||
* changes to the code to allow walking the xml-tree using "*" as a node name
|
||||
* add printxml, an example utility that walks an xml-tree and prints it
|
||||
contenst
|
||||
|
||||
27-04-2009
|
||||
* add xmlInitBuffer() for processing of a preallocated buffer
|
||||
* add xmlErrorGetColumnNo to get the column number of the syntax error
|
||||
* pass an error at a higher level to lower levels
|
||||
* detect a number of extra syntax errors
|
||||
|
||||
26-04-2009
|
||||
* add support for comments inside xml-tags, e.g.: <test><!-- --></test>
|
||||
|
||||
25-04-2009
|
||||
* add support for self-contained tags like <test/>
|
||||
* fix a problem if a file could not be mmaped
|
||||
* add a few comments which hopefully makes the code easier to understand
|
||||
* code cleanups
|
||||
|
||||
20-04-2009
|
||||
* fix a case where a single-element root path (e.g. "/printer") would not
|
||||
pass xmlNodeGetPath
|
||||
* fix a problem where attributes or elements starting with the same letter
|
||||
sequence could give a false negative result
|
||||
* Add a 'clear' attribute to the xmlErrorGet functions that indicates whether
|
||||
the error should be cleared or not
|
||||
* detect more xml syntax errors
|
||||
|
||||
18-04-2009
|
||||
* Make the code compiler correctly under windows
|
||||
* Introduce a root-node that can hold extra information which is necessary
|
||||
for thread safety under windows
|
||||
* Add xmlErrorGetString, xmlErrorGetLineNo for syntax error detetction
|
||||
* Add xmlErrGetNo for detection of, and clearing the last error
|
||||
|
||||
16-04-2009
|
||||
* Rename xmlGetNode functions to xmlNodeGet for better consistancy
|
||||
* likewise for xmlCopyNode en xmlCompareNode
|
||||
* add xmlAttributeGetDouble, xmlAttributeGetInt, xmlAttributeGetString
|
||||
xmlAttributeCopyString and xmlAttributeCompareString functions
|
||||
* fix some small bugs and problems along the way
|
||||
* add support for filtering on attribute value in xmlgrep
|
||||
|
||||
21-07-2008
|
||||
* change a number of function parameters to const where appropriate
|
||||
* fix a problem where the wrong node-name length was returned
|
||||
* xmlgrep now also works when only the -e options is specified
|
||||
* fix xmlgrep to show the correct node-name (it reported the parent
|
||||
node-name in the previous version)
|
||||
|
||||
20-07-2008
|
||||
* fix __xmlSkipComment to properly find the end of comment tag.
|
||||
* add the xmlGetNodeName and xmlCopyNodeName functions
|
||||
* add the xmlCopyString function
|
||||
* clean up some code
|
||||
|
||||
19-07-2008
|
||||
* rewrite the code to always recursively walk the node tree when searching
|
||||
for a particular node. this is required for cases where a node with a
|
||||
particular name is located deeper in a node with the same name;
|
||||
for example -r /configuration/device/reference/device would fail in the
|
||||
previous verion
|
||||
* rename xmlGetElement to xmlGetNodeNum and add the possibility to request
|
||||
the nth node with this name
|
||||
* rename xmlGetNumElements to xmlGetNumNodes
|
||||
|
||||
06-07-2008
|
||||
* reorganize the code to be able to skip comment sections
|
||||
* depreciate __xmlFindNextElement and use __xmlGetNode instead
|
||||
* xmlGetNextElement now returns char* instead of void* for furute use
|
||||
* add preliminary support for wildcards in the search path ('*' and '?')
|
||||
|
||||
01-07-2008
|
||||
* fix a problem caused by removing the last unnecessary alloc
|
||||
* strip leading-, and trailing spaces from the string before comparing
|
||||
* fix a problem where trailing spaces weren't removed
|
||||
|
||||
30-06-2008:
|
||||
* some small changes; fix some typo's and fix a small memory leak
|
||||
* update the documentation in README
|
||||
* remove the last unnecessary alloc
|
||||
|
||||
29-06-2008:
|
||||
* rename xmlGet(Int/Double/String) to xmlGetNode(Int/Double/String)
|
||||
* add new xmlGet(Int/Double/String) functions
|
||||
* rename xmlCompareString to xmlCompareNodeString for consistency
|
||||
* rename xmlCompareElement to xmlCompareString for consistency
|
||||
* add a README file with short examples of various functions
|
||||
|
||||
27-06-2008:
|
||||
* removed some memory allocation in xmlGetNode and XMLGetNextElement
|
||||
* use the file-size for mmap and remove the root node from the xml-id
|
||||
* rearrange xmlGetNode to work with complicated xml files
|
||||
* add the xmlMarkId function to save the id before using xmlGetNextElement
|
||||
* speed up xmlGetNextId
|
||||
|
||||
23-06-2008: Initial release
|
|
@ -1,146 +1,6 @@
|
|||
This library is specially designed for reading xml configuration files and
|
||||
to be as low on memory management as possible. Modifying or writing xml files
|
||||
is not planned for the future. In most situations being able to gather data
|
||||
by reading an xml file is more than enough and the read-only decision
|
||||
provides a number of advantages over a one-size fits all approach. For isntance
|
||||
the memory footprint can be kept low and the library can be kept simple.
|
||||
|
||||
To achieve these goals the mmap function is used to map the configuration file
|
||||
to a memory region. The only places where memory is allocated is when creating
|
||||
a new XML-id, when requesting a string from a node, when requestiong the node
|
||||
name or when a request is made to copy a node into a new memory region.
|
||||
The xmlgrep utility is part op the ZeroXML package which is now hosted at:
|
||||
http://www.adalin.com
|
||||
|
||||
Using this library should be pretty simple for most tasks; just open a file,
|
||||
read every parameter one by one and close the id again.
|
||||
{
|
||||
void *xid;
|
||||
Any further development will take place there.
|
||||
|
||||
xid = xmlOpen("/tmp/file.xml");
|
||||
xpos = xmlNodeGetDouble(xid, "/configuration/x-pos");
|
||||
ypos = xmlNodeGetDouble(xid, "/configuration/y-pos");
|
||||
zpos = xmlNodeGetDouble(xid, "/configuration/z-pos");
|
||||
xmlClose(xid);
|
||||
}
|
||||
|
||||
While it is certainly possible to access every node directly by calling the
|
||||
xmlNodeGet(Int/Double/String) functions, when more than one node need to be
|
||||
gathered from a parent node it is advised to get the id of the parent node
|
||||
and work from there since the XML-id holds the boundaries of the (parent)node
|
||||
which limits the searching area resulting in improved searching speed.
|
||||
{
|
||||
void *xnid;
|
||||
char *s;
|
||||
|
||||
xnid = xmlNodeGet(id, "/configuration/setup/");
|
||||
version = xmlNodeGetDouble(xnid, "version");
|
||||
s = xmlNodeGetString(xnid, "author");
|
||||
if (s) author = s;
|
||||
free(s);
|
||||
free(xnid);
|
||||
}
|
||||
|
||||
Overview of the available functions:
|
||||
-----------------------------------------------------------------------------
|
||||
#
|
||||
# Functions to Open and Close the XML file
|
||||
# e.g.
|
||||
# id = xmlOpen("/tmp/file.xml");
|
||||
# xmlClose(id);
|
||||
#
|
||||
void *xmlOpen(const char *filename);
|
||||
void *xmlInitBuffer(const char *buffer, size_t size);
|
||||
void xmlClose(void *xid);
|
||||
|
||||
#
|
||||
# Get the Id of a node at the specified path
|
||||
# e.g.
|
||||
# xnid = xmlNodeGet(id, "/path/to/specified/node");
|
||||
#
|
||||
void *xmlNodeGet(const void *xid, const char *path);
|
||||
void *xmlNodeCopy(const void *xid, const char *path);
|
||||
|
||||
#
|
||||
# Functions to walk the node tree and process them one by one.
|
||||
# e.g.
|
||||
# xmid = xmlMarkId(id);
|
||||
# num = xmlNodeGetNum(xmid, "node");
|
||||
# for (i=0; i<num; i++) {
|
||||
# if (xmlNodeGetPos(id, xmid, "element", i) != 0) {
|
||||
# if ((s = xmlGetString(xmid)) != 0) {
|
||||
# printf("%s\n", s);
|
||||
# free(s);
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
# free(xmid);
|
||||
#
|
||||
void *xmlMarkId(const void *xid);
|
||||
unsigned int xmlNodeGetNum(const void *xid, const char *path);
|
||||
void *xmlNodeGetPos(const void *pid, void *xid, const char *element, int pos);
|
||||
|
||||
#
|
||||
# Get the name of the current node
|
||||
#
|
||||
char *xmlNodeGetName(const void *xid);
|
||||
size_t xmlNodeCopyName(const void *xid, const char *buffer, size_t size);
|
||||
|
||||
#
|
||||
# These functions work on the current node.
|
||||
# e.g.
|
||||
# xnid = xmlNodeGet(id, "/path/to/last/node");
|
||||
# i = xmlGetInt(xnid);
|
||||
# or
|
||||
# xnid = xmlNodeGet(id, "/path/to/specified/node");
|
||||
# if (xmlCompareString(xnid, "value") == 0) printf("We have a match!\n");
|
||||
#
|
||||
long int xmlGetInt(const void *xid);
|
||||
double xmlGetDouble(const void *xid);
|
||||
char *xmlGetString(const void *xid);
|
||||
size_t xmlCopyString(const void *xid, char *buffer, const size_t size);
|
||||
int xmlCompareString(const void *xid, const char *str);
|
||||
|
||||
#
|
||||
# These functions work on a specified node path
|
||||
# e.g.
|
||||
# d = xmlNodeGetDouble(id, "/path/to/node");
|
||||
# or
|
||||
# xnid = xmlNodeGet(id, "/path/to");
|
||||
# i = xmlNodeGetInt(xnid, "node");
|
||||
#
|
||||
long int xmlNodeGetInt(const void *xid, const char *path);
|
||||
double xmlNodeGetDouble(const void *xid, const char *path);
|
||||
char *xmlNodeGetString(const void *xid, const char *path);
|
||||
size_t xmlNodeCopyString(const void *xid, const char *path,
|
||||
char *buffer, const size_t size);
|
||||
int xmlNodeCompareString(const void *xid, const char *path, const char *str);
|
||||
|
||||
#
|
||||
# These functions work on a specified atribute
|
||||
# e.g.
|
||||
# i = xmlAttributeGetInt(id, "n");
|
||||
#
|
||||
# or
|
||||
# s = xmlAttributeGetString(id, "type");
|
||||
# if (s) printf("node is of type '%s'\n", s);
|
||||
# free(s);
|
||||
#
|
||||
long int xmlAttributeGetInt(const void *xid, const char *attr);
|
||||
double xmlAttributeGetDouble(const void *xid, const char *attr);
|
||||
char *xmlAttributeGetString(const void *xid, const char *attr);
|
||||
size_t xmlAttributeCopyString(const void *xid, const char *attr,
|
||||
const char *buffer, size_t size);
|
||||
int xmlAttributeCompareString(const void *xid, const char *attr,
|
||||
const char *str);
|
||||
|
||||
#
|
||||
# Error detection and reporting functions
|
||||
#
|
||||
# char *err_str = xmlErrorGetString(id, 0);
|
||||
# size_t err_lineno = xmlErrorGetLineNo(id, 0);
|
||||
# int err = xmlErrorGetNo(id, 1); /* clear last error */
|
||||
# if (err) printf("Error #%i at line %u: '%s'\n", err, err_lineno, err_str);
|
||||
#
|
||||
int xmlErrorGetNo(const void *xid, int clear);
|
||||
size_t xmlErrorGetLineNo(const void *xid, int clear);
|
||||
size_t xmlErrorGetColumnNo(const void *xid, int clear);
|
||||
const char *xmlErrorGetString(const void *xid, int clear);
|
||||
|
|
|
@ -1,96 +0,0 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#include "xml.h"
|
||||
|
||||
void print_xml(void *, char *, unsigned int);
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc < 1)
|
||||
{
|
||||
printf("usage: printtree <filename>\n\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
void *rid;
|
||||
|
||||
rid = xmlOpen(argv[1]);
|
||||
if (xmlErrorGetNo(rid, 0) != XML_NO_ERROR)
|
||||
{
|
||||
printf("%s\n", xmlErrorGetString(rid, 1));
|
||||
}
|
||||
else if (rid)
|
||||
{
|
||||
unsigned int i, num;
|
||||
void *xid;
|
||||
|
||||
xid = xmlMarkId(rid);
|
||||
num = xmlNodeGetNum(xid, "*");
|
||||
for (i=0; i<num; i++)
|
||||
{
|
||||
if (xmlNodeGetPos(rid, xid, "*", i) != 0)
|
||||
{
|
||||
char name[4096] = "";
|
||||
print_xml(xid, (char *)&name, 0);
|
||||
}
|
||||
}
|
||||
free(xid);
|
||||
|
||||
xmlClose(rid);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Error while opening file for reading: '%s'\n", argv[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void print_xml(void *id, char *name, unsigned int len)
|
||||
{
|
||||
void *xid = xmlMarkId(id);
|
||||
unsigned int i, num;
|
||||
|
||||
num = xmlNodeGetNum(xid, "*");
|
||||
if (num == 0)
|
||||
{
|
||||
char *s;
|
||||
s = xmlGetString(xid);
|
||||
if (s)
|
||||
{
|
||||
name[len] = 0;
|
||||
printf("%s = %s\n", name, s);
|
||||
free(s);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int i, q;
|
||||
|
||||
name[len++] = '/';
|
||||
for (i=0; i<num; i++)
|
||||
{
|
||||
if (xmlNodeGetPos(id, xid, "*", i) != 0)
|
||||
{
|
||||
unsigned int res, i = 4096 - len;
|
||||
res = xmlNodeCopyName(xid, (char *)&name[len], i);
|
||||
if (res)
|
||||
{
|
||||
unsigned int index = xmlAttributeGetInt(xid, "n");
|
||||
if (index)
|
||||
{
|
||||
unsigned int pos = len+res;
|
||||
|
||||
name[pos++] = '[';
|
||||
i = snprintf((char *)&name[pos], 4096-pos, "%i", index);
|
||||
name[pos+i] = ']';
|
||||
res += i+2;
|
||||
}
|
||||
}
|
||||
print_xml(xid, name, len+res);
|
||||
}
|
||||
else printf("error\n");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,95 +0,0 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#include "xml.h"
|
||||
|
||||
void print_xml(void *);
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc < 1)
|
||||
{
|
||||
printf("usage: printxml <filename>\n\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
void *rid;
|
||||
|
||||
rid = xmlOpen(argv[1]);
|
||||
if (xmlErrorGetNo(rid, 0) != XML_NO_ERROR)
|
||||
{
|
||||
printf("%s\n", xmlErrorGetString(rid, 1));
|
||||
}
|
||||
else if (rid)
|
||||
{
|
||||
unsigned int i, num;
|
||||
void *xid;
|
||||
|
||||
xid = xmlMarkId(rid);
|
||||
num = xmlNodeGetNum(xid, "*");
|
||||
for (i=0; i<num; i++)
|
||||
{
|
||||
if (xmlNodeGetPos(rid, xid, "*", i) != 0)
|
||||
{
|
||||
char name[256];
|
||||
xmlNodeCopyName(xid, (char *)&name, 256);
|
||||
printf("<%s>\n", name);
|
||||
print_xml(xid);
|
||||
printf("\n</%s>\n", name);
|
||||
}
|
||||
}
|
||||
free(xid);
|
||||
|
||||
xmlClose(rid);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Error while opening file for reading: '%s'\n", argv[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void print_xml(void *id)
|
||||
{
|
||||
static int level = 1;
|
||||
void *xid = xmlMarkId(id);
|
||||
unsigned int i, num;
|
||||
|
||||
num = xmlNodeGetNum(xid, "*");
|
||||
if (num == 0)
|
||||
{
|
||||
char *s;
|
||||
s = xmlGetString(xid);
|
||||
if (s)
|
||||
{
|
||||
printf("%s", s);
|
||||
free(s);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int i, q;
|
||||
for (i=0; i<num; i++)
|
||||
{
|
||||
if (xmlNodeGetPos(id, xid, "*", i) != 0)
|
||||
{
|
||||
char name[256];
|
||||
int r;
|
||||
|
||||
xmlNodeCopyName(xid, (char *)&name, 256);
|
||||
|
||||
printf("\n");
|
||||
for(q=0; q<level; q++) printf(" ");
|
||||
printf("<%s>", name);
|
||||
level++;
|
||||
print_xml(xid);
|
||||
level--;
|
||||
printf("</%s>", name);
|
||||
}
|
||||
else printf("error\n");
|
||||
}
|
||||
printf("\n");
|
||||
for(q=1; q<level; q++) printf(" ");
|
||||
}
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
|
||||
<Configuration>
|
||||
|
||||
<output>
|
||||
<frequency-hz>48000</frequency-hz>
|
||||
<interval-hz>20</interval-hz>
|
||||
<num-speakers>2</num-speakers>
|
||||
|
||||
<tmp><!-- --></tmp>
|
||||
<test n="0" ëlémènt="bjôrn"/>
|
||||
<test n="1"/>
|
||||
<test n="2"/>
|
||||
|
||||
<menu><name>* Traffic, # taxiing to runway (.</name></menu>
|
||||
<sample><test> * Traffic, # taxiing to runway (. </test></sample>
|
||||
|
||||
<!--
|
||||
- x is positive to the right
|
||||
- y is positive upwards
|
||||
- z is positive backwards
|
||||
-->
|
||||
<speaker n="0">
|
||||
<channel>0</channel>
|
||||
<volume-norm>1.0</volume-norm>
|
||||
<desc><!-- empty --></desc>
|
||||
</speaker>
|
||||
|
||||
<speaker n="1">
|
||||
<channel>1</channel>
|
||||
<volume-norm>1.0</volume-norm>
|
||||
<desc>
|
||||
<!--
|
||||
empty --></desc>
|
||||
</speaker>
|
||||
|
||||
<script><![CDATA[
|
||||
getprop(call(sprintf, size(arg));
|
||||
c--; x >>= 33;
|
||||
// --> comment ]>
|
||||
;]]></script>
|
||||
</output>
|
||||
|
||||
<backend>
|
||||
<name type="stereo">ALSA Hardware</name>
|
||||
<Output>
|
||||
<renderer>hw:0</renderer>
|
||||
<channels>2</channels>
|
||||
<!-- periods>16</periods -->
|
||||
<frequency-hz>44100</frequency-hz>
|
||||
<bits-per-sample>16</bits-per-sample>
|
||||
</Output>
|
||||
<Input>
|
||||
<renderer>default</renderer>
|
||||
<frequency-hz>44100</frequency-hz>
|
||||
</Input>
|
||||
</backend>
|
||||
|
||||
<nasal>
|
||||
<YF23>
|
||||
<script><![CDATA[
|
||||
# If the ground-roll-heading-hold has been reset (<-999) set:
|
||||
if(agl > 50) {};
|
||||
]]></script>
|
||||
</YF23>
|
||||
</nasal>
|
||||
|
||||
</Configuration>
|
|
@ -1,188 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
#include <assert.h>
|
||||
#include "xml.h"
|
||||
|
||||
#define ROOTNODE "/Configuration/output/menu"
|
||||
#define LEAFNODE "name"
|
||||
#define PATH ROOTNODE"/"LEAFNODE
|
||||
#define BUFLEN 4096
|
||||
|
||||
#define PRINT_ERROR_AND_EXIT(id) \
|
||||
if (xmlErrorGetNo(id, 0) != XML_NO_ERROR) { \
|
||||
const char *errstr = xmlErrorGetString(id, 0); \
|
||||
size_t column = xmlErrorGetColumnNo(id, 0); \
|
||||
size_t lineno = xmlErrorGetLineNo(id, 1); \
|
||||
printf("Error at line %i, column %i: %s\n", lineno, column, errstr); \
|
||||
exit(-1); \
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
void *root_id;
|
||||
|
||||
root_id = xmlOpen("sample.xml");
|
||||
if (root_id)
|
||||
{
|
||||
void *path_id, *node_id;
|
||||
char *s;
|
||||
|
||||
printf("\nTesting xmlNodeGetString for /*/*/test:\t\t\t\t\t");
|
||||
s = xmlNodeGetString(root_id , "/*/*/test");
|
||||
if (s)
|
||||
{
|
||||
printf("failed.\n\t'%s' should be empty\n", s);
|
||||
free(s);
|
||||
}
|
||||
else
|
||||
printf("succes.\n");
|
||||
|
||||
printf("Testing xmlGetString for /Configuration/output/test:\t\t\t");
|
||||
path_id = xmlNodeGet(root_id, "/Configuration/output/test");
|
||||
if (path_id)
|
||||
{
|
||||
s = xmlGetString(path_id);
|
||||
if (s)
|
||||
{
|
||||
printf("failed.\n\t'%s' should be empty\n", s);
|
||||
free(s);
|
||||
}
|
||||
else
|
||||
printf("succes.\n");
|
||||
}
|
||||
else
|
||||
PRINT_ERROR_AND_EXIT(root_id);
|
||||
|
||||
path_id = xmlNodeGet(root_id, PATH);
|
||||
node_id = xmlNodeGet(root_id, ROOTNODE);
|
||||
|
||||
if (path_id && node_id)
|
||||
{
|
||||
char buf[BUFLEN];
|
||||
size_t len;
|
||||
|
||||
xmlCopyString(path_id, buf, BUFLEN);
|
||||
printf("Testing xmlNodeCopyString against xmlGetString:\t\t\t\t");
|
||||
if ((s = xmlGetString(path_id)) != 0)
|
||||
{
|
||||
if (strcmp(s, buf)) /* not the same */
|
||||
printf("failed.\n\t'%s' differs from '%s'\n", s, buf);
|
||||
else
|
||||
printf("succes.\n");
|
||||
|
||||
printf("Testing xmlCopyString against xmlGetString:\t\t\t\t");
|
||||
xmlCopyString(path_id, buf, BUFLEN);
|
||||
if (strcmp(s, buf)) /* not the same */
|
||||
printf("failed.\n\t'%s' differs from\n\t'%s'\n", s, buf);
|
||||
else
|
||||
printf("succes.\n");
|
||||
}
|
||||
else
|
||||
PRINT_ERROR_AND_EXIT(path_id);
|
||||
|
||||
printf("Testing xmlCopyString against xmlCompareString:\t\t\t\t");
|
||||
if (xmlCompareString(path_id, buf)) /* not the same */
|
||||
printf ("failed.\n\t'%s' differs from\n\t'%s'\n", s, buf);
|
||||
else
|
||||
printf("succes.\n");
|
||||
|
||||
printf("Testing xmlCopyString against xmlNodeCompareString:\t\t\t");
|
||||
if (xmlNodeCompareString(node_id, LEAFNODE, buf)) /* not the same */
|
||||
printf("failed.\n\t'%s' differs from\n\t'%s'\n", s, buf);
|
||||
else
|
||||
printf("succes.\n");
|
||||
|
||||
if (s) free(s);
|
||||
|
||||
printf("Testing xmlCopyString against xmlNodeGetString:\t\t\t\t");
|
||||
if ((s = xmlNodeGetString(node_id, LEAFNODE)) != 0)
|
||||
{
|
||||
if (strcmp(s, buf)) /* not the same */
|
||||
printf("failed.\n\t'%s' differs from\n\t'%s'\n", s, buf);
|
||||
else
|
||||
printf("succes.\n");
|
||||
free(s);
|
||||
}
|
||||
else
|
||||
PRINT_ERROR_AND_EXIT(node_id);
|
||||
|
||||
free(path_id);
|
||||
path_id = xmlNodeGet(root_id, "/Configuration/backend/name");
|
||||
if (path_id)
|
||||
{
|
||||
printf("Testing xmlAttributeCopyString against xmlAttributeCompareString:\t");
|
||||
xmlAttributeCopyString(path_id, "type", buf, BUFLEN);
|
||||
if (xmlAttributeCompareString(path_id, "type", buf)) /* no match */
|
||||
printf("failed.\n\t'%s' differs\n", buf);
|
||||
else
|
||||
printf("succes.\n");
|
||||
|
||||
printf("Testing xmlAttributeCopyString against xmlAttributeGetString:\t\t");
|
||||
if ((s = xmlAttributeGetString(path_id, "type")) != 0)
|
||||
{
|
||||
if (strcmp(s, buf)) /* not the same */
|
||||
printf("failed.\n\t'%s' differs from '%s'\n", s, buf);
|
||||
else
|
||||
printf("succes.\n");
|
||||
free(s);
|
||||
}
|
||||
else
|
||||
PRINT_ERROR_AND_EXIT(path_id);
|
||||
|
||||
}
|
||||
else
|
||||
PRINT_ERROR_AND_EXIT(root_id);
|
||||
|
||||
free(node_id);
|
||||
free(path_id);
|
||||
|
||||
path_id = xmlNodeGet(root_id, "Configuration/output/sample/test");
|
||||
if (path_id)
|
||||
{
|
||||
xmlNodeCopyString(root_id ,"Configuration/output/menu/name", buf, BUFLEN);
|
||||
printf("Testing xmlCompareString against a fixed string: \t\t\t");
|
||||
if (xmlCompareString(path_id, buf)) /* no match */
|
||||
printf("failed.\n\t'%s' differs\n", buf);
|
||||
else
|
||||
printf("succes.\n");
|
||||
|
||||
s = xmlGetString(path_id);
|
||||
if (s)
|
||||
{
|
||||
printf("Testing xmlGetString against a fixed string: \t\t\t\t");
|
||||
if (strcmp(s, buf)) /* mismatch */
|
||||
printf("failed.\n\t'%s' differs from\n\t'%s'\n", s, buf);
|
||||
else
|
||||
printf("succes.\n");
|
||||
|
||||
printf("Testing xmlCopyString gainst a fixed string: \t\t\t\t");
|
||||
xmlCopyString(path_id, buf, BUFLEN);
|
||||
if (strcmp(s, buf)) /* mismatch */
|
||||
printf("failed.\n\t'%s' differs from\n\t'%s'\n", s, buf);
|
||||
else
|
||||
printf("succes.\n");
|
||||
|
||||
free(s);
|
||||
}
|
||||
else
|
||||
PRINT_ERROR_AND_EXIT(path_id);
|
||||
|
||||
free(path_id);
|
||||
}
|
||||
}
|
||||
|
||||
if (xmlErrorGetNo(root_id, 0) != XML_NO_ERROR)
|
||||
{
|
||||
const char *errstr = xmlErrorGetString(root_id, 0);
|
||||
size_t column = xmlErrorGetColumnNo(root_id, 0);
|
||||
size_t lineno = xmlErrorGetLineNo(root_id, 1);
|
||||
|
||||
printf("Error at line %i, column %i: %s\n", lineno, column, errstr);
|
||||
}
|
||||
|
||||
xmlClose(root_id);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
return 0;
|
||||
}
|
1995
utils/xmlgrep/xml.c
1995
utils/xmlgrep/xml.c
File diff suppressed because it is too large
Load diff
|
@ -1,434 +0,0 @@
|
|||
/* Copyright (c) 2007-2009 by Adalin B.V.
|
||||
* Copyright (c) 2007-2009 by Erik Hofman
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of (any of) the copyrightholder(s) nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS 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 COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __XML_CONFIG
|
||||
#define __XML_CONFIG 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#undef XML_NONVALIDATING
|
||||
|
||||
#ifdef XML_USE_NODECACHE
|
||||
#include "xml_cache.h"
|
||||
#else
|
||||
void *cacheGet(void *);
|
||||
#endif
|
||||
|
||||
enum
|
||||
{
|
||||
XML_NO_ERROR = 0,
|
||||
XML_OUT_OF_MEMORY,
|
||||
XML_FILE_NOT_FOUND,
|
||||
XML_INVALID_NODE_NAME,
|
||||
XML_UNEXPECTED_EOF,
|
||||
XML_TRUNCATE_RESULT,
|
||||
XML_INVALID_COMMENT,
|
||||
XML_INVALID_INFO_BLOCK,
|
||||
XML_ELEMENT_NO_OPENING_TAG,
|
||||
XML_ELEMENT_NO_CLOSING_TAG,
|
||||
XML_ATTRIB_NO_OPENING_QUOTE,
|
||||
XML_ATTRIB_NO_CLOSING_QUOTE,
|
||||
XML_MAX_ERROR
|
||||
};
|
||||
|
||||
#ifdef WIN32
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# include <windows.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
HANDLE m;
|
||||
void *p;
|
||||
} SIMPLE_UNMMAP;
|
||||
#endif
|
||||
|
||||
#ifndef XML_NONVALIDATING
|
||||
struct _xml_error
|
||||
{
|
||||
char *pos;
|
||||
int err_no;
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* It is required for both the rood node and the normal xml nodes to both
|
||||
* have 'char *name' defined as the first entry. The code tests whether
|
||||
* name == 0 to detect the root node.
|
||||
*/
|
||||
struct _root_id
|
||||
{
|
||||
char *name;
|
||||
char *start;
|
||||
size_t len;
|
||||
int fd;
|
||||
#ifdef XML_USE_NODECACHE
|
||||
void *node;
|
||||
#endif
|
||||
#ifndef XML_NONVALIDATING
|
||||
struct _xml_error *info;
|
||||
#endif
|
||||
#ifdef WIN32
|
||||
SIMPLE_UNMMAP un;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct _xml_id
|
||||
{
|
||||
char *name;
|
||||
char *start;
|
||||
size_t len;
|
||||
size_t name_len;
|
||||
#ifndef XML_NONVALIDATING
|
||||
struct _root_id *root;
|
||||
#endif
|
||||
#ifdef XML_USE_NODECACHE
|
||||
void *node;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Open an XML file for processing.
|
||||
*
|
||||
* @param fname path to the file
|
||||
* @return XML-id which is used for further processing
|
||||
*/
|
||||
void *xmlOpen(const char *);
|
||||
|
||||
/**
|
||||
* Process a section of XML code in a preallocated buffer.
|
||||
* The buffer may not be free'd until xmlClose has been called.
|
||||
*
|
||||
* @param buffer pointer to the buffer
|
||||
* @param size size of the buffer
|
||||
* @return XML-id which is used for further processing
|
||||
*/
|
||||
void *xmlInitBuffer(const char *, size_t);
|
||||
|
||||
/**
|
||||
* Close the XML file after which no further processing is possible.
|
||||
*
|
||||
* @param xid XML-id
|
||||
*/
|
||||
void xmlClose(void *);
|
||||
|
||||
|
||||
/**
|
||||
* Locate a subsection of the xml tree for further processing.
|
||||
* This adds processing speed since the reuired nodes will only be searched
|
||||
* in the subsection.
|
||||
*
|
||||
* The memory allocated for the XML-subsection-id has to be freed by the
|
||||
* calling process.
|
||||
*
|
||||
* @param xid XML-id
|
||||
* @param node path to the node containing the subsection
|
||||
* @return XML-subsection-id for further processing
|
||||
*/
|
||||
void *xmlNodeGet(const void *, const char *);
|
||||
|
||||
/**
|
||||
* Copy a subsection of the xml tree for further processing.
|
||||
* This is useful when it's required to process a section of the XML code
|
||||
* after the file has been closed. The drawback is the added memory
|
||||
* requirements.
|
||||
*
|
||||
* The memory allocated for the XML-subsection-id has to be freed by the
|
||||
* calling process.
|
||||
*
|
||||
* @param xid XML-id
|
||||
* @param node path to the node containing the subsection
|
||||
* @return XML-subsection-id for further processing
|
||||
*/
|
||||
void *xmlNodeCopy(const void *, const char *);
|
||||
|
||||
|
||||
/**
|
||||
* Return the name of this node.
|
||||
* The returned string has to be freed by the calling process.
|
||||
*
|
||||
* @param xid XML-id
|
||||
* @return a newly alocated string containing the node name
|
||||
*/
|
||||
char *xmlNodeGetName(const void *);
|
||||
|
||||
/**
|
||||
* Copy the name of this node in a pre-allocated buffer.
|
||||
*
|
||||
* @param xid XML-id
|
||||
* @param buffer the buffer to copy the string to
|
||||
* @param buflen length of the destination buffer
|
||||
* @return the length of the node name
|
||||
*/
|
||||
size_t xmlNodeCopyName(const void *, char *, size_t);
|
||||
|
||||
|
||||
/**
|
||||
* Create a marker XML-id that starts out with the same settings as the
|
||||
* refference XML-id.
|
||||
*
|
||||
* Marker id's are required when xmlNodeGetNum() and xmlNodeGetPos() are used
|
||||
* to walk a number of nodes. The xmlNodeGetPos function adjusts the contents
|
||||
* of the provided XML-id to keep track of it's position within the xml section.
|
||||
* The returned XML-id is limited to the boundaries of the requested XML tag
|
||||
* and has to be freed by the calling process.
|
||||
*
|
||||
* @param xid reference XML-id
|
||||
* @return a copy of the reference XML-id
|
||||
*/
|
||||
void *xmlMarkId(const void *);
|
||||
|
||||
/**
|
||||
* Get the number of nodes with the same name from a specified xml path.
|
||||
*
|
||||
* @param xid XML-id
|
||||
* @param path path to the xml node
|
||||
* @return the number count of the nodename
|
||||
*/
|
||||
unsigned int xmlNodeGetNum(const void *, const char *);
|
||||
|
||||
/**
|
||||
* Get the nth occurrence of node in the parent node.
|
||||
* The return value should never be altered or freed by the caller.
|
||||
*
|
||||
* @param pid XML-id of the parent node of this node
|
||||
* @param xid XML-id
|
||||
* @param node name of the node to search for
|
||||
* @param num specify which occurence to return
|
||||
* @return XML-subsection-id for further processing or NULL if unsuccessful
|
||||
*/
|
||||
void *xmlNodeGetPos(const void *, void *, const char *, size_t);
|
||||
|
||||
|
||||
/**
|
||||
* Get a string of characters from the current node.
|
||||
* The returned string has to be freed by the calling process.
|
||||
*
|
||||
* @param xid XML-id
|
||||
* @return a newly alocated string containing the contents of the node
|
||||
*/
|
||||
char *xmlGetString(const void *);
|
||||
|
||||
/**
|
||||
* Get a string of characters from the current node.
|
||||
* This function has the advantage of not allocating its own return buffer,
|
||||
* keeping the memory management to an absolute minimum but the disadvantage
|
||||
* is that it's unreliable in multithread environments.
|
||||
*
|
||||
* @param xid XML-id
|
||||
* @param buffer the buffer to copy the string to
|
||||
* @param buflen length of the destination buffer
|
||||
* @return the length of the string
|
||||
*/
|
||||
size_t xmlCopyString(const void *, char *, size_t);
|
||||
|
||||
/**
|
||||
* Compare the value of this node to a reference string.
|
||||
* Comparing is done in a case insensitive way.
|
||||
*
|
||||
* @param xid XML-id
|
||||
* @param str the string to compare to
|
||||
* @return an integer less than, equal to, ro greater than zero if the value
|
||||
* of the node is found, respectively, to be less than, to match, or be greater
|
||||
* than str
|
||||
*/
|
||||
int xmlCompareString(const void *, const char *);
|
||||
|
||||
/**
|
||||
* Get a string of characters from a specified xml path.
|
||||
* The returned string has to be freed by the calling process.
|
||||
*
|
||||
* @param xid XML-id
|
||||
* @param path path to the xml node
|
||||
* @return a newly alocated string containing the contents of the node
|
||||
*/
|
||||
char *xmlNodeGetString(const void *, const char *);
|
||||
|
||||
/**
|
||||
* Get a string of characters from a specified xml path.
|
||||
* This function has the advantage of not allocating its own return buffer,
|
||||
* keeping the memory management to an absolute minimum but the disadvantage
|
||||
* is that it's unreliable in multithread environments.
|
||||
*
|
||||
* @param xid XML-id
|
||||
* @param path path to the xml node
|
||||
* @param buffer the buffer to copy the string to
|
||||
* @param buflen length of the destination buffer
|
||||
* @return the length of the string
|
||||
*/
|
||||
size_t xmlNodeCopyString(const void *, const char *, char *, size_t);
|
||||
|
||||
/**
|
||||
* Compare the value of a node to a reference string.
|
||||
* Comparing is done in a case insensitive way.
|
||||
*
|
||||
* @param xid XML-id
|
||||
* @param path path to the xml node to compare to
|
||||
* @param str the string to compare to
|
||||
* @return an integer less than, equal to, ro greater than zero if the value
|
||||
* of the node is found, respectively, to be less than, to match, or be greater
|
||||
* than str
|
||||
*/
|
||||
int xmlNodeCompareString(const void *, const char *, const char *);
|
||||
|
||||
/**
|
||||
* Get a string of characters from a named attribute.
|
||||
* The returned string has to be freed by the calling process.
|
||||
*
|
||||
* @param xid XML-id
|
||||
* @param name name of the attribute to acquire
|
||||
* @return the contents of the node converted to an integer value
|
||||
*/
|
||||
char *xmlAttributeGetString(const void *, const char *);
|
||||
|
||||
/**
|
||||
* Get a string of characters from a named attribute.
|
||||
* This function has the advantage of not allocating its own return buffer,
|
||||
* keeping the memory management to an absolute minimum but the disadvantage
|
||||
* is that it's unreliable in multithread environments.
|
||||
*
|
||||
* @param xid XML-id
|
||||
* @param name name of the attribute to acquire.
|
||||
* @param buffer the buffer to copy the string to
|
||||
* @param buflen length of the destination buffer
|
||||
* @return the length of the string
|
||||
*/
|
||||
size_t xmlAttributeCopyString(const void *, const char *, char *, size_t);
|
||||
|
||||
/**
|
||||
* Compare the value of an attribute to a reference string.
|
||||
* Comparing is done in a case insensitive way.
|
||||
*
|
||||
* @param xid XML-id
|
||||
* @param name name of the attribute to acquire.
|
||||
* @param str the string to compare to
|
||||
* @return an integer less than, equal to, ro greater than zero if the value
|
||||
* of the node is found, respectively, to be less than, to match, or be greater
|
||||
* than str
|
||||
*/
|
||||
int xmlAttributeCompareString(const void *, const char *, const char *);
|
||||
|
||||
|
||||
/**
|
||||
* Get the integer value from the current node/
|
||||
*
|
||||
* @param xid XML-id
|
||||
* @return the contents of the node converted to an integer value
|
||||
*/
|
||||
long int xmlGetInt(const void *);
|
||||
|
||||
/**
|
||||
* Get an integer value from a specified xml path.
|
||||
*
|
||||
* @param xid XML-id
|
||||
* @param path path to the xml node
|
||||
* @return the contents of the node converted to an integer value
|
||||
*/
|
||||
long int xmlNodeGetInt(const void *, const char *);
|
||||
|
||||
/**
|
||||
* Get the integer value from the named attribute.
|
||||
*
|
||||
* @param xid XML-id
|
||||
* @param name name of the attribute to acquire
|
||||
* @return the contents of the node converted to an integer value
|
||||
*/
|
||||
long int xmlAttributeGetInt(const void *, const char *);
|
||||
|
||||
|
||||
/**
|
||||
* Get the double value from the curent node/
|
||||
*
|
||||
* @param xid XML-id
|
||||
* @return the contents of the node converted to a double value
|
||||
*/
|
||||
double xmlGetDouble(const void *);
|
||||
|
||||
/**
|
||||
* Get a double value from a specified xml path/
|
||||
*
|
||||
* @param xid XML-id
|
||||
* @param path path to the xml node
|
||||
* @return the contents of the node converted to a double value
|
||||
*/
|
||||
double xmlNodeGetDouble(const void *, const char *);
|
||||
|
||||
/**
|
||||
* Get the double value from the named attribute.
|
||||
*
|
||||
* @param xid XML-id
|
||||
* @param name name of the attribute to acquire
|
||||
* @return the contents of the node converted to an integer value
|
||||
*/
|
||||
double xmlAttributeGetDouble(const void *, const char *);
|
||||
|
||||
|
||||
/**
|
||||
* Get the error number of the last error and clear it.
|
||||
*
|
||||
* @param xid XML-id
|
||||
* @param clear clear the error state if non zero
|
||||
* @return the numer of the last error, 0 means no error detected.
|
||||
*/
|
||||
int xmlErrorGetNo(const void *, int);
|
||||
|
||||
/**
|
||||
* Get the line number of the last detected syntax error in the xml file.
|
||||
*
|
||||
* @param xid XML-id
|
||||
* @param clear clear the error state if non zero
|
||||
* @return the line number of the detected syntax error.
|
||||
*/
|
||||
size_t xmlErrorGetLineNo(const void *, int);
|
||||
|
||||
/**
|
||||
* Get the column number of the last detected syntax error in the xml file.
|
||||
*
|
||||
* @param xid XML-id
|
||||
* @param clear clear the error state if non zero
|
||||
* @return the line number of the detected syntax error.
|
||||
*/
|
||||
size_t xmlErrorGetColumnNo(const void *, int);
|
||||
|
||||
/**
|
||||
* Get a string that explains the last error.
|
||||
*
|
||||
* @param xid XML-id
|
||||
* @param clear clear the error state if non zero
|
||||
* @return a string that explains the last error.
|
||||
*/
|
||||
const char *xmlErrorGetString(const void *, int);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __XML_CONFIG */
|
||||
|
|
@ -1,250 +0,0 @@
|
|||
/* Copyright (c) 2007-2009 by Adalin B.V.
|
||||
* Copyright (c) 2007-2009 by Erik Hofman
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of (any of) the copyrightholder(s) nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS 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 COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* 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 <sys/types.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "xml.h"
|
||||
|
||||
#ifndef NDEBUG
|
||||
# define PRINT(a, b, c) { \
|
||||
size_t l1 = (b), l2 = (c); \
|
||||
char *s = (a); \
|
||||
if (s) { \
|
||||
size_t q, len = l2; \
|
||||
if (l1 < l2) len = l1; \
|
||||
if (len < 50000) { \
|
||||
printf("(%i) '", len); \
|
||||
for (q=0; q<len; q++) printf("%c", s[q]); \
|
||||
printf("'\n"); \
|
||||
} else printf("Length (%u) seems too large at line %i\n",len, __LINE__); \
|
||||
} else printf("NULL pointer at line %i\n", __LINE__); \
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(XML_USE_NODECACHE)
|
||||
void *
|
||||
cacheNodeGet(void *id, const char *node)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define NODE_BLOCKSIZE 16
|
||||
|
||||
struct _xml_node
|
||||
{
|
||||
void *parent;
|
||||
char *name;
|
||||
size_t name_len;
|
||||
char *data;
|
||||
size_t data_len;
|
||||
void **node;
|
||||
size_t no_nodes;
|
||||
size_t first_free;
|
||||
};
|
||||
|
||||
char *
|
||||
__xmlNodeGetFromCache(void **nc, const char *start, size_t *len,
|
||||
char **element, size_t *elementlen , size_t *nodenum)
|
||||
{
|
||||
struct _xml_node *cache;
|
||||
size_t num = *nodenum;
|
||||
char *name = *element;
|
||||
void *rv = 0;
|
||||
|
||||
assert(nc != 0);
|
||||
|
||||
cache = (struct _xml_node *)*nc;
|
||||
assert(cache != 0);
|
||||
|
||||
assert((cache->first_free > num) || (cache->first_free == 0));
|
||||
|
||||
if (cache->first_free == 0) /* leaf node */
|
||||
{
|
||||
rv = cache->data;
|
||||
*len = cache->data_len;
|
||||
*element = cache->name;
|
||||
*elementlen = cache->name_len;
|
||||
*nodenum = 0;
|
||||
}
|
||||
else if (*name == '*')
|
||||
{
|
||||
struct _xml_node *node = cache->node[num];
|
||||
*nc = node;
|
||||
rv = node->data;
|
||||
*len = node->data_len;
|
||||
*element = node->name;
|
||||
*elementlen = node->name_len;
|
||||
*nodenum = cache->first_free;
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t namelen = *elementlen;
|
||||
size_t i, pos = 0;
|
||||
|
||||
for (i=0; i<cache->first_free; i++)
|
||||
{
|
||||
struct _xml_node *node = cache->node[i];
|
||||
|
||||
assert(node);
|
||||
|
||||
if ((node->name_len == namelen) &&
|
||||
(!strncasecmp(node->name, name, namelen)))
|
||||
{
|
||||
if (pos == num)
|
||||
{
|
||||
*nc = node;
|
||||
rv = node->data;
|
||||
*element = node->name;
|
||||
*elementlen = node->name_len;
|
||||
*len = node->data_len;
|
||||
*nodenum = cache->first_free;
|
||||
break;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
cacheInit()
|
||||
{
|
||||
return calloc(1, sizeof(struct _xml_node));
|
||||
}
|
||||
|
||||
void
|
||||
cacheInitLevel(void *nc)
|
||||
{
|
||||
struct _xml_node *cache = (struct _xml_node *)nc;
|
||||
|
||||
assert(cache != 0);
|
||||
|
||||
cache->node = calloc(NODE_BLOCKSIZE, sizeof(struct _xml_node *));
|
||||
cache->no_nodes = NODE_BLOCKSIZE;
|
||||
}
|
||||
|
||||
void
|
||||
cacheFree(void *nc)
|
||||
{
|
||||
struct _xml_node *cache = (struct _xml_node *)nc;
|
||||
|
||||
assert(nc != 0);
|
||||
|
||||
if (cache->first_free)
|
||||
{
|
||||
struct _xml_node **node = (struct _xml_node **)cache->node;
|
||||
size_t i = 0;
|
||||
|
||||
while(i < cache->first_free)
|
||||
{
|
||||
cacheFree(node[i++]);
|
||||
}
|
||||
|
||||
free(node);
|
||||
}
|
||||
free(cache);
|
||||
}
|
||||
|
||||
void *
|
||||
cacheNodeGet(void *id)
|
||||
{
|
||||
struct _xml_id *xid = (struct _xml_id *)id;
|
||||
struct _xml_node *cache = 0;
|
||||
|
||||
assert(xid != 0);
|
||||
|
||||
if (xid->name)
|
||||
{
|
||||
cache = xid->node;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct _root_id *rid = (struct _root_id *)xid;
|
||||
cache = rid->node;
|
||||
}
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
void *
|
||||
cacheNodeNew(void *nc)
|
||||
{
|
||||
struct _xml_node *cache = (struct _xml_node *)nc;
|
||||
struct _xml_node *rv = 0;
|
||||
size_t i = 0;
|
||||
|
||||
assert(nc != 0);
|
||||
|
||||
i = cache->first_free;
|
||||
if (i == cache->no_nodes)
|
||||
{
|
||||
size_t size, no_nodes;
|
||||
void *p;
|
||||
|
||||
no_nodes = cache->no_nodes + NODE_BLOCKSIZE;
|
||||
size = no_nodes * sizeof(struct _xml_node *);
|
||||
p = realloc(cache->node, size);
|
||||
if (!p) return 0;
|
||||
|
||||
cache->node = p;
|
||||
cache->no_nodes = no_nodes;
|
||||
}
|
||||
|
||||
rv = calloc(1, sizeof(struct _xml_node));
|
||||
if (rv) rv->parent = cache;
|
||||
cache->node[i] = rv;
|
||||
cache->first_free++;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
cacheDataSet(void *n, char *name, size_t namelen, char *data, size_t datalen)
|
||||
{
|
||||
struct _xml_node *node = (struct _xml_node *)n;
|
||||
|
||||
assert(node != 0);
|
||||
assert(name != 0);
|
||||
assert(namelen != 0);
|
||||
assert(data != 0);
|
||||
|
||||
node->name = name;
|
||||
node->name_len = namelen;
|
||||
node->data = data;
|
||||
node->data_len = datalen;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
/* Copyright (c) 2007-2009 by Adalin B.V.
|
||||
* Copyright (c) 2007-2009 by Erik Hofman
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of (any of) the copyrightholder(s) nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS 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 COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __XML_NODECACHE
|
||||
#define __XML_NODECACHE 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void *cacheInit();
|
||||
void cacheInitLevel(void *);
|
||||
void cacheFree(void *);
|
||||
void *cacheNodeNew(void *);
|
||||
|
||||
void *cacheNodeGet(void *);
|
||||
void cacheDataSet(void *, char *, size_t, char *, size_t);
|
||||
|
||||
char *__xmlNodeGetFromCache(void **, const char *, size_t *, char **, size_t *, size_t *);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __XML_NODECACHE */
|
||||
|
|
@ -1,442 +0,0 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifndef _MSC_VER
|
||||
# include <strings.h>
|
||||
# include <unistd.h> /* read */
|
||||
#else
|
||||
# define strncasecmp strnicmp
|
||||
# include <stdlib.h>
|
||||
# include <io.h>
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#include <sys/stat.h> /* fstat */
|
||||
#include <fcntl.h> /* open */
|
||||
|
||||
#include "xml.h"
|
||||
|
||||
static const char *_static_root = "/";
|
||||
static const char *_static_element = "*";
|
||||
static unsigned int _fcount = 0;
|
||||
static char **_filenames = 0;
|
||||
static char *_element = 0;
|
||||
static char *_value = 0;
|
||||
static char *_root = 0;
|
||||
static char *_print = 0;
|
||||
static char *_attribute = 0;
|
||||
static int print_filenames = 0;
|
||||
|
||||
static void free_and_exit(int i);
|
||||
|
||||
#define USE_BUFFER 0
|
||||
#define NODE_NAME_LEN 256
|
||||
#define STRING_LEN 2048
|
||||
|
||||
#define SHOW_NOVAL(opt) \
|
||||
{ \
|
||||
printf("option '%s' requires a value\n\n", (opt)); \
|
||||
free_and_exit(-1); \
|
||||
}
|
||||
|
||||
void
|
||||
show_help ()
|
||||
{
|
||||
printf("usage: xmlgrep [options] [file ...]\n\n");
|
||||
printf("Options:\n");
|
||||
printf("\t-h\t\tshow this help message\n");
|
||||
printf("\t-a <string>\tprint this attribute as the output\n");
|
||||
printf("\t-e <id>\t\tshow sections that contain this element\n");
|
||||
printf("\t-p <id>\t\tprint this element as the output\n");
|
||||
printf("\t-r <path>\tspecify the XML search root\n");
|
||||
printf("\t-v <string>\tfilter sections that contain this vale\n\n");
|
||||
printf(" To print the contents of the 'type' element of the XML section ");
|
||||
printf("that begins\n at '/printer/output' use the following command:\n\n");
|
||||
printf("\txmlgrep -r /printer/output -p type sample.xml\n\n");
|
||||
printf(" To filter 'output' elements under '/printer' that have attribute");
|
||||
printf(" 'n' set to '1'\n use the following command:\n\n");
|
||||
printf("\txmlgrep -r /printer -p output -a n -v 1 sample.xml\n\n");
|
||||
printf(" To filter out sections that contain the 'driver' element with ");
|
||||
printf("'generic' as\n it's value use the following command:");
|
||||
printf("\n\n\txmlgrep -r /printer/output -e driver -v generic sample.xml");
|
||||
printf("\n\n");
|
||||
free_and_exit(0);
|
||||
}
|
||||
|
||||
void
|
||||
free_and_exit(int ret)
|
||||
{
|
||||
if (_root && _root != _static_root) free(_root);
|
||||
if (_element && _element != _static_element) free(_element);
|
||||
if (_value) free(_value);
|
||||
if (_print) free(_print);
|
||||
if (_attribute) free(_attribute);
|
||||
if (_filenames)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i=0; i < _fcount; i++)
|
||||
{
|
||||
if (_filenames[i])
|
||||
{
|
||||
if (print_filenames) printf("%s\n", _filenames[i]);
|
||||
free(_filenames[i]);
|
||||
}
|
||||
}
|
||||
free(_filenames);
|
||||
}
|
||||
|
||||
exit(ret);
|
||||
}
|
||||
|
||||
int
|
||||
parse_option(char **args, int n, int max)
|
||||
{
|
||||
char *opt, *arg = 0;
|
||||
unsigned int alen = 0;
|
||||
unsigned int olen;
|
||||
|
||||
opt = args[n];
|
||||
if (strncmp(opt, "--", 2) == 0)
|
||||
opt++;
|
||||
|
||||
if ((arg = strchr(opt, '=')) != NULL)
|
||||
{
|
||||
*arg++ = 0;
|
||||
}
|
||||
else if (++n < max)
|
||||
{
|
||||
arg = args[n];
|
||||
#if 0
|
||||
if (arg && arg[0] == '-')
|
||||
arg = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
olen = strlen(opt);
|
||||
if (strncmp(opt, "-help", olen) == 0)
|
||||
{
|
||||
show_help();
|
||||
}
|
||||
else if (strncmp(opt, "-root", olen) == 0)
|
||||
{
|
||||
if (arg == 0) SHOW_NOVAL(opt);
|
||||
alen = strlen(arg)+1;
|
||||
if (_root) free(_root);
|
||||
_root = malloc(alen);
|
||||
memcpy(_root, arg, alen);
|
||||
return 2;
|
||||
}
|
||||
else if (strncmp(opt, "-element", olen) == 0)
|
||||
{
|
||||
if (arg == 0) SHOW_NOVAL(opt);
|
||||
alen = strlen(arg)+1;
|
||||
if (_element) free(_element);
|
||||
_element = malloc(alen);
|
||||
memcpy(_element, arg, alen);
|
||||
return 2;
|
||||
}
|
||||
else if (strncmp(opt, "-value", olen) == 0)
|
||||
{
|
||||
if (arg == 0) SHOW_NOVAL(opt);
|
||||
alen = strlen(arg)+1;
|
||||
if (_value) free(_value);
|
||||
_value = malloc(alen);
|
||||
memcpy(_value, arg, alen);
|
||||
return 2;
|
||||
}
|
||||
else if (strncmp(opt, "-print", olen) == 0)
|
||||
{
|
||||
if (arg == 0) SHOW_NOVAL(opt);
|
||||
alen = strlen(arg)+1;
|
||||
if (_print) free(_print);
|
||||
_print = malloc(alen);
|
||||
memcpy(_print, arg, alen);
|
||||
return 2;
|
||||
}
|
||||
else if (strncmp(opt, "-attribute", olen) == 0)
|
||||
{
|
||||
if (arg == 0) SHOW_NOVAL(opt);
|
||||
alen = strlen(arg)+1;
|
||||
if (_attribute) free(_attribute);
|
||||
_attribute = malloc(alen);
|
||||
memcpy(_attribute, arg, alen);
|
||||
return 2;
|
||||
}
|
||||
else if (strncmp(opt, "-list-filenames", olen) == 0)
|
||||
{ /* undocumented test argument */
|
||||
print_filenames = 1;
|
||||
return 1;
|
||||
}
|
||||
else if (opt[0] == '-')
|
||||
{
|
||||
printf("Unknown option %s\n", opt);
|
||||
free_and_exit(-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
int pos = _fcount++;
|
||||
if (_filenames == 0)
|
||||
{
|
||||
_filenames = (char **)malloc(sizeof(char*));
|
||||
}
|
||||
else
|
||||
{
|
||||
char **ptr = (char **)realloc(_filenames, _fcount*sizeof(char*));
|
||||
if (ptr == 0)
|
||||
{
|
||||
printf("Out of memory.\n\n");
|
||||
free_and_exit(-1);
|
||||
}
|
||||
_filenames = ptr;
|
||||
}
|
||||
|
||||
alen = strlen(opt)+1;
|
||||
_filenames[pos] = malloc(alen);
|
||||
memcpy(_filenames[pos], opt, alen);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void walk_the_tree(size_t num, void *xid, char *tree)
|
||||
{
|
||||
unsigned int i, no_elements;
|
||||
|
||||
if (!tree) /* last node from the tree */
|
||||
{
|
||||
void *xmid = xmlMarkId(xid);
|
||||
if (xmid && _print)
|
||||
{
|
||||
no_elements = xmlNodeGetNum(xid, _print);
|
||||
for (i=0; i<no_elements; i++)
|
||||
{
|
||||
if (xmlNodeGetPos(xid, xmid, _print, i) != 0)
|
||||
{
|
||||
char *value;
|
||||
|
||||
value = xmlGetString(xmid);
|
||||
if (_value && _attribute && value)
|
||||
{
|
||||
#if 1
|
||||
char *a = xmlAttributeGetString(xmid, _attribute);
|
||||
if (a && !strcmp(a, _value))
|
||||
#else
|
||||
if (!xmlAttributeCompareString(xmid, _attribute, _value))
|
||||
#endif
|
||||
{
|
||||
printf("%s: <%s %s=\"%s\">%s</%s>\n",
|
||||
_filenames[num], _print, _attribute, _value,
|
||||
value, _print);
|
||||
}
|
||||
if (value) free(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("%s: <%s>%s</%s>\n",
|
||||
_filenames[num], _print, value, _print);
|
||||
}
|
||||
}
|
||||
}
|
||||
free(xmid);
|
||||
}
|
||||
else if (xmid && _value)
|
||||
{
|
||||
no_elements = xmlNodeGetNum(xmid, _element);
|
||||
for (i=0; i<no_elements; i++)
|
||||
{
|
||||
if (xmlNodeGetPos(xid, xmid, _element, i) != 0)
|
||||
{
|
||||
char nodename[NODE_NAME_LEN];
|
||||
|
||||
xmlNodeCopyName(xmid, (char *)&nodename, NODE_NAME_LEN);
|
||||
if (xmlCompareString(xmid, _value) == 0)
|
||||
{
|
||||
printf("%s: <%s>%s</%s>\n",
|
||||
_filenames[num], nodename, _value, nodename);
|
||||
}
|
||||
}
|
||||
}
|
||||
free(xmid);
|
||||
}
|
||||
else if (xmid && _element)
|
||||
{
|
||||
char parentname[NODE_NAME_LEN];
|
||||
|
||||
xmlNodeCopyName(xid, (char *)&parentname, NODE_NAME_LEN);
|
||||
|
||||
no_elements = xmlNodeGetNum(xmid, _element);
|
||||
for (i=0; i<no_elements; i++)
|
||||
{
|
||||
if (xmlNodeGetPos(xid, xmid, _element, i) != 0)
|
||||
{
|
||||
char nodename[NODE_NAME_LEN];
|
||||
|
||||
xmlNodeCopyName(xmid, (char *)&nodename, NODE_NAME_LEN);
|
||||
if (!strncasecmp((char*)&nodename, _element, NODE_NAME_LEN))
|
||||
{
|
||||
char value[NODE_NAME_LEN];
|
||||
xmlCopyString(xmid, (char *)&value, NODE_NAME_LEN);
|
||||
printf("%s: <%s> <%s>%s</%s> </%s>\n",
|
||||
_filenames[num], parentname, nodename, value,
|
||||
nodename, parentname);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else printf("Error executing xmlMarkId\n");
|
||||
}
|
||||
else if (xid) /* walk the rest of the tree */
|
||||
{
|
||||
char *elem, *next;
|
||||
void *xmid;
|
||||
|
||||
elem = tree;
|
||||
if (*elem == '/') elem++;
|
||||
|
||||
next = strchr(elem, '/');
|
||||
|
||||
xmid = xmlMarkId(xid);
|
||||
if (xmid)
|
||||
{
|
||||
if (next)
|
||||
{
|
||||
*next++ = 0;
|
||||
}
|
||||
|
||||
no_elements = xmlNodeGetNum(xid, elem);
|
||||
for (i=0; i<no_elements; i++)
|
||||
{
|
||||
if (xmlNodeGetPos(xid, xmid, elem, i) != 0)
|
||||
walk_the_tree(num, xmid, next);
|
||||
}
|
||||
|
||||
if (next)
|
||||
{
|
||||
*--next = '/';
|
||||
}
|
||||
|
||||
free(xmid);
|
||||
}
|
||||
else printf("Error executing xmlMarkId\n");
|
||||
}
|
||||
}
|
||||
|
||||
void grep_file(unsigned num)
|
||||
{
|
||||
void *xid;
|
||||
|
||||
xid = xmlOpen(_filenames[num]);
|
||||
if (xid)
|
||||
{
|
||||
void *xrid = xmlMarkId(xid);
|
||||
int r = 0;
|
||||
|
||||
walk_the_tree(num, xrid, _root);
|
||||
|
||||
r = xmlErrorGetNo(xrid, 0);
|
||||
if (r)
|
||||
{
|
||||
size_t n = xmlErrorGetLineNo(xrid, 0);
|
||||
size_t c = xmlErrorGetColumnNo(xrid, 0);
|
||||
const char *s = xmlErrorGetString(xrid, 1); /* clear the error */
|
||||
printf("%s: at line %u, column %u: '%s'\n",_filenames[num], n,c, s);
|
||||
}
|
||||
|
||||
free(xrid);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Error reading file '%s'\n", _filenames[num]);
|
||||
}
|
||||
|
||||
xmlClose(xid);
|
||||
}
|
||||
|
||||
|
||||
void grep_file_buffer(unsigned num)
|
||||
{
|
||||
struct stat st;
|
||||
void *xid, *buf;
|
||||
int fd, res;
|
||||
|
||||
fd = open(_filenames[num], O_RDONLY);
|
||||
if (fd == -1)
|
||||
{
|
||||
printf("read error opening file '%s'\n", _filenames[num]);
|
||||
return;
|
||||
}
|
||||
|
||||
fstat(fd, &st);
|
||||
buf = malloc(st.st_size);
|
||||
if (!buf)
|
||||
{
|
||||
printf("unable to allocate enough memory for reading.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
res = read(fd, buf, st.st_size);
|
||||
if (res == -1)
|
||||
{
|
||||
printf("unable to read from file '%s'.\n", _filenames[num]);
|
||||
return;
|
||||
}
|
||||
close(fd);
|
||||
|
||||
xid = xmlInitBuffer(buf, st.st_size);
|
||||
if (xid)
|
||||
{
|
||||
void *xrid = xmlMarkId(xid);
|
||||
int r = 0;
|
||||
|
||||
walk_the_tree(num, xrid, _root);
|
||||
|
||||
r = xmlErrorGetNo(xrid, 0);
|
||||
if (r)
|
||||
{
|
||||
size_t n = xmlErrorGetLineNo(xrid, 0);
|
||||
size_t c = xmlErrorGetColumnNo(xrid, 0);
|
||||
const char *s = xmlErrorGetString(xrid, 1); /* clear the error */
|
||||
printf("%s: at line %u, column %u: '%s'\n",_filenames[num], n,c, s);
|
||||
}
|
||||
|
||||
free(xrid);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Error reading file '%s'\n", _filenames[num]);
|
||||
}
|
||||
|
||||
xmlClose(xid);
|
||||
free(buf);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
unsigned int u;
|
||||
int i;
|
||||
|
||||
if (argc == 1)
|
||||
show_help();
|
||||
|
||||
for (i=1; i<argc;)
|
||||
{
|
||||
int ret = parse_option(argv, i, argc);
|
||||
i += ret;
|
||||
}
|
||||
|
||||
if (_root == 0) _root = (char *)_static_root;
|
||||
if (_element == 0) _element = (char *)_static_element;
|
||||
|
||||
for (u=0; u<_fcount; u++)
|
||||
#if USE_BUFFER
|
||||
grep_file_buffer(u);
|
||||
#else
|
||||
grep_file(u);
|
||||
#endif
|
||||
|
||||
free_and_exit(0);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue