]> git.ipfire.org Git - thirdparty/nettle.git/commitdiff
New files, implementing an sexp-parser.
authorNiels Möller <nisse@lysator.liu.se>
Sat, 28 Sep 2002 13:54:57 +0000 (15:54 +0200)
committerNiels Möller <nisse@lysator.liu.se>
Sat, 28 Sep 2002 13:54:57 +0000 (15:54 +0200)
Rev: src/nettle/sexp.c:1.1
Rev: src/nettle/sexp.h:1.1

sexp.c [new file with mode: 0644]
sexp.h [new file with mode: 0644]

diff --git a/sexp.c b/sexp.c
new file mode 100644 (file)
index 0000000..9869d13
--- /dev/null
+++ b/sexp.c
@@ -0,0 +1,228 @@
+/* sexp.c
+ *
+ * Parsing s-expressions.
+ */
+
+/* nettle, low-level cryptographics library
+ *
+ * Copyright (C) 2002 Niels Möller
+ *  
+ * The nettle library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ * 
+ * The nettle library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the nettle library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#include "sexp.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+void
+sexp_iterator_init(struct sexp_iterator *iterator,
+                  unsigned length, const uint8_t *input)
+{
+  iterator->length = length;
+  iterator->buffer = input;
+  iterator->pos = 0;
+  iterator->level = 0;
+  iterator->type = SEXP_START;
+  iterator->display_length = 0;
+  iterator->display = NULL;
+  iterator->atom_length = 0;
+  iterator->atom = NULL;
+
+  /* FIXME: For other than canonical syntax,
+   * skip white space here. */
+}
+
+#define EMPTY(i) ((i)->pos == (i)->length)
+#define NEXT(i) ((i)->buffer[(i)->pos++])
+
+static int
+sexp_iterator_simple(struct sexp_iterator *iterator,
+                    unsigned *size,
+                    const uint8_t **string)
+{
+  unsigned length = 0;
+  uint8_t c;
+  
+  if (EMPTY(iterator)) return 0;
+  c = NEXT(iterator);
+
+  if (c >= '1' && c <= '9')
+    do
+      {
+       length = length * 10 + (c - '0');
+
+       if (EMPTY(iterator)) return 0;
+       c = NEXT(iterator);
+      }
+    while (c < '0' || c > '9');
+
+  else if (c != '0')
+    return 0;
+
+  if (EMPTY(iterator) || NEXT(iterator) != ':')
+    return 0;
+
+  if (length > (iterator->length - iterator->pos))
+    return 0;
+
+  *size = length;
+  *string = iterator->buffer + iterator->pos;
+  iterator->pos += length;
+
+  return 1;
+}
+
+/* All these functions return 1 on success, 0 on failure */
+int
+sexp_iterator_next(struct sexp_iterator *iterator)
+{
+  if (iterator->type == SEXP_END)
+    return 1;
+  
+  if (EMPTY(iterator))
+    {
+      if (iterator->level)
+       return 0;
+      
+      iterator->type = SEXP_END;
+      return 1;
+    }
+  switch (iterator->buffer[iterator->pos])
+    {
+    case '(': /* A list */
+      if (iterator->type == SEXP_START)
+       iterator->type = SEXP_LIST;
+      else
+       return sexp_iterator_enter_list(iterator)
+         && sexp_iterator_exit_list(iterator);
+    case '[': /* Atom with display type */
+      iterator->pos++;
+      if (!sexp_iterator_simple(iterator,
+                               &iterator->display_length,
+                               &iterator->display))
+       return 0;
+      if (EMPTY(iterator) || NEXT(iterator) != ']')
+       return 0;
+
+      break;
+
+    default:
+      iterator->display_length = 0;
+      iterator->display = NULL;
+
+      break;
+    }
+
+  iterator->type = SEXP_ATOM;
+      
+  return sexp_iterator_simple(iterator,
+                             &iterator->atom_length,
+                             &iterator->atom);
+}
+
+/* Current element must be a list. */
+int
+sexp_iterator_enter_list(struct sexp_iterator *iterator)
+{
+  if (iterator->type != SEXP_LIST)
+    return 0;
+
+  if (EMPTY(iterator) || NEXT(iterator) != '(')
+    /* Internal error */
+    abort();
+
+  iterator->level++;
+  return 1;
+}
+
+/* Skips the rest of the current list */
+int
+sexp_iterator_exit_list(struct sexp_iterator *iterator)
+{
+  if (!iterator->level)
+    return 0;
+
+  while (sexp_iterator_next(iterator))
+    if (iterator->type == SEXP_END)
+      {
+       if (NEXT(iterator) != ')')
+         return 0;
+       iterator->level--;
+       return 1;
+      }
+  return 0;
+}
+
+int
+sexp_iterator_assoc(struct sexp_iterator *iterator,
+                   unsigned nkeys,
+                   const struct sexp_assoc_key *keys,
+                   struct sexp_iterator *values)
+{
+  if (!sexp_iterator_enter_list(iterator))
+    return 0;
+
+  for (;;)
+    {
+      if (!sexp_iterator_next(iterator))
+       return 0;
+
+      switch (iterator->type)
+       {
+       case SEXP_LIST:
+         
+         if (sexp_iterator_enter_list(iterator)
+             && sexp_iterator_next(iterator))
+           return 0;
+         
+         if (iterator->type == SEXP_ATOM
+             && !iterator->display)
+           {
+             /* Compare to the given keys */
+             unsigned i;
+             for (i = 0; i<nkeys; i++)
+               {
+                 if (keys[i].length == iterator->atom_length
+                     && !memcmp(keys[i].name, iterator->atom,
+                                keys[i].length))
+                   {
+                     /* Match found. NOTE: We allow multiple matches. */
+                     if (!sexp_iterator_next(iterator))
+                       return 0;
+
+                     /* Record this position. */
+                     values[i] = *iterator;
+
+                     break;
+                   }
+               }
+           }
+         if (!sexp_iterator_exit_list(iterator))
+           return 0;
+         break;
+       case SEXP_ATOM:
+         /* Just ignore */
+         break;
+         
+       case SEXP_END:
+         return sexp_iterator_exit_list(iterator);
+
+       default:
+         abort();
+       }
+    }
+}
diff --git a/sexp.h b/sexp.h
new file mode 100644 (file)
index 0000000..b751b0c
--- /dev/null
+++ b/sexp.h
@@ -0,0 +1,87 @@
+/* sexp.h
+ *
+ * Parsing s-expressions.
+ */
+
+/* nettle, low-level cryptographics library
+ *
+ * Copyright (C) 2002 Niels Möller
+ *  
+ * The nettle library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ * 
+ * The nettle library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the nettle library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+#ifndef NETTLE_SEXP_H_INCLUDED
+#define NETTLE_SEXP_H_INCLUDED
+
+#include <inttypes.h>
+
+enum sexp_type
+  { SEXP_START, SEXP_ATOM, SEXP_LIST, SEXP_END };
+
+struct sexp_iterator
+{
+  unsigned length;
+  const uint8_t *buffer;
+  unsigned pos;
+  unsigned level;
+
+  enum sexp_type type;
+  
+  unsigned display_length;
+  const uint8_t *display;
+
+  unsigned atom_length;
+  const uint8_t *atom;
+};
+
+struct sexp_assoc_key
+{
+  unsigned length;
+  const uint8_t *name;
+};
+
+/* Initializes the iterator. You have to call next to get to the first
+ * element. */
+void
+sexp_iterator_init(struct sexp_iterator *iterator,
+                  unsigned length, const uint8_t *input);
+
+/* All these functions return 1 on success, 0 on failure */
+int
+sexp_iterator_next(struct sexp_iterator *iterator);
+
+/* Current element must be a list. */
+int
+sexp_iterator_enter_list(struct sexp_iterator *iterator);
+
+/* Skips the rest of the current list */
+int
+sexp_iterator_exit_list(struct sexp_iterator *iterator);
+
+/* Current element must be a list. Looks up element of type
+ *
+ *   (key rest...)
+ *
+ * For a matching key, the corersponding iterator is initialized
+ * pointing at the start of REST.
+ */
+int
+sexp_iterator_assoc(struct sexp_iterator *iterator,
+                   unsigned nkeys,
+                   const struct sexp_assoc_key *keys,
+                   struct sexp_iterator *values);
+
+#endif /* NETTLE_SEXP_H_INCLUDED */