Update for new keydata interface.
[catacomb-perl] / key.xs
diff --git a/key.xs b/key.xs
index d4162e9..db58921 100644 (file)
--- a/key.xs
+++ b/key.xs
 
 MODULE = Catacomb PACKAGE = Catacomb::Key PREFIX = key_
 
+SV *
+DESTROY(k)
+       Key *k
+       CODE:
+       keyfile_dec(k->kf);
+       DESTROY(k);
+       XSRETURN_YES;
+
 bool
 key_chkident(me, p)
        SV *me
@@ -61,7 +69,17 @@ Key_Data *
 data(k)
        Key *k
        CODE:
-       RETVAL = &k->k->k;
+       RETVAL = k->k->k;
+       key_incref(RETVAL);
+       OUTPUT:
+       RETVAL
+
+KeyErr
+setdata(k, kd)
+       Key *k
+       Key_Data *kd
+       CODE:
+       RETVAL = key_setkeydata(&k->kf->kf, k->k, kd);
        OUTPUT:
        RETVAL
 
@@ -102,20 +120,20 @@ key_setcomment(k, p)
        Key *k
        char *p
        C_ARGS:
-       k->kf, k->k, p
+       &k->kf->kf, k->k, p
 
 KeyErr
 key_settag(k, p)
        Key *k
        char *p
        C_ARGS:
-       k->kf, k->k, p
+       &k->kf->kf, k->k, p
 
 KeyErr
 key_delete(k)
        Key *k
        C_ARGS:
-       k->kf, k->k
+       &k->kf->kf, k->k
 
 SV *
 fulltag(k)
@@ -124,7 +142,7 @@ fulltag(k)
        dstr d = DSTR_INIT;
        CODE:
        key_fulltag(k->k, &d);
-       RETVAL = newSVpv(d.buf, d.len);
+       RETVAL = newSVpvn(d.buf, d.len);
        dstr_destroy(&d);
        OUTPUT:
        RETVAL
@@ -134,25 +152,35 @@ key_getattr(k, a)
        Key *k
        char *a
        C_ARGS:
-       k->kf, k->k, a
+       &k->kf->kf, k->k, a
 
 KeyErr
-key_putattr(k, a, v)
+putattr(k, a, v = &PL_sv_undef)
        Key *k
        char *a
-       char *v
-       C_ARGS:
-       k->kf, k->k, a, v
+       SV *v
+       PREINIT:
+       char *vv;
+       STRLEN len;
+       CODE:
+       if (!SvOK(v))
+         vv = 0;
+       else
+         vv = SvPV(v, len);
+       RETVAL = key_putattr(&k->kf->kf, k->k, a, vv);
+       OUTPUT:
+       RETVAL
 
-void
-attrlist(k)
+Key_AttrIter *
+attriter(k)
        Key *k
-       PREINIT:
-       key_attriter i;
-       const char *a, *v;
-       PPCODE:
-       for (key_mkattriter(&i, k->k); key_nextattr(&i, &a, &v); )
-         XPUSHs(sv_2mortal(newSVpv((char *)a, strlen(a))));
+       CODE:
+       RETVAL = CREATE(Key_AttrIter);
+       key_mkattriter(&RETVAL->i, k->k);
+       RETVAL->kf = k->kf;
+       k->kf->ref++;
+       OUTPUT:
+       RETVAL
 
 bool
 expiredp(k)
@@ -166,31 +194,22 @@ KeyErr
 key_expire(k)
        Key *k
        C_ARGS:
-       k->kf, k->k
+       &k->kf->kf, k->k
 
 KeyErr
 key_used(k, t)
        Key *k
        time_t t
        C_ARGS:
-       k->kf, k->k, t
+       &k->kf->kf, k->k, t
 
 bool
-fingerprint(k, h, kfiltstr)
+key_fingerprint(k, h, kf = 0)
        Key *k
        ghash *h
-       char *kfiltstr
-       PREINIT:
-       key_filter kfilt;
-       dstr d = DSTR_INIT;
-       CODE:
-       if (!kfiltstr)
-         kfilt.f = kfilt.m = 0;
-       else if (key_readflags(kfiltstr, 0, &kfilt.f, &kfilt.m))
-         croak("bad filter string `%s'", kfiltstr);
-       RETVAL = key_fingerprint(k->k, h, &kfilt);
-       OUTPUT:
-       RETVAL
+       Key_Filter *kf
+       C_ARGS:
+       k->k, h, kf
 
 const char *
 key_strerror(me, err)
