X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?a=blobdiff_plain;f=base%2Fidtable.c;h=b23a97cebf686a4e82430b9f40467451180d5ea1;hb=b92528a0a95714d8b738e619de5a1d80f2fbd413;hp=f64a1013bc6a15581e4853a0e35ecc0a0d6a47c2;hpb=9e72d3c3d91b86842aa947297e0d30bbc741c7b1;p=chiark-tcl.git diff --git a/base/idtable.c b/base/idtable.c index f64a101..b23a97c 100644 --- a/base/idtable.c +++ b/base/idtable.c @@ -6,56 +6,104 @@ /* Arg parsing */ -static void setobjdataid(Tcl_Obj *o, int ix, IdDataTable *tab) { - unsigned long *ulp; +typedef struct { + const IdDataSpec *idds; + int n; + void **a; +} IdDataAssocData; + +typedef struct { + Tcl_Interp *interp; + IdDataAssocData *assoc; + int ix; +} IdDataValue; + +static void assoc_del(ClientData assoc_cd, Tcl_Interp *ip) { + IdDataAssocData *assoc; + int ix; + void **p, *v; + + assoc= assoc_cd; + for (ix=0, p=assoc->a; ixn; ix++, p++) { + v= *p; + if (!v) continue; + assert(*(int*)v == ix); + *(int*)v= -1; + assoc->idds->destroyitem(ip,v); + *p= 0; + } + TFREE(assoc->a); + TFREE(assoc); +} + +static void setobjdataid(Tcl_Interp *interp, Tcl_Obj *o, + int ix, const IdDataSpec *idds) { + IdDataValue *dv; + IdDataAssocData *assoc; + + assoc= Tcl_GetAssocData(interp, (char*)idds->assockey, 0); + if (!assoc) { + assoc= TALLOC(sizeof(*assoc)); + assoc->idds= idds; + assoc->n= 0; + assoc->a= 0; + Tcl_SetAssocData(interp, (char*)idds->assockey, assoc_del, assoc); + } + + dv= TALLOC(sizeof(*dv)); + dv->interp= interp; + dv->assoc= assoc; + dv->ix= ix; - ulp= TALLOC(sizeof(unsigned long)); - *ulp= ix; - o->internalRep.twoPtrValue.ptr1= tab; - o->internalRep.twoPtrValue.ptr2= ulp; o->typePtr= &tabledataid_nearlytype; + o->internalRep.otherValuePtr= dv; } -int tabledataid_parse(Tcl_Interp *ip, Tcl_Obj *o, IdDataTable *tab) { +int tabledataid_parse(Tcl_Interp *ip, Tcl_Obj *o, const IdDataSpec *idds) { int l; unsigned long ul; + IdDataValue *dv; + IdDataAssocData *assoc; char *ep, *str; - if (o->typePtr == &tabledataid_nearlytype && - o->internalRep.twoPtrValue.ptr1 == tab) return TCL_OK; + if (o->typePtr != &tabledataid_nearlytype) goto convert; + + dv= o->internalRep.otherValuePtr; + if (dv->interp != ip) goto convert; + assoc= dv->assoc; + if (dv->assoc->idds != idds) goto convert; - l= strlen(tab->prefix); + return TCL_OK; + +convert: + l= strlen(idds->valprefix); str= Tcl_GetStringFromObj(o,0); - if (memcmp(str,tab->prefix,l)) + if (memcmp(str,idds->valprefix,l)) return staticerr(ip,"bad id (wrong prefix)",0); + errno=0; ul=strtoul(str+l,&ep,10); if (errno || *ep) return staticerr(ip,"bad id number",0); if (ul > INT_MAX) return staticerr(ip,"out of range id number",0); objfreeir(o); - setobjdataid(o,ul,tab); + setobjdataid(ip,o,ul,idds); return TCL_OK; } -void tabledataid_disposing(void *val, IdDataTable *tab) { - int ix; - - ix= *(int*)val; - if (ix==-1) return; - assert(tab->a[ix] == val); - tab->a[ix]= 0; - *(int*)val= -1; -} - -int pat_iddata(Tcl_Interp *ip, Tcl_Obj *o, void **rv, IdDataTable *tab) { +int pat_iddata(Tcl_Interp *ip, Tcl_Obj *o, void **rv, const IdDataSpec *idds) { int rc, ix; + IdDataValue *dv; + IdDataAssocData *assoc; void *r; - rc= tabledataid_parse(ip,o,tab); + rc= tabledataid_parse(ip,o,idds); if (rc) return rc; - ix= *(unsigned long*)o->internalRep.twoPtrValue.ptr2; - if (ix >= tab->n || !(r= tab->a[ix])) + dv= o->internalRep.otherValuePtr; + ix= dv->ix; + assoc= dv->assoc; + + if (ix >= assoc->n || !(r= assoc->a[ix])) return staticerr(ip,"id not in use",0); assert(*(int*)r == ix); @@ -64,59 +112,86 @@ int pat_iddata(Tcl_Interp *ip, Tcl_Obj *o, void **rv, IdDataTable *tab) { return TCL_OK; } -Tcl_Obj *ret_iddata(Tcl_Interp *ip, void *val, IdDataTable *tab) { +Tcl_Obj *ret_iddata(Tcl_Interp *ip, void *val, const IdDataSpec *idds) { /* Command procedure implementation may set val->ix, * ie *(int*)val, to -1, to mean it's a new struct. Otherwise * it had better be an old one ! */ Tcl_Obj *o; + IdDataValue *dv; + IdDataAssocData *assoc; int ix; + o= Tcl_NewObj(); + setobjdataid(ip,o,0,idds); + dv= o->internalRep.otherValuePtr; + assoc= dv->assoc; + ix= *(int*)val; if (ix==-1) { - for (ix=0; ixn && tab->a[ix]; ix++); - if (ix>=tab->n) { - tab->n += 2; - tab->n *= 2; - tab->a= (void*)Tcl_Realloc((void*)tab->a, tab->n*sizeof(*tab->a)); - while (ixn) tab->a[ix++]=0; + for (ix=0; ixn && assoc->a[ix]; ix++); + if (ix>=assoc->n) { + assoc->n += 2; + assoc->n *= 2; + assoc->a= TREALLOC(assoc->a, assoc->n*sizeof(*assoc->a)); + while (ixn) assoc->a[ix++]=0; ix--; } - tab->a[ix]= val; + assoc->a[ix]= val; *(int*)val= ix; } else { - assert(val == tab->a[ix]); + assert(val == assoc->a[ix]); } - - o= Tcl_NewObj(); - setobjdataid(o,ix,tab); + dv->ix= ix; Tcl_InvalidateStringRep(o); return o; } +void tabledataid_disposing(Tcl_Interp *ip, void *val, const IdDataSpec *idds) { + IdDataAssocData *assoc; + int ix; + + ix= *(int*)val; + if (ix==-1) return; + + assoc= Tcl_GetAssocData(ip, (char*)idds->assockey, 0); + assert(assoc->a[ix] == val); + assoc->a[ix]= 0; + *(int*)val= -1; +} + static int tabledataid_nt_sfa(Tcl_Interp *ip, Tcl_Obj *o) { abort(); } static void tabledataid_nt_free(Tcl_Obj *o) { - TFREE(o->internalRep.twoPtrValue.ptr2); - o->internalRep.twoPtrValue.ptr2= 0; + TFREE(o->internalRep.otherValuePtr); + o->internalRep.otherValuePtr= 0; } static void tabledataid_nt_dup(Tcl_Obj *src, Tcl_Obj *dup) { - setobjdataid(dup,*(unsigned long*)src->internalRep.twoPtrValue.ptr2, - src->internalRep.twoPtrValue.ptr1); + IdDataValue *sv, *dv; + + sv= src->internalRep.otherValuePtr; + dv= TALLOC(sizeof(*dv)); + *dv= *sv; + dup->typePtr= &tabledataid_nearlytype; + dup->internalRep.otherValuePtr= dv; } static void tabledataid_nt_ustr(Tcl_Obj *o) { + const IdDataValue *dv; + const IdDataAssocData *assoc; + const IdDataSpec *idds; char buf[75]; - const char *prefix; - prefix= ((IdDataTable*)o->internalRep.twoPtrValue.ptr1)->prefix; - snprintf(buf,sizeof(buf), "%lu", - *(unsigned long*)o->internalRep.twoPtrValue.ptr2); + dv= o->internalRep.otherValuePtr; + assoc= dv->assoc; + idds= assoc->idds; + + snprintf(buf,sizeof(buf), "%d", dv->ix); obj_updatestr_vstringls(o, - prefix, strlen(prefix), + idds->valprefix, strlen(idds->valprefix), buf, strlen(buf), (char*)0); }