+/* -*-c-*-
+ *
+ * $Id: atom.c,v 1.1 2001/01/20 11:50:16 mdw Exp $
+ *
+ * Atom management
+ *
+ * (c) 2000 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of the mLib utilities library.
+ *
+ * mLib is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * mLib 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with mLib; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: atom.c,v $
+ * Revision 1.1 2001/01/20 11:50:16 mdw
+ * Implementation of atom tables (for example, as found in X11).
+ *
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <stdio.h>
+#include <string.h>
+
+#include "alloc.h"
+#include "atom.h"
+#include "hash.h"
+#include "sym.h"
+
+/*----- Static variables --------------------------------------------------*/
+
+static atom_table atoms;
+
+/*----- Handy macros ------------------------------------------------------*/
+
+#define ATOM_RESOLVE(t) do { \
+ if (t == ATOM_GLOBAL) \
+ t = &atoms; \
+ if (!t->t.t.v) \
+ atom_createtable(t); \
+} while (0)
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @atom_createtable@ --- *
+ *
+ * Arguments: @atom_table *t@ = pointer to an atom table
+ *
+ * Returns: ---
+ *
+ * Use: Initializes an atom table.
+ */
+
+void atom_createtable(atom_table *t)
+{
+ sym_create(&t->t);
+ t->g = 0;
+ t->gseq = 0;
+}
+
+/* --- @atom_destroytable@ --- *
+ *
+ * Arguments: @atom_table *t@ = pointer to an atom table
+ *
+ * Returns: ---
+ *
+ * Use: Destroys all of the atoms in an atom table. All of the atoms
+ * (including uninterned atoms) are freed. Any references to
+ * atoms from the table become invalid, and any association
+ * tables dependent on the atom table are unusable, except that
+ * they may be destroyed safely.
+ */
+
+void atom_destroytable(atom_table *t)
+{
+ atom *a, *aa;
+
+ ATOM_RESOLVE(t);
+ for (a = (atom *)t->g; a; a = aa) {
+ aa = (atom *)a->b.b.next;
+ x_free(t->t.t.a, a);
+ }
+ sym_destroy(&t->t);
+}
+
+/* --- @atom_intern@ --- *
+ *
+ * Arguments: @atom_table *t@ = pointer to an atom table
+ * @const char *p@ = pointer to the string to intern
+ *
+ * Returns: A pointer to the atom block for the given symbol string.
+ *
+ * Use: Interns an atom, returning the atom block. The string can be
+ * extracted from the atom by means of the @ATOM_NAME@ macro.
+ */
+
+atom *atom_intern(atom_table *t, const char *p)
+{
+ atom *a;
+ unsigned f;
+
+ ATOM_RESOLVE(t);
+ a = sym_find(&t->t, p, -1, sizeof(atom), &f);
+ if (!f)
+ a->f = 0;
+ return (a);
+}
+
+/* --- @atom_gensym@ --- *
+ *
+ * Arguments: @atom_table *t@ = pointer to a symbol table
+ *
+ * Returns: A pointer to a new atom block, not previously interned.
+ *
+ * Use: Creates a new, uninterned atom. This atom will never be
+ * returned by either @atom_intern@ or any other call to
+ * @atom_gensym@, while the symbol table exists.
+ */
+
+atom *atom_gensym(atom_table *t)
+{
+ atom *a;
+ char buf[64];
+ size_t sz;
+
+ ATOM_RESOLVE(t);
+ sprintf(buf, "*gen-%lu*", t->gseq++);
+ sz = strlen(buf) + 1;
+ a = x_alloc(t->t.t.a, sizeof(atom) + sz);
+ a->b.name = (char *)(a + 1);
+ memcpy(a->b.name, buf, sz);
+ a->b.len = sz;
+ CRC32(a->b.b.hash, 0, buf, sz);
+ a->f = ATOMF_GENSYM;
+ a->b.b.next = t->g;
+ t->g = &a->b.b;
+ return (a);
+}
+
+/* --- @atom_name@ --- *
+ *
+ * Arguments: @atom *a@ = pointer to an atom
+ *
+ * Returns: The atom's textual name.
+ *
+ * Use: Given an atom, returns the name with which it was interned
+ * (or a made-up name if it was created using @gensym@.
+ */
+
+const char *atom_name(const atom *a) { return ATOM_NAME(a); }
+
+/* --- @atom_len@ --- *
+ *
+ * Arguments: @atom *a@ = pointer to an atom
+ *
+ * Returns: The atom string's length.
+ *
+ * Use: Given an atom, return the length of its textual
+ * representation.
+ */
+
+size_t atom_len(const atom *a) { return ATOM_LEN(a); }
+
+/* --- @atom_hash@ --- *
+ *
+ * Arguments: @atom *a@ = pointer to an atom
+ *
+ * Returns: The atom's hash.
+ *
+ * Use: Given an atom, returns its hash.
+ */
+
+uint32 atom_hash(const atom *a) { return ATOM_HASH(a); }
+
+/* --- @atom_mkiter@ , @atom_next@ --- *
+ *
+ * Arguments: @atom_table *t@ = pointer to an atom table
+ * @atom_iter *i@ = pointer to an iterator structure
+ *
+ * Returns: Next atom, for @atom_next@; nothing for @atom_mkiter@.
+ *
+ * Use: Iterates over atoms (both interned and uninterned).
+ */
+
+void atom_mkiter(atom_iter *i, atom_table *t)
+{
+ ATOM_RESOLVE(t);
+ i->i.i.t = &t->t.t;
+ i->i.i.p = t->g;
+ i->i.i.i = 0;
+}
+
+atom *atom_next(atom_iter *i)
+{
+ atom *a;
+ SYM_NEXT(&i->i, a);
+ return (a);
+}
+
+/*----- That's all, folks -------------------------------------------------*/