@@ -199,72 +218,101 @@ key_strerror(me, err)
        C_ARGS:
        err
 
-MODULE = Catacomb PACKAGE = Catacomb::Key::Data PREFIX = key_
+MODULE = Catacomb PACKAGE = Catacomb::Key::AttrIter
 
-Key_Data *
-_new(me)
-       SV *me
-       CODE:
-       RETVAL = CREATE(key_data);
-       RETVAL->e = 0;
-       RETVAL->u.k.k = 0;
-       RETVAL->u.k.sz = 0;
-       OUTPUT:
-       RETVAL
+void
+next(i)
+       Key_AttrIter *i
+       PREINIT:
+       const char *a, *v;
+       PPCODE:
+       if (key_nextattr(&i->i, &a, &v)) {
+         XPUSHs(sv_2mortal(newSVpv(a, 0)));
+         if (GIMME_V == G_ARRAY)
+           XPUSHs(sv_2mortal(newSVpv(v, 0)));
+       }
 
 SV *
-destroy(kd)
-       Key_Data *kd
+DESTROY(i)
+       Key_AttrIter *i
        CODE:
-       key_destroy(kd);
+       keyfile_dec(i->kf);
+       DESTROY(i);
        XSRETURN_YES;
 
-SV *
-setbinary(kd, sv)
-       Key_Data *kd
-       SV *sv
+MODULE = Catacomb PACKAGE = Catacomb::Key::Filter
+
+Key_Filter *
+new(me, f = 0, m = 0)
+       SV *me
+       SV *f
+       SV *m
        PREINIT:
        char *p;
        STRLEN len;
        CODE:
-       p = SvPV(sv, len);
-       key_binary(kd, p, len);
-       XSRETURN_YES;
+       RETVAL = CREATE(Key_Filter);
+       if (!f || !SvOK(f))
+         RETVAL->f = RETVAL->m = 0;
+       else if (m) {
+         RETVAL->f = SvUV(f);
+         RETVAL->m = SvUV(m);
+       } else {
+         p = SvPV(f, len);
+         if (key_readflags(p, 0, &RETVAL->f, &RETVAL->m)) {
+           DESTROY(RETVAL);
+           RETVAL = 0;
+         }
+       }
+       OUTPUT:
+       RETVAL
 
 SV *
-setencrypted(kd, sv)
-       Key_Data *kd
-       SV *sv
-       PREINIT:
-       char *p;
-       STRLEN len;
+DESTROY(kf)
+       Key_Filter *kf
        CODE:
-       p = SvPV(sv, len);
-       key_encrypted(kd, p, len);
+       if (!kf)
+         XSRETURN_UNDEF;
+       DESTROY(kf);
        XSRETURN_YES;
 
 SV *
-setmp(kd, x)
-       Key_Data *kd
-       mp *x
+tostring(kf)
+       Key_Filter *kf
+       PREINIT:
+       dstr d = DSTR_INIT;
        CODE:
-       key_mp(kd, x);
-       XSRETURN_YES;
+       if (!kf)
+         XSRETURN_UNDEF;
+       key_writeflags(kf->f, &d);
+       RETVAL = newSVpvn(d.buf, d.len);
+       dstr_destroy(&d);
+       OUTPUT:
+       RETVAL
 
-SV *
-setstring(kd, p)
-       Key_Data *kd
-       char *p
+UV
+f(kf)
+       Key_Filter *kf
        CODE:
-       key_string(kd, p);
-       XSRETURN_YES;
+       RETVAL = kf ? kf->f : 0;
+       OUTPUT:
+       RETVAL
+
+UV
+m(kf)
+       Key_Filter *kf
+       CODE:
+       RETVAL = kf ? kf->m : 0;
+       OUTPUT:
+       RETVAL
+
+MODULE = Catacomb PACKAGE = Catacomb::Key::Data PREFIX = key_
 
 SV *
-setec(kd, p)
+DESTROY(kd)
        Key_Data *kd
-       EC_Point *p
        CODE:
-       key_ec(kd, p);
+       key_drop(kd);
        XSRETURN_YES;
 
 U32
@@ -275,251 +323,362 @@ flags(kd)
        OUTPUT: 
        RETVAL
 
