#define CR_CB_RET_OK 0
#define CR_CB_RET_ERR 1
+typedef enum {
+ CR_XML_WARNING_UNKNOWNTAG, /*!< Unknown tag */
+ CR_XML_WARNING_MISSINGATTR, /*!< Missing attribute */
+ CR_XML_WARNING_UNKNOWNVAL, /*!< Unknown tag or attribute value */
+ CR_XML_WARNING_SENTINEL,
+} cr_XmlParserWarningType;
/** Callback for XML parser wich is called when a package element is parsed.
* @param pkg Currently parsed package.
void *cbdata,
GError **err);
+/** Callback for XML parser warnings. All reported warnings are non-fatal,
+ * and ignored by default. But if callback return CR_CB_RET_ERR instead of
+ * CR_CB_RET_OK then parsing is immediately interrupted.
+ * @param type Type of warning
+ * @param msg Warning msg
+ * @param cbdata User data.
+ * @param err GError **
+ * @return CR_CB_RET_OK (0) or CR_CB_RET_ERR (1) - stops the parsing
+ */
+typedef int (*cr_XmlParserWarningCb)(cr_XmlParserWarningType type,
+ char *msg,
+ void *cbdata,
+ GError **err);
+
/** Parse filelists.xml. File could be compressed.
- * @param path Path to filelists.xml (plain or compressed)
- * @param newpkgcb Callback for new package (Called when new package
- * xml chunk is found and package object to store
- * the data is needed). If NULL cr_newpkgcb is used.
- * @param newpkgcb_data User data for the newpkgcb.
- * @param pkgcb Package callback. (Called when complete package
- * xml chunk is parsed.). Could be NULL if newpkgcb is
- * not NULL.
- * @param pkgcb_data User data for the pkgcb.
- * @param messages Pointer to char* where messages (warnings)
- * from parsing will be stored.
- * @param err GError **
- * @return cr_Error code.
+ * @param path Path to filelists.xml (plain or compressed)
+ * @param newpkgcb Callback for new package (Called when new package
+ * xml chunk is found and package object to store
+ * the data is needed). If NULL cr_newpkgcb is used.
+ * @param newpkgcb_data User data for the newpkgcb.
+ * @param pkgcb Package callback. (Called when complete package
+ * xml chunk is parsed.). Could be NULL if newpkgcb is
+ * not NULL.
+ * @param pkgcb_data User data for the pkgcb.
+ * @param warningcb Callback for warning messages.
+ * @param warningcb_data User data for the warningcb.
+ * @param err GError **
+ * @return cr_Error code.
*/
int cr_xml_parse_filelists(const char *path,
cr_XmlParserNewPkgCb newpkgcb,
void *newpkgcb_data,
cr_XmlParserPkgCb pkgcb,
void *pkgcb_data,
- char **messages,
+ cr_XmlParserWarningCb warningcb,
+ void *warningcb_data,
GError **err);
/** @} */
#include "logging.h"
#include "misc.h"
+#define ERR_DOMAIN CR_XML_PARSER_FIL_ERROR
+#define ERR_CODE_XML CRE_BADXMLFILELISTS
+
typedef enum {
STATE_START,
STATE_FILELISTS,
return; // There was an error -> do nothing
if (pd->depth != pd->statedepth) {
- // There probably was an unknown element
+ // We are inside of unknown element
pd->depth++;
return;
}
pd->depth++;
- if (!pd->swtab[pd->state])
- return; // Current element should not have any sub elements
+ if (!pd->swtab[pd->state]) {
+ // Current element should not have any sub elements
+ return;
+ }
if (!pd->pkg && pd->state != STATE_FILELISTS && pd->state != STATE_START)
return; // Do not parse current package tag and its content
for (sw = pd->swtab[pd->state]; sw->from == pd->state; sw++)
if (!strcmp(element, sw->ename))
break;
- if (sw->from != pd->state)
- return; // There is no state for the name -> skip
+ if (sw->from != pd->state) {
+ // No state for current element (unknown element)
+ cr_xml_parser_warning(pd, CR_XML_WARNING_UNKNOWNTAG,
+ "Unknown element \"%s\"", element);
+ return;
+ }
// Update parser data
pd->state = sw->to;
if (!pkgId) {
// Package without a pkgid attr is error
- g_set_error(&pd->err, CR_XML_PARSER_FIL_ERROR, CRE_BADXMLFILELISTS,
+ g_set_error(&pd->err, ERR_DOMAIN, ERR_CODE_XML,
"Package pkgid attributte is missing!");
break;
}
+ if (!name)
+ cr_xml_parser_warning(pd, CR_XML_WARNING_MISSINGATTR,
+ "Missing attribute \"name\" of a package element");
+
+ if (!arch)
+ cr_xml_parser_warning(pd, CR_XML_WARNING_MISSINGATTR,
+ "Missing attribute \"arch\" of a package element");
+
// Get package object to store current package or NULL if
// current XML package element shoud be skipped/ignored.
if (pd->newpkgcb(&pd->pkg,
tmp_err,
"Parsing interrupted:");
else
- g_set_error(&pd->err, CR_XML_PARSER_FIL_ERROR, CRE_CBINTERRUPTED,
+ g_set_error(&pd->err, ERR_DOMAIN, CRE_CBINTERRUPTED,
"Parsing interrupted");
+ break;
} else {
// If callback return CRE_OK but it simultaneously set
// the tmp_err then it's a programming error.
}
case STATE_VERSION:
- if (!pd->pkg)
- break;
+ assert(pd->pkg);
// Version string insert only if them don't already exists
break;
case STATE_FILE: {
+ assert(pd->pkg);
+
const char *type = cr_find_attr("type", attr);
pd->last_file_type = FILE_FILE;
if (type) {
else if (!strcmp(type, "ghost"))
pd->last_file_type = FILE_GHOST;
else
- g_string_append_printf(pd->msgs,
- "Unknown file type \"%s\";",
- type);
+ cr_xml_parser_warning(pd, CR_XML_WARNING_UNKNOWNVAL,
+ "Unknown file type \"%s\"", type);
}
break;
}
CR_UNUSED(element);
if (pd->err)
- return; /* There was an error -> do nothing */
+ return; // There was an error -> do nothing
if (pd->depth != pd->statedepth) {
- /* Back from the unknown state */
+ // Back from the unknown state
pd->depth--;
return;
}
if (tmp_err)
g_propagate_prefixed_error(&pd->err,
tmp_err,
- "Parsing interrupted:");
+ "Parsing interrupted: ");
else
- g_set_error(&pd->err, CR_XML_PARSER_FIL_ERROR, CRE_CBINTERRUPTED,
+ g_set_error(&pd->err, ERR_DOMAIN, CRE_CBINTERRUPTED,
"Parsing interrupted");
} else {
// If callback return CRE_OK but it simultaneously set
break;
case STATE_FILE: {
- if (!pd->pkg || !pd->content)
+ assert(pd->pkg);
+
+ if (!pd->content)
break;
cr_PackageFile *pkg_file = cr_package_file_new();
void *newpkgcb_data,
cr_XmlParserPkgCb pkgcb,
void *pkgcb_data,
- char **messages,
+ cr_XmlParserWarningCb warningcb,
+ void *warningcb_data,
GError **err)
{
int ret = CRE_OK;
cr_ParserData *pd;
XML_Parser parser;
- char *msgs;
GError *tmp_err = NULL;
assert(path);
assert(newpkgcb || pkgcb);
- assert(!messages || *messages == NULL);
assert(!err || *err == NULL);
if (!newpkgcb) // Use default newpkgcb
pd->newpkgcb = newpkgcb;
pd->pkgcb_data = pkgcb_data;
pd->pkgcb = pkgcb;
+ pd->warningcb = warningcb;
+ pd->warningcb_data = warningcb_data;
for (cr_StatesSwitch *sw = stateswitches; sw->from != NUMSTATES; sw++) {
if (!pd->swtab[sw->from])
pd->swtab[sw->from] = sw;
cr_package_free(pd->pkg);
}
- msgs = cr_xml_parser_data_free(pd);
- if (messages)
- *messages = msgs;
- else
- g_free(msgs);
-
+ cr_xml_parser_data_free(pd);
XML_ParserFree(parser);
return ret;
g_assert(!err || *err == NULL);
if (cbdata) *((int *)cbdata) += 1;
cr_package_free(pkg);
- return CRE_OK;
+ return CR_CB_RET_OK;
}
static int
g_assert(!err || *err == NULL);
if (cbdata) *((int *)cbdata) += 1;
cr_package_free(pkg);
- return 1;
+ return CR_CB_RET_ERR;
}
static int
return CRE_OK;
*pkg = cr_package_new();
- return CRE_OK;
+ return CR_CB_RET_OK;
}
static int
g_assert(pkgId != NULL);
g_assert(!err || *err == NULL);
- return 1;
+ if (cbdata) *((int *)cbdata) += 1;
+
+ return CR_CB_RET_ERR;
+}
+
+static int
+warningcb(cr_XmlParserWarningType type,
+ char *msg,
+ void *cbdata,
+ GError **err)
+{
+ CR_UNUSED(type);
+ CR_UNUSED(msg);
+ CR_UNUSED(err);
+
+ g_assert(type < CR_XML_WARNING_SENTINEL);
+ g_assert(!err || *err == NULL);
+
+ g_string_append((GString *) cbdata, msg);
+ g_string_append((GString *) cbdata, ";");
+
+ return CR_CB_RET_OK;
+}
+
+static int
+warningcb_interrupt(cr_XmlParserWarningType type,
+ char *msg,
+ void *cbdata,
+ GError **err)
+{
+ CR_UNUSED(type);
+ CR_UNUSED(msg);
+ CR_UNUSED(cbdata);
+ CR_UNUSED(err);
+
+ g_assert(type < CR_XML_WARNING_SENTINEL);
+ g_assert(!err || *err == NULL);
+
+ if (cbdata) *((int *)cbdata) += 1;
+
+ return CR_CB_RET_ERR;
}
// Tests
{
GError *tmp_err = NULL;
int ret = cr_xml_parse_filelists(TEST_REPO_00_FILELISTS, NULL, NULL,
- pkgcb, NULL, NULL, &tmp_err);
+ pkgcb, NULL, NULL, NULL, &tmp_err);
g_assert(tmp_err == NULL);
g_assert_cmpint(ret, ==, CRE_OK);
}
int parsed = 0;
GError *tmp_err = NULL;
int ret = cr_xml_parse_filelists(TEST_REPO_01_FILELISTS, NULL, NULL,
- pkgcb, &parsed, NULL, &tmp_err);
+ pkgcb, &parsed, NULL, NULL, &tmp_err);
g_assert(tmp_err == NULL);
g_assert_cmpint(ret, ==, CRE_OK);
g_assert_cmpint(parsed, ==, 1);
int parsed = 0;
GError *tmp_err = NULL;
int ret = cr_xml_parse_filelists(TEST_REPO_02_FILELISTS, NULL, NULL,
- pkgcb, &parsed, NULL, &tmp_err);
+ pkgcb, &parsed, NULL, NULL, &tmp_err);
g_assert(tmp_err == NULL);
g_assert_cmpint(ret, ==, CRE_OK);
g_assert_cmpint(parsed, ==, 2);
int parsed = 0;
GError *tmp_err = NULL;
int ret = cr_xml_parse_filelists(TEST_MRF_UE_FIL_00, NULL, NULL,
- pkgcb, &parsed, NULL, &tmp_err);
+ pkgcb, &parsed, NULL, NULL, &tmp_err);
g_assert(tmp_err == NULL);
g_assert_cmpint(ret, ==, CRE_OK);
g_assert_cmpint(parsed, ==, 2);
int parsed = 0;
GError *tmp_err = NULL;
int ret = cr_xml_parse_filelists(TEST_MRF_UE_FIL_01, NULL, NULL,
- pkgcb, &parsed, NULL, &tmp_err);
+ pkgcb, &parsed, NULL, NULL, &tmp_err);
g_assert(tmp_err == NULL);
g_assert_cmpint(ret, ==, CRE_OK);
g_assert_cmpint(parsed, ==, 1);
int parsed = 0;
GError *tmp_err = NULL;
int ret = cr_xml_parse_filelists(TEST_MRF_UE_FIL_02, NULL, NULL,
- pkgcb, &parsed, NULL, &tmp_err);
+ pkgcb, &parsed, NULL, NULL, &tmp_err);
g_assert(tmp_err == NULL);
g_assert_cmpint(ret, ==, CRE_OK);
g_assert_cmpint(parsed, ==, 2);
int parsed = 0;
GError *tmp_err = NULL;
int ret = cr_xml_parse_filelists(TEST_MRF_NO_PKGID_FIL, NULL, NULL,
- pkgcb, &parsed, NULL, &tmp_err);
+ pkgcb, &parsed, NULL, NULL, &tmp_err);
g_assert(tmp_err != NULL);
g_error_free(tmp_err);
g_assert_cmpint(ret, ==, CRE_BADXMLFILELISTS);
GError *tmp_err = NULL;
int ret = cr_xml_parse_filelists(TEST_MRF_UE_FIL_00,
newpkgcb_skip_fake_bash, NULL,
- pkgcb, &parsed, NULL, &tmp_err);
+ pkgcb, &parsed, NULL, NULL, &tmp_err);
g_assert(tmp_err == NULL);
g_assert_cmpint(ret, ==, CRE_OK);
g_assert_cmpint(parsed, ==, 1);
GError *tmp_err = NULL;
int ret = cr_xml_parse_filelists(TEST_MRF_UE_FIL_01,
newpkgcb_skip_fake_bash, NULL,
- pkgcb, &parsed, NULL, &tmp_err);
+ pkgcb, &parsed, NULL, NULL, &tmp_err);
g_assert(tmp_err == NULL);
g_assert_cmpint(ret, ==, CRE_OK);
g_assert_cmpint(parsed, ==, 0);
int parsed = 0;
GError *tmp_err = NULL;
int ret = cr_xml_parse_filelists(TEST_REPO_02_FILELISTS, NULL, NULL,
- pkgcb_interrupt, &parsed, NULL, &tmp_err);
+ pkgcb_interrupt, &parsed, NULL, NULL, &tmp_err);
g_assert(tmp_err != NULL);
g_error_free(tmp_err);
g_assert_cmpint(ret, ==, CRE_CBINTERRUPTED);
GError *tmp_err = NULL;
int ret = cr_xml_parse_filelists(TEST_REPO_02_FILELISTS,
newpkgcb_interrupt, NULL,
- pkgcb, &parsed, NULL, &tmp_err);
+ pkgcb, &parsed, NULL, NULL, &tmp_err);
g_assert(tmp_err != NULL);
g_error_free(tmp_err);
g_assert_cmpint(ret, ==, CRE_CBINTERRUPTED);
}
static void
-test_cr_xml_parse_filelists_bad_file_type_00(void)
+test_cr_xml_parse_filelists_warningcb_interrupt(void)
{
- int parsed = 0;
+ int parsed = 0, numofwarnings = 0;
GError *tmp_err = NULL;
int ret = cr_xml_parse_filelists(TEST_MRF_BAD_TYPE_FIL,
NULL, NULL,
- pkgcb, &parsed, NULL, &tmp_err);
+ pkgcb, &parsed, warningcb_interrupt,
+ &numofwarnings, &tmp_err);
+ g_assert(tmp_err != NULL);
+ g_error_free(tmp_err);
+ g_assert_cmpint(ret, ==, CRE_CBINTERRUPTED);
+ g_assert_cmpint(parsed, ==, 1);
+ g_assert_cmpint(numofwarnings, ==, 1);
+}
+
+static void
+test_cr_xml_parse_filelists_bad_file_type_00(void)
+{
+ int parsed = 0;
+ GError *tmp_err = NULL;
+ int ret = cr_xml_parse_filelists(TEST_MRF_BAD_TYPE_FIL, NULL, NULL,
+ pkgcb, &parsed, NULL, NULL, &tmp_err);
g_assert(tmp_err == NULL);
g_assert_cmpint(ret, ==, CRE_OK);
g_assert_cmpint(parsed, ==, 2);
static void
test_cr_xml_parse_filelists_bad_file_type_01(void)
{
+ char *warnmsgs;
int parsed = 0;
- char *msgs = NULL;
+ GString *warn_strings = g_string_new(0);
GError *tmp_err = NULL;
- int ret = cr_xml_parse_filelists(TEST_MRF_BAD_TYPE_FIL,
- NULL, NULL,
- pkgcb, &parsed, &msgs, &tmp_err);
- g_assert(msgs != NULL);
- g_assert_cmpstr(msgs, ==, "Unknown file type \"foo\";");
- g_free(msgs);
+ int ret = cr_xml_parse_filelists(TEST_MRF_BAD_TYPE_FIL, NULL, NULL,
+ pkgcb, &parsed, warningcb,
+ warn_strings, &tmp_err);
g_assert(tmp_err == NULL);
g_assert_cmpint(ret, ==, CRE_OK);
g_assert_cmpint(parsed, ==, 2);
+ warnmsgs = g_string_free(warn_strings, FALSE);
+ g_assert_cmpstr(warnmsgs, ==, "Unknown file type \"foo\";");
+ g_free(warnmsgs);
}
int
test_cr_xml_parse_filelists_pkgcb_interrupt);
g_test_add_func("/xml_parser_filelists/test_cr_xml_parse_filelists_newpkgcb_interrupt",
test_cr_xml_parse_filelists_newpkgcb_interrupt);
+ g_test_add_func("/xml_parser_filelists/test_cr_xml_parse_filelists_warningcb_interrupt",
+ test_cr_xml_parse_filelists_warningcb_interrupt);
g_test_add_func("/xml_parser_filelists/test_cr_xml_parse_filelists_bad_file_type_00",
test_cr_xml_parse_filelists_bad_file_type_00);
g_test_add_func("/xml_parser_filelists/test_cr_xml_parse_filelists_bad_file_type_01",