chiark / gitweb /
Lots of stuff seems to work
authorian <ian>
Sun, 1 Sep 2002 20:35:54 +0000 (20:35 +0000)
committerian <ian>
Sun, 1 Sep 2002 20:35:54 +0000 (20:35 +0000)
base/chiark-tcl.h
base/hook.c [new file with mode: 0644]
base/parse.c
base/tables-examples.tct
base/tcmdifgen
base/troglodyte-Makefile
hbytes/chop.c
hbytes/hbytes.c
hbytes/hbytes.h
hbytes/hook.c [new file with mode: 0644]
hbytes/parse.c

index 83469d5..ee69928 100644 (file)
@@ -34,18 +34,64 @@ typedef unsigned char Byte;
 
 /* from hbytes.c */
 
+/* Internal representation details: */
+#define HBYTES_ISEMPTY(hb)    (!(hb)->begin_complex && !(hb)->end_0)
+#define HBYTES_ISSENTINEL(hb) (!(hb)->begin_complex && (hb)->end_0)
+#define HBYTES_ISSIMPLE(hb)   ((hb)->begin_complex && (hb)->end_0)
+#define HBYTES_ISCOMPLEX(hb)  ((hb)->begin_complex && !(hb)->end_0)
+
 typedef struct {
-  Byte *start, *end; /* always allocated dynamically */
+  void *begin_complex, *end_0;
 } HBytes_Value; /* overlays internalRep */
 
+typedef struct {
+  Byte *dstart; /* always allocated dynamically */
+  int prespace, len, avail;
+  /*        
+   * | SPARE      | USED  | SPARE |
+   * |<-prespace->|<-len->|       |
+   * |            |<----avail---->|
+   *              ^start
+   */
+} HBytes_ComplexValue; /* pointed to from internalRep.otherValuePtr */
+
+/* Public interfaces: */
+
 extern Tcl_ObjType hbytes_type;
 
+int hbytes_len(const HBytes_Value *v);
+Byte *hbytes_data(const HBytes_Value *v); /* caller may then modify data! */
+int hbytes_issentinel(const HBytes_Value *v);
+
+Byte *hbytes_prepend(HBytes_Value *upd, int el);
+Byte *hbytes_append(HBytes_Value *upd, int el);
+  /* return value is where to put the data */
+
+const Byte *hbytes_unprepend(HBytes_Value *upd, int rl);
+const Byte *hbytes_unappend(HBytes_Value *upd, int rl);
+  /* return value points to the removed data, which remains valid
+   * until next op on the HBytes_Value.  If original value is
+   * shorter than rl or negative, returns 0 and does nothing. */
+
+void hbytes_empty(HBytes_Value *returns);
+void hbytes_sentinel(HBytes_Value *returns);
+void hbytes_array(HBytes_Value *returns, const Byte *array, int l);
+Byte *hbytes_arrayspace(HBytes_Value *returns, int l);
+void hbytes_free(HBytes_Value *frees);
+  /* _empty, _sentinel and _array do not free or read the old value;
+   * _free it first if needed.  _free leaves it garbage, so you
+   * have to call _empty to reuse it.  _arrayspace doesn't fill
+   * the array; you get a pointer and must fill it with data
+   * yourself. */
+
+/* The value made by hbytes_sentinel should not be passed to
+ * anything except HBYTES_IS..., and hbytes_free. */
+
+/* from hook.c */
+
 int staticerr(Tcl_Interp *ip, const char *m);
 void objfreeir(Tcl_Obj *o);
 
