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