7 /* nice simple functions */
9 int do_ulong_int2ul(ClientData cd, Tcl_Interp *ip, int v,
11 if (v<0) return staticerr(ip,"cannot convert -ve integer to ulong");
16 int do_ulong_add(ClientData cd, Tcl_Interp *ip,
17 uint32_t a, uint32_t b, uint32_t *result) {
22 int do_ulong_subtract(ClientData cd, Tcl_Interp *ip,
23 uint32_t a, uint32_t b, uint32_t *result) {
28 int do_ulong_compare(ClientData cd, Tcl_Interp *ip,
29 uint32_t a, uint32_t b, int *result) {
36 int do_ulong_ul2int(ClientData cd, Tcl_Interp *ip,
37 uint32_t v, int *result) {
38 if (v>INT_MAX) return staticerr(ip,"ulong too large to fit in an int");
43 int do_ulong_mask(ClientData cd, Tcl_Interp *ip,
44 uint32_t a, uint32_t b, uint32_t *result) {
49 int do_ulong_shift(ClientData cd, Tcl_Interp *ip, int right,
50 uint32_t v, int bits, uint32_t *result) {
51 if (bits > 32) return staticerr(ip,"shift out of range (32) bits");
52 *result= (bits==32 ? 0 :
53 right ? v >> bits : v << bits);
62 int (*reader_writer[2])(Tcl_Interp *ip, uint32_t *value_io,
63 int *ok_io, Tcl_Obj *arg);
66 static int bf_zero_read(Tcl_Interp *ip, uint32_t *value_io,
67 int *ok_io, Tcl_Obj *arg) {
68 if (*value_io) *ok_io= 0;
72 static int bf_zero_write(Tcl_Interp *ip, uint32_t *value_io,
73 int *ok_io, Tcl_Obj *arg) {
78 static int bf_ignore(Tcl_Interp *ip, uint32_t *value_io,
79 int *ok_io, Tcl_Obj *arg) {
83 static int bf_fixed_read(Tcl_Interp *ip, uint32_t *value_io,
84 int *ok_io, Tcl_Obj *arg) {
88 rc= pat_ulong(ip, arg, &ul); if (rc) return rc;
89 if (*value_io != ul) *ok_io= 0;
93 static int bf_ulong_write(Tcl_Interp *ip, uint32_t *value_io,
94 int *ok_io, Tcl_Obj *arg) {
98 rc= pat_ulong(ip, arg, &ul); if (rc) return rc;
103 static int bf_var_read(Tcl_Interp *ip, Tcl_Obj *varname, Tcl_Obj *val) {
105 rp= Tcl_ObjSetVar2(ip,varname,0,val,TCL_LEAVE_ERR_MSG);
106 if (!rp) return TCL_ERROR;
110 static int bf_ulong_read(Tcl_Interp *ip, uint32_t *value_io,
111 int *ok_io, Tcl_Obj *arg) {
112 return bf_var_read(ip,arg, ret_ulong(ip,*value_io));
115 static int bf_uint_write(Tcl_Interp *ip, uint32_t *value_io,
116 int *ok_io, Tcl_Obj *arg) {
118 rc= pat_int(ip, arg, &v); if (rc) return rc;
119 if (v<0) return staticerr(ip,"value for bitfield is -ve");
124 static int bf_uint_read(Tcl_Interp *ip, uint32_t *value_io,
125 int *ok_io, Tcl_Obj *arg) {
126 if (*value_io > INT_MAX)
127 return staticerr(ip,"value from bitfield exceeds INT_MAX");
128 return bf_var_read(ip,arg, ret_int(ip,*value_io));
131 #define BFT(t,a) { #t, a, { bf_read_##t, bf_write_##t } }
132 static const BitFieldType bitfieldtypes[]= {
133 { "zero", 0, { bf_zero_read, bf_zero_write } },
134 { "ignore", 0, { bf_ignore, bf_ignore } },
135 { "fixed", 1, { bf_fixed_read, bf_ulong_write } },
136 { "ulong", 1, { bf_ulong_read, bf_ulong_write } },
137 { "uint", 1, { bf_uint_read, bf_uint_write } },
141 static int do_bitfields(Tcl_Interp *ip, int writing, int *ok_r,
143 int objc, Tcl_Obj *const *objv) {
144 const BitFieldType *ftype;
147 uint32_t value, sz_mask, this_mask, this_field;
154 rc= Tcl_GetIntFromObj(ip,*++objv,&sz); if (rc) return rc;
155 if (!--objc) return staticerr(ip,"wrong # args: missing bitfield type");
157 if (sz<0) return staticerr(ip,"bitfield size is -ve");
158 if (sz>pos) return staticerr(ip,"total size of bitfields >32");
162 sz_mask= ~(~0UL << sz);
163 this_mask= (sz_mask << pos);
164 this_field= (value & this_mask) >> pos;
166 ftype= enum_lookup_cached(ip,*++objv,bitfieldtypes,"bitfield type");
167 if (!ftype) return TCL_ERROR;
169 if (ftype->want_arg) {
171 return staticerr(ip,"wrong # args: missing arg for bitfield");
176 rc= ftype->reader_writer[writing](ip, &this_field, ok_r, arg);
179 if (!*ok_r) return TCL_OK;
181 if (this_field & ~sz_mask)
182 return staticerr(ip,"bitfield value has more bits than bitfield");
185 value |= (this_field << pos);
189 return staticerr(ip,"bitfield sizes add up to <32");
195 int do_ulong_bitfields2ul(ClientData cd, Tcl_Interp *ip,
197 int objc, Tcl_Obj *const *objv,
202 rc= do_bitfields(ip,1,&ok,result,objc,objv);
207 int do_ulong_ul2bitfields(ClientData cd, Tcl_Interp *ip,
209 int objc, Tcl_Obj *const *objv,
211 return do_bitfields(ip,0,result,&value,objc,objv);
216 int pat_ulong(Tcl_Interp *ip, Tcl_Obj *o, uint32_t *val) {
219 rc= Tcl_ConvertToType(ip,o,&ulong_type);
221 *val= *(const uint32_t*)&o->internalRep.longValue;
225 Tcl_Obj *ret_ulong(Tcl_Interp *ip, uint32_t val) {
229 Tcl_InvalidateStringRep(o);
230 *(uint32_t*)&o->internalRep.longValue= val;
231 o->typePtr= &ulong_type;
237 static void ulong_t_free(Tcl_Obj *o) { }
239 static void ulong_t_dup(Tcl_Obj *src, Tcl_Obj *dup) {
240 dup->internalRep= src->internalRep;
241 dup->typePtr= &ulong_type;
244 static void ulong_t_ustr(Tcl_Obj *o) {
248 val= *(const uint32_t*)&o->internalRep.longValue;
250 assert(val <= 0xffffffffUL);
251 snprintf(buf,sizeof(buf), "%08lx", (unsigned long)val);
253 obj_updatestr_vstringls(o, buf, sizeof(buf)-1, (char*)0);
256 static int ulong_t_sfa(Tcl_Interp *ip, Tcl_Obj *o) {
260 if (o->typePtr == &hbytes_type) {
263 l= hbytes_len(OBJ_HBYTES(o));
264 if (l > 4) return staticerr(ip, "hbytes as ulong must be of length < 4");
266 memcpy((Byte*)&ul + 4 - l, hbytes_data(OBJ_HBYTES(o)), l);
271 str= Tcl_GetString(o);
273 if (str[0]=='0' && str[1]=='b' && str[2]) {
274 ul= strtoul(str+2,&ep,2);
275 } else if (str[0]=='0' && str[1]=='d' && str[2]) {
276 ul= strtoul(str+2,&ep,10);
278 ul= strtoul(str,&ep,16);
280 if (*ep || errno) return staticerr(ip, "bad unsigned long value");
285 *(uint32_t*)&o->internalRep.longValue= ul;
286 o->typePtr= &ulong_type;
290 Tcl_ObjType ulong_type = {
292 ulong_t_free, ulong_t_dup, ulong_t_ustr, ulong_t_sfa