bool softlist_parser::parse_name_and_value(const char **attributes, std::string &name, std::string &value) { bool found_value = false; // iterate over attribute/value pairs for( ; attributes[0]; attributes += 2) { // if found, set the corresponding output entry to the value if (strcmp(attributes[0], "name") == 0) { name = attributes[1]; } else if (strcmp(attributes[0], "value") == 0) { value = attributes[1]; found_value = true; } // if not found, report an unknown attribute else unknown_attribute(attributes[0]); } return !name.empty() && found_value; }
std::vector<std::string> softlist_parser::parse_attributes(const char **attributes, const T &attrlist) { std::vector<std::string> outlist(std::distance(std::begin(attrlist), std::end(attrlist))); // iterate over attribute/value pairs for( ; attributes[0]; attributes += 2) { auto iter = std::begin(attrlist); // look for a match among the attributes provided for (std::size_t index = 0; iter != std::end(attrlist); ++index, ++iter) { if (strcmp(attributes[0], *iter) == 0) { // if found, set the corresponding output entry to the value outlist[index] = attributes[1]; break; } } // if not found, report an unknown attribute if (iter == std::end(attrlist)) unknown_attribute(attributes[0]); } return outlist; }
/* called from the GMarkupParser */ static void start_element_handler (GMarkupParseContext *markup_context, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, gpointer user_data, GError **error) { XMPParseContext *context = user_data; gint attr; #ifdef DEBUG_XMP_PARSER g_print ("[%25s/%17s] %d <%s>\n", state_names[context->state], (context->saved_state == STATE_ERROR ? "-" : state_names[context->saved_state]), context->depth, element_name); #endif context->depth++; for (attr = 0; attribute_names[attr] != NULL; ++attr) if (g_str_has_prefix (attribute_names[attr], "xmlns:")) push_namespace (context, attribute_values[attr], attribute_names[attr] + sizeof ("xmlns:") - 1, error); switch (context->state) { case STATE_INSIDE_XPACKET: if (! strcmp (element_name, "x:xmpmeta") || ! strcmp (element_name, "x:xapmeta") || matches_with_prefix (element_name, context->xmp_prefix, context->xmp_prefix_len, "xmpmeta")) context->state = STATE_INSIDE_XMPMETA; else if (matches_rdf (element_name, context, "RDF")) { /* the x:xmpmeta element is missing, but this is allowed */ context->depth++; context->state = STATE_INSIDE_RDF; } else parse_error_element (context, error, "x:xmpmeta", FALSE, element_name); break; case STATE_INSIDE_XMPMETA: if (matches_rdf (element_name, context, "RDF")) context->state = STATE_INSIDE_RDF; else parse_error_element (context, error, "rdf:RDF", FALSE, element_name); break; case STATE_INSIDE_RDF: if (matches_rdf (element_name, context, "Description")) { XMLNameSpace *ns; gboolean about_seen = FALSE; context->state = STATE_INSIDE_TOPLEVEL_DESC; for (attr = 0; attribute_names[attr] != NULL; ++attr) { if (matches_rdf (attribute_names[attr], context, "about") || ! strcmp (attribute_names[attr], "about") /* old style */) about_seen = TRUE; else if (g_str_has_prefix (attribute_names[attr], "xmlns")) ; /* the namespace has already been pushed on the stack */ else { ns = new_property_in_ns (context, attribute_names[attr]); if (ns != NULL) { /* RDF shorthand notation */ add_property_value (context, XMP_PTYPE_TEXT, NULL, g_strdup (attribute_values[attr])); propagate_property (context, error); } else unknown_attribute (context, error, element_name, attribute_names[attr], attribute_values[attr]); } } if ((about_seen == FALSE) && (context->flags & XMP_FLAG_NO_MISSING_ABOUT)) parse_error (context, error, XMP_ERROR_MISSING_ABOUT, _("Required attribute rdf:about missing in <%s>"), element_name); } else parse_error_element (context, error, "rdf:Description", FALSE, element_name); break; case STATE_INSIDE_TOPLEVEL_DESC: { XMLNameSpace *ns; ns = new_property_in_ns (context, element_name); if (ns != NULL) { context->state = STATE_INSIDE_PROPERTY; for (attr = 0; attribute_names[attr] != NULL; ++attr) { if (matches_rdf (attribute_names[attr], context, "resource")) add_property_value (context, XMP_PTYPE_RESOURCE, NULL, g_strdup (attribute_values[attr])); else if (matches_rdf (attribute_names[attr], context, "parseType") && ! strcmp (attribute_values[attr], "Resource")) { context->saved_state = STATE_INSIDE_TOPLEVEL_DESC; context->state = STATE_INSIDE_STRUCT_ADD_NS; } else unknown_attribute (context, error, element_name, attribute_names[attr], attribute_values[attr]); } } else unknown_element (context, error, element_name); } break; case STATE_INSIDE_PROPERTY: if (matches_rdf (element_name, context, "Description")) { context->saved_state = context->state; context->state = STATE_INSIDE_QDESC; for (attr = 0; attribute_names[attr] != NULL; ++attr) { if (g_str_has_prefix (attribute_names[attr], "xmlns")) { /* this desc. is a structure, not a property qualifier */ context->state = STATE_INSIDE_STRUCT_ADD_NS; } else unknown_attribute (context, error, element_name, attribute_names[attr], attribute_values[attr]); } } else if (matches_rdf (element_name, context, "Alt")) context->state = STATE_INSIDE_ALT; else if (matches_rdf (element_name, context, "Bag")) context->state = STATE_INSIDE_BAG; else if (matches_rdf (element_name, context, "Seq")) context->state = STATE_INSIDE_SEQ; else unknown_element (context, error, element_name); break; case STATE_INSIDE_QDESC: if (matches_rdf (element_name, context, "value")) context->state = STATE_INSIDE_QDESC_VALUE; else context->state = STATE_INSIDE_QDESC_QUAL; break; case STATE_INSIDE_STRUCT_ADD_NS: case STATE_INSIDE_STRUCT: { GSList *ns_list; XMLNameSpace *ns; gboolean found; /* compare with namespaces in scope of current rdf:Description */ found = FALSE; ns_list = context->namespaces; while (ns_list != NULL) { ns = ns_list->data; if (ns->depth < context->depth - 2) break; if (has_ns_prefix (element_name, ns)) { if (context->state == STATE_INSIDE_STRUCT_ADD_NS) { /* first element - save the namespace prefix and uri */ add_property_value (context, XMP_PTYPE_STRUCTURE, g_strdup (ns->prefix), g_strdup (ns->uri)); } context->state = STATE_INSIDE_STRUCT_ELEMENT; add_property_value (context, XMP_PTYPE_STRUCTURE, g_strdup (element_name + ns->prefix_len + 1), NULL); found = TRUE; break; } ns_list = ns_list->next; } if (found == FALSE) unknown_element (context, error, element_name); } break; case STATE_INSIDE_ALT: if (matches_rdf (element_name, context, "li")) { context->state = STATE_INSIDE_ALT_LI; for (attr = 0; attribute_names[attr] != NULL; ++attr) { if (matches_rdf (attribute_names[attr], context, "parseType") && ! strcmp (attribute_values[attr], "Resource")) context->state = STATE_INSIDE_ALT_LI_RSC; else if (! strcmp (attribute_names[attr], "xml:lang")) add_property_value (context, XMP_PTYPE_ALT_LANG, g_strdup (attribute_values[attr]), NULL); else unknown_attribute (context, error, element_name, attribute_names[attr], attribute_values[attr]); } /* rdf:Alt is not an ordered list, but some broken XMP files use */ /* it instead of rdf:Seq. Workaround: if we did not find some */ /* attributes for the valid cases ALT_LANG or ALT_LI_RSC, then */ /* we pretend that we are parsing a real list (bug #343315). */ if ((context->property_type != XMP_PTYPE_ALT_LANG) && (context->state != STATE_INSIDE_ALT_LI_RSC)) add_property_value (context, XMP_PTYPE_ORDERED_LIST, NULL, NULL); } else parse_error_element (context, error, "rdf:li", FALSE, element_name); break; case STATE_INSIDE_BAG: if (matches_rdf (element_name, context, "li")) { context->state = STATE_INSIDE_BAG_LI; for (attr = 0; attribute_names[attr] != NULL; ++attr) { if (matches_rdf (attribute_names[attr], context, "parseType") && ! strcmp (attribute_values[attr], "Resource")) context->state = STATE_INSIDE_BAG_LI_RSC; else unknown_attribute (context, error, element_name, attribute_names[attr], attribute_values[attr]); } if (context->state != STATE_INSIDE_BAG_LI_RSC) add_property_value (context, XMP_PTYPE_UNORDERED_LIST, NULL, NULL); } else parse_error_element (context, error, "rdf:li", FALSE, element_name); break; case STATE_INSIDE_SEQ: if (matches_rdf (element_name, context, "li")) { context->state = STATE_INSIDE_SEQ_LI; for (attr = 0; attribute_names[attr] != NULL; ++attr) { if (matches_rdf (attribute_names[attr], context, "parseType") && ! strcmp (attribute_values[attr], "Resource")) context->state = STATE_INSIDE_SEQ_LI_RSC; else unknown_attribute (context, error, element_name, attribute_names[attr], attribute_values[attr]); } if (context->state != STATE_INSIDE_SEQ_LI_RSC) add_property_value (context, XMP_PTYPE_ORDERED_LIST, NULL, NULL); } else parse_error_element (context, error, "rdf:li", FALSE, element_name); break; case STATE_INSIDE_BAG_LI: case STATE_INSIDE_SEQ_LI: if (matches_rdf (element_name, context, "Description")) { context->saved_state = context->state; context->state = STATE_INSIDE_QDESC; } else parse_error_element (context, error, "rdf:Description", TRUE, element_name); break; case STATE_INSIDE_ALT_LI_RSC: /* store the thumbnail image and ignore the other elements */ if (! strcmp (element_name, "xapGImg:image")) /* FIXME */ context->state = STATE_INSIDE_ALT_LI_RSC_IMG; else if (! strcmp (element_name, "xapGImg:format") || ! strcmp (element_name, "xapGImg:width") || ! strcmp (element_name, "xapGImg:height")) ignore_element (context); else unknown_element (context, error, element_name); break; case STATE_INSIDE_BAG_LI_RSC: case STATE_INSIDE_SEQ_LI_RSC: unknown_element (context, error, element_name); break; case STATE_SKIPPING_UNKNOWN_ELEMENTS: case STATE_SKIPPING_IGNORED_ELEMENTS: break; default: parse_error (context, error, XMP_ERROR_PARSE, _("Nested elements (<%s>) are not allowed in this context"), element_name); break; } }
/* * Parse a function call * * For historical reasons, Postgres tries to treat the notations tab.col * and col(tab) as equivalent: if a single-argument function call has an * argument of complex type and the (unqualified) function name matches * any attribute of the type, we take it as a column projection. Conversely * a function of a single complex-type argument can be written like a * column reference, allowing functions to act like computed columns. * * Hence, both cases come through here. The is_column parameter tells us * which syntactic construct is actually being dealt with, but this is * intended to be used only to deliver an appropriate error message, * not to affect the semantics. When is_column is true, we should have * a single argument (the putative table), unqualified function name * equal to the column name, and no aggregate or variadic decoration. * * The argument expressions (in fargs) must have been transformed already. */ Node * ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, bool agg_star, bool agg_distinct, bool func_variadic, WindowDef *over, bool is_column, int location) { Oid rettype; Oid funcid; ListCell *l; ListCell *nextl; Node *first_arg = NULL; int nargs; int nargsplusdefs; Oid actual_arg_types[FUNC_MAX_ARGS]; Oid *declared_arg_types; List *argdefaults; Node *retval; bool retset; int nvargs; FuncDetailCode fdresult; /* * Most of the rest of the parser just assumes that functions do not have * more than FUNC_MAX_ARGS parameters. We have to test here to protect * against array overruns, etc. Of course, this may not be a function, * but the test doesn't hurt. */ if (list_length(fargs) > FUNC_MAX_ARGS) ereport(ERROR, (errcode(ERRCODE_TOO_MANY_ARGUMENTS), errmsg_plural("cannot pass more than %d argument to a function", "cannot pass more than %d arguments to a function", FUNC_MAX_ARGS, FUNC_MAX_ARGS), parser_errposition(pstate, location))); /* * Extract arg type info in preparation for function lookup. * * If any arguments are Param markers of type VOID, we discard them from * the parameter list. This is a hack to allow the JDBC driver to not * have to distinguish "input" and "output" parameter symbols while * parsing function-call constructs. We can't use foreach() because we * may modify the list ... */ nargs = 0; for (l = list_head(fargs); l != NULL; l = nextl) { Node *arg = lfirst(l); Oid argtype = exprType(arg); nextl = lnext(l); if (argtype == VOIDOID && IsA(arg, Param) &&!is_column) { fargs = list_delete_ptr(fargs, arg); continue; } actual_arg_types[nargs++] = argtype; } if (fargs) { first_arg = linitial(fargs); Assert(first_arg != NULL); } /* * Check for column projection: if function has one argument, and that * argument is of complex type, and function name is not qualified, then * the "function call" could be a projection. We also check that there * wasn't any aggregate or variadic decoration. */ if (nargs == 1 && !agg_star && !agg_distinct && over == NULL && !func_variadic && list_length(funcname) == 1) { Oid argtype = actual_arg_types[0]; if (argtype == RECORDOID || ISCOMPLEX(argtype)) { retval = ParseComplexProjection(pstate, strVal(linitial(funcname)), first_arg, location); if (retval) return retval; /* * If ParseComplexProjection doesn't recognize it as a projection, * just press on. */ } } /* * Okay, it's not a column projection, so it must really be a function. * func_get_detail looks up the function in the catalogs, does * disambiguation for polymorphic functions, handles inheritance, and * returns the funcid and type and set or singleton status of the * function's return value. It also returns the true argument types to * the function. In the case of a variadic function call, the reported * "true" types aren't really what is in pg_proc: the variadic argument is * replaced by a suitable number of copies of its element type. We'll fix * it up below. We may also have to deal with default arguments. */ fdresult = func_get_detail(funcname, fargs, nargs, actual_arg_types, !func_variadic, true, &funcid, &rettype, &retset, &nvargs, &declared_arg_types, &argdefaults); if (fdresult == FUNCDETAIL_COERCION) { /* * We interpreted it as a type coercion. coerce_type can handle these * cases, so why duplicate code... */ return coerce_type(pstate, linitial(fargs), actual_arg_types[0], rettype, -1, COERCION_EXPLICIT, COERCE_EXPLICIT_CALL, location); } else if (fdresult == FUNCDETAIL_NORMAL) { /* * Normal function found; was there anything indicating it must be an * aggregate? */ if (agg_star) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("%s(*) specified, but %s is not an aggregate function", NameListToString(funcname), NameListToString(funcname)), parser_errposition(pstate, location))); if (agg_distinct) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("DISTINCT specified, but %s is not an aggregate function", NameListToString(funcname)), parser_errposition(pstate, location))); if (over) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("OVER specified, but %s is not a window function nor an aggregate function", NameListToString(funcname)), parser_errposition(pstate, location))); } else if (!(fdresult == FUNCDETAIL_AGGREGATE || fdresult == FUNCDETAIL_WINDOWFUNC)) { /* * Oops. Time to die. * * If we are dealing with the attribute notation rel.function, give an * error message that is appropriate for that case. */ if (is_column) { Assert(nargs == 1); Assert(list_length(funcname) == 1); unknown_attribute(pstate, first_arg, strVal(linitial(funcname)), location); } /* * Else generate a detailed complaint for a function */ if (fdresult == FUNCDETAIL_MULTIPLE) ereport(ERROR, (errcode(ERRCODE_AMBIGUOUS_FUNCTION), errmsg("function %s is not unique", func_signature_string(funcname, nargs, actual_arg_types)), errhint("Could not choose a best candidate function. " "You might need to add explicit type casts."), parser_errposition(pstate, location))); else ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("function %s does not exist", func_signature_string(funcname, nargs, actual_arg_types)), errhint("No function matches the given name and argument types. " "You might need to add explicit type casts."), parser_errposition(pstate, location))); } /* * If there are default arguments, we have to include their types in * actual_arg_types for the purpose of checking generic type consistency. * However, we do NOT put them into the generated parse node, because * their actual values might change before the query gets run. The * planner has to insert the up-to-date values at plan time. */ nargsplusdefs = nargs; foreach(l, argdefaults) { Node *expr = (Node *) lfirst(l); /* probably shouldn't happen ... */ if (nargsplusdefs >= FUNC_MAX_ARGS) ereport(ERROR, (errcode(ERRCODE_TOO_MANY_ARGUMENTS), errmsg_plural("cannot pass more than %d argument to a function", "cannot pass more than %d arguments to a function", FUNC_MAX_ARGS, FUNC_MAX_ARGS), parser_errposition(pstate, location))); actual_arg_types[nargsplusdefs++] = exprType(expr); }