53a9021998-10-14Niels Möller /* parse_line.pike * */ class partial_literal { int length; void create(int l) { length = l; } } string buffer; void create(string line) { buffer = line; } void skip_whitespace() { sscanf(buffer, "%*[ \t]%s", buffer); }
4d026b1998-10-26Niels Möller #if 0
e992931998-10-21Niels Möller int eolp() { skip_whitespace(); return !strlen(buffer); }
4d026b1998-10-26Niels Möller #endif
e992931998-10-21Niels Möller 
53a9021998-10-14Niels Möller // Returns -1 on error. All valid numbers ar non-negative. int get_number() { skip_whitespace(); if (!strlen(buffer)) return -1; int i; for(i = 0; i<strlen(buffer); i++) if ( (buffer[i] < '0') || ('9' < buffer[i]) ) break; // Disallow too large numbers if (!i || (i > 9) ) return -1; int res = array_sscanf(buffer[..i-1], "%d")[0]; buffer = buffer[i..]; return res; } string get_atom(int|void with_options) { string atom; werror("get_atom: buffer = '%s'\n", buffer);
5e5d111999-02-02Henrik Grubbström (Grubba) 
53a9021998-10-14Niels Möller  sscanf(buffer, (with_options
d5cd421999-02-13Henrik Grubbström (Grubba)  ? "%*[ \t]%[^][(){ \0-\037\177%\"]%s" : "%*[ \t]%[^(){ \0-\037\177%\"]%s"),
53a9021998-10-14Niels Möller  atom, buffer);
5e5d111999-02-02Henrik Grubbström (Grubba) 
95b5b61999-02-02Henrik Grubbström (Grubba)  werror(sprintf("=> atom: %O\n", atom));
53a9021998-10-14Niels Möller  return strlen(atom) && atom; } string|object get_string() { werror("get_string: buffer = '%s'\n", buffer); skip_whitespace(); if (!strlen(buffer)) return 0; switch(buffer[0]) { case '"': { int i = 0; while(1) { i = search(buffer, "\"", i+1); if (i<0) return 0; if (buffer[i-1] != '\\') { string res = replace(buffer[1..i-1], ({ "\\\"", "\\\\" }), ({ "\"", "\\" }) ); buffer = buffer[i+1..]; return res; } } } case '{': { if (buffer[strlen(buffer)-1..] != "}") return 0; string n = buffer[1..strlen(buffer)-2]; buffer = ""; if ( (sizeof(values(n) - values("0123456789"))) || (sizeof(n) > 9) ) return 0; if (!sizeof(n)) return 0; return partial_literal(array_sscanf(n, "%d")[0]); } } } string|object get_astring() { werror("get_astring: buffer = '%s'\n", buffer); skip_whitespace(); if (!strlen(buffer)) return 0; switch(buffer[0]) { case '"': case '{': return get_string(); default: return get_atom(); } } /* Returns a set object. */ object get_set() { string atom = get_atom(); if (!atom) return 0; return .types.imap_set()->init(atom); }
c6b66a1998-10-16Niels Möller /* Parses an object that can be a string, an atom (possibly with
4d026b1998-10-26Niels Möller  * options in brackets) or a list. * * eol can be 0, meaning no end of line or list expected, * a positive int, meaning a character (e.g. ')' or ']' that terminates the list, * or -1, meaning that the list terminates at end of line. */ mapping get_token(int eol, int accept_options)
c6b66a1998-10-16Niels Möller { skip_whitespace(); if (!strlen(buffer))
4d026b1998-10-26Niels Möller  return (eol == -1) && ([ "type" : "eol", "eol" : 1 ]);
c6b66a1998-10-16Niels Möller  if (eol && (buffer[0] == eol)) { buffer = buffer[1..]; return ([ "type" : "eol", "eol" : 1 ]); } switch(buffer[0]) { case '(': buffer = buffer[1..]; return ([ "type" : "list", "list" : 1 ]); case '"': { string s = get_string(); return s && ([ "type" : "string", "string" : s ]); } case "{": { object s = get_string();
9406111998-10-16Niels Möller  return s && ([ "type" : "literal", "length" : s->length ]);
c6b66a1998-10-16Niels Möller  } default: {
a1b1301999-03-22Henrik Grubbström (Grubba)  if (accept_options) { return get_atom_options(2); } else { string atom = get_atom(accept_options);
c6b66a1998-10-16Niels Möller  return ([ "type" : "atom", "atom" : atom ]);
a1b1301999-03-22Henrik Grubbström (Grubba)  }
c6b66a1998-10-16Niels Möller  } } } /* Reads a <start.size> suffix */ mapping get_range(mapping atom) { if (!strlen(buffer) || (buffer[0] != '<')) return atom; buffer = buffer[1..]; int start = get_number(); if ((start < 0) || !strlen(buffer) || (buffer[0] != '.')) return 0; buffer = buffer[1..]; int size = get_number(); if ((size <= 0) || !strlen(buffer) || (buffer[0] != '>')) return 0; buffer = buffer[1..]; atom->range = ({ start, size }); return atom; }
cf70fa1999-02-17Henrik Grubbström (Grubba) /* Get a list of atoms. * Primarily intended for use by STORE for the flags argument. */ array(string) get_flag_list() { skip_whitespace(); if (!strlen(buffer) || (buffer[0] != '(') ) return 0; buffer = buffer[1..];
a96b3d1999-02-18Henrik Grubbström (Grubba)  array(string) res = ({});
cf70fa1999-02-17Henrik Grubbström (Grubba)  skip_whitespace(); string atom; while (atom = get_atom()) { res += ({ atom }); skip_whitespace(); } skip_whitespace(); // This one shouldn't be needed, but... if (!strlen(buffer))
d0e1571999-02-17Henrik Grubbström (Grubba)  return 0;
cf70fa1999-02-17Henrik Grubbström (Grubba)  if (buffer[0] = ')') { buffer = buffer[1..]; return res; } return 0; }
53a9021998-10-14Niels Möller /* Parses an object that (recursivly) can contain atoms (possible
d5cd421999-02-13Henrik Grubbström (Grubba)  * with options in brackets) or lists. Note that strings are not * accepted, as it is a little difficult to wait for the * continuation of the request. * * FIXME: This function is used to read fetch commands. This breaks * rfc-2060 compliance, as the names of headers can be represented * as string literals. */
53a9021998-10-14Niels Möller  mapping get_simple_list(int max_depth) { skip_whitespace(); if (!strlen(buffer)) return 0;
ee55471999-03-22Henrik Grubbström (Grubba)  if (buffer[0] == '(') {
53a9021998-10-14Niels Möller  /* Recurse */
ee55471999-03-22Henrik Grubbström (Grubba)  if (max_depth > 0) {
53a9021998-10-14Niels Möller  array a = do_parse_simple_list(max_depth - 1, ')'); return a && ([ "type": "list", "list": a ]);
ee55471999-03-22Henrik Grubbström (Grubba)  } else { werror("get_simple_list(): Too deep recursion.\n");
53a9021998-10-14Niels Möller  return 0;
ee55471999-03-22Henrik Grubbström (Grubba)  }
53a9021998-10-14Niels Möller  } return get_atom_options(max_depth); } array do_parse_simple_list(int max_depth, int terminator) { array a = ({ });
ee55471999-03-22Henrik Grubbström (Grubba)  werror(sprintf("do_parse_simple_list(%d, '%c')\n", max_depth, terminator));
53a9021998-10-14Niels Möller 
c270a81999-03-22Henrik Grubbström (Grubba)  buffer = buffer[1..];
53a9021998-10-14Niels Möller  while(1) { skip_whitespace(); if (!strlen(buffer)) return 0; if (buffer[0] == terminator) { buffer = buffer[1..]; return a; }
c270a81999-03-22Henrik Grubbström (Grubba)  a += ({ get_atom(max_depth-1) });
3142621999-03-22Henrik Grubbström (Grubba)  mapping m = get_simple_list(max_depth); if (!m) {
c270a81999-03-22Henrik Grubbström (Grubba)  werror(sprintf("get_simple_list(%d) failed\n", max_depth)); } else { a->list = m;
3142621999-03-22Henrik Grubbström (Grubba)  }
53a9021998-10-14Niels Möller  } } /* Reads an atom, optionally followd by a list enclosed in square
d5cd421999-02-13Henrik Grubbström (Grubba)  * brackets. Naturally, the atom itself cannot contain any brackets. * * Returns a mapping * type : "atom", * atom : name, * raw : name[options] * options : parsed options, * range : ({ start, size }) */
53a9021998-10-14Niels Möller mapping get_atom_options(int max_depth) { string atom = get_atom(1); if (!atom) return 0; mapping res = ([ "type" : "atom", "atom" : atom ]); if (!strlen(buffer) || (buffer[0] != '[')) { res->raw = atom; return res; } /* Parse options */ string option_start = buffer; array options = do_parse_simple_list(max_depth - 1, ']');
8eb8d61999-03-22Henrik Grubbström (Grubba) 
a1b1301999-03-22Henrik Grubbström (Grubba)  if (!options) {
ee55471999-03-22Henrik Grubbström (Grubba)  werror("get_atom_options(): No options.\n");
21eae21999-03-22Henrik Grubbström (Grubba)  res->raw = atom + "[]";
a1b1301999-03-22Henrik Grubbström (Grubba)  res->options = ({ ([ "type":"atom", "atom":"" ]) }); return res; }
53a9021998-10-14Niels Möller  res->options = options;
21eae21999-03-22Henrik Grubbström (Grubba)  res->raw = atom + "[" + option_start[..sizeof(option_start) - sizeof(buffer) - 1];
8eb8d61999-03-22Henrik Grubbström (Grubba) 
53a9021998-10-14Niels Möller  if (!strlen(buffer) || (buffer[0] != '<')) return res; /* Parse <start.size> suffix */ buffer = buffer[1..]; int start = get_number(); if ((start < 0) || !strlen(buffer) || (buffer[0] != '.')) return 0; buffer = buffer[1..]; int size = get_number(); if ((size < 0) || !strlen(buffer) || (buffer[0] != '>')) return 0; buffer = buffer[1..]; res->range = ({ start, size }); return res; }