chiark / gitweb /
mask-map amend implemented, but untested
[chiark-tcl.git] / maskmap / maskmap.c
index 1f122e9f114e53a85749cde15a7227a3774f0fc4..77c677fba4314558887ae45ebbe9c06b3c8f2efc 100644 (file)
@@ -97,22 +97,72 @@ 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;
+  
+  newentries= TREALLOC(mm->entries, sizeof(*newentries)*len);
+  assert(!len || newentries);
+  
+  for (i=mm->allocd, clear=&mm->entries[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) {
+                    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);
+  if (findend > insertat)
+    memmove(&mm->entries[insertat+1],
+           &mm->entries[insertat],
+           sizeof(mm->entries[0]) * (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,
@@ -153,7 +203,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;
        i<dm->allocd;
        i++, sme++, dme++) {
@@ -199,11 +250,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<len; i++) {
     rc= Tcl_ListObjIndex(ip,o,i,&eo);  if (rc) goto x_rc;