--- /dev/null
+/* -*-c-*-
+ *
+ * $Id: key-fetch.c,v 1.1 2000/06/17 10:42:54 mdw Exp $
+ *
+ * Higher-level key unpacking
+ *
+ * (c) 2000 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb 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.
+ *
+ * Catacomb 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 Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: key-fetch.c,v $
+ * Revision 1.1 2000/06/17 10:42:54 mdw
+ * Convenient table-driven extraction of structured keys.
+ *
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <mLib/dstr.h>
+
+#include "key.h"
+#include "key-data.h"
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @key_fetchinit@ --- *
+ *
+ * Arguments: @const key_fetchdef *kf@ = pointer to base definition
+ * @key_packstruct *kps@ = pointer to destination packing def
+ * @void *p@ = pointer to destination block
+ *
+ * Returns: Pointer to packing definition.
+ *
+ * Use: Initializes a packing definition (@key_packdef@ structure).
+ * If @kps@ is null on entry, an appropriately sized block is
+ * allocated automatically. Otherwise it must be large enough.
+ */
+
+static size_t kfcount(const key_fetchdef *kf)
+{
+ size_t n = 1;
+ while (kf->name) {
+ n++;
+ if (kf->kf)
+ n += kfcount(kf->kf);
+ kf++;
+ }
+ return (n);
+}
+
+key_packdef *key_fetchinit(const key_fetchdef *kf,
+ key_packstruct *kp, void *p)
+{
+ size_t n = 1 + kfcount(kf);
+ key_packdef *kpd;
+ key_packstruct *kps;
+ char *cp = p;
+
+ /* --- If @kps@ is null, count the entries and allocate --- */
+
+ if (kp)
+ kp->name = 0;
+ else {
+ kp = xmalloc(n * sizeof(*kp));
+ kp->name = (char *)kp;
+ }
+
+ /* --- Fill in the top part --- */
+
+ kp->kp.kd.e = KENC_STRUCT;
+ kp->kp.p = &kp[1];
+ kpd = &kp->kp;
+
+ /* --- Initialize for the main loop --- */
+
+ kps = kp + n;
+ n = 0;
+ kp++;
+
+ /* --- Iterate over the entries in the table --- *
+ *
+ * The end of the target block is used as a stack to record where
+ * substructure is meant to occur. The integer @n@ is the depth of the
+ * stack; @kps@ is a full descending stack pointer. The @kp.p@ member of a
+ * stack element points back to an entry with substructure, the @kp.p@
+ * member of which refers to the @kf@ table for the substructure.
+ *
+ * This should all be about as clear as mud.
+ */
+
+ for (;;) {
+
+ /* --- Blat out a level's worth --- */
+
+ while (kf->name) {
+ kp->name = kf->name;
+ kp->kp.kd.e = kf->e;
+ if ((kf->e & KF_ENCMASK) != KENC_STRUCT)
+ kp->kp.p = cp + kf->off;
+ else {
+ (--kps)->kp.p = kp;
+ kp->kp.p = (void *)kf->kf;
+ n++;
+ }
+ kf++;
+ kp++;
+ }
+ (kp++)->name = 0;
+ if (!n)
+ break;
+
+ /* --- Pop an entry from the stack --- */
+
+ {
+ key_packstruct *kkp = (kps++)->kp.p;
+ kf = kkp->kp.p;
+ kkp->kp.p = kp;
+ n--;
+ }
+ }
+
+ /* --- We're done --- */
+
+ return (kpd);
+}
+
+/* --- @key_fetch@ --- *
+ *
+ * Arguments: @key_packdef *kp@ = pointer to packing structure
+ * @key *k@ = key file containing desired key
+ *
+ * Returns: Error code, or zero.
+ *
+ * Use: Fetches an unpacked key from a packed one.
+ */
+
+int key_fetch(key_packdef *kp, key *k)
+{
+ dstr d = DSTR_INIT;
+ int e;
+
+ key_fulltag(k, &d);
+ e = key_unpack(kp, &k->k, &d);
+ dstr_destroy(&d);
+ return (e);
+}
+
+/* --- @key_fetchbyname@ --- *
+ *
+ * Arguments: @key_packdef *kp@ = pointer to packing structure
+ * @key_file *kf@ = key file containing desired key
+ * @const char *tag@ = user's tag describing the key
+ *
+ * Returns: Error code, or zero.
+ *
+ * Use: Fetches a named key from a key file and unpacks it
+ * conveniently.
+ */
+
+int key_fetchbyname(key_packdef *kp, key_file *kf, const char *tag)
+{
+ dstr d = DSTR_INIT;
+ key_data *kd;
+ int e;
+
+ if (key_qtag(kf, tag, &d, 0, &kd))
+ e = KERR_NOTFOUND;
+ else
+ e = key_unpack(kp, kd, &d);
+ dstr_destroy(&d);
+ return (e);
+}
+
+/* --- @key_fetchdone@ --- *
+ *
+ * Arguments: @key_packdef *kp@ = pointer to packing structure
+ *
+ * Returns: ---
+ *
+ * Use: Frees a packing structure. If the structure was allocated by
+ * @key_fetchinit@ then it is freed.
+ */
+
+void key_fetchdone(key_packdef *kp)
+{
+ key_packstruct *kps = (key_packstruct *)(((char *)kp) -
+ offsetof(key_packstruct, kp));
+ key_unpackdone(kp);
+ if (kps->name)
+ free(kps);
+}
+
+/*----- That's all, folks -------------------------------------------------*/