chiark / gitweb /
fix c violations detected by newer gcc - urgh
[chiark-tcl.git] / maskmap / maskmap.c
index 77c677fba4314558887ae45ebbe9c06b3c8f2efc..f51dba4b19cf587690b170174a9c933dd36b6150 100644 (file)
@@ -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;
 }
@@ -105,11 +106,14 @@ static void mm_init(MaskMap_Value *mm) {
 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(!len || newentries);
+  assert(newentries);
   
-  for (i=mm->allocd, clear=&mm->entries[mm->allocd];
+  for (i=mm->allocd, clear=newentries+mm->allocd;
        i < len;
        i++, clear++)
     mme_init(clear);
@@ -148,11 +152,12 @@ int do_maskmap_amend(ClientData cd, Tcl_Interp *ip,
 
   /* 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 == mm->allocd) {
+    mm_reallocentries(mm, mm->allocd*2 + 1);
+    search= mm->entries + insertat;
+  }
   if (findend > insertat)
-    memmove(&mm->entries[insertat+1],
-           &mm->entries[insertat],
-           sizeof(mm->entries[0]) * (findend - insertat));
+    memmove(search + 1, search, sizeof(*search) * (findend - insertat));
   *search= mme;
 
  put_here:
@@ -166,11 +171,45 @@ int do_maskmap_amend(ClientData cd, Tcl_Interp *ip,
 }
 
 int do_maskmap_lookup(ClientData cd, Tcl_Interp *ip,
-                     Tcl_Obj *mapo, HBytes_Value addr, Tcl_Obj *def,
+                     Tcl_Obj *mapo, HBytes_Value addrhb, Tcl_Obj *def,
                      Tcl_Obj **result) {
-  /*MaskMap_Var *map= (void*)&mapo->internalRep;*/
-  *result= Tcl_NewIntObj(42);
-  return TCL_OK; /*fixme*/
+  MaskMap_Value *mm= (void*)&mapo->internalRep;
+  MaskMap_Entry *search;
+  const Byte *addr= hbytes_data(&addrhb);
+  int addrbytes= hbytes_len(&addrhb);
+  int i, directbytes, leftoverbits;
+
+  search= mm->entries;
+  if (!search || search->prefixlen==-1) goto not_found;
+
+  /* longest masks are first, so we can test this once */
+  if (addrbytes < prefix_bytes(search->prefixlen))
+    return staticerr(ip, "address shorter than mask(s) in map",
+                    "HBYTES MASKMAP UNDERRUN");
+
+  for (i=0;
+       i < mm->allocd && search->prefixlen != -1;
+       i++, search++) {
+    directbytes= search->prefixlen / 8;
+    if (memcmp(search->prefix, addr, directbytes)) continue;
+
+    leftoverbits= search->prefixlen % 8;
+    if (leftoverbits)
+      if ((addr[directbytes] & (0xffu << leftoverbits))
+         != search->prefix[directbytes])
+       continue;
+
+    /*found*/
+    *result= search->data;
+    return TCL_OK;
+  }
+
+ not_found:
+  if (!def)
+    return staticerr(ip, "address not found in mask-map",
+                    "HBYTES MASKMAP NOMATCH");
+  *result= def;
+  return TCL_OK;
 }
 
 /*---------- Tcl type and arg parsing functions ----------*/