23a0882000-08-12Martin Stjernholm //! Things that belong elsewhere but can't lie there for various silly //! reasons. Everything here is considered internal and not part of //! the RXML.pmod API.
26ff092000-01-21Martin Stjernholm //! //! E.g. one reason is to avoid circular references in the parser //! objects when the callbacks are defined in them. //! //! Created 2000-01-21 by Martin Stjernholm //!
32cd1c2008-10-13Martin Stjernholm //! $Id: utils.pmod,v 1.35 2008/10/12 22:14:03 mast Exp $
c1ee002001-06-29Martin Stjernholm  constant is_RXML_encodable = 1;
26ff092000-01-21Martin Stjernholm 
40c67c2001-07-09Martin Stjernholm #ifdef RXML_ENCODE_DEBUG string _sprintf() {return "RXML.utils.pmod";} #endif
6fae202001-05-19Martin Stjernholm constant short_format_length = 40;
26ff092000-01-21Martin Stjernholm 
32cd1c2008-10-13Martin Stjernholm // Tell Pike.count_memory this is global. constant pike_cycle_depth = 0;
958fa92001-07-16Martin Stjernholm final string format_short (mixed val, void|int length)
6fae202001-05-19Martin Stjernholm // This one belongs somewhere else..
7dd3f82001-04-18Martin Stjernholm {
6fae202001-05-19Martin Stjernholm  string res = "";
958fa92001-07-16Martin Stjernholm  if (!length) length = short_format_length;
6fae202001-05-19Martin Stjernholm  void format_val (mixed val) { if (arrayp (val) || multisetp (val)) { string end; if (multisetp (val)) res += "(<", end = ">)", val = indices (val); else res += "({", end = "})";
958fa92001-07-16Martin Stjernholm  if (sizeof (res) >= length) throw (0);
6fae202001-05-19Martin Stjernholm  for (int i = 0; i < sizeof (val);) {
1293eb2001-06-18Martin Stjernholm  format_val (val[i]); if (++i < sizeof (val)) res += ", ";
958fa92001-07-16Martin Stjernholm  if (sizeof (res) >= length) throw (0);
6fae202001-05-19Martin Stjernholm  } res += end; } else if (mappingp (val)) { res += "([";
958fa92001-07-16Martin Stjernholm  if (sizeof (res) >= length) throw (0);
652d442002-07-16Martin Stjernholm  array ind = indices (val); catch (ind = sort (ind)); // sort might fail if there are objects without `< or `>.
6fae202001-05-19Martin Stjernholm  for (int i = 0; i < sizeof (ind);) {
40c67c2001-07-09Martin Stjernholm  format_val (ind[i]); res += ": ";
958fa92001-07-16Martin Stjernholm  if (sizeof (res) >= length) throw (0);
1293eb2001-06-18Martin Stjernholm  format_val (val[ind[i]]); if (++i < sizeof (ind)) res += ", ";
958fa92001-07-16Martin Stjernholm  if (sizeof (res) >= length) throw (0);
6fae202001-05-19Martin Stjernholm  } res += "])"; }
7d18422008-09-28Martin Stjernholm  else if (stringp (val)) { if (sizeof (val) > length - sizeof (res)) {
6fae202001-05-19Martin Stjernholm  sscanf (val, "%[ \t\n\r]", string lead); if (sizeof (lead) > sizeof ("/.../") && sizeof (lead) < sizeof (val)) val = val[sizeof (lead)..], res += "/.../";
958fa92001-07-16Martin Stjernholm  if (sizeof (val) > length - sizeof (res)) {
7d18422008-09-28Martin Stjernholm  res += sprintf ("%q", val[..length - sizeof (res) - 1]);
6fae202001-05-19Martin Stjernholm  throw (0); } }
7d18422008-09-28Martin Stjernholm  res += sprintf ("%q", val);
6fae202001-05-19Martin Stjernholm  }
7d18422008-09-28Martin Stjernholm  else res += sprintf ("%O", val);
6fae202001-05-19Martin Stjernholm  }; mixed err = catch { format_val (val); return res; }; if (err) throw (err); return res + "/.../";
7dd3f82001-04-18Martin Stjernholm }
26ff092000-01-21Martin Stjernholm 
7dd3f82001-04-18Martin Stjernholm final array return_zero (mixed... ignored) {return 0;} final array return_empty_array (mixed... ignored) {return ({});}
a08cd72001-06-09Martin Stjernholm final mapping(string:string) return_empty_mapping (mixed... ignored) {return ([]);} final mapping(string:string) return_help_arg (mixed... ignored) {return (["help": "help"]);} final mixed get_non_nil (RXML.Type type, mixed... vals) // Returns the single argument in vals that isn't RXML.nil, or // RXML.nil if all of them are that value. Throws an rxml parse error // if more than one argument isn't nil. { int pos = -1; do if (++pos == sizeof (vals)) return RXML.nil; while (vals[pos] == RXML.nil); mixed res = vals[pos]; for (pos++; pos < sizeof (vals); pos++) if (vals[pos] != RXML.nil) RXML.parse_error ( "Cannot append another value %s to non-sequential value of type %s.\n", format_short (vals[pos]), type->name); return res; }
7dd3f82001-04-18Martin Stjernholm  final int(1..1)|string|array unknown_tag_error (object/*(RMXL.PXml)*/ p, string str)
9265b52000-02-11Martin Stjernholm {
446bfa2001-06-21Martin Stjernholm  p->context->handle_exception ( catch (RXML.parse_error ( "Unknown tag %s is not allowed in context of type %s.\n",
6f77372002-04-03Martin Stjernholm  format_short (p->tag_name()), p->type->name)), p, p->p_code);
9265b52000-02-11Martin Stjernholm  return ({}); }
7dd3f82001-04-18Martin Stjernholm final int(1..1)|string|array unknown_pi_tag_error (object/*(RMXL.PXml)*/ p, string str) { sscanf (str, "%[^ \t\n\r]", str);
446bfa2001-06-21Martin Stjernholm  p->context->handle_exception ( catch (RXML.parse_error ( "Unknown processing instruction %s not allowed in context of type %s.\n",
6f77372002-04-03Martin Stjernholm  format_short ("<" + p->tag_name() + str), p->type->name)), p, p->p_code);
7dd3f82001-04-18Martin Stjernholm  return ({}); } final int(1..1)|string|array invalid_cdata_error (object/*(RXML.PXml)*/ p, string str) {
446bfa2001-06-21Martin Stjernholm  p->context->handle_exception ( catch (RXML.parse_error ( "CDATA text %O is not allowed in context of type %s.\n",
6f77372002-04-03Martin Stjernholm  format_short (str), p->type->name)), p, p->p_code);
7dd3f82001-04-18Martin Stjernholm  return ({}); } final int(1..1)|string|array output_error_cb (object/*(RMXL.PXml)*/ p, string str)
f9dcf62000-02-13Martin Stjernholm {
446bfa2001-06-21Martin Stjernholm  p->output_errors();
f9dcf62000-02-13Martin Stjernholm  return ({str}); }
26ff092000-01-21Martin Stjernholm 
9f74bb2000-02-15Martin Stjernholm // PXml and PEnt callbacks.
26ff092000-01-21Martin Stjernholm 
7dd3f82001-04-18Martin Stjernholm final int(1..1)|string|array p_xml_comment_cb (object/*(RXML.PXml)*/ p, string str)
b1c1d32000-03-06Martin Stjernholm // FIXME: This is a kludge until quote tags are handled like other tags. {
446bfa2001-06-21Martin Stjernholm  p->drain_output();
5eef022000-03-06Martin Stjernholm  string name = p->parse_tag_name (str);
b1c1d32000-03-06Martin Stjernholm  if (sizeof (name)) { name = p->tag_name() + name; if (string|array|function tdef = p->tags()[name]) { if (stringp (tdef)) return ({tdef}); else if (arrayp (tdef)) return tdef[0] (p, p->parse_tag_args (str), @tdef[1..]); else return tdef (p, p->parse_tag_args (str)); } else if (p->containers()[name])
446bfa2001-06-21Martin Stjernholm  p->context->handle_exception ( catch (RXML.parse_error ( "Sorry, can't handle containers beginning with %s.\n",
6f77372002-04-03Martin Stjernholm  p->tag_name())), p, p->p_code);
b1c1d32000-03-06Martin Stjernholm  } return p->type->free_text ? 0 : ({}); }
7dd3f82001-04-18Martin Stjernholm final int(1..1)|string|array p_xml_cdata_cb (object/*(RXML.PXml)*/ p, string str) { return ({str}); } final int(1..1)|string|array p_xml_entity_cb (object/*(RXML.PXml)*/ p, string str)
26ff092000-01-21Martin Stjernholm {
7dd3f82001-04-18Martin Stjernholm  RXML.Type type = p->type;
26ff092000-01-21Martin Stjernholm  string entity = p->tag_name();
7dd3f82001-04-18Martin Stjernholm  if (sizeof (entity))
cbf0e02004-05-21Henrik Grubbström (Grubba)  switch(entity[0]) { case ':': return ({"&", entity[1..], ";"}); case '#':
7dd3f82001-04-18Martin Stjernholm  if (!p->type->entity_syntax) { // Don't decode normal entities if we're outputting xml-like stuff. if (sscanf (entity, (<"#x", "#X">)[entity[..1]] ? "%*2s%x%*c" : "%*c%d%*c", int char) == 2) catch (str = (string) ({char})); // Lax error handling: Just let it through if it can't be // converted. Not really good, though. }
cbf0e02004-05-21Henrik Grubbström (Grubba)  break; default: if (has_value (entity, ".")) {
446bfa2001-06-21Martin Stjernholm  p->drain_output();
7dd3f82001-04-18Martin Stjernholm  mixed value = p->handle_var ( entity, // No quoting of splice args. FIXME: Add some sort of // safeguard against splicing in things like "nice><evil // stuff='...'"?
1293eb2001-06-18Martin Stjernholm  p->html_context() == "splice_arg" ? RXML.t_any_text : type);
cfe6c92006-08-22Martin Stjernholm  if (value != RXML.nil && value != RXML.empty) p->add_value (value);
7dd3f82001-04-18Martin Stjernholm  return ({}); }
cbf0e02004-05-21Henrik Grubbström (Grubba)  }
7dd3f82001-04-18Martin Stjernholm  return ({str});
26ff092000-01-21Martin Stjernholm }
7dd3f82001-04-18Martin Stjernholm final int(1..1)|string|array p_xml_compat_entity_cb (object/*(RMXL.PXml)*/ p, string str)
26ff092000-01-21Martin Stjernholm {
7dd3f82001-04-18Martin Stjernholm  RXML.Type type = p->type;
26ff092000-01-21Martin Stjernholm  string entity = p->tag_name();
b8e84a2000-03-04Martin Stjernholm  if (sizeof (entity) && entity[0] != '#')
648aba2002-07-17Martin Stjernholm  if (entity[0] == ':') return ({"&", entity[1..], ";"});
7dd3f82001-04-18Martin Stjernholm  else if (has_value (entity, ".")) {
446bfa2001-06-21Martin Stjernholm  p->drain_output();
7dd3f82001-04-18Martin Stjernholm  mixed value = p->handle_var ( entity, // No quoting of splice args. FIXME: Add some sort of // safeguard against splicing in things like "nice><evil // stuff='...'"?
1293eb2001-06-18Martin Stjernholm  p->html_context() == "splice_arg" ? RXML.t_any_text : type);
cfe6c92006-08-22Martin Stjernholm  if (value != RXML.nil && value != RXML.empty) p->add_value (value);
7dd3f82001-04-18Martin Stjernholm  return ({}); } return ({str});
26ff092000-01-21Martin Stjernholm }