X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?a=blobdiff_plain;f=maskmap%2Fmaskmap.c;h=9c92810f0197c4a5d8aea6356ba72ba36e5bb2f5;hb=0bcca45f296b613b1f1449d232f43eb0ada0014b;hp=e0c7f90ee6aa1b44e27004449aba93a23755c176;hpb=ed0fcd1b27831486f2894edb2d0838e38657b4fb;p=chiark-tcl.git diff --git a/maskmap/maskmap.c b/maskmap/maskmap.c index e0c7f90..9c92810 100644 --- a/maskmap/maskmap.c +++ b/maskmap/maskmap.c @@ -26,6 +26,7 @@ static int prefix_bytes (int prefixlen) { /*---------- operations on MaskMap_Entry ----------*/ static void mme_init(MaskMap_Entry *mme) { + mme->prefixlen= -1; mme->prefix= 0; mme->data= 0; } @@ -36,21 +37,22 @@ static void mme_free(MaskMap_Entry *mme) { } static int mme_parsekey(Tcl_Interp *ip, MaskMap_Entry *mme, - Tcl_Obj *prefixo, Tcl_Obj *prefixleno, + Tcl_Obj *prefixo, Tcl_Obj *prefixbitso, 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 suppliedprefixbytes, prefixbits, wantprefixbytes, sparebits; + const Byte *data; int rc; 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; + rc= pat_int(ip,prefixbitso,&prefixbits); if (rc) goto x_rc; - wantprefixbytes= prefix_bytes(prefixlen); + wantprefixbytes= prefix_bytes(prefixbits); suppliedprefixbytes= hbytes_len(&prefix); if (suppliedprefixbytes < wantprefixbytes) { @@ -63,9 +65,17 @@ static int mme_parsekey(Tcl_Interp *ip, MaskMap_Entry *mme, "HBYTES MASKMAP SYNTAX OVERRUN"); goto x_rc; } - mme->prefixlen= prefixlen; + sparebits= wantprefixbytes*8 - prefixbits; + data= hbytes_data(&prefix); + if (sparebits && (data[wantprefixbytes-1] & ((1u << sparebits)-1))) { + rc= staticerr(ip, "mask-map entry PREFIX contains bits excluded" + " by PREFIX-LEN", "HBYTES MASKMAP SYNTAX EXCLBITS"); + goto x_rc; + } + + mme->prefixlen= prefixbits; mme->prefix= TALLOC(wantprefixbytes); assert(mme->prefix); - memcpy(mme->prefix, hbytes_data(&prefix), wantprefixbytes); + memcpy(mme->prefix, data, wantprefixbytes); return TCL_OK; x_rc: @@ -88,26 +98,82 @@ static int mm_count(const MaskMap_Value *mm) { return i; } -static void mm_allocentries(MaskMap_Value *mm, int len) { +static void mm_init(MaskMap_Value *mm) { + mm->allocd= 0; + mm->entries= 0; +} + +static void mm_reallocentries(MaskMap_Value *mm, int len) { int i; + MaskMap_Entry *newentries, *clear; + + assert(len >= mm->allocd); + if (!len) return; + + newentries= TREALLOC(mm->entries, sizeof(*newentries)*len); + assert(newentries); + + for (i=mm->allocd, clear=newentries+mm->allocd; + i < len; + i++, clear++) + mme_init(clear); + mm->allocd= len; - mm->entries= TALLOC(sizeof(*mm->entries) * len); - assert(mm->entries); - for (i=0; i < len; i++) - mme_init(&mm->entries[i]); + mm->entries= newentries; } /*---------- 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; /*fixme*/ + MaskMap_Var map, Tcl_Obj *prefix, + Tcl_Obj *preflen, Tcl_Obj *data) { + MaskMap_Value *mm= map.mm; + MaskMap_Entry mme, *search; + int rc, insertat, findend, cmp; + + mme_init(&mme); + + rc= mme_parsekey(ip,&mme,prefix,preflen,0); if (rc) goto x_rc; + + for (insertat=0, search=mm->entries; + insertat < mm->allocd && + search->prefixlen != -1; + insertat++, search++) { + cmp= mme_ordercompare(&mme,search); + if (!cmp) { + mme_free(&mme); + Tcl_DecrRefCount(search->data); + goto put_here; + } + if (cmp>0) + /* the new one sorts later, insert it here */ + break; + } + + /* we're adding an entry, make room for it */ + findend= mm_count(mm); + if (findend == mm->allocd) { + mm_reallocentries(mm, mm->allocd*2 + 1); + search= mm->entries + insertat; + } + if (findend > insertat) + memmove(search + 1, search, sizeof(*search) * (findend - insertat)); + *search= mme; + + put_here: + Tcl_IncrRefCount(data); + search->data= data; + return TCL_OK; + + x_rc: + mme_free(&mme); + return rc; } 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*/ } @@ -142,7 +208,8 @@ static void maskmap_t_dup(Tcl_Obj *sob, Tcl_Obj *dob) { objfreeir(dob); l= mm_count(sm); - mm_allocentries(dm,l); + mm_init(dm); + mm_reallocentries(dm,l); for (i=0, sme=sm->entries, dme=dm->entries; iallocd; i++, sme++, dme++) { @@ -188,11 +255,10 @@ static int maskmap_t_sfa(Tcl_Interp *ip, Tcl_Obj *o) { MaskMap_Value mm; Tcl_Obj *eo, *prefixo, *prefixleno; - mm.allocd= 0; - mm.entries= 0; + mm_init(&mm); rc= Tcl_ListObjLength(ip,o,&len); if (rc) goto x_rc; - mm_allocentries(&mm, len); + mm_reallocentries(&mm, len); for (i=0; i