Beispiel #1
0
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;
}
Beispiel #2
0
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;
}
Beispiel #3
0
/* 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);
	}