chiark / gitweb /
adns compiles ish, working on transferring the rest
[chiark-tcl.git] / hbytes / hook.c
1 /*
2 /* WARNING - FILE COPIED IN REPO TO CHIARK-TCL THEN
3    EDITED - THIS VERSION IS OBSOLETE */
4  */
5
6 #include <errno.h>
7
8 #include "hbytes.h"
9 #include "tables.h"
10
11 int staticerr(Tcl_Interp *ip, const char *m, const char *ec) {
12   Tcl_SetResult(ip, (char*)m, TCL_STATIC);
13   if (ec) Tcl_SetObjErrorCode(ip, Tcl_NewStringObj(ec,-1));
14   return TCL_ERROR;
15 }
16
17 int posixerr(Tcl_Interp *ip, int errnoval, const char *m) {
18   const char *em;
19   
20   Tcl_ResetResult(ip);
21   errno= errnoval;
22   em= Tcl_PosixError(ip);
23   Tcl_AppendResult(ip, m, ": ", em, (char*)0);
24   return TCL_ERROR;
25 }
26
27 int newfdposixerr(Tcl_Interp *ip, int fd, const char *m) {
28   int e;
29   e= errno;
30   close(fd);
31   return posixerr(ip,e,m);
32 }
33
34 void objfreeir(Tcl_Obj *o) {
35   if (o->typePtr && o->typePtr->freeIntRepProc)
36     o->typePtr->freeIntRepProc(o);
37   o->typePtr= 0;
38 }  
39
40 int do_hbytes_rep_info(ClientData cd, Tcl_Interp *ip,
41                        Tcl_Obj *obj, Tcl_Obj **result) {
42   const char *tn;
43   int nums[3], i, lnl;
44   Tcl_Obj *objl[4];
45
46   if (obj->typePtr == &hbytes_type) {
47     HBytes_Value *v= OBJ_HBYTES(obj);
48     memset(nums,0,sizeof(nums));
49     nums[1]= hbytes_len(v);
50   
51     if (HBYTES_ISEMPTY(v)) tn= "empty";
52     else if (HBYTES_ISSENTINEL(v)) tn= "sentinel!";
53     else if (HBYTES_ISSIMPLE(v)) tn= "simple";
54     else {
55       HBytes_ComplexValue *cx= v->begin_complex;
56       tn= "complex";
57       nums[0]= cx->prespace;
58       nums[2]= cx->avail - cx->len;
59     }
60     lnl= 3;
61   } else {
62     tn= "other";
63     lnl= 0;
64   }
65     
66   objl[0]= Tcl_NewStringObj((char*)tn,-1);
67   for (i=0; i<lnl; i++) objl[i+1]= Tcl_NewIntObj(nums[i]);
68   *result= Tcl_NewListObj(lnl+1,objl);
69     
70   return TCL_OK;
71 }
72
73 static void hbytes_t_dup(Tcl_Obj *src, Tcl_Obj *dup) {
74   hbytes_array(OBJ_HBYTES(dup),
75                hbytes_data(OBJ_HBYTES(src)),
76                hbytes_len(OBJ_HBYTES(src)));
77   dup->typePtr= &hbytes_type;
78 }
79
80 static void hbytes_t_free(Tcl_Obj *o) {
81   hbytes_free(OBJ_HBYTES(o));
82 }
83
84 void obj_updatestr_array_prefix(Tcl_Obj *o, const Byte *byte,
85                                 int l, const char *prefix) {
86   char *str;
87   int pl;
88
89   pl= strlen(prefix);
90   o->length= l*2+pl;
91   str= o->bytes= TALLOC(o->length+1);
92   
93   memcpy(str,prefix,pl);
94   str += pl;
95
96   while (l>0) {
97     sprintf(str,"%02x",*byte);
98     str+=2; byte++; l--;
99   }
100   *str= 0;
101 }
102
103 void obj_updatestr_array(Tcl_Obj *o, const Byte *byte, int l) {
104   obj_updatestr_array_prefix(o,byte,l,"");
105 }
106
107 void obj_updatestr_vstringls(Tcl_Obj *o, ...) {
108   va_list al;
109   char *p;
110   const char *part;
111   int l, pl;
112
113   va_start(al,o);
114   for (l=0; (part= va_arg(al, const char*)); )
115     l+= va_arg(al, int);
116   va_end(al);
117   
118   o->length= l;
119   o->bytes= TALLOC(l+1);
120
121   va_start(al,o);
122   for (p= o->bytes; (part= va_arg(al, const char*)); p += pl) {
123     pl= va_arg(al, int);
124     memcpy(p, part, pl);
125   }
126   va_end(al);
127
128   *p= 0;
129 }
130
131 void obj_updatestr_string(Tcl_Obj *o, const char *str) {
132   obj_updatestr_vstringls(o, str, strlen(str), (char*)0);
133 }
134
135 static void hbytes_t_ustr(Tcl_Obj *o) {
136   obj_updatestr_array(o,
137                       hbytes_data(OBJ_HBYTES(o)),
138                       hbytes_len(OBJ_HBYTES(o)));
139 }
140
141 static int hbytes_t_sfa(Tcl_Interp *ip, Tcl_Obj *o) {
142   char *str, *ep, *os;
143   Byte *startbytes, *bytes;
144   int l;
145   char cbuf[3];
146
147   if (o->typePtr == &ulong_type) {
148     uint32_t ul;
149
150     ul= htonl(*(const uint32_t*)&o->internalRep.longValue);
151     hbytes_array(OBJ_HBYTES(o), (const Byte*)&ul, 4);
152
153   } else {
154   
155     os= str= Tcl_GetStringFromObj(o,&l);  assert(str);
156     objfreeir(o);
157
158     if (l & 1) return staticerr(ip, "hbytes: conversion from hex:"
159                                 " odd length in hex", "HBYTES SYNTAX");
160
161     startbytes= bytes= hbytes_arrayspace(OBJ_HBYTES(o), l/2);
162
163     cbuf[2]= 0;
164     while (l>0) {
165       cbuf[0]= *str++;
166       cbuf[1]= *str++;
167       *bytes++= strtoul(cbuf,&ep,16);
168       if (ep != cbuf+2) {
169         hbytes_free(OBJ_HBYTES(o));
170         return staticerr(ip, "hbytes: conversion from hex:"
171                          " bad hex digit", "HBYTES SYNTAX");
172       }
173       l -= 2;
174     }
175
176   }
177
178   o->typePtr = &hbytes_type;
179   return TCL_OK;
180 }
181
182 Tcl_ObjType hbytes_type = {
183   "hbytes",
184   hbytes_t_free, hbytes_t_dup, hbytes_t_ustr, hbytes_t_sfa
185 };
186
187 int do_hbytes_raw2h(ClientData cd, Tcl_Interp *ip,
188                     Tcl_Obj *binary, HBytes_Value *result) {
189   const unsigned char *str;
190   int l;
191
192   str= Tcl_GetByteArrayFromObj(binary,&l);
193   hbytes_array(result, str, l);
194   return TCL_OK;
195 }
196
197 int do_hbytes_h2raw(ClientData cd, Tcl_Interp *ip,
198                     HBytes_Value hex, Tcl_Obj **result) {
199   *result= Tcl_NewByteArrayObj(hbytes_data(&hex), hbytes_len(&hex));
200   return TCL_OK;
201 }
202
203 int do_hbytes_length(ClientData cd, Tcl_Interp *ip,
204                      HBytes_Value v, int *result) {
205   *result= hbytes_len(&v);
206   return TCL_OK;
207 }
208
209 int do_hbytes_random(ClientData cd, Tcl_Interp *ip,
210                      int length, HBytes_Value *result) {
211   Byte *space;
212   int rc;
213   
214   space= hbytes_arrayspace(result, length);
215   rc= get_urandom(ip, space, length);
216   if (rc) { hbytes_free(result); return rc; }
217   return TCL_OK;
218 }  
219   
220 int do_hbytes_overwrite(ClientData cd, Tcl_Interp *ip,
221                         HBytes_Var v, int start, HBytes_Value sub) {
222   int sub_l;
223
224   sub_l= hbytes_len(&sub);
225   if (start < 0)
226     return staticerr(ip, "hbytes overwrite start -ve",
227                      "HBYTES LENGTH RANGE");
228   if (start + sub_l > hbytes_len(v.hb))
229     return staticerr(ip, "hbytes overwrite out of range",
230                      "HBYTES LENGTH UNDERRUN");
231   memcpy(hbytes_data(v.hb) + start, hbytes_data(&sub), sub_l);
232   return TCL_OK;
233 }
234
235 int do_hbytes_trimleft(ClientData cd, Tcl_Interp *ip, HBytes_Var v) {
236   const Byte *o, *p, *e;
237   o= p= hbytes_data(v.hb);
238   e= p + hbytes_len(v.hb);
239
240   while (p<e && !*p) p++;
241   if (p != o)
242     hbytes_unprepend(v.hb, p-o);
243
244   return TCL_OK;
245 }
246
247 int do_hbytes_repeat(ClientData cd, Tcl_Interp *ip,
248                      HBytes_Value sub, int count, HBytes_Value *result) {
249   int sub_l;
250   Byte *data;
251   const Byte *sub_d;
252
253   sub_l= hbytes_len(&sub);
254   if (count < 0) return staticerr(ip, "hbytes repeat count -ve",
255                                   "HBYTES LENGTH RANGE");
256   if (count > INT_MAX/sub_l) return staticerr(ip, "hbytes repeat too long", 0);
257
258   data= hbytes_arrayspace(result, sub_l*count);
259   sub_d= hbytes_data(&sub);
260   while (count) {
261     memcpy(data, sub_d, sub_l);
262     count--; data += sub_l;
263   }
264   return TCL_OK;
265 }  
266
267 int do_hbytes_xor(ClientData cd, Tcl_Interp *ip,
268                   HBytes_Var v, HBytes_Value d) {
269   int l;
270   Byte *dest;
271   const Byte *source;
272
273   l= hbytes_len(v.hb);
274   if (hbytes_len(&d) != l) return
275     staticerr(ip, "hbytes xor lengths do not match", "HBYTES LENGTH MISMATCH");
276
277   dest= hbytes_data(v.hb);
278   source= hbytes_data(&d);
279   memxor(dest,source,l);
280   return TCL_OK;
281 }
282   
283 int do_hbytes_zeroes(ClientData cd, Tcl_Interp *ip,
284                      int length, HBytes_Value *result) {
285   Byte *space;
286   space= hbytes_arrayspace(result, length);
287   memset(space,0,length);
288   return TCL_OK;
289 }
290
291 int do_hbytes_compare(ClientData cd, Tcl_Interp *ip,
292                       HBytes_Value a, HBytes_Value b, int *result) {
293   int al, bl, minl, r;
294
295   al= hbytes_len(&a);
296   bl= hbytes_len(&b);
297   minl= al<bl ? al : bl;
298
299   r= memcmp(hbytes_data(&a), hbytes_data(&b), minl);
300   
301   if (r<0) *result= -2;
302   else if (r>0) *result= +2;
303   else {
304     if (al<bl) *result= -1;
305     else if (al>bl) *result= +1;
306     else *result= 0;
307   }
308   return TCL_OK;
309 }
310
311 int do_hbytes_range(ClientData cd, Tcl_Interp *ip,
312                     HBytes_Value v, int start, int size,
313                     HBytes_Value *result) {
314   const Byte *data;
315   int l;
316
317   l= hbytes_len(&v);
318   if (start<0 || size<0)
319     return staticerr(ip,"hbytes range subscript(s) -ve","HBYTES LENGTH RANGE");
320   if (l<start+size)
321     return staticerr(ip, "hbytes range subscripts too big",
322                      "HBYTES LENGTH UNDERRUN");
323
324   data= hbytes_data(&v);
325   hbytes_array(result, data+start, size);
326   return TCL_OK;
327 }
328
329 int do_hbytes_addr_map(ClientData cd, Tcl_Interp *ip,
330                        const AddrMap_SubCommand *subcmd,
331                        int objc, Tcl_Obj *const *objv) {
332   return subcmd->func(0,ip,objc,objv);
333 }
334
335 /* hbytes representing uint16_t's */
336
337 int do_hbytes_h2ushort(ClientData cd, Tcl_Interp *ip,
338                        HBytes_Value hex, long *result) {
339   const Byte *data;
340   int l;
341
342   l= hbytes_len(&hex);
343   if (l>2)
344     return staticerr(ip, "hbytes h2ushort input more than 4 hex digits",
345                      "HBYTES VALUE OVERFLOW");
346
347   data= hbytes_data(&hex);
348   *result= data[l-1] | (l>1 ? data[0]<<8 : 0);
349   return TCL_OK;
350 }
351
352 int do_hbytes_ushort2h(ClientData cd, Tcl_Interp *ip,
353                        long input, HBytes_Value *result) {
354   uint16_t us;
355
356   if (input > 0x0ffff)
357     return staticerr(ip, "hbytes ushort2h input >2^16",
358                      "HBYTES VALUE OVERFLOW");
359
360   us= htons(input);
361   hbytes_array(result,(const Byte*)&us,2);
362   return TCL_OK;
363 }
364
365 /* toplevel functions */
366
367 int do_toplevel_hbytes(ClientData cd, Tcl_Interp *ip,
368                        const HBytes_SubCommand *subcmd,
369                        int objc, Tcl_Obj *const *objv) {
370   return subcmd->func(0,ip,objc,objv);
371 }
372
373 int do_toplevel_dgram_socket(ClientData cd, Tcl_Interp *ip,
374                              const DgramSocket_SubCommand *subcmd,
375                              int objc, Tcl_Obj *const *objv) {
376   return subcmd->func(0,ip,objc,objv);
377 }
378
379 int do_toplevel_tuntap_socket_raw(ClientData cd, Tcl_Interp *ip,
380                                   const TunSocket_SubCommand *subcmd,
381                                   int objc, Tcl_Obj *const *objv) {
382   return subcmd->func(0,ip,objc,objv);
383 }
384
385 int do_toplevel_ulong(ClientData cd, Tcl_Interp *ip,
386                       const ULong_SubCommand *subcmd,
387                       int objc, Tcl_Obj *const *objv) {
388   return subcmd->func(0,ip,objc,objv);
389 }
390
391 int do_toplevel_adns(ClientData cd, Tcl_Interp *ip,
392                       const Adns_SubCommand *subcmd,
393                       int objc, Tcl_Obj *const *objv) {
394   return subcmd->func(0,ip,objc,objv);
395 }
396
397 #define URANDOM "/dev/urandom"
398
399 int get_urandom(Tcl_Interp *ip, Byte *buffer, int l) {
400   static FILE *urandom;
401
402   int r, esave;
403
404   if (!urandom) {
405     urandom= fopen(URANDOM,"rb");
406     if (!urandom) return posixerr(ip,errno,"open " URANDOM);
407   }
408   r= fread(buffer,1,l,urandom);
409   if (r==l) return 0;
410
411   esave= errno;
412   fclose(urandom); urandom=0;
413
414   if (ferror(urandom)) {
415     return posixerr(ip,errno,"read " URANDOM);
416   } else {
417     assert(feof(urandom));
418     return staticerr(ip, URANDOM " gave eof!", 0);
419   }
420 }
421
422 int Hbytes_Init(Tcl_Interp *ip) {
423   const TopLevel_Command *cmd;
424
425   Tcl_RegisterObjType(&hbytes_type);
426   Tcl_RegisterObjType(&blockcipherkey_type);
427   Tcl_RegisterObjType(&enum_nearlytype);
428   Tcl_RegisterObjType(&enum1_nearlytype);
429   Tcl_RegisterObjType(&sockaddr_type);
430   Tcl_RegisterObjType(&tabledataid_nearlytype);
431   Tcl_RegisterObjType(&ulong_type);
432   Tcl_RegisterObjType(&addrmap_type);
433
434   for (cmd=toplevel_commands;
435        cmd->name;
436        cmd++)
437     Tcl_CreateObjCommand(ip, (char*)cmd->name, cmd->func, 0,0);
438
439   return TCL_OK;
440 }