chiark / gitweb /
copyright dates
[chiark-tcl.git] / hbytes / hook.c
1 /*
2  * hbytes - hex-stringrep efficient byteblocks for Tcl
3  * Copyright 2006-2012 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   assert(l < INT_MAX/2 - 1 - pl);
77   o->length= l*2+pl;
78   str= o->bytes= TALLOC(o->length+1);
79   
80   memcpy(str,prefix,pl);
81   str += pl;
82
83   while (l>0) {
84     sprintf(str,"%02x",*byte);
85     str+=2; byte++; l--;
86   }
87   *str= 0;
88 }
89
90 void cht_obj_updatestr_array(Tcl_Obj *o, const Byte *byte, int l) {
91   cht_obj_updatestr_array_prefix(o,byte,l,"");
92 }
93
94 static void hbytes_t_ustr(Tcl_Obj *o) {
95   cht_obj_updatestr_array(o,
96                       cht_hb_data(OBJ_HBYTES(o)),
97                       cht_hb_len(OBJ_HBYTES(o)));
98 }
99
100 static int hbytes_t_sfa(Tcl_Interp *ip, Tcl_Obj *o) {
101   char *str, *ep, *os;
102   Byte *startbytes, *bytes;
103   int l;
104   char cbuf[3];
105
106   if (o->typePtr == &cht_ulong_type) {
107     uint32_t ul;
108
109     ul= htonl(*(const uint32_t*)&o->internalRep.longValue);
110     cht_hb_array(OBJ_HBYTES(o), (const Byte*)&ul, 4);
111
112   } else {
113   
114     os= str= Tcl_GetStringFromObj(o,&l);  assert(str);
115     cht_objfreeir(o);
116
117     if (l & 1) return cht_staticerr(ip, "hbytes: conversion from hex:"
118                                 " odd length in hex", "HBYTES SYNTAX");
119
120     startbytes= bytes= cht_hb_arrayspace(OBJ_HBYTES(o), l/2);
121
122     cbuf[2]= 0;
123     while (l>0) {
124       cbuf[0]= *str++;
125       cbuf[1]= *str++;
126       *bytes++= strtoul(cbuf,&ep,16);
127       if (ep != cbuf+2) {
128         cht_hb_free(OBJ_HBYTES(o));
129         return cht_staticerr(ip, "hbytes: conversion from hex:"
130                          " bad hex digit", "HBYTES SYNTAX");
131       }
132       l -= 2;
133     }
134
135   }
136
137   o->typePtr = &cht_hbytes_type;
138   return TCL_OK;
139 }
140
141 Tcl_ObjType cht_hbytes_type = {
142   "hbytes",
143   hbytes_t_free, hbytes_t_dup, hbytes_t_ustr, hbytes_t_sfa
144 };
145
146 int cht_do_hbytes_raw2h(ClientData cd, Tcl_Interp *ip,
147                     Tcl_Obj *binary, HBytes_Value *result) {
148   const unsigned char *str;
149   int l;
150
151   str= Tcl_GetByteArrayFromObj(binary,&l);
152   cht_hb_array(result, str, l);
153   return TCL_OK;
154 }
155
156 int cht_do_hbytes_h2raw(ClientData cd, Tcl_Interp *ip,
157                     HBytes_Value hex, Tcl_Obj **result) {
158   *result= Tcl_NewByteArrayObj(cht_hb_data(&hex), cht_hb_len(&hex));
159   return TCL_OK;
160 }
161
162 int cht_do_hbytes_length(ClientData cd, Tcl_Interp *ip,
163                      HBytes_Value v, int *result) {
164   *result= cht_hb_len(&v);
165   return TCL_OK;
166 }
167
168 int cht_do_hbytes_random(ClientData cd, Tcl_Interp *ip,
169                      int length, HBytes_Value *result) {
170   Byte *space;
171   int rc;
172   
173   space= cht_hb_arrayspace(result, length);
174   rc= cht_get_urandom(ip, space, length);
175   if (rc) { cht_hb_free(result); return rc; }
176   return TCL_OK;
177 }  
178   
179 int cht_do_hbytes_overwrite(ClientData cd, Tcl_Interp *ip,
180                         HBytes_Var v, int start, HBytes_Value sub) {
181   int sub_l;
182
183   sub_l= cht_hb_len(&sub);
184   if (start < 0)
185     return cht_staticerr(ip, "hbytes overwrite start -ve",
186                      "HBYTES LENGTH RANGE");
187   if (start + sub_l > cht_hb_len(v.hb))
188     return cht_staticerr(ip, "hbytes overwrite out of range",
189                      "HBYTES LENGTH UNDERRUN");
190   memcpy(cht_hb_data(v.hb) + start, cht_hb_data(&sub), sub_l);
191   return TCL_OK;
192 }
193
194 int cht_do_hbytes_trimleft(ClientData cd, Tcl_Interp *ip, HBytes_Var v) {
195   const Byte *o, *p, *e;
196   o= p= cht_hb_data(v.hb);
197   e= p + cht_hb_len(v.hb);
198
199   while (p<e && !*p) p++;
200   if (p != o)
201     cht_hb_unprepend(v.hb, p-o);
202
203   return TCL_OK;
204 }
205
206 int cht_do_hbytes_repeat(ClientData cd, Tcl_Interp *ip,
207                      HBytes_Value sub, int count, HBytes_Value *result) {
208   int sub_l;
209   Byte *data;
210   const Byte *sub_d;
211
212   sub_l= cht_hb_len(&sub);
213   if (count < 0) return cht_staticerr(ip, "hbytes repeat count -ve",
214                                   "HBYTES LENGTH RANGE");
215   if (count > INT_MAX/sub_l) return cht_staticerr(ip, "hbytes repeat too long", 0);
216
217   data= cht_hb_arrayspace(result, sub_l*count);
218   sub_d= cht_hb_data(&sub);
219   while (count) {
220     memcpy(data, sub_d, sub_l);
221     count--; data += sub_l;
222   }
223   return TCL_OK;
224 }  
225
226 int cht_do_hbytes_xor(ClientData cd, Tcl_Interp *ip,
227                   HBytes_Var v, HBytes_Value d) {
228   int l;
229   Byte *dest;
230   const Byte *source;
231
232   l= cht_hb_len(v.hb);
233   if (cht_hb_len(&d) != l) return
234     cht_staticerr(ip, "hbytes xor lengths do not match", "HBYTES LENGTH MISMATCH");
235
236   dest= cht_hb_data(v.hb);
237   source= cht_hb_data(&d);
238   memxor(dest,source,l);
239   return TCL_OK;
240 }
241   
242 int cht_do_hbytes_zeroes(ClientData cd, Tcl_Interp *ip,
243                      int length, HBytes_Value *result) {
244   Byte *space;
245   space= cht_hb_arrayspace(result, length);
246   memset(space,0,length);
247   return TCL_OK;
248 }
249
250 int cht_do_hbytes_compare(ClientData cd, Tcl_Interp *ip,
251                       HBytes_Value a, HBytes_Value b, int *result) {
252   int al, bl, minl, r;
253
254   al= cht_hb_len(&a);
255   bl= cht_hb_len(&b);
256   minl= al<bl ? al : bl;
257
258   r= memcmp(cht_hb_data(&a), cht_hb_data(&b), minl);
259   
260   if (r<0) *result= -2;
261   else if (r>0) *result= +2;
262   else {
263     if (al<bl) *result= -1;
264     else if (al>bl) *result= +1;
265     else *result= 0;
266   }
267   return TCL_OK;
268 }
269
270 int cht_do_hbytes_range(ClientData cd, Tcl_Interp *ip,
271                     HBytes_Value v, int start, int size,
272                     HBytes_Value *result) {
273   const Byte *data;
274   int l;
275
276   l= cht_hb_len(&v);
277   if (start<0 || size<0)
278     return cht_staticerr(ip,"hbytes range subscript(s) -ve","HBYTES LENGTH RANGE");
279   if (l<start+size)
280     return cht_staticerr(ip, "hbytes range subscripts too big",
281                      "HBYTES LENGTH UNDERRUN");
282
283   data= cht_hb_data(&v);
284   cht_hb_array(result, data+start, size);
285   return TCL_OK;
286 }
287
288 /* hbytes representing uint16_t's */
289
290 int cht_do_hbytes_h2ushort(ClientData cd, Tcl_Interp *ip,
291                        HBytes_Value hex, long *result) {
292   const Byte *data;
293   int l;
294
295   l= cht_hb_len(&hex);
296   if (l>2)
297     return cht_staticerr(ip, "hbytes h2ushort input more than 4 hex digits",
298                      "HBYTES VALUE OVERFLOW");
299
300   data= cht_hb_data(&hex);
301   *result= data[l-1] | (l>1 ? data[0]<<8 : 0);
302   return TCL_OK;
303 }
304
305 int cht_do_hbytes_ushort2h(ClientData cd, Tcl_Interp *ip,
306                        long input, HBytes_Value *result) {
307   uint16_t us;
308
309   if (input > 0x0ffff)
310     return cht_staticerr(ip, "hbytes ushort2h input >2^16",
311                      "HBYTES VALUE OVERFLOW");
312
313   us= htons(input);
314   cht_hb_array(result,(const Byte*)&us,2);
315   return TCL_OK;
316 }
317
318 /* toplevel functions */
319
320 CHT_INIT(hbytes,
321          CHTI_TYPE(cht_hbytes_type) CHTI_TYPE(cht_ulong_type),
322          CHTI_COMMANDS(cht_hbytestoplevel_entries))