+void
+readflags(me, p)
+       SV *me
+       char *p
+       PREINIT:
+       unsigned f, m;
+       PPCODE:
+       if (key_readflags(p, &p, &f, &m) || *p)
+         croak("bad flags string");
+       XPUSHs(sv_2mortal(newSVuv(m)));
+       XPUSHs(sv_2mortal(newSVuv(f)));
+
 SV *
-getbinary(kd)
-       Key_Data *kd
+getflags(me, f)
+       SV *me
+       U32 f
+       PREINIT:
+       dstr d = DSTR_INIT;
        CODE:
-       if ((kd->e & KF_ENCMASK) != KENC_BINARY)
-         croak("key is not binary");
-       RETVAL = newSVpv(kd->u.k.k, kd->u.k.sz);
+       key_writeflags(f, &d);
+       RETVAL = newSVpvn(d.buf, d.len);
+       dstr_destroy(&d);
        OUTPUT:
        RETVAL
 
 SV *
-getencrypted(kd)
+setflags(kd, f)
        Key_Data *kd
+       U32 f
        CODE:
-       if ((kd->e & KF_ENCMASK) != KENC_ENCRYPT)
-         croak("key is not encrypted");
-       RETVAL = newSVpv(kd->u.k.k, kd->u.k.sz);
-       OUTPUT:
-       RETVAL
+       kd->e = (kd->e & KF_ENCMASK) | (f & ~KF_ENCMASK);
+       XSRETURN_YES;
 
-mp *
-getmp(kd)
+void
+read(me, p)
+       SV *me
+       char *p
+       PREINIT:
+       key_data *kd;
+       char *pp;
+       PPCODE:
+       if ((kd = key_read(p, &pp)) != 0) {
+         XPUSHs(RET(kd, keydata_type(kd)));
+         if (GIMME_V == G_ARRAY)
+           XPUSHs(sv_2mortal(newSVpvn(pp, strlen(pp))));
+       }
+
+SV *
+write(kd, kf = 0)
        Key_Data *kd
+       Key_Filter *kf
+       PREINIT:
+       dstr d = DSTR_INIT;
        CODE:
-       if ((kd->e & KF_ENCMASK) != KENC_MP)
-         croak("key is not bignum");
-       RETVAL = kd->u.m;
+       if (key_write(kd, &d, kf))
+         RETVAL = newSVpvn(d.buf, d.len);
+       else
+         RETVAL = &PL_sv_undef;
+       dstr_destroy(&d);
        OUTPUT:
        RETVAL
 
-EC_Point *
-getec(kd)
-       Key_Data *kd
+Key_Data *
+decode(me, sv)
+       SV *me
+       SV *sv
+       PREINIT:
+       char *p;
+       STRLEN len;
        CODE:
-       if ((kd->e & KF_ENCMASK) != KENC_EC)
-         croak("key is not a curve point");
-       RETVAL = CREATE(ec);
-       EC_CREATE(RETVAL);
-       EC_COPY(RETVAL, &kd->u.e);
+       p = SvPV(sv, len);
+       RETVAL = key_decode(p, len);
        OUTPUT:
        RETVAL
 
-char *
-getstring(kd)
+SV *
+encode(kd, kf = 0)
        Key_Data *kd
+       Key_Filter *kf
+       PREINIT:
+       dstr d = DSTR_INIT;
        CODE:
-       if ((kd->e & KF_ENCMASK) != KENC_STRING)
-         croak("key is not string");
-       RETVAL = kd->u.p;
+       if (key_encode(kd, &d, kf))
+         RETVAL = newSVpvn(d.buf, d.len);
+       else
+         RETVAL = &PL_sv_undef;
+       dstr_destroy(&d);
        OUTPUT:
        RETVAL
 
-SV *
-setstruct(kd)
+Key_Data *
+lock(kd, key)
        Key_Data *kd
+       SV *key
+       PREINIT:
+       STRLEN len;
+       char *p;
        CODE:
-       key_structure(kd);
-       XSRETURN_YES;
+       p = SvPV(key, len);
+       key_lock(&RETVAL, kd, p, len);
+       OUTPUT:
+       RETVAL
 
 Key_Data *
-key_structfind(kd, tag)
+plock(kd, tag)
        Key_Data *kd
        char *tag
+       PREINIT:
+       int rc;
+       CODE:
+       if ((rc = key_plock(&RETVAL, kd, tag)) != 0) {
+         keyerr(rc);
+         RETVAL = 0;
+       }
+       OUTPUT:
+       RETVAL
 
-Key_Data *
-key_structcreate(kd, tag)
+bool
+key_match(kd, kf)
        Key_Data *kd
-       char *tag
+       Key_Filter *kf
 
-void
-getstruct(kd)
-       Key_Data *kd
+MODULE = Catacomb PACKAGE = Catacomb::Key::Data::Binary PREFIX = key_
+
+Key_Data *
+new(me, sv, f = 0)
+       SV *me
+       SV *sv
+       unsigned f
        PREINIT:
-       sym_iter i;
-       key_struct *ks;
-       PPCODE:
-       if ((kd->e & KF_ENCMASK) != KENC_STRUCT)
-         croak("key is not structured");
-       for (sym_mkiter(&i, &kd->u.s); ks = sym_next(&i); )
-         XPUSHs(RET(&ks->k, "Catacomb::Key::Data"));
+       char *p;
+       STRLEN len;
+       CODE:
+       p = SvPV(sv, len);
+       RETVAL = key_newbinary(f, p, len);
+       OUTPUT:
+       RETVAL
 
 SV *
-structdel(kd, tag)
+bin(kd)
        Key_Data *kd
-       char *tag
-       PREINIT:
-       key_struct *ks;
        CODE:
-       if ((kd->e & KF_ENCMASK) != KENC_STRUCT)
-         croak("key is not structured");
-       if ((ks = sym_find(&kd->u.s, tag, -1, 0, 0)) == 0)
-         XSRETURN_UNDEF;
-       sym_remove(&kd->u.s, ks);
-       XSRETURN_YES;
+       RETVAL = newSVpvn((char *)kd->u.k.k, kd->u.k.sz);
+       OUTPUT:
+       RETVAL
 
-void
-readflags(me, p)
+MODULE = Catacomb PACKAGE = Catacomb::Key::Data::Encrypted PREFIX = key_
+
+Key_Data *
+new(me, sv, f = 0)
        SV *me
-       char *p
+       SV *sv
+       unsigned f
        PREINIT:
-       unsigned f, m;
-       PPCODE:
-       if (key_readflags(p, &p, &f, &m) || *p)
-         croak("bad flags string");
-       XPUSHs(sv_2mortal(newSVuv(m)));
-       XPUSHs(sv_2mortal(newSVuv(f)));
+       char *p;
+       STRLEN len;
+       CODE:
+       p = SvPV(sv, len);
+       RETVAL = key_newencrypted(f, p, len);
+       OUTPUT:
+       RETVAL
 
 SV *
-getflags(me, f)
-       SV *me
-       U32 f
-       PREINIT:
-       dstr d = DSTR_INIT;
+ct(kd)
+       Key_Data *kd
        CODE:
-       key_writeflags(f, &d);
-       RETVAL = newSVpv(d.buf, d.len);
-       dstr_destroy(&d);
+       RETVAL = newSVpvn((char *)kd->u.k.k, kd->u.k.sz);
        OUTPUT:
        RETVAL
 
+SV *
+lock(kd, key)
+       Key_Data *kd
+       SV *key
+       CODE:
+       croak("already encrypted");
+
+SV *
+plock(kd, tag)
+       Key_Data *kd
+       char *tag
+       CODE:
+       croak("already encrypted");
+
 Key_Data *
-copy(kd, kfiltstr = 0)
+unlock(kd, key)
        Key_Data *kd
-       char *kfiltstr
+       SV *key
        PREINIT:
