X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?a=blobdiff_plain;f=maskmap%2Fmaskmap.c;h=1ae8439b6a3c28acac50ee6e1f729968f7e6a659;hb=dbe2c107cd10f3e944187613b9b50f10304d0994;hp=99688015252641a884983c387dd33f8af8b7ba0c;hpb=20f8f9dd8dcdc4b5c68331c8015c18eaf1813360;p=chiark-tcl.git diff --git a/maskmap/maskmap.c b/maskmap/maskmap.c index 9968801..1ae8439 100644 --- a/maskmap/maskmap.c +++ b/maskmap/maskmap.c @@ -1,6 +1,8 @@ /* */ +#include + #include "tables.h" #include "hbytes.h" @@ -15,29 +17,224 @@ struct MaskMap_Value { MaskMap_Entry *entries; }; /* overlays internalRep */ -int pat_maskmapv(Tcl_Interp *ip, Tcl_Obj *var, MaskMap_Var *agg) { +/*---------- useful stuff ----------*/ + +static int prefix_bytes (int prefixlen) { + return (prefixlen + 7)/8; +} + +/*---------- operations on MaskMap_Entry ----------*/ + +static void mme_init(MaskMap_Entry *mme) { + mme->prefix= 0; + mme->data= 0; +} + +static void mme_free(MaskMap_Entry *mme) { + TFREE(mme->prefix); mme->prefix=0; + if (mme->data) { Tcl_DecrRefCount(mme->data); mme->data=0; } +} + +static int mme_parsekey(Tcl_Interp *ip, MaskMap_Entry *mme, + Tcl_Obj *prefixo, Tcl_Obj *prefixleno, + int inmap) { + /* *mme should be blank entry; after exit (even error exit) it will be valid + * - on errors, it will be blank. inmap is 1 if we're parsing an existing + * map or 0 if it's an entry to be added or modified. */ + HBytes_Value prefix; + int suppliedprefixbytes, prefixlen, wantprefixbytes; int rc; - rc= pat_somethingv(ip,var,&agg->sth,&maskmap_type); if (rc) return rc; - agg->mm= (void*)&agg->sth.obj->internalRep; + + hbytes_empty(&prefix); + + rc= pat_hb(ip,prefixo,&prefix); if (rc) goto x_rc; + rc= pat_int(ip,prefixleno,&prefixlen); if (rc) goto x_rc; + + wantprefixbytes= prefix_bytes(prefixlen); + suppliedprefixbytes= hbytes_len(&prefix); + + if (suppliedprefixbytes < wantprefixbytes) { + rc= staticerr(ip, "mask-map entry PREFIX too short for PREFIX-LEN", + "HBYTES MASKMAP SYNTAX UNDERRUN"); + goto x_rc; + } + if (inmap && suppliedprefixbytes > wantprefixbytes) { + rc= staticerr(ip, "mask-map existing entry PREFIX too long for PREFIX-LEN", + "HBYTES MASKMAP SYNTAX OVERRUN"); + goto x_rc; + } + mme->prefixlen= prefixlen; + mme->prefix= TALLOC(wantprefixbytes); assert(mme->prefix); + memcpy(mme->prefix, hbytes_data(&prefix), wantprefixbytes); return TCL_OK; + + x_rc: + mme_free(mme); + return rc; +} + +static int mme_ordercompare(MaskMap_Entry *a, MaskMap_Entry *b) { + if (a->prefixlen != b->prefixlen) + return a->prefixlen - b->prefixlen; + else + return memcmp(b->prefix, a->prefix, prefix_bytes(a->prefixlen)); +} + +/*---------- useful operations on MaskMap_Value etc. ----------*/ + +static int mm_count(const MaskMap_Value *mm) { + int i; + for (i=0; iallocd && mm->entries[i].prefixlen != -1; i++); + return i; +} + +static void mm_allocentries(MaskMap_Value *mm, int len) { + int i; + mm->allocd= len; + mm->entries= TALLOC(sizeof(*mm->entries) * len); + assert(mm->entries); + for (i=0; i < len; i++) + mme_init(&mm->entries[i]); } + +/*---------- substantial operations on mask maps ----------*/ int do_maskmap_amend(ClientData cd, Tcl_Interp *ip, MaskMap_Var map, HBytes_Value prefix, int preflen, Tcl_Obj *data) { - return TCL_OK; + return TCL_OK; /*fixme*/ } int do_maskmap_lookup(ClientData cd, Tcl_Interp *ip, - MaskMap_Var map, HBytes_Value addr, Tcl_Obj *def, + Tcl_Obj *mapo, HBytes_Value addr, Tcl_Obj *def, Tcl_Obj **result) { + /*MaskMap_Var *map= (void*)&mapo->internalRep;*/ + *result= Tcl_NewIntObj(42); + return TCL_OK; /*fixme*/ +} + +/*---------- Tcl type and arg parsing functions ----------*/ + +int pat_maskmapv(Tcl_Interp *ip, Tcl_Obj *var, MaskMap_Var *agg) { + int rc; + rc= pat_somethingv(ip,var,&agg->sth,&maskmap_type); if (rc) return rc; + agg->mm= (void*)&agg->sth.obj->internalRep; return TCL_OK; } -static void maskmap_t_free(Tcl_Obj *o) { } -static void maskmap_t_dup(Tcl_Obj *src, Tcl_Obj *dup) { } -static void maskmap_t_ustr(Tcl_Obj *o) { } -static int maskmap_t_sfa(Tcl_Interp *ip, Tcl_Obj *o) { return TCL_ERROR; } +static void maskmap_t_free(Tcl_Obj *o) { + MaskMap_Value *mm= (void*)&o->internalRep; + MaskMap_Entry *mme; + int i; + + for (i=0, mme=mm->entries; iallocd; i++, mme++) { + if (mme->prefixlen==-1) break; + mme_free(mme); + } +} + +static void maskmap_t_dup(Tcl_Obj *sob, Tcl_Obj *dob) { + MaskMap_Value *sm= (void*)&sob->internalRep; + MaskMap_Value *dm= (void*)&dob->internalRep; + MaskMap_Entry *sme, *dme; + int l, i, nbytes; + + assert(sob->typePtr == &maskmap_type); + objfreeir(dob); + l= mm_count(sm); + + mm_allocentries(dm,l); + for (i=0, sme=sm->entries, dme=dm->entries; + iallocd; + i++, sme++, dme++) { + *dme= *sme; + nbytes= prefix_bytes(sme->prefixlen); + dme->prefix= TALLOC(nbytes); assert(dme->prefix); + memcpy(dme->prefix, sme->prefix, nbytes); + Tcl_IncrRefCount(dme->data); + } + dob->typePtr= &maskmap_type; +} + +static void maskmap_t_ustr(Tcl_Obj *so) { + MaskMap_Value *sm= (void*)&so->internalRep; + Tcl_Obj **mainlobjsl, *mainobj; + int i, l; + + assert(so->typePtr == &maskmap_type); + l= mm_count(sm); + mainlobjsl= TALLOC(sizeof(*mainlobjsl) * l); assert(mainlobjsl); + + for (i=0; ientries[i]; + HBytes_Value hb; + Tcl_Obj *subl[3], *sublo; + + hbytes_array(&hb, sme->prefix, prefix_bytes(sme->prefixlen)); + subl[0]= ret_hb(0, hb); assert(subl[0]); + subl[1]= Tcl_NewIntObj(sme->prefixlen); assert(subl[1]); + subl[2]= sme->data; + + sublo= Tcl_NewListObj(3,subl); assert(sublo); + mainlobjsl[i]= sublo; + } + + mainobj= Tcl_NewListObj(l,mainlobjsl); assert(mainobj); + so->bytes= Tcl_GetStringFromObj(mainobj, &so->length); assert(so->bytes); + mainobj->bytes= 0; mainobj->length= 0; /* we stole it */ +} + +static int maskmap_t_sfa(Tcl_Interp *ip, Tcl_Obj *o) { + int rc, len, eol, i; + MaskMap_Value mm; + Tcl_Obj *eo, *prefixo, *prefixleno; + + mm.allocd= 0; + mm.entries= 0; + + rc= Tcl_ListObjLength(ip,o,&len); if (rc) goto x_rc; + mm_allocentries(&mm, len); + + for (i=0; i0) { + if (mme_ordercompare(&mm.entries[i-1], &mm.entries[i]) <= 0) { + rc= staticerr(ip, "mask-map entries out of order", + "HBYTES MASKMAP SYNTAX ORDER"); + goto x_rc; + } + } + } + + /* we commit now */ + assert(sizeof(mm) <= sizeof(o->internalRep)); + objfreeir(o); + memcpy(&o->internalRep, &mm, sizeof(mm)); + o->typePtr= &maskmap_type; + return TCL_OK; + +x_rc: + if (mm.entries) { + for (i=0; i