-void hbytes_set(HBytes_Value *upd, const Byte *array, int l);
-Tcl_Obj *hbytes_set_obj(Tcl_Obj *overwrite, const Byte *array, int l);
-
 /* from parse.c */
 
 typedef struct {
@@ -55,6 +101,8 @@ typedef struct {
 
 void fini_hbv(Tcl_Interp *ip, int rc, HBytes_Var *agg);
 
+/* from chop.c */
+
 /* from enum.c */
 
 extern Tcl_ObjType enum_nearlytype;
@@ -94,8 +142,7 @@ typedef struct {
 
 /* useful macros */
 
-#define HBYTES(o) (*(HBytes_Value*)&(o)->internalRep.twoPtrValue)
-#define HBYTES_LEN(hb) ((hb).end - (hb).start)
+#define OBJ_HBYTES(o) ((HBytes_Value*)&(o)->internalRep.twoPtrValue)
 
 #define TALLOC(s) ((void*)Tcl_Alloc((s)))
 #define TFREE(f) (Tcl_Free((void*)(f)))
diff --git a/base/hook.c b/base/hook.c
new file mode 100644 (file)
index 0000000..08e055d
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ */
+
+#include "hbytes.h"
+#include "tables.h"
+
+int staticerr(Tcl_Interp *ip, const char *m) {
+  Tcl_SetResult(ip, (char*)m, TCL_STATIC);
+  return TCL_ERROR;
+}
+
+void objfreeir(Tcl_Obj *o) {
+  if (o->typePtr && o->typePtr->freeIntRepProc)
+    o->typePtr->freeIntRepProc(o);
+  o->typePtr= 0;
+}  
+
+int do_hbytes_rep_info(ClientData cd, Tcl_Interp *ip,
+                      HBytes_Value v, Tcl_Obj **result) {
+  const char *tn;
+  int nums[3], i;
+  Tcl_Obj *objl[4];
+
+  memset(nums,0,sizeof(nums));
+  nums[1]= hbytes_len(&v);
+  
+  if (HBYTES_ISEMPTY(&v)) tn= "empty";
+  else if (HBYTES_ISSENTINEL(&v)) tn= "sentinel!";
+  else if (HBYTES_ISSIMPLE(&v)) tn= "simple";
+  else {
+    HBytes_ComplexValue *cx= v.begin_complex;
+    tn= "complex";
+    nums[0]= cx->prespace;
+    nums[2]= cx->avail - cx->len;
+  }
+    
+  objl[0]= Tcl_NewStringObj((char*)tn,-1);
+  for (i=0; i<3; i++) objl[i+1]= Tcl_NewIntObj(nums[i]);
+  *result= Tcl_NewListObj(4,objl);
+  return TCL_OK;
+}
+
+static void hbytes_t_dup(Tcl_Obj *src, Tcl_Obj *dup) {
+  objfreeir(dup);
+  hbytes_array(OBJ_HBYTES(dup),
+              hbytes_data(OBJ_HBYTES(src)),
+              hbytes_len(OBJ_HBYTES(src)));
+}
+
+static void hbytes_t_free(Tcl_Obj *o) {
+  hbytes_free(OBJ_HBYTES(o));
+}
+
+static void hbytes_t_ustr(Tcl_Obj *o) {
+  int l;
+  char *str;
+  const Byte *byte;
+
+  byte= hbytes_data(OBJ_HBYTES(o));
+  l= hbytes_len(OBJ_HBYTES(o));
+  str= o->bytes= TALLOC(l*2+1);
+  o->length= l*2;
+  while (l>0) {
+    sprintf(str,"%02x",*byte);
+    str+=2; byte++; l--;
+  }
+  *str= 0;
+}
+
+static int hbytes_t_sfa(Tcl_Interp *ip, Tcl_Obj *o) {
+  char *str, *ep, *os;
+  Byte *startbytes, *bytes;
+  int l;
+  char cbuf[3];
+
+  os= str= Tcl_GetStringFromObj(o,&l);  assert(str);
+  objfreeir(o);
+
+  if (l & 1) return staticerr(ip, "hbytes: conversion from hex:"
+                             " odd length in hex");
+
+  startbytes= bytes= hbytes_arrayspace(OBJ_HBYTES(o), l/2);
+
+  cbuf[2]= 0;
+  while (l>0) {
+    cbuf[0]= *str++;
+    cbuf[1]= *str++;
+    *bytes++= strtoul(cbuf,&ep,16);
+    if (ep != cbuf+2) {
+      hbytes_free(OBJ_HBYTES(o));
+      return staticerr(ip, "hbytes: conversion from hex:"
+                      " bad hex digit");
+    }
+    l -= 2;
+  }
+
+  o->typePtr = &hbytes_type;
+  return TCL_OK;
+}
+
+Tcl_ObjType hbytes_type = {
+  "hbytes",
+  hbytes_t_free, hbytes_t_dup, hbytes_t_ustr, hbytes_t_sfa
+};
+
+int do_hbytes_raw2h(ClientData cd, Tcl_Interp *ip,
+                   Tcl_Obj *binary, HBytes_Value *result) {
+  const char *str;
+  int l;
+
+  str= Tcl_GetStringFromObj(binary,&l);
+  hbytes_array(result, str, l);
+  return TCL_OK;
+}
+
+int do_hbytes_h2raw(ClientData cd, Tcl_Interp *ip,
+                   HBytes_Value hex, Tcl_Obj **result) {
+  *result= Tcl_NewStringObj(hbytes_data(&hex), hbytes_len(&hex));
+  return TCL_OK;
+}
+
+#if 0
+HC_DEFINE(pkcs5) {
+  static const PadKindInfo padkindinfos[0]= {
+    { "pa", 1, 1 },
+    { "pn", 1, 0 },
+    { "ua", 0, 1 },
+    { "un", 0, 0 },
+    { 0 }
+  };
+
+  HC_DECLS_HBV;
+  Tcl_Obj *v;
+  int blocksize;
+  const PadKindInfo *pk;
+  const BlockCipherInfo *bc;
+
+  HC_ARG_ENUM(pk, padkindinfos);
+  HC_ARG_HBV;
+  if (!pk->algname) HC_ARG_INTRANGE(blocksize, 1,255);
+  else { HC_ARG_ENUM(bc, blockciphers); blocksize= bc->blocksize; }
+  HC_ARGS_E;
+
+  /* do nothing :-) */
+
+  HC_FINI_HBV;
+}
+#endif
+
+int do__hbytes(ClientData cd, Tcl_Interp *ip,
+              const HBytes_SubCommand *subcmd,
+              int objc, Tcl_Obj *const *objv) {
+  return subcmd->func(0,ip,objc,objv);
+}
+
+int Hbytes_Init(Tcl_Interp *ip) {
+  Tcl_RegisterObjType(&hbytes_type);
+  Tcl_RegisterObjType(&enum_nearlytype);
+  Tcl_RegisterObjType(&enum1_nearlytype);
+  Tcl_CreateObjCommand(ip,"hbytes", pa__hbytes,0,0);
+  return TCL_OK;
+}
index 1e1e5bb..e5e3465 100644 (file)
@@ -42,7 +42,7 @@ int pat_hbv(Tcl_Interp *ip, Tcl_Obj *var, HBytes_Var *agg) {
   rc= Tcl_ConvertToType(ip,val,&hbytes_type);
   if (rc) return rc;
 
-  agg->hb= &HBYTES(val);
+  agg->hb= OBJ_HBYTES(val);
   return TCL_OK;
 }
 
@@ -62,12 +62,17 @@ void fini_hbv(Tcl_Interp *ip, int rc, HBytes_Var *agg) {
 int pat_hb(Tcl_Interp *ip, Tcl_Obj *obj, HBytes_Value *val) {
   int rc;
   rc= Tcl_ConvertToType(ip,obj,&hbytes_type);  if (rc) return rc;
-  *val= HBYTES(obj);
+  *val= *OBJ_HBYTES(obj);
   return TCL_OK;
 }
 
 Tcl_Obj *ret_hb(Tcl_Interp *ip, HBytes_Value val) {
-  return hbytes_set_obj(0, val.start, HBYTES_LEN(val));
+  Tcl_Obj *obj;
+  obj= Tcl_NewObj();
+  Tcl_InvalidateStringRep(obj);
+  *OBJ_HBYTES(obj)= val;
+  obj->typePtr= &hbytes_type;
+  return obj;
 }
 
 Tcl_Obj *ret_obj(Tcl_Interp *ip, Tcl_Obj *val) {
index 2c6711a..ecb5d7c 100644 (file)
@@ -1,5 +1,5 @@
 Type hb:                       HBytes_Value @
-Init hb                                @.start=0; @.end=0;
+Init hb                                hbytes_sentinel(&@);
 Type hbv:                      HBytes_Var @
 Init hbv                       @.hb=0; @.obj=0; @.var=0;
 Fini hbv                       fini_hbv(ip, rc, &@);
@@ -24,21 +24,24 @@ Table hbytes HBytes_SubCommand
        append
                v       hbv
                str     ...
+       rep-info
+               v       hb
+               =>      obj
        concat
                str     ...
                =>      hb
-#      unprepend
-#              v       hbv
-#              length  int
-#              =>      hb
-#      unappend
-#              v       hbv
-#              length  int
-#              =>      hb
-#      chopto
-#              v       hbv
-#              length  int
-#              =>      hb
+       unprepend
+               v       hbv
+               length  int
+               =>      hb
+       unappend
+               v       hbv
+               length  int
+               =>      hb
+       chopto
+               v       hbv
+               length  int
+               =>      hb
 #      pkcs5
 #              meth    enum(PadMethod, "hbytes pad subcommand")
 #              obj     ...
index 21833c1..514dc01 100755 (executable)
@@ -63,9 +63,9 @@ sub parse ($$) {
        } elsif (@i>=1 && defined $c_entryextra) {
            $entrytype_x{$c_entryextra} .= "  $_\n";
        } elsif (@i==1 && m/^[a-z].*$/ && defined $c_table) {
-           if (m/^\w+$/) {
+           if (m/^[-_0-9A-Za-z]+$/) {
                $c_entry= $_;
-           } elsif (m/^(\w+)\s+(\S.*)$/) {
+           } elsif (m/^([-_0-9A-Za-z]+)\s+(\S.*)$/) {
                $c_entry= $1;
                $tables{$c_table}{$c_entry}{I} .= ", $2";
            } else {
@@ -144,11 +144,12 @@ foreach $c_table (sort keys %tables) {
     $x_table= $table_x{$c_table};
     $op_tab= '';
 
-    foreach $c_entry (keys %$r_table) {
+    foreach $c_entry (sort keys %$r_table) {
+       $c_entry_c= $c_entry; $c_entry_c =~ y/-/_/;
        $r_entry= $r_table->{$c_entry};
-       $pa_decl= "int pa_${c_table}_${c_entry}(ClientData cd,".
+       $pa_decl= "int pa_${c_table}_${c_entry_c}(ClientData cd,".
            " Tcl_Interp *ip, int objc, Tcl_Obj *const *objv)";
-       $do_decl= "int do_${c_table}_${c_entry}(";
+       $do_decl= "int do_${c_table}_${c_entry_c}(";
        @do_al= ('ClientData cd', 'Tcl_Interp *ip');
        @do_aa= qw(cd ip);
        $pa_init= '';
@@ -226,7 +227,7 @@ foreach $c_table (sort keys %tables) {
            $pa_rslt .= "  Tcl_SetObjResult(ip, ret_$t(ip, result));\n";
        }
        $pa_body .= "\n";
-       $pa_body .= "  rc= do_${c_table}_${c_entry}(";
+       $pa_body .= "  rc= do_${c_table}_${c_entry_c}(";
        $pa_body .= join ', ', @do_aa;
        $pa_body .= ");\n";
        $pa_body .= "  if (rc) goto rc_err;\n";
@@ -268,7 +269,7 @@ foreach $c_table (sort keys %tables) {
 
        $op_tab .= sprintf("  { %-20s %-40s%s },\n",
                           "\"$c_entry\",",
-                          "pa_${c_table}_${c_entry}",
+                          "pa_${c_table}_${c_entry_c}",
                           $r_entry->{I});
     }
     if (length $c_table) {
index 0f82126..784273a 100644 (file)
@@ -2,6 +2,7 @@ OBJS=           tables.o \
                hbytes.o \
                enum.o \
                chop.o \
+               hook.o \
                parse.o
 
 HDRS=          hbytes.h \
index 4999533..c81e5d6 100644 (file)
@@ -5,57 +5,82 @@
 
 #include "hbytes.h"
 
-static int strs(Tcl_Interp *ip, int strc, Tcl_Obj *const *strv, int *l_r) {
+static int strs1(Tcl_Interp *ip, int strc, Tcl_Obj *const *strv, int *l_r) {
   int rc, l, i;
 
   l= 0;
   for (i=1; i<strc; i++) {
     rc= Tcl_ConvertToType(ip,strv[i],&hbytes_type);
     if (rc) return rc;
-    l += HBYTES_LEN(HBYTES(strv[i]));
-fprintf(stderr,"strs #%d %d %02x\n",i,l,
-       HBYTES(strv[i]).start ? HBYTES(strv[i]).start[0] : 0xff);
+    l += hbytes_len(OBJ_HBYTES(strv[i]));
   }
   *l_r= l;
   return TCL_OK;
 }
 
-int app_pre(ClientData cd, Tcl_Interp *ip, int begin,
-           HBytes_Var v, int strc, Tcl_Obj *const *strv) {
-  int ol, rc, al, i, tl;
-
-  rc= strs(ip,strc,strv,&al);  if (rc) return rc;
-
-  ol= HBYTES_LEN(*v.hb);
-  v.hb->start= v.hb->end= Tcl_Realloc(v.hb->start, ol + al);
-
-  if (begin) v.hb->end += ol;
-  else memmove(v.hb->start + al, v.hb->start, ol);
+static void strs2(Byte *dest, int strc, Tcl_Obj *const *strv) {
+  int tl, i;
   
   for (i=1; i<strc; i++) {
-    tl= HBYTES_LEN(HBYTES(strv[i]));
-    memcpy(v.hb->end, HBYTES(strv[i]).start, tl);
-    v.hb->end += tl;
+    tl= hbytes_len(OBJ_HBYTES(strv[i]));
+    memcpy(dest, hbytes_data(OBJ_HBYTES(strv[i])), tl);
+    dest += tl;
   }
-  return TCL_OK;
-}  
-
-int do_hbytes_append(ClientData cd, Tcl_Interp *ip,
-                    HBytes_Var v, int strc, Tcl_Obj *const *strv) {
-  return app_pre(cd,ip,0,v,strc,strv);
 }
-  
+
 int do_hbytes_prepend(ClientData cd, Tcl_Interp *ip,
                      HBytes_Var v, int strc, Tcl_Obj *const *strv) {
-  return app_pre(cd,ip,1,v,strc,strv);
+  int rc, el;
+  Byte *dest;
+  
+  rc= strs1(ip,strc,strv,&el);  if (rc) return rc;
+  dest= hbytes_prepend(v.hb, el);
+  strs2(dest, strc,strv);
+  return TCL_OK;
+}
+  
+int do_hbytes_append(ClientData cd, Tcl_Interp *ip,
+                    HBytes_Var v, int strc, Tcl_Obj *const *strv) {
+  int rc, el;
+  Byte *dest;
+
+  rc= strs1(ip,strc,strv,&el);  if (rc) return rc;
+  dest= hbytes_append(v.hb, el);
+  strs2(dest,  strc,strv);
+  return TCL_OK;
 }
 
 int do_hbytes_concat(ClientData cd, Tcl_Interp *ip,
                     int strc, Tcl_Obj *const *strv, HBytes_Value *result) {
-  HBytes_Var fake;
+  int rc, l;
+  Byte *dest;
   
-  result->start= result->end= 0;
-  fake.hb= result;
-  return app_pre(cd,ip,1,fake,strc,strv);
+  rc= strs1(ip,strc,strv,&l);  if (rc) return rc;
+  dest= hbytes_arrayspace(result,l);
+  strs2(dest, strc,strv);
+  return TCL_OK;
 }
 
+static int underrun(Tcl_Interp *ip) { return staticerr(ip,"data underrun"); }
+
+int do_hbytes_unprepend(ClientData cd, Tcl_Interp *ip,
+                       HBytes_Var v, int preflength, HBytes_Value *result) {
+  const Byte *rdata= hbytes_unprepend(v.hb, preflength);
+  if (!rdata) return underrun(ip);
+  hbytes_array(result, rdata, preflength);
+  return TCL_OK;
+}
+
+int do_hbytes_unappend(ClientData cd, Tcl_Interp *ip,
+                      HBytes_Var v, int suflength, HBytes_Value *result) {
+  const Byte *rdata= hbytes_unappend(v.hb, suflength);
+  if (!rdata) return underrun(ip);
+  hbytes_array(result, rdata, suflength);
+  return TCL_OK;
+}
+
+int do_hbytes_chopto(ClientData cd, Tcl_Interp *ip,
+                    HBytes_Var v, int newlength, HBytes_Value *result) {
+  int suflength= hbytes_len(v.hb) - newlength;
+  return do_hbytes_unappend(0,ip,v, suflength, result);
+}
index 626b2da..4bbf8f6 100644 (file)
  *
  */
 
+#include <string.h>
+
 #include "hbytes.h"
 #include "tables.h"
+#include "hbintern.h"
 
-int staticerr(Tcl_Interp *ip, const char *m) {
-  Tcl_SetResult(ip, (char*)m, TCL_STATIC);
-  return TCL_ERROR;
-}
+#define COMPLEX(hb) ((HBytes_ComplexValue*)hb->begin_complex)
+#define SIMPLE_LEN(hb) ((Byte*)(hb)->end_0 - (Byte*)(hb)->begin_complex)
 
-void hbytes_set(HBytes_Value *upd, const Byte *array, int l) {
-  Byte *np;
+/* enquirers */
 
-  upd->start= np= l ? TALLOC(l) : 0;
-  memcpy(np, array, l);
-  upd->end= np + l;
+int hbytes_len(const HBytes_Value *hb) {
+  if (HBYTES_ISEMPTY(hb)) return 0;
+  else if (HBYTES_ISCOMPLEX(hb)) return COMPLEX(hb)->len;
+  else return SIMPLE_LEN(hb);
 }
 
-static void hbytes_setintern(Tcl_Obj *o, const Byte *array, int l) {
-  hbytes_set(&HBYTES(o), array, l);
-  o->typePtr = &hbytes_type;
+Byte *hbytes_data(const HBytes_Value *hb) {
+  if (HBYTES_ISEMPTY(hb)) return 0;
+  else if (HBYTES_ISCOMPLEX(hb)) return COMPLEX(hb)->dstart;
+  else return hb->begin_complex;
 }
 
-static void hbytes_t_dup(Tcl_Obj *src, Tcl_Obj *dup) {
-  hbytes_setintern(src, HBYTES(src).start, HBYTES_LEN(HBYTES(src)));
+int hbytes_issentinel(const HBytes_Value *hb) {
+  return HBYTES_ISCOMPLEX(hb);
 }
 
-Tcl_Obj *hbytes_set_obj(Tcl_Obj *overwrite, const Byte *array, int l) {
-  if (!overwrite) overwrite= Tcl_NewObj();
-  objfreeir(overwrite);
-  Tcl_InvalidateStringRep(overwrite);
-  hbytes_setintern(overwrite, array, l);
-  return overwrite;
+/* constructors */
+
+void hbytes_empty(HBytes_Value *returns) {
+  returns->begin_complex= returns->end_0= 0;
 }
 
-static void hbytes_t_free(Tcl_Obj *o) {
-  TFREE(HBYTES(o).start);
+void hbytes_sentinel(HBytes_Value *returns) {
+  returns->begin_complex= 0;
+  returns->end_0= (void*)&hbytes_type;
 }
 
-static void hbytes_t_ustr(Tcl_Obj *o) {
-  int l;
-  char *str;
-  const Byte *byte;
-
-  l= HBYTES_LEN(HBYTES(o));
-  byte= HBYTES(o).start;
-  str= o->bytes= TALLOC(l*2+1);
-  o->length= l*2;
-  while (l>0) {
-    sprintf(str,"%02x",*byte);
-    str+=2; byte++; l--;
-  }
+Byte *hbytes_arrayspace(HBytes_Value *returns, int l) {
+  if (!l) { hbytes_empty(returns); return 0; }
+  returns->begin_complex= TALLOC(l);
+  returns->end_0= returns->begin_complex + l;
+  return returns->begin_complex;
+}
+  
+void hbytes_array(HBytes_Value *returns, const Byte *array, int l) {
+  memcpy(hbytes_arrayspace(returns,l), array, l);
 }
 
-void objfreeir(Tcl_Obj *o) {
-  if (o->typePtr && o->typePtr->freeIntRepProc)
-    o->typePtr->freeIntRepProc(o);
-}  
-
-static int hbytes_t_sfa(Tcl_Interp *ip, Tcl_Obj *o) {
-  char *str, *ep, *os;
-  Byte *startbytes, *bytes;
-  int l;
-  char cbuf[3];
-
-  os= str= Tcl_GetStringFromObj(o,&l);  assert(str);
-  if (l & 1) return staticerr(ip, "hbytes: conversion from hex:"
-                             " odd length in hex");
-
-  startbytes= bytes= l ? TALLOC(l*2) : 0;
-  cbuf[2]= 0;
-  while (l>0) {
-    cbuf[0]= *str++;
-    cbuf[1]= *str++;
-    *bytes++= strtoul(cbuf,&ep,16);
-    if (ep != cbuf+2) {
-      TFREE(startbytes);
-fprintf(stderr,">%d|%s|%s<\n",l,os,cbuf);
-      return staticerr(ip, "hbytes: conversion from hex:"
-                      " bad hex digit");
-    }
-    l -= 2;
-  }
-  objfreeir(o);
+/* destructor */
 
-  HBYTES(o).start= startbytes;
-  HBYTES(o).end= bytes;
-  o->typePtr = &hbytes_type;
-  return TCL_OK;
+void hbytes_free(HBytes_Value *frees) {
+  if (HBYTES_ISCOMPLEX(frees)) {
+    HBytes_ComplexValue *cx= COMPLEX(frees);
+    TFREE(cx->dstart - cx->prespace);
+  }
+  TFREE(frees->begin_complex);
 }
 
-Tcl_ObjType hbytes_type = {
-  "hbytes",
-  hbytes_t_free, hbytes_t_dup, hbytes_t_ustr, hbytes_t_sfa
-};
+/* mutators */
+
+static HBytes_ComplexValue *complex(HBytes_Value *hb) {
+  HBytes_ComplexValue *cx;
+
+  if (HBYTES_ISCOMPLEX(hb)) return hb->begin_complex;
 
-int do_hbytes_raw2h(ClientData cd, Tcl_Interp *ip,
-                   Tcl_Obj *binary, HBytes_Value *result) {
-  const char *str;
-  int l;
+  cx= TALLOC(sizeof(*cx));
+  cx->dstart= hb->begin_complex;
+  cx->len= cx->avail= SIMPLE_LEN(hb);
+  cx->prespace= 0;
 
-  str= Tcl_GetStringFromObj(binary,&l);
-  hbytes_set(result, str, l);
-  return TCL_OK;
+  hb->begin_complex= cx;
+  hb->end_0= 0;
+
+  return cx;
 }
 
-int do_hbytes_h2raw(ClientData cd, Tcl_Interp *ip,
-                   HBytes_Value hex, Tcl_Obj **result) {
-  *result= Tcl_NewStringObj(hex.start, HBYTES_LEN(hex));
-  return TCL_OK;
+Byte *hbytes_prepend(HBytes_Value *hb, int el) {
+  HBytes_ComplexValue *cx;
+  int new_prespace;
+  Byte *old_block, *new_block, *new_dstart;
+
+  cx= complex(hb);
+  
+  if (cx->prespace < el) {
+    new_prespace= el*2 + cx->len;
+    old_block= cx->dstart - cx->prespace;
+    new_block= Tcl_Realloc(old_block, new_prespace + cx->avail);
+    new_dstart= new_block + new_prespace;
+    memmove(new_dstart, new_block + cx->prespace, cx->len);
+    cx->prespace= new_prespace;
+    cx->dstart= new_dstart;
+  }
+  cx->dstart -= el;
+  cx->prespace -= el;
+  cx->len += el;
+  cx->avail += el;
+  return cx->dstart;
 }
 
-#if 0
-HC_DEFINE(pkcs5) {
-  static const PadKindInfo padkindinfos[0]= {
-    { "pa", 1, 1 },
-    { "pn", 1, 0 },
-    { "ua", 0, 1 },
-    { "un", 0, 0 },
-    { 0 }
-  };
-
-  HC_DECLS_HBV;
-  Tcl_Obj *v;
-  int blocksize;
-  const PadKindInfo *pk;
-  const BlockCipherInfo *bc;
-
-  HC_ARG_ENUM(pk, padkindinfos);
-  HC_ARG_HBV;
-  if (!pk->algname) HC_ARG_INTRANGE(blocksize, 1,255);
-  else { HC_ARG_ENUM(bc, blockciphers); blocksize= bc->blocksize; }
-  HC_ARGS_E;
-
-  /* do nothing :-) */
-
-  HC_FINI_HBV;
+Byte *hbytes_append(HBytes_Value *hb, int el) {
+  HBytes_ComplexValue *cx;
+  int new_len, new_avail;
+  Byte *newpart, *new_block, *old_block;
+
+  cx= complex(hb);
+
+  new_len= cx->len + el;
+  if (new_len > cx->avail) {
+    new_avail= new_len*2;
+    old_block= cx->dstart - cx->prespace;
+    new_block= Tcl_Realloc(old_block, cx->prespace + new_avail);
+    cx->dstart= new_block + cx->prespace;
+    cx->avail= new_avail;
+  }
+  newpart= cx->dstart + cx->len;
+  cx->len= new_len;
+  return newpart;
 }
-#endif
 
-int do__hbytes(ClientData cd, Tcl_Interp *ip,
-              const HBytes_SubCommand *subcmd,
-              int objc, Tcl_Obj *const *objv) {
-  return subcmd->func(0,ip,objc,objv);
+HBytes_ComplexValue *prechop(HBytes_Value *hb, int cl, const Byte **rv) {
+  HBytes_ComplexValue *cx;
+
+  if (cl<0) { *rv=0; return 0; }
+  if (cl==0) { *rv= (const void*)&hbytes_type; return 0; }
+  
+  cx= complex(hb);
+  if (cl > cx->len) { *rv=0; return 0; }
+  return cx;
+}
+
+const Byte *hbytes_unprepend(HBytes_Value *hb, int pl) {
+  const Byte *chopped;
+  HBytes_ComplexValue *cx= prechop(hb,pl,&chopped);
+  if (!cx) return chopped;
+
+  chopped= cx->dstart;
+  cx->dstart += pl;
+  cx->prespace += pl;
+  cx->len -= pl;
+  cx->avail -= pl;
+  return chopped;
 }
 
-int Hbytes_Init(Tcl_Interp *ip) {
-  Tcl_RegisterObjType(&hbytes_type);
-  Tcl_RegisterObjType(&enum_nearlytype);
-  Tcl_RegisterObjType(&enum1_nearlytype);
-  Tcl_CreateObjCommand(ip,"hbytes", pa__hbytes,0,0);
-  return TCL_OK;
+const Byte *hbytes_unappend(HBytes_Value *hb, int sl) {
+  const Byte *chopped;
+  HBytes_ComplexValue *cx= prechop(hb,sl,&chopped);
+  if (!cx) return chopped;
+
+  cx->len -= sl;
+  return cx->dstart + cx->len;
 }
index 83469d5..ee69928 100644 (file)
@@ -34,18 +34,64 @@ typedef unsigned char Byte;
 
 /* from hbytes.c */
 
+/* Internal representation details: */
+#define HBYTES_ISEMPTY(hb)    (!(hb)->begin_complex && !(hb)->end_0)
+#define HBYTES_ISSENTINEL(hb) (!(hb)->begin_complex && (hb)->end_0)
+#define HBYTES_ISSIMPLE(hb)   ((hb)->begin_complex && (hb)->end_0)
+#define HBYTES_ISCOMPLEX(hb)  ((hb)->begin_complex && !(hb)->end_0)
+
 typedef struct {
-  Byte *start, *end; /* always allocated dynamically */
+  void *begin_complex, *end_0;
 } HBytes_Value; /* overlays internalRep */
 
+typedef struct {
+  Byte *dstart; /* always allocated dynamically */
+  int prespace, len, avail;
+  /*        
+   * | SPARE      | USED  | SPARE |
+   * |<-prespace->|<-len->|       |
+   * |            |<----avail---->|
+   *              ^start
+   */
+} HBytes_ComplexValue; /* pointed to from internalRep.otherValuePtr */
+
+/* Public interfaces: */
+
 extern Tcl_ObjType hbytes_type;
 
+int hbytes_len(const HBytes_Value *v);
+Byte *hbytes_data(const HBytes_Value *v); /* caller may then modify data! */
+int hbytes_issentinel(const HBytes_Value *v);
+
+Byte *hbytes_prepend(HBytes_Value *upd, int el);
+Byte *hbytes_append(HBytes_Value *upd, int el);
+  /* return value is where to put the data */
+
+const Byte *hbytes_unprepend(HBytes_Value *upd, int rl);
+const Byte *hbytes_unappend(HBytes_Value *upd, int rl);
+  /* return value points to the removed data, which remains valid
+   * until next op on the HBytes_Value.  If original value is
+   * shorter than rl or negative, returns 0 and does nothing. */
+
+void hbytes_empty(HBytes_Value *returns);
+void hbytes_sentinel(HBytes_Value *returns);
+void hbytes_array(HBytes_Value *returns, const Byte *array, int l);
+Byte *hbytes_arrayspace(HBytes_Value *returns, int l);
+void hbytes_free(HBytes_Value *frees);
+  /* _empty, _sentinel and _array do not free or read the old value;
+   * _free it first if needed.  _free leaves it garbage, so you
+   * have to call _empty to reuse it.  _arrayspace doesn't fill
+   * the array; you get a pointer and must fill it with data
+   * yourself. */
+
+/* The value made by hbytes_sentinel should not be passed to
+ * anything except HBYTES_IS..., and hbytes_free. */
+
+/* from hook.c */
+
 int staticerr(Tcl_Interp *ip, const char *m);
 void objfreeir(Tcl_Obj *o);
 
-void hbytes_set(HBytes_Value *upd, const Byte *array, int l);
-Tcl_Obj *hbytes_set_obj(Tcl_Obj *overwrite, const Byte *array, int l);
-
 /* from parse.c */
 
 typedef struct {
@@ -55,6 +101,8 @@ typedef struct {
 
 void fini_hbv(Tcl_Interp *ip, int rc, HBytes_Var *agg);
 
+/* from chop.c */
+
 /* from enum.c */
 
 extern Tcl_ObjType enum_nearlytype;
@@ -94,8 +142,7 @@ typedef struct {
 
 /* useful macros */
 
-#define HBYTES(o) (*(HBytes_Value*)&(o)->internalRep.twoPtrValue)
-#define HBYTES_LEN(hb) ((hb).end - (hb).start)
+#define OBJ_HBYTES(o) ((HBytes_Value*)&(o)->internalRep.twoPtrValue)
 
 #define TALLOC(s) ((void*)Tcl_Alloc((s)))
 #define TFREE(f) (Tcl_Free((void*)(f)))
diff --git a/hbytes/hook.c b/hbytes/hook.c
new file mode 100644 (file)
index 0000000..08e055d
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ */
+
+#include "hbytes.h"
+#include "tables.h"
+
+int staticerr(Tcl_Interp *ip, const char *m) {
+  Tcl_SetResult(ip, (char*)m, TCL_STATIC);
+  return TCL_ERROR;
+}
+
+void objfreeir(Tcl_Obj *o) {
+  if (o->typePtr && o->typePtr->freeIntRepProc)
+    o->typePtr->freeIntRepProc(o);
+  o->typePtr= 0;
+}  
+
+int do_hbytes_rep_info(ClientData cd, Tcl_Interp *ip,
+                      HBytes_Value v, Tcl_Obj **result) {
+  const char *tn;
+  int nums[3], i;
+  Tcl_Obj *objl[4];
+
+  memset(nums,0,sizeof(nums));
+  nums[1]= hbytes_len(&v);
+  
+  if (HBYTES_ISEMPTY(&v)) tn= "empty";
+  else if (HBYTES_ISSENTINEL(&v)) tn= "sentinel!";
+  else if (HBYTES_ISSIMPLE(&v)) tn= "simple";
+  else {
+    HBytes_ComplexValue *cx= v.begin_complex;
+    tn= "complex";
+    nums[0]= cx->prespace;
+    nums[2]= cx->avail - cx->len;
+  }
+    
+  objl[0]= Tcl_NewStringObj((char*)tn,-1);
+  for (i=0; i<3; i++) objl[i+1]= Tcl_NewIntObj(nums[i]);
+  *result= Tcl_NewListObj(4,objl);
+  return TCL_OK;
+}
+
+static void hbytes_t_dup(Tcl_Obj *src, Tcl_Obj *dup) {
+  objfreeir(dup);
+  hbytes_array(OBJ_HBYTES(dup),
+              hbytes_data(OBJ_HBYTES(src)),
+              hbytes_len(OBJ_HBYTES(src)));
+}
+
+static void hbytes_t_free(Tcl_Obj *o) {
+  hbytes_free(OBJ_HBYTES(o));
+}
+
+static void hbytes_t_ustr(Tcl_Obj *o) {
+  int l;
+  char *str;
+  const Byte *byte;
+
+  byte= hbytes_data(OBJ_HBYTES(o));
+  l= hbytes_len(OBJ_HBYTES(o));
+  str= o->bytes= TALLOC(l*2+1);
+  o->length= l*2;
+  while (l>0) {
+    sprintf(str,"%02x",*byte);
+    str+=2; byte++; l--;
+  }
+  *str= 0;
+}
+
+static int hbytes_t_sfa(Tcl_Interp *ip, Tcl_Obj *o) {
+  char *str, *ep, *os;
+  Byte *startbytes, *bytes;
+  int l;
+  char cbuf[3];
+
+  os= str= Tcl_GetStringFromObj(o,&l);  assert(str);
+  objfreeir(o);
+
+  if (l & 1) return staticerr(ip, "hbytes: conversion from hex:"
+                             " odd length in hex");
+
+  startbytes= bytes= hbytes_arrayspace(OBJ_HBYTES(o), l/2);
+
+  cbuf[2]= 0;
+  while (l>0) {
+    cbuf[0]= *str++;
+    cbuf[1]= *str++;
+    *bytes++= strtoul(cbuf,&ep,16);
+    if (ep != cbuf+2) {
+      hbytes_free(OBJ_HBYTES(o));
+      return staticerr(ip, "hbytes: conversion from hex:"
+                      " bad hex digit");
+    }
+    l -= 2;
+  }
+
+  o->typePtr = &hbytes_type;
+  return TCL_OK;
+}
+
+Tcl_ObjType hbytes_type = {
+  "hbytes",
+  hbytes_t_free, hbytes_t_dup, hbytes_t_ustr, hbytes_t_sfa
+};
+
+int do_hbytes_raw2h(ClientData cd, Tcl_Interp *ip,
+                   Tcl_Obj *binary, HBytes_Value *result) {
+  const char *str;
+  int l;
+
+  str= Tcl_GetStringFromObj(binary,&l);
+  hbytes_array(result, str, l);
+  return TCL_OK;
+}
+
+int do_hbytes_h2raw(ClientData cd, Tcl_Interp *ip,
+                   HBytes_Value hex, Tcl_Obj **result) {
+  *result= Tcl_NewStringObj(hbytes_data(&hex), hbytes_len(&hex));
+  return TCL_OK;
+}
+
+#if 0
+HC_DEFINE(pkcs5) {
+  static const PadKindInfo padkindinfos[0]= {
+    { "pa", 1, 1 },
+    { "pn", 1, 0 },
+    { "ua", 0, 1 },
+    { "un", 0, 0 },
+    { 0 }
+  };
+
+  HC_DECLS_HBV;
+  Tcl_Obj *v;
+  int blocksize;
+  const PadKindInfo *pk;
+  const BlockCipherInfo *bc;
+
+  HC_ARG_ENUM(pk, padkindinfos);
+  HC_ARG_HBV;
+  if (!pk->algname) HC_ARG_INTRANGE(blocksize, 1,255);
+  else { HC_ARG_ENUM(bc, blockciphers); blocksize= bc->blocksize; }
+  HC_ARGS_E;
+
+  /* do nothing :-) */
+
+  HC_FINI_HBV;
+}
+#endif
+
+int do__hbytes(ClientData cd, Tcl_Interp *ip,
+              const HBytes_SubCommand *subcmd,
+              int objc, Tcl_Obj *const *objv) {
+  return subcmd->func(0,ip,objc,objv);
+}
+
+int Hbytes_Init(Tcl_Interp *ip) {
+  Tcl_RegisterObjType(&hbytes_type);
+  Tcl_RegisterObjType(&enum_nearlytype);
+  Tcl_RegisterObjType(&enum1_nearlytype);
+  Tcl_CreateObjCommand(ip,"hbytes", pa__hbytes,0,0);
+  return TCL_OK;
+}
index 1e1e5bb..e5e3465 100644 (file)
@@ -42,7 +42,7 @@ int pat_hbv(Tcl_Interp *ip, Tcl_Obj *var, HBytes_Var *agg) {
   rc= Tcl_ConvertToType(ip,val,&hbytes_type);
   if (rc) return rc;
 
-  agg->hb= &HBYTES(val);
+  agg->hb= OBJ_HBYTES(val);
   return TCL_OK;
 }
 
@@ -62,12 +62,17 @@ void fini_hbv(Tcl_Interp *ip, int rc, HBytes_Var *agg) {
 int pat_hb(Tcl_Interp *ip, Tcl_Obj *obj, HBytes_Value *val) {
   int rc;
   rc= Tcl_ConvertToType(ip,obj,&hbytes_type);  if (rc) return rc;
-  *val= HBYTES(obj);
+  *val= *OBJ_HBYTES(obj);
   return TCL_OK;
 }
 
 Tcl_Obj *ret_hb(Tcl_Interp *ip, HBytes_Value val) {
-  return hbytes_set_obj(0, val.start, HBYTES_LEN(val));
+  Tcl_Obj *obj;
+  obj= Tcl_NewObj();
+  Tcl_InvalidateStringRep(obj);
+  *OBJ_HBYTES(obj)= val;
+  obj->typePtr= &hbytes_type;
+  return obj;
 }
 
 Tcl_Obj *ret_obj(Tcl_Interp *ip, Tcl_Obj *val) {