-       key_filter kfilt;
-       CODE:
-       if (!kfiltstr)
-         kfilt.f = kfilt.m = 0;
-       else if (key_readflags(kfiltstr, 0, &kfilt.f, &kfilt.m))
-         croak("bad filter string `%s'", kfiltstr);
-       RETVAL = CREATE(key_data);
-       if (!key_copy(RETVAL, kd, &kfilt)) {
-         DESTROY(RETVAL);
+       STRLEN len;
+       char *p;
+       int rc;
+       CODE:
+       p = SvPV(key, len);
+       if ((rc = key_unlock(&RETVAL, kd, p, len)) != 0) {
+         keyerr(rc);
          RETVAL = 0;
        }
        OUTPUT:
        RETVAL
 
 Key_Data *
-plock(kd, tag)
+punlock(kd, tag)
        Key_Data *kd
        char *tag
+       PREINIT:
+       int rc;
        CODE:
-       RETVAL = CREATE(Key_Data);
-       if (key_plock(tag, kd, RETVAL)) {
-         DESTROY(RETVAL);
+       if ((rc = key_punlock(&RETVAL, kd, tag)) != 0) {
+         keyerr(rc);
          RETVAL = 0;
        }
        OUTPUT:
        RETVAL
 
+MODULE = Catacomb PACKAGE = Catacomb::Key::Data::MP PREFIX = key_
+
 Key_Data *
-punlock(kd, tag)
+new(me, x, f = 0)
+       SV *me
+       mp *x
+       unsigned f
+       CODE:
+       RETVAL = key_newmp(f, x);
+       OUTPUT:
+       RETVAL
+
+mp *
+mp(kd)
        Key_Data *kd
-       char *tag
        CODE:
-       RETVAL = CREATE(Key_Data);
-       if (key_punlock(tag, kd, RETVAL)) {
-         DESTROY(RETVAL);
-         RETVAL = 0;
-       }
+       RETVAL = MP_COPY(kd->u.m);
        OUTPUT:
        RETVAL
 
+MODULE = Catacomb PACKAGE = Catacomb::Key::Data::EC PREFIX = key_
+
 Key_Data *
-read(me, p)
+new(me, p, f = 0)
        SV *me
-       char *p
+       ec *p
+       unsigned f
        CODE:
-       RETVAL = CREATE(key_data);
-       if (key_read(p, RETVAL, 0)) {
-         DESTROY(RETVAL);
-         RETVAL = 0;
-       }
+       RETVAL = key_newec(f, p);
        OUTPUT:
        RETVAL
 
-SV *
-write(kd, kfiltstr = 0)
+ec *
+ec(kd)
        Key_Data *kd
-       char *kfiltstr
-       PREINIT:
-       key_filter kfilt;
-       dstr d = DSTR_INIT;
        CODE:
-       if (!kfiltstr)
-         kfilt.f = kfilt.m = 0;
-       else if (key_readflags(kfiltstr, 0, &kfilt.f, &kfilt.m))
-         croak("bad filter string `%s'", kfiltstr);
-       if (key_write(kd, &d, &kfilt))
-         RETVAL = newSVpv(d.buf, d.len);
-       else
-         RETVAL = &PL_sv_undef;
-       dstr_destroy(&d);
+       RETVAL = CREATE(ec);
+       EC_CREATE(RETVAL);
+       EC_COPY(RETVAL, &kd->u.e);
        OUTPUT:
        RETVAL
 
+MODULE = Catacomb PACKAGE = Catacomb::Key::Data::String PREFIX = key_
+
 Key_Data *
-decode(me, sv)
+new(me, p, f = 0)
        SV *me
-       SV *sv
-       PREINIT:
-       char *p;
-       STRLEN len;
+       char *p
+       unsigned f
        CODE:
-       p = SvPV(sv, len);
-       RETVAL = CREATE(key_data);
-       if (key_decode(p, len, RETVAL)) {
-         DESTROY(RETVAL);
-         RETVAL = 0;
-       }
+       RETVAL = key_newstring(f, p);
+       OUTPUT:
+       RETVAL
+
+char *
+str(kd)
+       Key_Data *kd
+       CODE:
+       RETVAL = kd->u.p;
+       OUTPUT:
+       RETVAL
+
+MODULE = Catacomb PACKAGE = Catacomb::Key::Data::Structured PREFIX = key_
+
+Key_Data *
+new()
+       CODE:
+       RETVAL = key_newstruct();
+       OUTPUT:
+       RETVAL
+
+Key_StructIter *
+iterate(kd)
+       Key_Data *kd
+       CODE:
+       RETVAL = CREATE(Key_StructIter);
+       sym_mkiter(RETVAL, &kd->u.s);
+       OUTPUT:
+       RETVAL
+
+Key_Data *
+find(kd, tag)
+       Key_Data *kd
+       char *tag
+       CODE:
+       RETVAL = key_structfind(kd, tag);
+       if (RETVAL) key_incref(RETVAL);
        OUTPUT:
        RETVAL
 
 SV *
-encode(kd, kfiltstr = 0)
+del(kd, tag)
        Key_Data *kd
-       char *kfiltstr
+       char *tag
+       CODE:
+       key_structset(kd, tag, 0);
+       XSRETURN_YES;
+
+SV *
+set(kd, tag, kdnew = 0)
+       Key_Data *kd
+       char *tag
+       Key_Data *kdnew
+       CODE:
+       key_structset(kd, tag, kdnew);
+       XSRETURN_YES;
+       
+MODULE = Catacomb PACKAGE = Catacomb::Key::StructIter
+
+SV *
+next(i)
+       Key_StructIter *i
        PREINIT:
-       key_filter kfilt;
-       dstr d = DSTR_INIT;
+       key_struct *s;
        CODE:
-       if (!kfiltstr)
-         kfilt.f = kfilt.m = 0;
-       else if (key_readflags(kfiltstr, 0, &kfilt.f, &kfilt.m))
-         croak("bad filter string `%s'", kfiltstr);
-       if (key_encode(kd, &d, &kfilt))
-         RETVAL = newSVpv(d.buf, d.len);
-       else
-         RETVAL = &PL_sv_undef;
-       dstr_destroy(&d);
+       if ((s = sym_next(i)) == 0)
+         XSRETURN_UNDEF;
+       RETVAL = newSVpvn(SYM_NAME(s), SYM_LEN(s));
        OUTPUT:
        RETVAL
 
+SV *
+DESTROY(i)
+       Key_StructIter *i
+       CODE:
+       DESTROY(i);
+       XSRETURN_YES;
+
+MODULE = Catacomb PACKAGE = Catacomb::Key::Data
+
 MODULE = Catacomb PACKAGE = Catacomb::Key::File PREFIX = key_
 
 Key_File *
-new(me, file, how)
+new(me, file, how = KOPEN_READ, report = &PL_sv_undef)
        SV *me
        char *file
        unsigned how
+       SV *report
        CODE:
        RETVAL = CREATE(key_file);
-       if (key_open(RETVAL, file, how, warn_keyreporter, 0)) {
+       if (key_open(&RETVAL->kf, file, how, keyreport, report)) {
          DESTROY(RETVAL);
          RETVAL = 0;
        }
@@ -530,75 +689,80 @@ SV *
 DESTROY(kf)
        Key_File *kf
        CODE:
-       key_close(kf);
-       DESTROY(kf);
+       keyfile_dec(kf);
        XSRETURN_UNDEF;
 
 KeyErr
-merge(kf, name, fp)
+merge(kf, name, fp, report = &PL_sv_undef)
        Key_File *kf
        char *name
        FILE *fp
+       SV *report
        CODE:
-       RETVAL = key_merge(kf, name, fp, warn_keyreporter, 0);
+       RETVAL = key_merge(&kf->kf, name, fp, keyreport, report);
        OUTPUT:
        RETVAL
 
 bool
-extract(kf, k, fp, kfiltstr = 0)
+key_extract(kf, k, fp, kfilt = 0)
        Key_File *kf
        Key *k
        FILE *fp
-       char *kfiltstr
-       PREINIT:
-       key_filter kfilt;
-       CODE:
-       if (!kfiltstr)
-         kfilt.f = kfilt.m = 0;
-       else if (key_readflags(kfiltstr, 0, &kfilt.f, &kfilt.m))
-         croak("bad filter string `%s'", kfiltstr);
-       RETVAL = key_extract(kf, k->k, fp, &kfilt);
-       OUTPUT:
-       RETVAL
-
-int
-key_save(kf)
-       Key_File *kf
+       Key_Filter *kfilt
+       C_ARGS:
+       &kf->kf, k->k, fp, kfilt
 
 void
-qtag(kf, tag)
+qtag(kf, tag, kdnew = 0)
        Key_File *kf
        char *tag
+       Key_Data *kdnew
        PREINIT:
        dstr d = DSTR_INIT;
-       Key *k;
-       key_data *kd;
+       key_data **kd;
+       key_data *okd;
+       key *k;
+       Key *kk;
        PPCODE:
-       k = CREATE(Key);
-       kd = CREATE(key_data);
-       if (key_qtag(kf, tag, &d, &k->k, &kd)) {
-         DESTROY(k);
-         DESTROY(kd);
-         XPUSHs(&PL_sv_undef);
-         XPUSHs(&PL_sv_undef);
-         XPUSHs(&PL_sv_undef);
-       } else {
-         k->kf = kf;
-         XPUSHs(sv_2mortal(newSVpv(d.buf, d.len)));
-         XPUSHs(RET(k, "Catacomb::Key"));
-         XPUSHs(RET(k, "Catacomb::Key::Data"));
+       if (key_qtag(&kf->kf, tag, &d, &k, &kd)) {
+         keyerr(KERR_NOTFOUND);
+         XSRETURN_UNDEF;
        }
+       okd = *kd;
+       if (kdnew) {
+         if (!(kf->kf.f & KF_WRITE)) {
+           keyerr(KERR_READONLY);
+           XSRETURN_UNDEF;
+         }
+         kf->kf.f |= KF_MODIFIED;
+         *kd = kdnew;
+       }
+       key_incref(*kd);
+       kk = CREATE(Key);
+       kk->k = k;
+       kk->kf = kf;
+       kf->ref++;
+       XPUSHs(sv_2mortal(newSVpvn(d.buf, d.len)));
+       XPUSHs(RET(kk, "Catacomb::Key"));
+       XPUSHs(RET(okd, keydata_type(okd)));
        dstr_destroy(&d);
 
+int
+key_save(kf)
+       Key_File *kf
+       C_ARGS:
+       &kf->kf
+
 Key *
 bytype(kf, type)
        Key_File *kf
        char *type
        CODE:
        RETVAL = CREATE(Key);
-       if ((RETVAL->k = key_bytype(kf, type)) != 0)
+       if ((RETVAL->k = key_bytype(&kf->kf, type)) != 0) {
+         kf->ref++;
          RETVAL->kf = kf;
-       else {
+       else {
          DESTROY(RETVAL);
          RETVAL = 0;
        }
@@ -611,9 +775,10 @@ byid(kf, id)
        U32 id
        CODE:
        RETVAL = CREATE(Key);
-       if ((RETVAL->k = key_byid(kf, id)) != 0)
+       if ((RETVAL->k = key_byid(&kf->kf, id)) != 0) {
+         kf->ref++;
          RETVAL->kf = kf;
-       else {
+       else {
          DESTROY(RETVAL);
          RETVAL = 0;
        }
@@ -626,28 +791,71 @@ bytag(kf, tag)
        char *tag
        CODE:
        RETVAL = CREATE(Key);
-       if ((RETVAL->k = key_bytag(kf, tag)) != 0)
+       if ((RETVAL->k = key_bytag(&kf->kf, tag)) != 0) {
+         kf->ref++;
          RETVAL->kf = kf;
-       else {
+       else {
          DESTROY(RETVAL);
          RETVAL = 0;
        }
        OUTPUT:
        RETVAL
 
-void
-list(kf)
+Key *
+newkey(kf, id, type, exp = KEXP_FOREVER)
        Key_File *kf
+       U32 id
+       const char *type
+       time_t exp
        PREINIT:
-       key_iter i;
-       key *k;
-       Key *kk;
-       PPCODE:
-       for (key_mkiter(&i, kf); k = key_next(&i); ) {
-         kk = CREATE(Key);
-         kk->kf = kf;
-         kk->k = k;
-         XPUSHs(RET(kk, "Catacomb::Key"));
+       int err;
+       CODE:
+       RETVAL = CREATE(Key);
+       if ((err = key_new(&kf->kf, id, type, exp, &RETVAL->k)) == 0) {
+         DESTROY(RETVAL);
+         keyerr(err);
+         RETVAL = 0;
+       } else {
+         kf->ref++;
+         RETVAL->kf = kf;
        }
+       OUTPUT:
+       RETVAL
+
+Key_FileIter *
+iterate(kf)
+       Key_File *kf
+       CODE:
+       RETVAL = CREATE(Key_FileIter);
+       key_mkiter(&RETVAL->i, &kf->kf);
+       RETVAL->kf = kf;
+       kf->ref++;
+       OUTPUT: 
+       RETVAL
+
+MODULE = Catacomb PACKAGE = Catacomb::Key::FileIter
+
+Key *
+next(ki)
+       Key_FileIter *ki
+       CODE:
+       RETVAL = CREATE(Key);
+       if ((RETVAL->k = key_next(&ki->i)) == 0) {
+         DESTROY(RETVAL);
+         RETVAL = 0;
+       } else {
+         RETVAL->kf = ki->kf;
+         ki->kf->ref++;
+       }
+       OUTPUT:
+       RETVAL
+
+SV *
+DESTROY(ki)
+       Key_FileIter *ki
+       CODE:
+       keyfile_dec(ki->kf);
+       DESTROY(ki);
+       XSRETURN_YES;
 
 #----- That's all, folks ----------------------------------------------------