Skip to content
Snippets Groups Projects
Commit 4d090a2a authored by Kipp Cannon's avatar Kipp Cannon
Browse files

gstlal: add "ezligolw" library

- due to push back from collaboration over our desire to switch ilwd:char
  IDs in LIGO LW tables to integers, we are forced to decouple ourselves
  from the I/O code in LAL.
parent 177fe13b
No related branches found
No related tags found
No related merge requests found
......@@ -72,6 +72,8 @@ EXTRA_HFILES=
# Header files or dirs to ignore when scanning. Use base file/dir names
# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h private_code
IGNORE_HFILES= \
ezxml.c ezxml.h \
ezligolw.c ezligolw.h \
gstlal_peakfinder_top.h \
gstlal_peakfinder_types.h
......
EXTRA_DIST =
CLEANFILES =
pkginclude_HEADERS = gstlal.h gstlal_debug.h gstlal_marshal.h gstlal_tags.h gstlal_cdf_weighted_chisq_P.h gstlal_segments.h gstaudioadapter.h gstlalcollectpads.h gstlal_peakfinder.h gstlal_autocorrelation_chi2.h gstlal_gps_clock.h gstlal_frhistory.h gstlal_audio_info.h
pkginclude_HEADERS = ezligolw.h ezxml.h gstlal.h gstlal_debug.h gstlal_marshal.h gstlal_tags.h gstlal_cdf_weighted_chisq_P.h gstlal_segments.h gstaudioadapter.h gstlalcollectpads.h gstlal_peakfinder.h gstlal_autocorrelation_chi2.h gstlal_gps_clock.h gstlal_frhistory.h gstlal_audio_info.h
pkgconfig_DATA = gstlal.pc
lib_LTLIBRARIES = libgstlal.la libgstlaltags.la libgstlaltypes.la
lib_LTLIBRARIES = libezligolw.la libgstlal.la libgstlaltags.la libgstlaltypes.la
libezligolw_la_SOURCES = ezligolw.c ezligolw.h ezxml.c ezxml.h
libezligolw_la_CFLAGS = $(AM_CFLAGS) -I..
libezligolw_la_LDFLAGS = -version-info $(LIBVERSION) $(AM_LDFLAGS)
libgstlal_la_SOURCES = gstlal.c gstlal.h gstlal_debug.h gstlal_fftw.c gstlal_marshal.c gstlal_marshal.h gstlal_cdf_weighted_chisq_P.c gstlal_cdf_weighted_chisq_P.h gstlal_segments.h gstlal_segments.c gstlal_peakfinder.h gstlal_peakfinder.c gstlal_autocorrelation_chi2.h gstlal_autocorrelation_chi2.c gstlal_audio_info.c
libgstlal_la_CFLAGS = $(AM_CFLAGS) $(FFTW_CFLAGS) $(GSL_CFLAGS) $(LAL_CFLAGS) $(gstreamer_CFLAGS)
......
/*
* $Id: ezligolw.c,v 1.4 2008/07/31 08:28:42 kipp Exp $
*
* Copyright (C) 2007 Kipp Cannon
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ezligolw.h>
#include <ezxml.h>
/*
* Extract the meaningful portion of a table name. Returns a pointer to
* the last colon-delimited substring before an optional ":table" suffix.
*/
static const char *ligolw_strip_table_name(const char *Name)
{
char buff[strlen(Name) + 1];
char *pos = buff;
char *start;
strcpy(buff, Name);
do
start = strsep(&pos, ":");
while(pos && strncmp(pos, "table", 5));
return Name + (start - buff);
}
/*
* Extract the meaningful portion of a column name. Returns a pointer to
* the last colon-delimited substring.
*/
static const char *ligolw_strip_column_name(const char *Name)
{
char buff[strlen(Name) + 1];
char *pos = buff;
char *start;
strcpy(buff, Name);
do
start = strsep(&pos, ":");
while(pos);
return Name + (start - buff);
}
/*
* Convert a LIGO Light Weight type name string to/from a numeric type
* index.
*/
static const struct name_to_enum {
const char *name;
enum ligolw_table_cell_type type;
} name_to_enum[] = {
{"char_s", ligolw_cell_type_char_s},
{"char_v", ligolw_cell_type_char_v},
{"ilwd:char", ligolw_cell_type_ilwdchar},
{"ilwd:char_u", ligolw_cell_type_ilwdchar_u},
{"lstring", ligolw_cell_type_lstring},
{"string", ligolw_cell_type_lstring},
{"int_2s", ligolw_cell_type_int_2s},
{"int_2u", ligolw_cell_type_int_2u},
{"int_4s", ligolw_cell_type_int_4s},
{"int", ligolw_cell_type_int_4s},
{"int_4u", ligolw_cell_type_int_4u},
{"int_8s", ligolw_cell_type_int_8s},
{"int_8u", ligolw_cell_type_int_8u},
{"real_4", ligolw_cell_type_real_4},
{"float", ligolw_cell_type_real_4},
{"real_8", ligolw_cell_type_real_8},
{"double", ligolw_cell_type_real_8},
{NULL, -1}
};
enum ligolw_table_cell_type ligolw_table_type_name_to_enum(const char *name)
{
const struct name_to_enum *n_to_e;
for(n_to_e = name_to_enum; n_to_e->name; n_to_e++)
if(!strcmp(n_to_e->name, name))
/* found it */
return n_to_e->type;
/* unrecognized type */
return -1;
}
const char *ligolw_table_type_enum_to_name(enum ligolw_table_cell_type t)
{
const struct name_to_enum *n_to_e;
for(n_to_e = name_to_enum; n_to_e->name; n_to_e++)
if(n_to_e->type == t)
/* found it */
return n_to_e->name;
/* unrecognized type */
return NULL;
}
/*
* Default row builder call-back.
*/
int ligolw_table_default_row_callback(struct ligolw_table *table, struct ligolw_table_row row, void *ignored)
{
table->rows = realloc(table->rows, (table->n_rows + 1) * sizeof(*table->rows));
table->rows[table->n_rows] = row;
table->n_rows++;
return 0;
}
/*
* Parse an ezxml_t Table element into a struct ligolw_table structure. If
* row_callback() is NULL, then the default row builder is used, which
* inserts the rows into the ligolw_table structure. Calling code can
* provide it's own function, which will be called after each row is
* constructed. This allows the rows to be "intercepted", so that some
* other thing can be done with them other than being inserted into the
* ligolw_table. The call-back function will be passed the pointer to the
* current ligolw_table structure as its first argument, the pointer to the
* new row as its second, and the callback_data pointer as its third
* argument. The row_callback() function must free the row's cells element
* if it will not be saving it, or memory will be leaked. The call-back
* returns 0 to indicate success, non-zero to indicate failure.
*
* ligolw_table_parse() return the pointer to the new struct ligolw_table
* structure on success, NULL on failure.
*/
static void next_token(char **start, char **end, char **end_end, char delimiter)
{
char *s, *e, *ee;
int quoted = 0;
/* find the token's start */
for(s = *start; *s && isspace(*s) && *s != delimiter && !(quoted = *s == '"'); s++);
if(!*s || *s == delimiter) {
/* token has zero length */
*start = *end = *end_end = s;
return;
}
/* find the end end of the token */
for(ee = s + 1; *ee && (quoted || *ee != delimiter); ee++)
if(quoted && *ee == '"')
quoted = 0;
/* move backwards from end end to find end */
for(e = ee - 1; e > s && isspace(*e); e--);
/* adjust */
if(*s == '"')
s++;
if(*e != '"')
e++;
/* answer */
*start = s;
*end = e;
*end_end = ee;
}
struct ligolw_table *ligolw_table_parse(ezxml_t elem, int (row_callback)(struct ligolw_table *, struct ligolw_table_row, void *), void *callback_data)
{
struct ligolw_table *table;
char *txt;
ezxml_t column;
ezxml_t stream;
table = malloc(sizeof(*table));
if(!table)
return NULL;
table->name = ligolw_strip_table_name(ezxml_attr(elem, "Name"));
table->n_columns = 0;
table->columns = NULL;
table->n_rows = 0;
table->rows = NULL;
for(column = ezxml_child(elem, "Column"); column; column = column->next) {
table->columns = realloc(table->columns, (table->n_columns + 1) * sizeof(*table->columns));
table->columns[table->n_columns].name = ligolw_strip_column_name(ezxml_attr(column, "Name"));
table->columns[table->n_columns].table = table;
table->columns[table->n_columns].type = ligolw_table_type_name_to_enum(ezxml_attr(column, "Type"));
table->n_columns++;
}
stream = ezxml_child(elem, "Stream");
if(!stream) {
/* DTD allows Table to have 0 Stream children */
table->delimiter = '\0';
return table;
}
table->delimiter = *ezxml_attr(stream, "Delimiter");
if(!row_callback)
row_callback = ligolw_table_default_row_callback;
for(txt = stream->txt; txt && *txt; ) {
struct ligolw_table_row row;
int c;
row.table = table;
row.cells = malloc(table->n_columns * sizeof(*row.cells));
for(c = 0; c < table->n_columns; c++) {
char *end, *end_end;
next_token(&txt, &end, &end_end, table->delimiter);
switch(table->columns[c].type) {
case ligolw_cell_type_char_s:
case ligolw_cell_type_char_v:
case ligolw_cell_type_ilwdchar:
case ligolw_cell_type_ilwdchar_u:
case ligolw_cell_type_blob:
case ligolw_cell_type_lstring:
/* FIXME: move into a separate buffer so
* that the original document is not
* modified (see null terminator below) */
/* FIXME: binary types need to be sent
* through a decoder following this */
row.cells[c].as_string = txt;
break;
case ligolw_cell_type_int_2s:
case ligolw_cell_type_int_4s:
case ligolw_cell_type_int_8s:
row.cells[c].as_int = strtoll(txt, NULL, 0);
break;
case ligolw_cell_type_int_2u:
case ligolw_cell_type_int_4u:
case ligolw_cell_type_int_8u:
row.cells[c].as_uint = strtoull(txt, NULL, 0);
break;
case ligolw_cell_type_real_4:
row.cells[c].as_float = strtod(txt, NULL);
break;
case ligolw_cell_type_real_8:
row.cells[c].as_double = strtod(txt, NULL);
break;
}
/* don't set null at end until after testing
* end_end incase they point to the same place */
if(!*end_end) {
*end = '\0';
txt = end_end;
break;
}
*end = '\0';
txt = end_end + 1;
}
if(row_callback(table, row, callback_data)) {
ligolw_table_free(table);
return NULL;
}
}
return table;
}
/*
* Free a struct ligolw_table.
*/
void ligolw_table_free(struct ligolw_table *table)
{
if(table) {
int i;
for(i = 0; i < table->n_rows; i++)
free(table->rows[i].cells);
free(table->rows);
free(table->columns);
}
free(table);
}
/*
* Get a column index by name from within a table. Returns the index of
* the column within table's columns array (and thus of the corresponding
* cell within each row's cell array) or -1 on failure. If type is not
* NULL, the place it points to is set to the columns's table_cell_type.
*/
int ligolw_table_get_column(struct ligolw_table *table, const char *name, enum ligolw_table_cell_type *type)
{
int i;
for(i = 0; i < table->n_columns; i++)
if(!strcmp(table->columns[i].name, name)) {
/* found it */
if(type)
*type = table->columns[i].type;
return i;
}
/* couldn't find that column name */
if(type)
*type = -1;
return -1;
}
/*
* Retrieve the value stored in a cell within a table row. No error
* checking is done, you should ensure the requested column is present
* before calling this function.
*/
union ligolw_table_cell ligolw_row_get_cell(struct ligolw_table_row row, const char *name)
{
return row.cells[ligolw_table_get_column(row.table, name, NULL)];
}
/*
* Find an ezxml_t Table element in a document.
*/
ezxml_t ligolw_table_get(ezxml_t xmldoc, const char *table_name)
{
int n = strlen(table_name);
ezxml_t table;
for(table = ezxml_child(xmldoc, "Table"); table; table = table->next)
if(!strncmp(ligolw_strip_table_name(ezxml_attr(table, "Name")), table_name, n))
break;
return table;
}
/*
* Generic unpacking row builder.
*/
int ligolw_unpacking_row_builder(struct ligolw_table *table, struct ligolw_table_row row, void *data)
{
struct ligolw_unpacking_spec *spec;
for(spec = data; spec->name; spec++) {
int c;
enum ligolw_table_cell_type type;
if((c = ligolw_table_get_column(table, spec->name, &type)) < 0) {
/* no column by that name */
if(!(spec->flags & LIGOLW_UNPACKING_REQUIRED))
/* not required */
continue;
free(row.cells);
return spec - (struct ligolw_unpacking_spec *) data + 1;
}
if(spec->type != type) {
/* type mismatch */
free(row.cells);
return -(spec - (struct ligolw_unpacking_spec *) data + 1);
}
if(!spec->dest)
/* column has a valid name and the correct type,
* but is ignored */
continue;
switch(spec->type) {
case ligolw_cell_type_char_s:
case ligolw_cell_type_char_v:
case ligolw_cell_type_ilwdchar:
case ligolw_cell_type_ilwdchar_u:
case ligolw_cell_type_lstring:
*(const char **) spec->dest = row.cells[c].as_string;
break;
case ligolw_cell_type_blob:
*(const unsigned char **) spec->dest = row.cells[c].as_blob;
break;
case ligolw_cell_type_int_2s:
*(int16_t *) spec->dest = row.cells[c].as_int;
break;
case ligolw_cell_type_int_2u:
*(int16_t *) spec->dest = row.cells[c].as_uint;
break;
case ligolw_cell_type_int_4s:
*(int32_t *) spec->dest = row.cells[c].as_int;
break;
case ligolw_cell_type_int_4u:
*(uint32_t *) spec->dest = row.cells[c].as_uint;
break;
case ligolw_cell_type_int_8s:
*(int64_t *) spec->dest = row.cells[c].as_int;
break;
case ligolw_cell_type_int_8u:
*(uint64_t *) spec->dest = row.cells[c].as_uint;
break;
case ligolw_cell_type_real_4:
*(float *) spec->dest = row.cells[c].as_float;
break;
case ligolw_cell_type_real_8:
*(double *) spec->dest = row.cells[c].as_double;
break;
}
}
free(row.cells);
if(spec - (struct ligolw_unpacking_spec *) data != table->n_columns) {
/* table has more columns than allowed */
/* FIXME: if this is an error, return an error code */
/* FIXME: this test doesn't work if the same column gets
* unpacked into more than one location, which the design
* of the loop above would allow */
}
return 0;
}
/*
* Print a struct ligolw_table structure
*/
int ligolw_table_print(FILE *f, struct ligolw_table *table)
{
char short_name[strlen(table->name) + 1];
int r, c;
/* create a version of the table name with the optional :table
* suffix removed */
strcpy(short_name, table->name);
{
char *x = strchr(short_name, ':');
if(x)
*x = '\0';
}
/* print the table metadata */
fprintf(f, "<Table Name=\"%s\">\n", table->name);
for(c = 0; c < table->n_columns; c++)
fprintf(f, "\t<Column Name=\"%s:%s\" Type=\"%s\"/>\n", short_name, table->columns[c].name, ligolw_table_type_enum_to_name(table->columns[c].type));
fprintf(f, "\t<Stream Name=\"%s\" Type=\"Local\" Delimiter=\"%c\">\n", table->name, table->delimiter);
/* print the rows */
for(r = 0; r < table->n_rows; r++) {
if(r)
fprintf(f, ",\n\t\t");
else
fprintf(f, "\t\t");
for(c = 0; c < table->n_columns; c++) {
if(c)
fprintf(f, "%c", table->delimiter);
switch(table->columns[c].type) {
case ligolw_cell_type_char_s:
case ligolw_cell_type_char_v:
case ligolw_cell_type_ilwdchar:
case ligolw_cell_type_ilwdchar_u:
case ligolw_cell_type_blob:
case ligolw_cell_type_lstring:
/* FIXME: binary types need to pass through
* encoders first */
/* FIXME: string types need to pass through
* encoders first */
fprintf(f, "\"%s\"", table->rows[r].cells[c].as_string);
break;
case ligolw_cell_type_int_2s:
case ligolw_cell_type_int_4s:
case ligolw_cell_type_int_8s:
fprintf(f, "%lld", (long long) table->rows[r].cells[c].as_int);
break;
case ligolw_cell_type_int_2u:
case ligolw_cell_type_int_4u:
case ligolw_cell_type_int_8u:
fprintf(f, "%llu", (unsigned long long) table->rows[r].cells[c].as_uint);
break;
case ligolw_cell_type_real_4:
fprintf(f, "%.7g", (double) table->rows[r].cells[c].as_float);
break;
case ligolw_cell_type_real_8:
fprintf(f, "%.16g", table->rows[r].cells[c].as_double);
break;
}
}
}
/* finish 'er off */
fprintf(f, "\n\t</Stream>\n</Table>\n");
return 0;
}
/*
* $Id: ezligolw.h,v 1.4 2008/07/31 08:28:42 kipp Exp $
*
* Copyright (C) 2007 Kipp Cannon
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <stdio.h>
#include <stdint.h>
#include <gstlal/ezxml.h>
struct ligolw_table {
const char *name;
char delimiter;
int n_columns;
struct ligolw_table_column {
const char *name;
struct ligolw_table *table;
enum ligolw_table_cell_type {
ligolw_cell_type_char_s,
ligolw_cell_type_char_v,
ligolw_cell_type_ilwdchar,
ligolw_cell_type_ilwdchar_u,
ligolw_cell_type_blob,
ligolw_cell_type_lstring,
ligolw_cell_type_int_2s,
ligolw_cell_type_int_2u,
ligolw_cell_type_int_4s,
ligolw_cell_type_int_4u,
ligolw_cell_type_int_8s,
ligolw_cell_type_int_8u,
ligolw_cell_type_real_4,
ligolw_cell_type_real_8
} type;
} *columns;
int n_rows;
struct ligolw_table_row {
struct ligolw_table *table;
union ligolw_table_cell {
int64_t as_int;
uint64_t as_uint;
float as_float;
double as_double;
const char *as_string;
const unsigned char *as_blob;
} *cells;
} *rows;
};
ezxml_t ligolw_table_get(ezxml_t, const char *);
enum ligolw_table_cell_type ligolw_table_type_name_to_enum(const char *);
const char *ligolw_table_type_enum_to_name(enum ligolw_table_cell_type);
int ligolw_table_default_row_callback(struct ligolw_table *, struct ligolw_table_row, void *);
struct ligolw_table *ligolw_table_parse(ezxml_t, int (*)(struct ligolw_table *, struct ligolw_table_row, void *), void *);
union ligolw_table_cell ligolw_row_get_cell(struct ligolw_table_row, const char *);
void ligolw_table_free(struct ligolw_table *);
int ligolw_table_get_column(struct ligolw_table *, const char *, enum ligolw_table_cell_type *);
int ligolw_table_print(FILE *, struct ligolw_table *);
#define LIGOLW_UNPACKING_REQUIRED 0x1
struct ligolw_unpacking_spec {
void *dest;
const char *name;
enum ligolw_table_cell_type type;
int flags;
};
int ligolw_unpacking_row_builder(struct ligolw_table *, struct ligolw_table_row, void *);
This diff is collapsed.
/* ezxml.h
*
* Copyright 2004-2006 Aaron Voisine <aaron@voisine.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef _EZXML_H
#define _EZXML_H
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <fcntl.h>
#ifdef __cplusplus
extern "C" {
#endif
#define EZXML_BUFSIZE 1024 // size of internal memory buffers
#define EZXML_NAMEM 0x80 // name is malloced
#define EZXML_TXTM 0x40 // txt is malloced
#define EZXML_DUP 0x20 // attribute name and value are strduped
typedef struct ezxml *ezxml_t;
struct ezxml {
char *name; // tag name
char **attr; // tag attributes { name, value, name, value, ... NULL }
char *txt; // tag character content, empty string if none
size_t off; // tag offset from start of parent tag character content
ezxml_t next; // next tag with same name in this section at this depth
ezxml_t sibling; // next tag with different name in same section and depth
ezxml_t ordered; // next tag, same section and depth, in original order
ezxml_t child; // head of sub tag list, NULL if none
ezxml_t parent; // parent tag, NULL if current tag is root tag
short flags; // additional information
};
// Given a string of xml data and its length, parses it and creates an ezxml
// structure. For efficiency, modifies the data by adding null terminators
// and decoding ampersand sequences. If you don't want this, copy the data and
// pass in the copy. Returns NULL on failure.
ezxml_t ezxml_parse_str(char *s, size_t len);
// A wrapper for ezxml_parse_str() that accepts a file descriptor. First
// attempts to mem map the file. Failing that, reads the file into memory.
// Returns NULL on failure.
ezxml_t ezxml_parse_fd(int fd);
// a wrapper for ezxml_parse_fd() that accepts a file name
ezxml_t ezxml_parse_file(const char *file);
// Wrapper for ezxml_parse_str() that accepts a file stream. Reads the entire
// stream into memory and then parses it. For xml files, use ezxml_parse_file()
// or ezxml_parse_fd()
ezxml_t ezxml_parse_fp(FILE *fp);
// returns the first child tag (one level deeper) with the given name or NULL
// if not found
ezxml_t ezxml_child(ezxml_t xml, const char *name);
// returns the next tag of the same name in the same section and depth or NULL
// if not found
#define ezxml_next(xml) ((xml) ? xml->next : NULL)
// Returns the Nth tag with the same name in the same section at the same depth
// or NULL if not found. An index of 0 returns the tag given.
ezxml_t ezxml_idx(ezxml_t xml, int idx);
// returns the name of the given tag
#define ezxml_name(xml) ((xml) ? xml->name : NULL)
// returns the given tag's character content or empty string if none
#define ezxml_txt(xml) ((xml) ? xml->txt : "")
// returns the value of the requested tag attribute, or NULL if not found
const char *ezxml_attr(ezxml_t xml, const char *attr);
// Traverses the ezxml sturcture to retrieve a specific subtag. Takes a
// variable length list of tag names and indexes. The argument list must be
// terminated by either an index of -1 or an empty string tag name. Example:
// title = ezxml_get(library, "shelf", 0, "book", 2, "title", -1);
// This retrieves the title of the 3rd book on the 1st shelf of library.
// Returns NULL if not found.
ezxml_t ezxml_get(ezxml_t xml, ...);
// Converts an ezxml structure back to xml. Returns a string of xml data that
// must be freed.
char *ezxml_toxml(ezxml_t xml);
// returns a NULL terminated array of processing instructions for the given
// target
const char **ezxml_pi(ezxml_t xml, const char *target);
// frees the memory allocated for an ezxml structure
void ezxml_free(ezxml_t xml);
// returns parser error message or empty string if none
const char *ezxml_error(ezxml_t xml);
// returns a new empty ezxml structure with the given root tag name
ezxml_t ezxml_new(const char *name);
// wrapper for ezxml_new() that strdup()s name
#define ezxml_new_d(name) ezxml_set_flag(ezxml_new(strdup(name)), EZXML_NAMEM)
// Adds a child tag. off is the offset of the child tag relative to the start
// of the parent tag's character content. Returns the child tag.
ezxml_t ezxml_add_child(ezxml_t xml, const char *name, size_t off);
// wrapper for ezxml_add_child() that strdup()s name
#define ezxml_add_child_d(xml, name, off) \
ezxml_set_flag(ezxml_add_child(xml, strdup(name), off), EZXML_NAMEM)
// sets the character content for the given tag and returns the tag
ezxml_t ezxml_set_txt(ezxml_t xml, const char *txt);
// wrapper for ezxml_set_txt() that strdup()s txt
#define ezxml_set_txt_d(xml, txt) \
ezxml_set_flag(ezxml_set_txt(xml, strdup(txt)), EZXML_TXTM)
// Sets the given tag attribute or adds a new attribute if not found. A value
// of NULL will remove the specified attribute. Returns the tag given.
ezxml_t ezxml_set_attr(ezxml_t xml, const char *name, const char *value);
// Wrapper for ezxml_set_attr() that strdup()s name/value. Value cannot be NULL
#define ezxml_set_attr_d(xml, name, value) \
ezxml_set_attr(ezxml_set_flag(xml, EZXML_DUP), strdup(name), strdup(value))
// sets a flag for the given tag and returns the tag
ezxml_t ezxml_set_flag(ezxml_t xml, short flag);
// removes a tag along with its subtags without freeing its memory
ezxml_t ezxml_cut(ezxml_t xml);
// inserts an existing tag into an ezxml structure
ezxml_t ezxml_insert(ezxml_t xml, ezxml_t dest, size_t off);
// Moves an existing tag to become a subtag of dest at the given offset from
// the start of dest's character content. Returns the moved tag.
#define ezxml_move(xml, dest, off) ezxml_insert(ezxml_cut(xml), dest, off)
// removes a tag along with all its subtags
#define ezxml_remove(xml) ezxml_free(ezxml_cut(xml))
#ifdef __cplusplus
}
#endif
#endif // _EZXML_H
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment