Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
ccan
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
mirror
ccan
Commits
385e0e53
Commit
385e0e53
authored
Sep 05, 2011
by
Daniel Burke
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
ttxml: Rplaced ratchet buffer with regular buffer, 20x speed increase
parent
b679512e
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
166 additions
and
114 deletions
+166
-114
ccan/ttxml/ttxml.c
ccan/ttxml/ttxml.c
+164
-112
ccan/ttxml/ttxml.h
ccan/ttxml/ttxml.h
+2
-2
No files found.
ccan/ttxml/ttxml.c
View file @
385e0e53
/* Licensed under GPL - see LICENSE file for details */
/* Licensed under GPL - see LICENSE file for details */
#include <stdlib.h>
#include <stdlib.h>
#include <string.h>
#include <string.h>
#include <stdio.h>
#include <stdio.h>
...
@@ -6,7 +7,34 @@
...
@@ -6,7 +7,34 @@
#include "ttxml.h"
#include "ttxml.h"
XmlNode
*
xml_new
(
char
*
name
,
char
*
attrib
)
#define BUFFER 3264
#define XML_LETTER 1
#define XML_NUMBER 2
#define XML_SPACE 4
#define XML_SLASH 8
#define XML_OPEN 16
#define XML_EQUALS 32
#define XML_CLOSE 64
#define XML_QUOTE 128
#define XML_OTHER 256
#define XML_ALL 0xFFFFFFFF
typedef
struct
XMLBUF
{
FILE
*
fptr
;
char
*
buf
;
int
len
;
int
read_index
;
int
eof
;
}
XMLBUF
;
/* Allocate a new XmlNode */
XmlNode
*
xml_new
(
char
*
name
)
{
{
XmlNode
*
ret
=
malloc
(
sizeof
(
XmlNode
));
XmlNode
*
ret
=
malloc
(
sizeof
(
XmlNode
));
if
(
!
ret
)
return
NULL
;
if
(
!
ret
)
return
NULL
;
...
@@ -19,7 +47,7 @@ XmlNode* xml_new(char * name, char * attrib)
...
@@ -19,7 +47,7 @@ XmlNode* xml_new(char * name, char * attrib)
return
ret
;
return
ret
;
}
}
/* free a previously allocated XmlNode */
void
xml_free
(
XmlNode
*
target
)
void
xml_free
(
XmlNode
*
target
)
{
{
int
i
;
int
i
;
...
@@ -34,19 +62,12 @@ void xml_free(XmlNode *target)
...
@@ -34,19 +62,12 @@ void xml_free(XmlNode *target)
free
(
target
);
free
(
target
);
}
}
#define XML_LETTER 1
/* raise flags if we have a character of special meaning
#define XML_NUMBER 2
*
#define XML_SPACE 4
* This is where I've hidden the switch statements :-p
#define XML_SLASH 8
*
#define XML_OPEN 16
*/
#define XML_EQUALS 32
int
is_special
(
char
item
)
#define XML_CLOSE 64
#define XML_QUOTE 128
#define XML_OTHER 256
#define XML_ALL 0xFFFFFFFF
static
int
is_special
(
char
item
)
{
{
if
((
item
>=
'a'
&&
item
<=
'z'
)
||
(
item
>=
'A'
&&
item
<=
'Z'
))
if
((
item
>=
'a'
&&
item
<=
'z'
)
||
(
item
>=
'A'
&&
item
<=
'Z'
))
return
XML_LETTER
;
return
XML_LETTER
;
...
@@ -67,67 +88,53 @@ static int is_special(char item)
...
@@ -67,67 +88,53 @@ static int is_special(char item)
return
128
;
return
128
;
}
}
struct
XMLBUF
/* Refresh the buffer, expects not to be called when EOF */
static
void
xml_read_file
(
XMLBUF
*
xml
)
{
{
FILE
*
fptr
;
int
size
;
char
*
buf
;
int
len
;
int
eof
;
};
static
void
xml_consume
(
struct
XMLBUF
*
xml
,
int
offset
)
{
int
size
,
request
,
received
;
size
=
xml
->
len
-
offset
;
size
=
fread
(
xml
->
buf
,
1
,
xml
->
len
,
xml
->
fptr
);
if
(
size
!=
xml
->
len
)
if
(
!
xml
->
len
)
return
;
if
(
size
)
{
// printf("Size=%d, off=%d, len=%d\n", size, offset, xml->len);
memmove
(
xml
->
buf
,
xml
->
buf
+
offset
,
size
);
}
if
(
xml
->
eof
)
{
{
xml
->
len
=
size
;
xml
->
len
=
size
;
xml
->
buf
[
size
]
=
0
;
xml
->
buf
[
size
]
=
0
;
return
;
xml
->
eof
=
1
;
}
}
}
request
=
xml
->
len
-
size
;
received
=
fread
(
xml
->
buf
+
size
,
1
,
request
,
xml
->
fptr
);
if
(
received
==
request
)
return
;
xml
->
len
=
size
+
received
;
/* All reading of the XML buffer done through these two functions */
xml
->
eof
=
1
;
/*** read a byte without advancing the offset */
xml
->
buf
[
xml
->
len
]
=
0
;
static
char
xml_peek
(
XMLBUF
*
xml
)
return
;
{
return
xml
->
buf
[
xml
->
read_index
];
}
}
/*** read a byte and advance the offset */
static
void
xml_skip
(
struct
XMLBUF
*
xml
,
int
mask
)
static
char
xml_read_byte
(
XMLBUF
*
xml
)
{
{
int
offset
=
0
;
char
ret
=
xml_peek
(
xml
)
;
if
(
!
xml
->
len
)
return
;
xml
->
read_index
++
;
while
(
is_special
(
xml
->
buf
[
offset
])
&
mask
)
if
(
xml
->
read_index
>=
xml
->
len
)
{
{
offset
++
;
if
(
xml
->
eof
)
return
ret
;
if
(
offset
==
xml
->
len
)
xml
->
read_index
=
0
;
{
xml_read_file
(
xml
);
xml_consume
(
xml
,
offset
);
offset
=
0
;
if
(
!
xml
->
len
)
return
;
}
}
}
xml_consume
(
xml
,
offset
)
;
return
ret
;
}
}
/* skip over bytes matching the is_special mask */
static
void
xml_skip
(
XMLBUF
*
xml
,
int
mask
)
{
printf
(
"just called
\n
"
);
while
(
is_special
(
xml_peek
(
xml
))
&
mask
&&
xml
->
len
)
xml_read_byte
(
xml
);
}
/* character matching tests for the feed functions */
static
char
quotechar
=
0
;
static
char
quotechar
=
0
;
static
int
test_quote
(
const
char
x
)
static
int
test_quote
(
const
char
x
)
{
{
...
@@ -148,38 +155,59 @@ static int test_mask(const char x)
...
@@ -148,38 +155,59 @@ static int test_mask(const char x)
return
!
(
is_special
(
x
)
&
feed_mask
);
return
!
(
is_special
(
x
)
&
feed_mask
);
}
}
static
char
*
xml_feed
(
struct
XMLBUF
*
xml
,
int
(
*
test
)(
char
)
)
/*
* char* xml_feed(x, test)
*
* Reads as many contiguous chars that pass test() into a newly allocated
* string.
*
* Instead of calling xml_read_byte and flogging realloc() for each byte,
* it checks the buffer itself.
*/
static
char
*
xml_feed
(
XMLBUF
*
xml
,
int
(
*
test
)(
char
)
)
{
{
int
offset
=
0
;
int
offset
=
xml
->
read_index
;
int
delta
;
char
*
ret
=
NULL
;
char
*
ret
=
NULL
;
int
size
=
0
;
int
size
=
0
;
/* perform first and N middle realloc()'s */
while
(
test
(
xml
->
buf
[
offset
])
)
while
(
test
(
xml
->
buf
[
offset
])
)
{
{
offset
++
;
offset
++
;
if
(
offset
==
xml
->
len
)
if
(
offset
>=
xml
->
len
)
{
{
ret
=
realloc
(
ret
,
size
+
offset
+
1
);
delta
=
offset
-
xml
->
read_index
;
memcpy
(
ret
+
size
,
xml
->
buf
,
offset
);
ret
=
realloc
(
ret
,
size
+
delta
+
1
);
size
+=
offset
;
memcpy
(
ret
+
size
,
xml
->
buf
+
xml
->
read_index
,
delta
);
size
+=
delta
;
ret
[
size
]
=
0
;
ret
[
size
]
=
0
;
xml_consume
(
xml
,
offset
);
if
(
xml
->
eof
)
return
ret
;
xml_read_file
(
xml
);
xml
->
read_index
=
0
;
offset
=
0
;
offset
=
0
;
if
(
!
xml
->
len
)
return
ret
;
}
}
}
}
/* perform final realloc() if needed */
if
(
offset
)
if
(
offset
>
xml
->
read_index
)
{
{
ret
=
realloc
(
ret
,
size
+
offset
+
1
);
delta
=
offset
-
xml
->
read_index
;
memcpy
(
ret
+
size
,
xml
->
buf
,
offset
);
ret
=
realloc
(
ret
,
size
+
delta
+
1
);
size
+=
offset
;
memcpy
(
ret
+
size
,
xml
->
buf
+
xml
->
read_index
,
delta
);
xml
->
read_index
=
offset
;
size
+=
delta
;
ret
[
size
]
=
0
;
ret
[
size
]
=
0
;
xml_consume
(
xml
,
offset
);
}
}
return
ret
;
return
ret
;
}
}
/* this reads attributes from tags, of the form...
*
* <tag attr1="some arguments" attr2=argument>
*
* It is aware of quotes, and will allow anything inside quoted arguments
*/
static
void
xml_read_attr
(
struct
XMLBUF
*
xml
,
XmlNode
*
node
)
static
void
xml_read_attr
(
struct
XMLBUF
*
xml
,
XmlNode
*
node
)
{
{
int
n
=
0
;
int
n
=
0
;
...
@@ -187,7 +215,7 @@ static void xml_read_attr(struct XMLBUF *xml, XmlNode *node)
...
@@ -187,7 +215,7 @@ static void xml_read_attr(struct XMLBUF *xml, XmlNode *node)
// how does this tag finish?
// how does this tag finish?
while
(
xml
->
len
)
while
(
xml
->
len
)
{
{
if
(
is_special
(
xml
->
buf
[
0
]
)
&
(
XML_CLOSE
|
XML_SLASH
)
)
if
(
is_special
(
xml
_peek
(
xml
)
)
&
(
XML_CLOSE
|
XML_SLASH
)
)
return
;
return
;
n
=
++
node
->
nattrib
;
n
=
++
node
->
nattrib
;
...
@@ -196,19 +224,18 @@ static void xml_read_attr(struct XMLBUF *xml, XmlNode *node)
...
@@ -196,19 +224,18 @@ static void xml_read_attr(struct XMLBUF *xml, XmlNode *node)
feed_mask
=
XML_EQUALS
|
XML_SPACE
|
XML_CLOSE
|
XML_SLASH
;
feed_mask
=
XML_EQUALS
|
XML_SPACE
|
XML_CLOSE
|
XML_SLASH
;
node
->
attrib
[
n
*
2
]
=
xml_feed
(
xml
,
test_mask
);
node
->
attrib
[
n
*
2
]
=
xml_feed
(
xml
,
test_mask
);
if
(
xml
->
buf
[
0
]
==
'='
)
if
(
xml
_peek
(
xml
)
==
'='
)
{
{
if
(
is_special
(
xml
->
buf
[
1
])
&
XML_QUOTE
)
xml_read_byte
(
xml
);
if
(
is_special
(
xml_peek
(
xml
))
&
XML_QUOTE
)
{
{
quotechar
=
xml
->
buf
[
1
];
quotechar
=
xml_read_byte
(
xml
);
xml_consume
(
xml
,
2
);
node
->
attrib
[
n
*
2
+
1
]
=
xml_feed
(
xml
,
test_quote
);
node
->
attrib
[
n
*
2
+
1
]
=
xml_feed
(
xml
,
test_quote
);
xml_
consume
(
xml
,
1
);
xml_
read_byte
(
xml
);
}
}
else
else
{
{
feed_mask
=
XML_SPACE
|
XML_CLOSE
|
XML_SLASH
;
feed_mask
=
XML_SPACE
|
XML_CLOSE
|
XML_SLASH
;
xml_consume
(
xml
,
1
);
node
->
attrib
[
n
*
2
+
1
]
=
xml_feed
(
xml
,
test_mask
);
node
->
attrib
[
n
*
2
+
1
]
=
xml_feed
(
xml
,
test_mask
);
}
}
}
}
...
@@ -216,6 +243,11 @@ static void xml_read_attr(struct XMLBUF *xml, XmlNode *node)
...
@@ -216,6 +243,11 @@ static void xml_read_attr(struct XMLBUF *xml, XmlNode *node)
}
}
}
}
/* The big decision maker, is it a regular node, or a text node.
* If it's a node, it will check if it should have children, and if so
* will recurse over them.
* Text nodes don't have children, so no recursing.
*/
static
XmlNode
*
xml_parse
(
struct
XMLBUF
*
xml
)
static
XmlNode
*
xml_parse
(
struct
XMLBUF
*
xml
)
{
{
int
offset
;
int
offset
;
...
@@ -227,43 +259,48 @@ static XmlNode* xml_parse(struct XMLBUF *xml)
...
@@ -227,43 +259,48 @@ static XmlNode* xml_parse(struct XMLBUF *xml)
xml_skip
(
xml
,
XML_SPACE
);
// skip whitespace
xml_skip
(
xml
,
XML_SPACE
);
// skip whitespace
offset
=
0
;
offset
=
0
;
while
(
xml
->
len
)
while
(
(
xml
->
read_index
<
xml
->
len
)
||
!
xml
->
eof
)
{
{
switch
(
is_special
(
xml
->
buf
[
offset
]
))
switch
(
is_special
(
xml
_peek
(
xml
)
))
{
{
case
XML_OPEN
:
case
XML_OPEN
:
xml_
consume
(
xml
,
1
);
xml_
read_byte
(
xml
);
if
(
xml
->
buf
[
offset
]
==
'/'
)
if
(
xml
_peek
(
xml
)
==
'/'
)
return
ret
;
// parents close tag
return
ret
;
// parents close tag
// read the tag name
// read the tag name
feed_mask
=
XML_SPACE
|
XML_SLASH
|
XML_CLOSE
;
feed_mask
=
XML_SPACE
|
XML_SLASH
|
XML_CLOSE
;
*
this
=
xml_new
(
xml_feed
(
xml
,
test_mask
)
,
NULL
);
*
this
=
xml_new
(
xml_feed
(
xml
,
test_mask
));
xml_skip
(
xml
,
XML_SPACE
);
// skip any whitespace
xml_skip
(
xml
,
XML_SPACE
);
// skip any whitespace
xml_read_attr
(
xml
,
*
this
);
// read attributes
xml_read_attr
(
xml
,
*
this
);
// read attributes
// how does this tag finish?
// how does this tag finish?
switch
(
is_special
(
xml
->
buf
[
0
]
))
switch
(
is_special
(
xml
_peek
(
xml
)
))
{
{
case
XML_CLOSE
:
// child-nodes ahead
case
XML_CLOSE
:
// child-nodes ahead
xml_
consume
(
xml
,
1
);
xml_
read_byte
(
xml
);
(
*
this
)
->
child
=
xml_parse
(
xml
);
(
*
this
)
->
child
=
xml_parse
(
xml
);
xml_skip
(
xml
,
XML_ALL
^
XML_CLOSE
);
xml_skip
(
xml
,
XML_ALL
^
XML_CLOSE
);
xml_
consume
(
xml
,
1
);
xml_
read_byte
(
xml
);
break
;
break
;
case
XML_SLASH
:
// self closing tag
case
XML_SLASH
:
// self closing tag
xml_consume
(
xml
,
2
);
xml_read_byte
(
xml
);
xml_read_byte
(
xml
);
break
;
break
;
}
}
break
;
break
;
default:
// text node
default:
// text node
*
this
=
xml_new
(
0
,
0
);
*
this
=
xml_new
(
0
);
xml_skip
(
xml
,
XML_SPACE
);
// skip any whitespace
xml_skip
(
xml
,
XML_SPACE
);
// skip any whitespace
feed_mask
=
XML_OPEN
;
feed_mask
=
XML_OPEN
;
(
*
this
)
->
nattrib
=
1
;
(
*
this
)
->
nattrib
=
1
;
(
*
this
)
->
attrib
=
malloc
(
sizeof
(
char
*
)
*
2
);
(
*
this
)
->
attrib
=
malloc
(
sizeof
(
char
*
)
*
2
);
(
*
this
)
->
attrib
[
1
]
=
NULL
;
tmp
=
(
*
this
)
->
attrib
[
0
]
=
xml_feed
(
xml
,
test_mask
);
tmp
=
(
*
this
)
->
attrib
[
0
]
=
xml_feed
(
xml
,
test_mask
);
/* trim the whitespace off the end of text nodes,
* by overwriting the spaces will null termination. */
toff
=
strlen
(
tmp
)
-
1
;
toff
=
strlen
(
tmp
)
-
1
;
while
(
(
is_special
(
tmp
[
toff
])
&
XML_SPACE
)
)
while
(
(
is_special
(
tmp
[
toff
])
&
XML_SPACE
)
)
{
{
...
@@ -271,7 +308,6 @@ static XmlNode* xml_parse(struct XMLBUF *xml)
...
@@ -271,7 +308,6 @@ static XmlNode* xml_parse(struct XMLBUF *xml)
toff
--
;
toff
--
;
}
}
(
*
this
)
->
attrib
[
1
]
=
NULL
;
break
;
break
;
}
}
this
=
&
(
*
this
)
->
next
;
this
=
&
(
*
this
)
->
next
;
...
@@ -282,14 +318,16 @@ static XmlNode* xml_parse(struct XMLBUF *xml)
...
@@ -282,14 +318,16 @@ static XmlNode* xml_parse(struct XMLBUF *xml)
}
}
/* bootstrap the structures for xml_parse() to be able to get started */
#define BUF 3264
XmlNode
*
xml_load
(
const
char
*
filename
)
XmlNode
*
xml_load
(
const
char
*
filename
)
{
{
struct
XMLBUF
xml
;
struct
XMLBUF
xml
;
XmlNode
*
ret
=
NULL
;
XmlNode
*
ret
=
NULL
;
// printf("xml_load(\"%s\");\n", filename);
xml
.
eof
=
0
;
xml
.
eof
=
0
;
xml
.
read_index
=
0
;
xml
.
fptr
=
fopen
(
filename
,
"rb"
);
xml
.
fptr
=
fopen
(
filename
,
"rb"
);
if
(
!
xml
.
fptr
)
if
(
!
xml
.
fptr
)
{
{
...
@@ -297,12 +335,13 @@ XmlNode* xml_load(const char * filename)
...
@@ -297,12 +335,13 @@ XmlNode* xml_load(const char * filename)
return
NULL
;
return
NULL
;
}
}
xml
.
buf
=
malloc
(
BUF
);
xml
.
buf
=
malloc
(
BUFFER
+
1
);
xml
.
buf
[
BUFFER
]
=
0
;
if
(
!
xml
.
buf
)
if
(
!
xml
.
buf
)
goto
xml_load_fail_malloc_buf
;
goto
xml_load_fail_malloc_buf
;
xml
.
len
=
fread
(
xml
.
buf
,
1
,
BUF
,
xml
.
fptr
);
xml
.
len
=
fread
(
xml
.
buf
,
1
,
BUF
FER
,
xml
.
fptr
);
if
(
xml
.
len
<
BUF
)
if
(
xml
.
len
<
BUF
FER
)
xml
.
eof
=
1
;
xml
.
eof
=
1
;
ret
=
xml_parse
(
&
xml
);
ret
=
xml_parse
(
&
xml
);
...
@@ -312,8 +351,8 @@ xml_load_fail_malloc_buf:
...
@@ -312,8 +351,8 @@ xml_load_fail_malloc_buf:
fclose
(
xml
.
fptr
);
fclose
(
xml
.
fptr
);
return
ret
;
return
ret
;
}
}
#undef BUF
/* very basic function that will get you the first node with a given name */
XmlNode
*
xml_find
(
XmlNode
*
xml
,
const
char
*
name
)
XmlNode
*
xml_find
(
XmlNode
*
xml
,
const
char
*
name
)
{
{
XmlNode
*
ret
;
XmlNode
*
ret
;
...
@@ -331,7 +370,7 @@ XmlNode * xml_find(XmlNode *xml, const char *name)
...
@@ -331,7 +370,7 @@ XmlNode * xml_find(XmlNode *xml, const char *name)
return
NULL
;
return
NULL
;
}
}
/* very basic attribute lookup function */
char
*
xml_attr
(
XmlNode
*
x
,
const
char
*
name
)
char
*
xml_attr
(
XmlNode
*
x
,
const
char
*
name
)
{
{
int
i
;
int
i
;
...
@@ -344,6 +383,7 @@ char* xml_attr(XmlNode *x, const char *name)
...
@@ -344,6 +383,7 @@ char* xml_attr(XmlNode *x, const char *name)
#ifdef TEST
#ifdef TEST
/* print out the heirarchy of an XML file, useful for debugging */
void
xp
(
XmlNode
*
x
,
int
level
,
int
max
)
void
xp
(
XmlNode
*
x
,
int
level
,
int
max
)
{
{
int
i
;
int
i
;
...
@@ -357,6 +397,7 @@ void xp(XmlNode *x, int level, int max)
...
@@ -357,6 +397,7 @@ void xp(XmlNode *x, int level, int max)
if
(
x
->
name
)
if
(
x
->
name
)
for
(
i
=
0
;
i
<
x
->
nattrib
;
i
++
)
for
(
i
=
0
;
i
<
x
->
nattrib
;
i
++
)
printf
(
"%s=
\"
%s
\"
,"
,
x
->
attrib
[
i
*
2
],
x
->
attrib
[
i
*
2
+
1
]);
printf
(
"%s=
\"
%s
\"
,"
,
x
->
attrib
[
i
*
2
],
x
->
attrib
[
i
*
2
+
1
]);
else
printf
(
"%s"
,
x
->
attrib
[
0
]);
printf
(
"
\n
"
);
printf
(
"
\n
"
);
if
(
x
->
child
)
xp
(
x
->
child
,
level
+
1
,
max
);
if
(
x
->
child
)
xp
(
x
->
child
,
level
+
1
,
max
);
if
(
x
->
next
)
xp
(
x
->
next
,
level
,
max
);
if
(
x
->
next
)
xp
(
x
->
next
,
level
,
max
);
...
@@ -365,7 +406,8 @@ void xp(XmlNode *x, int level, int max)
...
@@ -365,7 +406,8 @@ void xp(XmlNode *x, int level, int max)
int
main
(
int
argc
,
char
*
argv
[])
int
main
(
int
argc
,
char
*
argv
[])
{
{
XmlNode
*
x
;
XmlNode
*
x
,
*
tmp
;
int
i
;
if
(
!
argv
[
1
])
if
(
!
argv
[
1
])
{
{
...
@@ -374,19 +416,29 @@ int main(int argc, char *argv[])
...
@@ -374,19 +416,29 @@ int main(int argc, char *argv[])
return
1
;
return
1
;
}
}
printf
(
"Loading file
\"
%s
\"\n
"
,
argv
[
1
]);
#ifdef PROFILE
for
(
i
=
0
;
i
<
1000
;
i
++
)
x
=
xml_load
(
argv
[
1
]);
if
(
!
x
)
{
{
printf
(
"Failed to load.
\n
"
);
#endif
return
2
;
x
=
xml_load
(
argv
[
1
]);
if
(
!
x
)
{
printf
(
"Failed to load.
\n
"
);
return
2
;
}
#ifndef PROFILE
xp
(
x
,
1
,
20
);
#endif
xml_free
(
x
);
#ifdef PROFILE
}
}
#endif
xp
(
x
,
1
,
6
);
xml_free
(
x
);
// tmp = xml_find(x, "geometry");
printf
(
"Happily free.
\n
"
);
// xp(x, 1, 6);
// printf("Happily free.\n");
return
0
;
return
0
;
}
}
#endif
#endif
...
...
ccan/ttxml/ttxml.h
View file @
385e0e53
/* Licensed under GPL - see LICENSE file for details */
typedef
struct
XmlNode
{
typedef
struct
XmlNode
{
char
*
name
;
char
*
name
;
char
**
attrib
;
char
**
attrib
;
...
@@ -8,7 +8,7 @@ typedef struct XmlNode {
...
@@ -8,7 +8,7 @@ typedef struct XmlNode {
}
XmlNode
;
}
XmlNode
;
XmlNode
*
xml_new
(
char
*
name
,
char
*
attrib
);
XmlNode
*
xml_new
(
char
*
name
);
XmlNode
*
xml_load
(
const
char
*
filename
);
XmlNode
*
xml_load
(
const
char
*
filename
);
void
xml_free
(
XmlNode
*
target
);
void
xml_free
(
XmlNode
*
target
);
char
*
xml_attr
(
XmlNode
*
x
,
const
char
*
name
);
char
*
xml_attr
(
XmlNode
*
x
,
const
char
*
name
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment