chiark / gitweb /
fix build-depends for tinycdb; improve changelog
[chiark-tcl.git] / hbytes / hook.c
1 /*
2  * hbytes - hex-stringrep efficient byteblocks for Tcl
3  * Copyright 2006 Ian Jackson
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18  * 02110-1301, USA.
19  */
20
21
22 #include <errno.h>
23
24 #include "chiark_tcl_hbytes.h"
25
26 int cht_do_hbytes_rep_info(ClientData cd, Tcl_Interp *ip,
27                        Tcl_Obj *obj, Tcl_Obj **result) {
28   const char *tn;
29   int nums[3], i, lnl;
30   Tcl_Obj *objl[4];
31
32   if (obj->typePtr == &cht_hbytes_type) {
33     HBytes_Value *v= OBJ_HBYTES(obj);
34     memset(nums,0,sizeof(nums));
35     nums[1]= cht_hb_len(v);
36   
37     if (HBYTES_ISEMPTY(v)) tn= "empty";
38     else if (HBYTES_ISSENTINEL(v)) tn= "sentinel!";
39     else if (HBYTES_ISSIMPLE(v)) tn= "simple";
40     else {
41       HBytes_ComplexValue *cx= v->begin_complex;
42       tn= "complex";
43       nums[0]= cx->prespace;
44       nums[2]= cx->avail - cx->len;
45     }
46     lnl= 3;
47   } else {
48     tn= "other";
49     lnl= 0;
50   }
51     
52   objl[0]= Tcl_NewStringObj((char*)tn,-1);
53   for (i=0; i<lnl; i++) objl[i+1]= Tcl_NewIntObj(nums[i]);
54   *result= Tcl_NewListObj(lnl+1,objl);
55     
56   return TCL_OK;
57 }
58
59 static void hbytes_t_dup(Tcl_Obj *src, Tcl_Obj *dup) {
60   cht_hb_array(OBJ_HBYTES(dup),
61                cht_hb_data(OBJ_HBYTES(src)),
62                cht_hb_len(OBJ_HBYTES(src)));
63   dup->typePtr= &cht_hbytes_type;
64 }
65
66 static void hbytes_t_free(Tcl_Obj *o) {
67   cht_hb_free(OBJ_HBYTES(o));
68 }
69
70 void cht_obj_updatestr_array_prefix(Tcl_Obj *o, const Byte *byte,
71                                 int l, const char *prefix) {
72   char *str;
73   int pl;
74
75   pl= strlen(prefix);
76   o->length= l*2+pl;
77   str= o->bytes= TALLOC(o->length+1);
78   
79   memcpy(str,prefix,pl);
80   str += pl;
81
82   while (l>0) {
83     sprintf(str,"%02x",*byte);
84     str+=2; byte++; l--;
85   }
86   *str= 0;
87 }
88
89 void cht_obj_updatestr_array(Tcl_Obj *o, const Byte *byte, int l) {
90   cht_obj_updatestr_array_prefix(o,byte,l,"");
91 }
92
93 static void hbytes_t_ustr(Tcl_Obj *o) {
94   cht_obj_updatestr_array(o,
95                       cht_hb_data(OBJ_HBYTES(o)),
96                       cht_hb_len(OBJ_HBYTES(o)));
97 }
98
99 static int hbytes_t_sfa(Tcl_Interp *ip, Tcl_Obj *o) {
100   char *str, *ep, *os;
101   Byte *startbytes, *bytes;
102   int l;
103   char cbuf[3];
104
105   if (o->typePtr == &cht_ulong_type) {
106     uint32_t ul;
107
108     ul= htonl(*(const uint32_t*)&o->internalRep.longValue);
109     cht_hb_array(OBJ_HBYTES(o), (const Byte*)&ul, 4);
110
111   } else {
112   
113     os= str= Tcl_GetStringFromObj(o,&l);  assert(str);
114     cht_objfreeir(o);
115
116     if (l & 1) return cht_staticerr(ip, "hbytes: conversion from hex:"
117                                 " odd length in hex", "HBYTES SYNTAX");
118
119     startbytes= bytes= cht_hb_arrayspace(OBJ_HBYTES(o), l/2);
120
121     cbuf[2]= 0;
122     while (l>0) {
123       cbuf[0]= *str++;
124       cbuf[1]= *str++;
125       *bytes++= strtoul(cbuf,&ep,16);
126       if (ep != cbuf+2) {
127         cht_hb_free(OBJ_HBYTES(o));
128         return cht_staticerr(ip, "hbytes: conversion from hex:"
129                          " bad hex digit", "HBYTES SYNTAX");
130       }
131       l -= 2;
132     }
133
134   }
135
136   o->typePtr = &cht_hbytes_type;
137   return TCL_OK;
138 }
139
140 Tcl_ObjType cht_hbytes_type = {
141   "hbytes",
142   hbytes_t_free, hbytes_t_dup, hbytes_t_ustr, hbytes_t_sfa
143 };
144
145 int cht_do_hbytes_raw2h(ClientData cd, Tcl_Interp *ip,
146                     Tcl_Obj *binary, HBytes_Value *result) {
147   const unsigned char *str;
148   int l;
149
150   str= Tcl_GetByteArrayFromObj(binary,&l);
151   cht_hb_array(result, str, l);
152   return TCL_OK;
153 }
154
155 int cht_do_hbytes_h2raw(ClientData cd, Tcl_Interp *ip,
156                     HBytes_Value hex, Tcl_Obj **result) {
157   *result= Tcl_NewByteArrayObj(cht_hb_data(&hex), cht_hb_len(&hex));
158   return TCL_OK;
159 }
160
161 int cht_do_hbytes_length(ClientData cd, Tcl_Interp *ip,
162                      HBytes_Value v, int *result) {
163   *result= cht_hb_len(&v);
164   return TCL_OK;
165 }
166
167 int cht_do_hbytes_random(ClientData cd, Tcl_Interp *ip,
168                      int length, HBytes_Value *result) {
169   Byte *space;
170   int rc;
171   
172   space= cht_hb_arrayspace(result, length);
173   rc= cht_get_urandom(ip, space, length);
174   if (rc) { cht_hb_free(result); return rc; }
175   return TCL_OK;
176 }  
177   
178 int cht_do_hbytes_overwrite(ClientData cd, Tcl_Interp *ip,
179                         HBytes_Var v, int start, HBytes_Value sub) {
180   int sub_l;
181
182   sub_l= cht_hb_len(&sub);
183   if (start < 0)
184     return cht_staticerr(ip, "hbytes overwrite start -ve",
185                      "HBYTES LENGTH RANGE");
186   if (start + sub_l > cht_hb_len(v.hb))
187     return cht_staticerr(ip, "hbytes overwrite out of range",
188                      "HBYTES LENGTH UNDERRUN");
189   memcpy(cht_hb_data(v.hb) + start, cht_hb_data(&sub), sub_l);
190   return TCL_OK;
191 }
192
193 int cht_do_hbytes_trimleft(ClientData cd, Tcl_Interp *ip, HBytes_Var v) {
194   const Byte *o, *p, *e;
195   o= p= cht_hb_data(v.hb);
196   e= p + cht_hb_len(v.hb);
197
198   while (p<e && !*p) p++;
199   if (p != o)
200     cht_hb_unprepend(v.hb, p-o);
201
202   return TCL_OK;
203 }
204
205 int cht_do_hbytes_repeat(ClientData cd, Tcl_Interp *ip,
206                      HBytes_Value sub, int count, HBytes_Value *result) {
207   int sub_l;
208   Byte *data;
209   const Byte *sub_d;
210
211   sub_l= cht_hb_len(&sub);
212   if (count < 0) return cht_staticerr(ip, "hbytes repeat count -ve",
213                                   "HBYTES LENGTH RANGE");
214   if (count > INT_MAX/sub_l) return cht_staticerr(ip, "hbytes repeat too long", 0);
215
216   data= cht_hb_arrayspace(result, sub_l*count);
217   sub_d= cht_hb_data(&sub);
218   while (count) {
219     memcpy(data, sub_d, sub_l);
220     count--; data += sub_l;
221   }
222   return TCL_OK;
223 }  
224
225 int cht_do_hbytes_xor(ClientData cd, Tcl_Interp *ip,
226                   HBytes_Var v, HBytes_Value d) {
227   int l;
228   Byte *dest;
229   const Byte *source;
230
231   l= cht_hb_len(v.hb);
232   if (cht_hb_len(&d) != l) return
233     cht_staticerr(ip, "hbytes xor lengths do not match", "HBYTES LENGTH MISMATCH");
234
235   dest= cht_hb_data(v.hb);
236   source= cht_hb_data(&d);
237   memxor(dest,source,l);
238   return TCL_OK;
239 }
240   
241 int cht_do_hbytes_zeroes(ClientData cd, Tcl_Interp *ip,
242                      int length, HBytes_Value *result) {
243   Byte *space;
244   space= cht_hb_arrayspace(result, length);
245   memset(space,0,length);
246   return TCL_OK;
247 }
248
249 int cht_do_hbytes_compare(ClientData cd, Tcl_Interp *ip,
250                       HBytes_Value a, HBytes_Value b, int *result) {
251   int al, bl, minl, r;
252
253   al= cht_hb_len(&a);
254   bl= cht_hb_len(&b);
255   minl= al<bl ? al : bl;
256
257   r= memcmp(cht_hb_data(&a), cht_hb_data(&b), minl);
258   
259   if (r<0) *result= -2;
260   else if (r>0) *result= +2;
261   else {
262     if (al<bl) *result= -1;
263     else if (al>bl) *result= +1;
264     else *result= 0;
265   }
266   return TCL_OK;
267 }
268
269 int cht_do_hbytes_range(ClientData cd, Tcl_Interp *ip,
270                     HBytes_Value v, int start, int size,
271                     HBytes_Value *result) {
272   const Byte *data;
273   int l;
274
275   l= cht_hb_len(&v);
276   if (start<0 || size<0)
277     return cht_staticerr(ip,"hbytes range subscript(s) -ve","HBYTES LENGTH RANGE");
278   if (l<start+size)
279     return cht_staticerr(ip, "hbytes range subscripts too big",
280                      "HBYTES LENGTH UNDERRUN");
281
282   data= cht_hb_data(&v);
283   cht_hb_array(result, data+start, size);
284   return TCL_OK;
285 }
286
287 /* hbytes representing uint16_t's */
288
289 int cht_do_hbytes_h2ushort(ClientData cd, Tcl_Interp *ip,
290                        HBytes_Value hex, long *result) {
291   const Byte *data;
292   int l;
293
294   l= cht_hb_len(&hex);
295   if (l>2)
296     return cht_staticerr(ip, "hbytes h2ushort input more than 4 hex digits",
297                      "HBYTES VALUE OVERFLOW");
298
299   data= cht_hb_data(&hex);
300   *result= data[l-1] | (l>1 ? data[0]<<8 : 0);
301   return TCL_OK;
302 }
303
304 int cht_do_hbytes_ushort2h(ClientData cd, Tcl_Interp *ip,
305                        long input, HBytes_Value *result) {
306   uint16_t us;
307
308   if (input > 0x0ffff)
309     return cht_staticerr(ip, "hbytes ushort2h input >2^16",
310                      "HBYTES VALUE OVERFLOW");
311
312   us= htons(input);
313   cht_hb_array(result,(const Byte*)&us,2);
314   return TCL_OK;
315 }
316
317 /* toplevel functions */
318
319 CHT_INIT(hbytes,
320          CHTI_TYPE(cht_hbytes_type) CHTI_TYPE(cht_ulong_type),
321          CHTI_COMMANDS(cht_hbytestoplevel_entries))