From 2cf1bfc63e73a424f9f3899c204025a8346b38e0 Mon Sep 17 00:00:00 2001 From: ian Date: Sun, 1 Sep 2002 20:35:54 +0000 Subject: [PATCH] Lots of stuff seems to work --- base/chiark-tcl.h | 59 +++++++++- base/hook.c | 162 ++++++++++++++++++++++++++ base/parse.c | 11 +- base/tables-examples.tct | 29 ++--- base/tcmdifgen | 15 +-- base/troglodyte-Makefile | 1 + hbytes/chop.c | 85 +++++++++----- hbytes/hbytes.c | 241 ++++++++++++++++++++------------------- hbytes/hbytes.h | 59 +++++++++- hbytes/hook.c | 162 ++++++++++++++++++++++++++ hbytes/parse.c | 11 +- 11 files changed, 647 insertions(+), 188 deletions(-) create mode 100644 base/hook.c create mode 100644 hbytes/hook.c diff --git a/base/chiark-tcl.h b/base/chiark-tcl.h index 83469d5..ee69928 100644 --- a/base/chiark-tcl.h +++ b/base/chiark-tcl.h @@ -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 index 0000000..08e055d --- /dev/null +++ b/base/hook.c @@ -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; +} diff --git a/base/parse.c b/base/parse.c index 1e1e5bb..e5e3465 100644 --- a/base/parse.c +++ b/base/parse.c @@ -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) { diff --git a/base/tables-examples.tct b/base/tables-examples.tct index 2c6711a..ecb5d7c 100644 --- a/base/tables-examples.tct +++ b/base/tables-examples.tct @@ -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 ... diff --git a/base/tcmdifgen b/base/tcmdifgen index 21833c1..514dc01 100755 --- a/base/tcmdifgen +++ b/base/tcmdifgen @@ -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) { diff --git a/base/troglodyte-Makefile b/base/troglodyte-Makefile index 0f82126..784273a 100644 --- a/base/troglodyte-Makefile +++ b/base/troglodyte-Makefile @@ -2,6 +2,7 @@ OBJS= tables.o \ hbytes.o \ enum.o \ chop.o \ + hook.o \ parse.o HDRS= hbytes.h \ diff --git a/hbytes/chop.c b/hbytes/chop.c index 4999533..c81e5d6 100644 --- a/hbytes/chop.c +++ b/hbytes/chop.c @@ -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; istart= 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; iend, 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); +} diff --git a/hbytes/hbytes.c b/hbytes/hbytes.c index 626b2da..4bbf8f6 100644 --- a/hbytes/hbytes.c +++ b/hbytes/hbytes.c @@ -2,154 +2,155 @@ * */ +#include + #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; } diff --git a/hbytes/hbytes.h b/hbytes/hbytes.h index 83469d5..ee69928 100644 --- a/hbytes/hbytes.h +++ b/hbytes/hbytes.h @@ -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 index 0000000..08e055d --- /dev/null +++ b/hbytes/hook.c @@ -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; +} diff --git a/hbytes/parse.c b/hbytes/parse.c index 1e1e5bb..e5e3465 100644 --- a/hbytes/parse.c +++ b/hbytes/parse.c @@ -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) { -- 2.30.2