1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 2002-2013 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Eclipse Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.eclipse.org/org/documents/epl-v10.html *
11 * (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12 * *
13 * Information and Software Systems Research *
14 * AT&T Research *
15 * Florham Park NJ *
16 * *
17 * Glenn Fowler <glenn.s.fowler@gmail.com> *
18 * *
19 ***********************************************************************/
20 #pragma prototyped
21 /*
22 * C expression library open/close and global initialization
23 *
24 * Glenn Fowler
25 * AT&T Research
26 */
27
28 #include "cxlib.h"
29
30 #include <ccode.h>
31
32 typedef struct Type_s
33 {
34 Cxtype_t** state;
35 Cxtype_t type;
36 } Type_t;
37
38 static Cxstate_t state;
39 static Cxtable_t table;
40
41 static const char name_bool[] = "bool";
42 static const char name_buffer[] = "buffer";
43 static const char name_number[] = "number";
44 static const char name_pointer[] = "pointer";
45 static const char name_reference[] = "reference";
46 static const char name_string[] = "string";
47 static const char name_type[] = "type_t";
48 static const char name_void[] = "void";
49
50 static void*
match_string_comp(Cx_t * cx,Cxtype_t * st,Cxtype_t * pt,Cxvalue_t * pv,Cxdisc_t * disc)51 match_string_comp(Cx_t* cx, Cxtype_t* st, Cxtype_t* pt, Cxvalue_t* pv, Cxdisc_t* disc)
52 {
53 regex_t* re;
54
55 if (!cxisstring(pt))
56 {
57 if (disc->errorf)
58 (*disc->errorf)(NiL, disc, 2, "%s: match requires %s pattern", st->name, st->name);
59 return 0;
60 }
61 if (!(re = newof(0, regex_t, 1, 0)))
62 {
63 if (disc->errorf)
64 (*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
65 return 0;
66 }
67 re->re_disc = &cx->redisc;
68 if (regcomp(re, pv->string.data, REG_AUGMENTED|REG_DISCIPLINE))
69 {
70 free(re);
71 return 0;
72 }
73 return re;
74 }
75
76 static int
match_string_exec(Cx_t * cx,void * data,Cxtype_t * st,Cxvalue_t * sv,Cxdisc_t * disc)77 match_string_exec(Cx_t* cx, void* data, Cxtype_t* st, Cxvalue_t* sv, Cxdisc_t* disc)
78 {
79 int i;
80
81 if ((i = regnexec((regex_t*)data, sv->string.data, sv->string.size, 0, NiL, 0)) && i != REG_NOMATCH)
82 i = -1;
83 return i == 0;
84 }
85
86 static int
match_string_free(Cx_t * cx,void * data,Cxdisc_t * disc)87 match_string_free(Cx_t* cx, void* data, Cxdisc_t* disc)
88 {
89 if (data)
90 {
91 regfree((regex_t*)data);
92 free(data);
93 }
94 return 0;
95 }
96
97 static Cxmatch_t match_string =
98 {
99 "regex",
100 "Matches on this type treat the pattern as a regex(3) pattern string.",
101 CXH,
102 match_string_comp,
103 match_string_exec,
104 match_string_free
105 };
106
107 /*
108 * default void externalf
109 */
110
111 static ssize_t
void_external(Cx_t * cx,Cxtype_t * type,const char * details,Cxformat_t * format,Cxvalue_t * value,char * buf,size_t size,Cxdisc_t * disc)112 void_external(Cx_t* cx, Cxtype_t* type, const char* details, Cxformat_t* format, Cxvalue_t* value, char* buf, size_t size, Cxdisc_t* disc)
113 {
114 ssize_t i;
115
116 if (!format)
117 return 0;
118 if (format->width > size)
119 return format->width;
120 for (i = 0; i < format->width; i++)
121 buf[i] = 0;
122 return i;
123 }
124
125 /*
126 * default void internalf
127 */
128
129 static ssize_t
void_internal(Cx_t * cx,Cxtype_t * type,const char * details,Cxformat_t * format,Cxoperand_t * ret,const char * buf,size_t size,Vmalloc_t * vm,Cxdisc_t * disc)130 void_internal(Cx_t* cx, Cxtype_t* type, const char* details, Cxformat_t* format, Cxoperand_t* ret, const char* buf, size_t size, Vmalloc_t* vm, Cxdisc_t* disc)
131 {
132 ret->value.number = 0;
133 return format ? format->width : 0;
134 }
135
136 /*
137 * default number externalf
138 */
139
140 static ssize_t
number_external(Cx_t * cx,Cxtype_t * type,const char * details,Cxformat_t * format,Cxvalue_t * value,char * buf,size_t size,Cxdisc_t * disc)141 number_external(Cx_t* cx, Cxtype_t* type, const char* details, Cxformat_t* format, Cxvalue_t* value, char* buf, size_t size, Cxdisc_t* disc)
142 {
143 ssize_t n;
144 char* f;
145 char fmt[16];
146
147 if (CXDETAILS(details, format, type, 0))
148 n = sfsprintf(buf, size, details, (intmax_t)value->number);
149 else if (value->number == (intmax_t)value->number || (format->flags & CX_INTEGER))
150 {
151 f = fmt;
152 *f++ = '%';
153 if (format)
154 {
155 if (format->width)
156 {
157 if (format->fill > 0)
158 *f++ = format->fill;
159 f += sfsprintf(f, sizeof(fmt) - (f - fmt), "%d", format->width);
160 }
161 *f++ = 'l';
162 *f++ = 'l';
163 *f++ = (format->flags & CX_UNSIGNED) ? 'u' : 'd';
164 }
165 else
166 {
167 *f++ = 'l';
168 *f++ = 'l';
169 *f++ = 'd';
170 }
171 *f = 0;
172 n = sfsprintf(buf, size, fmt, (intmax_t)value->number);
173 }
174 else if (format->width)
175 {
176 int w;
177
178 w = format->width - ((value->number < 0) ? 2 : 1);
179 n = sfsprintf(buf, size, "%#.*I*g", w, sizeof(value->number), value->number);
180 if (n != w)
181 {
182 w += w - n;
183 n = sfsprintf(buf, size, "%#.*I*g", w, sizeof(value->number), value->number);
184 }
185 }
186 else
187 n = sfsprintf(buf, size, "%1.15I*g", sizeof(value->number), value->number);
188 if (n < 0)
189 return -1;
190 if (n > size)
191 return size ? 2 * size : 32;
192 return n;
193 }
194
195 /*
196 * default number internalf
197 */
198
199 static ssize_t
number_internal(Cx_t * cx,Cxtype_t * type,const char * details,Cxformat_t * format,Cxoperand_t * ret,const char * buf,size_t size,Vmalloc_t * vm,Cxdisc_t * disc)200 number_internal(Cx_t* cx, Cxtype_t* type, const char* details, Cxformat_t* format, Cxoperand_t* ret, const char* buf, size_t size, Vmalloc_t* vm, Cxdisc_t* disc)
201 {
202 Cxunsigned_t m;
203 char* e;
204
205 if (size == 0)
206 {
207 ret->value.number = 0;
208 return 0;
209 }
210 if (format && (format->flags & CX_UNSIGNED))
211 ret->value.number = (Cxinteger_t)strntoull(buf, size, &e, format->base);
212 else if (format && format->base)
213 ret->value.number = strntoll(buf, size, &e, format->base);
214 else
215 ret->value.number = strntod(buf, size, &e);
216 if (e != ((char*)buf + size) && *buf)
217 {
218 if (format && format->map && !cxstr2num(cx, format, buf, size, &m))
219 {
220 ret->value.number = (Cxinteger_t)m;
221 return size;
222 }
223 if (disc->errorf && !(cx->flags & CX_QUIET))
224 (*disc->errorf)(cx, disc, 1, "%s: invalid number [(buf+size)=%p e=%p%s base=%d size=%d]", fmtquote(buf, NiL, NiL, size, 0), (char*)buf+size, e, (format && (format->flags & CX_UNSIGNED)) ? " unsigned" : "", format ? format->base : 0, size);
225 }
226 return e - (char*)buf;
227 }
228
229 /*
230 * default bool externalf
231 */
232
233 static ssize_t
bool_external(Cx_t * cx,Cxtype_t * type,const char * details,Cxformat_t * format,Cxvalue_t * value,char * buf,size_t size,Cxdisc_t * disc)234 bool_external(Cx_t* cx, Cxtype_t* type, const char* details, Cxformat_t* format, Cxvalue_t* value, char* buf, size_t size, Cxdisc_t* disc)
235 {
236 return sfsprintf(buf, size, "%c", value->number ? '1' : '0');
237 }
238
239 /*
240 * default bool internalf
241 */
242
243 static ssize_t
bool_internal(Cx_t * cx,Cxtype_t * type,const char * details,Cxformat_t * format,Cxoperand_t * ret,const char * buf,size_t size,Vmalloc_t * vm,Cxdisc_t * disc)244 bool_internal(Cx_t* cx, Cxtype_t* type, const char* details, Cxformat_t* format, Cxoperand_t* ret, const char* buf, size_t size, Vmalloc_t* vm, Cxdisc_t* disc)
245 {
246 Cxunsigned_t m;
247 char* e;
248
249 if (size == 0)
250 {
251 ret->value.number = 0;
252 return 0;
253 }
254 ret->value.number = (Cxinteger_t)strntoull(buf, size, &e, format->base);
255 if (e != ((char*)buf + size) && *buf)
256 {
257 if (format && format->map && !cxstr2num(cx, format, buf, size, &m))
258 {
259 ret->value.number = (Cxinteger_t)m;
260 return size;
261 }
262 if (disc->errorf && !(cx->flags & CX_QUIET))
263 (*disc->errorf)(cx, disc, 1, "%s: invalid bool [(buf+size)=%p e=%p%s base=%d size=%d]", fmtquote(buf, NiL, NiL, size, 0), (char*)buf+size, e, (format && (format->flags & CX_UNSIGNED)) ? " unsigned" : "", format ? format->base : 0, size);
264 }
265 return e - (char*)buf;
266 }
267
268 /*
269 * default string externalf
270 */
271
272 static ssize_t
string_external(Cx_t * cx,Cxtype_t * type,const char * details,register Cxformat_t * format,register Cxvalue_t * value,char * buf,size_t size,Cxdisc_t * disc)273 string_external(Cx_t* cx, Cxtype_t* type, const char* details, register Cxformat_t* format, register Cxvalue_t* value, char* buf, size_t size, Cxdisc_t* disc)
274 {
275 if (format && format->width)
276 {
277 if (format->width > size)
278 return format->width;
279 if (format->width <= value->string.size)
280 memcpy(buf, value->string.data, format->width);
281 else
282 {
283 memcpy(buf, value->string.data, value->string.size);
284 memset(buf + value->string.size, format->fill >= 0 ? format->fill : 0, format->width - value->string.size);
285 }
286 return format->width;
287 }
288 else
289 {
290 if (value->string.size > size)
291 return value->string.size;
292 memcpy(buf, value->string.data, value->string.size);
293 return value->string.size;
294 }
295 }
296
297 /*
298 * default string internalf
299 */
300
301 static ssize_t
string_internal(Cx_t * cx,Cxtype_t * type,const char * details,Cxformat_t * format,Cxoperand_t * ret,const char * buf,size_t size,Vmalloc_t * vm,Cxdisc_t * disc)302 string_internal(Cx_t* cx, Cxtype_t* type, const char* details, Cxformat_t* format, Cxoperand_t* ret, const char* buf, size_t size, Vmalloc_t* vm, Cxdisc_t* disc)
303 {
304 char* s;
305
306 ret->value.string.data = (char*)buf;
307 if ((!format || !(format->flags & CX_NUL) && format->fill <= 0) && (s = memchr(buf, 0, size)))
308 size = s - (char*)buf;
309 return ret->value.string.size = size;
310 }
311
312 /*
313 * default buffer externalf -- mime base64 encode
314 */
315
316 static ssize_t
buffer_external(Cx_t * cx,Cxtype_t * type,const char * details,Cxformat_t * format,Cxvalue_t * value,char * buf,size_t size,Cxdisc_t * disc)317 buffer_external(Cx_t* cx, Cxtype_t* type, const char* details, Cxformat_t* format, Cxvalue_t* value, char* buf, size_t size, Cxdisc_t* disc)
318 {
319 register unsigned char* t;
320 register unsigned char* f;
321 register unsigned char* e;
322 register int v;
323 int z;
324
325 static const char hex[] = "0123456789abcdefg";
326
327 switch (details ? *details : 0)
328 {
329 case 0:
330 case 'b':
331 case 'm':
332 return base64encode(value->buffer.data, value->buffer.size, NiL, buf, size, NiL);
333 case 'h':
334 case 'x':
335 z = value->buffer.size;
336 f = (unsigned char*)value->buffer.data;
337 e = f + z;
338 z *= 2;
339 if (size < z)
340 return z;
341 t = (unsigned char*)buf;
342 while (f < e)
343 {
344 v = *f++;
345 *t++ = hex[v >> 4];
346 *t++ = hex[v & 0xf];
347 }
348 return z;
349 }
350 if (cx->disc->errorf)
351 (*cx->disc->errorf)(cx, cx->disc, ERROR_SYSTEM|2, "%s: unknown buffer representation details", details);
352 return -1;
353 }
354
355 /*
356 * default buffer internalf -- mime base64 decode
357 */
358
359 static ssize_t
buffer_internal(Cx_t * cx,Cxtype_t * type,const char * details,Cxformat_t * format,Cxoperand_t * ret,const char * buf,size_t size,Vmalloc_t * vm,Cxdisc_t * disc)360 buffer_internal(Cx_t* cx, Cxtype_t* type, const char* details, Cxformat_t* format, Cxoperand_t* ret, const char* buf, size_t size, Vmalloc_t* vm, Cxdisc_t* disc)
361 {
362 void* t;
363 size_t n;
364 ssize_t r;
365
366 n = (size * 3) / 4 + 1;
367 if (!vm)
368 vm = Vmregion;
369 if (!(t = vmnewof(vm, 0, unsigned char, n, 0)))
370 {
371 if (disc->errorf)
372 (*disc->errorf)(cx, disc, ERROR_SYSTEM|2, "out of space");
373 return -1;
374 }
375 if ((r = base64decode(buf, size, NiL, t, n, NiL)) > n)
376 vmfree(vm, t);
377 else
378 {
379 ret->value.buffer.data = t;
380 ret->value.buffer.size = r;
381 }
382 return r;
383 }
384
385 /*
386 * type externalf
387 */
388
389 static ssize_t
type_external(Cx_t * cx,Cxtype_t * type,const char * details,register Cxformat_t * format,register Cxvalue_t * value,char * buf,size_t size,Cxdisc_t * disc)390 type_external(Cx_t* cx, Cxtype_t* type, const char* details, register Cxformat_t* format, register Cxvalue_t* value, char* buf, size_t size, Cxdisc_t* disc)
391 {
392 size_t n;
393
394 type = (Cxtype_t*)value->pointer;
395 if ((n = strlen(type->name)) <= size)
396 memcpy(buf, type->name, n);
397 return n;
398 }
399
400 /*
401 * default string internalf
402 */
403
404 static ssize_t
type_internal(Cx_t * cx,Cxtype_t * type,const char * details,Cxformat_t * format,Cxoperand_t * ret,const char * buf,size_t size,Vmalloc_t * vm,Cxdisc_t * disc)405 type_internal(Cx_t* cx, Cxtype_t* type, const char* details, Cxformat_t* format, Cxoperand_t* ret, const char* buf, size_t size, Vmalloc_t* vm, Cxdisc_t* disc)
406 {
407 return -1;
408 }
409
410 #define BT(r,n,s,d,e,i,m) {s,{n,d,CXH,0,0,e,i,r,0,0,0,{0},m},},
411
412 /*
413 * NOTE: void must be first
414 */
415
416 static Type_t types[] =
417 {
418 BT(CX_void, &name_void[0], &state.type_void, "No value. May be used for padding.", void_external, void_internal, 0)
419 BT(CX_number, &name_number[0], &state.type_number, "An integral or floating point number.", number_external, number_internal, 0)
420 BT(CX_string, &name_string[0], &state.type_string, "A string. The format details string specifies quoting and C style character escape processing: \bquote\b[=\achar\a] quotes string with \achar\a (\b\"\b) as the begin and end quote; \bendquote\b=\achar\a changes the \bquote\b end to \achar\a; \bshell\b[=\abeg\a] quotes using shell conventions and \abeg\a (\b$'\b) as the quote begin; \bopt\b performs \bquote\b and \bshell\b quoting only when necessary; \bescape\b assumes that escape processing has already been performed; \bwide\b does not escape characters with the bit 8 set; \bexpand\b=\amask\a expands escaped characters according to \amask\a which may be a \b,\b or \b|\b separated list of \ball\b: expand all escaped chars, \bchar\b expands 7 bit character escapes, \bline\b expands \b\\r\b and \b\\n\b escapes, \bwide\b expands wide character escapes, \bnocr\b eliminates \b\\r\b, and \bnonl\b eliminates \b\\n\b.", string_external, string_internal, &match_string)
421 BT(CX_reference,&name_reference[0],&state.type_reference,"A referenced type.", 0,0,0)
422 BT(CX_buffer, &name_buffer[0], &state.type_buffer, "A separately allocated sized buffer. The external representation is a newline separated base64 mime encoding.", buffer_external, buffer_internal, 0)
423 BT(CX_bool, &name_bool[0], &state.type_bool, "An boolean value: 0==false, 1==true.", bool_external, bool_internal, 0)
424 BT(CX_type, &name_type[0], &state.type_type_t, "A type.", type_external, type_internal, 0)
425 BT(CX_pointer, &name_pointer[0], 0, "A generic pointer.", 0,0,0)
426 };
427
428 #define CX_bool_t ((Cxtype_t*)&name_bool[0])
429 #define CX_buffer_t ((Cxtype_t*)&name_buffer[0])
430 #define CX_number_t ((Cxtype_t*)&name_number[0])
431 #define CX_pointer_t ((Cxtype_t*)&name_pointer[0])
432 #define CX_reference_t ((Cxtype_t*)&name_reference[0])
433 #define CX_string_t ((Cxtype_t*)&name_string[0])
434 #define CX_type_t ((Cxtype_t*)&name_type[0])
435 #define CX_void_t ((Cxtype_t*)&name_void[0])
436
437 static int
op_call_V(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)438 op_call_V(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
439 {
440 return (*pc->data.variable->function)(cx, pc->data.variable, r, b + (pc->pp + 1), -pc->pp, data, disc);
441 }
442
443 static int
op_nop_V(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)444 op_nop_V(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
445 {
446 return 0;
447 }
448
449 static int
op_end_V(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)450 op_end_V(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
451 {
452 /*
453 * NOTE: this special case error return breaks out of the
454 * cxeval() execute() inner loop and is not recorded
455 * as an error
456 */
457
458 return -1;
459 }
460
461 static int
op_ref_V(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)462 op_ref_V(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
463 {
464 return (r->value.variable = cxvariable(cx, b->value.string.data, a->type, disc)) ? 0 : -1;
465 }
466
467 static int
op_sc_V(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)468 op_sc_V(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
469 {
470 if ((pc->op == CX_SC0) == (b->value.number == 0))
471 {
472 cx->jump = (int)pc->data.number;
473 return 1;
474 }
475 return 0;
476 }
477
478 static int
op_const_V(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)479 op_const_V(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
480 {
481 r->value = pc->data;
482 return 0;
483 }
484
485 static int
op_tst_V(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)486 op_tst_V(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
487 {
488 if (cx->disc->errorf)
489 (*cx->disc->errorf)(cx, cx->disc, 2, "CX_TST not implemented yet");
490 return -1;
491 }
492
493 static int
op_add_N(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)494 op_add_N(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
495 {
496 r->value.number = a->value.number + b->value.number;
497 return 0;
498 }
499
500 static int
op_sub_N(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)501 op_sub_N(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
502 {
503 r->value.number = a->value.number - b->value.number;
504 return 0;
505 }
506
507 static int
op_mpy_N(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)508 op_mpy_N(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
509 {
510 r->value.number = a->value.number * b->value.number;
511 return 0;
512 }
513
514 static int
op_div_N(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)515 op_div_N(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
516 {
517 if (b->value.number == 0.0)
518 {
519 if (cx->disc->errorf)
520 (*cx->disc->errorf)(cx, cx->disc, 2, "divide by 0");
521 return -1;
522 }
523 r->value.number = a->value.number / b->value.number;
524 return 0;
525 }
526
527 static int
op_mod_N(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)528 op_mod_N(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
529 {
530 if (b->value.number < 1.0)
531 {
532 if (cx->disc->errorf)
533 (*cx->disc->errorf)(cx, cx->disc, 2, "modulus by number < 1.0");
534 return -1;
535 }
536 r->value.number = a->value.number / b->value.number;
537 r->value.number = (Cxnumber_t)(((Cxinteger_t)a->value.number) % ((Cxinteger_t)b->value.number));
538 return 0;
539 }
540
541 static int
op_and_N(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)542 op_and_N(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
543 {
544 r->value.number = (Cxnumber_t)(((Cxinteger_t)a->value.number) & ((Cxinteger_t)b->value.number));
545 return 0;
546 }
547
548 static int
op_or_N(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)549 op_or_N(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
550 {
551 r->value.number = (Cxnumber_t)(((Cxinteger_t)a->value.number) | ((Cxinteger_t)b->value.number));
552 return 0;
553 }
554
555 static int
op_xor_N(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)556 op_xor_N(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
557 {
558 r->value.number = (Cxnumber_t)(((Cxinteger_t)a->value.number) ^ ((Cxinteger_t)b->value.number));
559 return 0;
560 }
561
562 static int
op_andand_L(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)563 op_andand_L(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
564 {
565 r->value.number = a->value.number > 0 && b->value.number > 0;
566 return 0;
567 }
568
569 static int
op_oror_L(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)570 op_oror_L(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
571 {
572 r->value.number = a->value.number > 0 || b->value.number > 0;
573 return 0;
574 }
575
576 static int
op_lsh_N(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)577 op_lsh_N(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
578 {
579 r->value.number = (Cxnumber_t)(((Cxinteger_t)a->value.number) << ((int)b->value.number));
580 return 0;
581 }
582
583 static int
op_rsh_N(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)584 op_rsh_N(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
585 {
586 r->value.number = (Cxnumber_t)(((Cxinteger_t)a->value.number) >> ((int)b->value.number));
587 return 0;
588 }
589
590 static int
op_inv_L(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)591 op_inv_L(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
592 {
593 r->value.number = (Cxnumber_t)(~((Cxinteger_t)a->value.number));
594 return 0;
595 }
596
597 static int
op_log_N(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)598 op_log_N(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
599 {
600 r->value.number = b->value.number > 0.0;
601 return 0;
602 }
603
604 static int
op_not_L(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)605 op_not_L(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
606 {
607 r->value.number = b->value.number == 0.0;
608 return 0;
609 }
610
611 static int
op_uplus_N(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)612 op_uplus_N(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
613 {
614 r->value.number = b->value.number;
615 return 0;
616 }
617
618 static int
op_uminus_N(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)619 op_uminus_N(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
620 {
621 r->value.number = -b->value.number;
622 return 0;
623 }
624
625 static int
op_lt_N(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)626 op_lt_N(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
627 {
628 r->value.number = a->value.number < b->value.number;
629 return 0;
630 }
631
632 static int
op_le_N(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)633 op_le_N(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
634 {
635 r->value.number = a->value.number <= b->value.number;
636 return 0;
637 }
638
639 static int
op_eq_N(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)640 op_eq_N(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
641 {
642 r->value.number = a->value.number == b->value.number;
643 return 0;
644 }
645
646 static int
op_ne_N(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)647 op_ne_N(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
648 {
649 r->value.number = a->value.number != b->value.number;
650 return 0;
651 }
652
653 static int
op_ge_N(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)654 op_ge_N(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
655 {
656 r->value.number = a->value.number >= b->value.number;
657 return 0;
658 }
659
660 static int
op_gt_N(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)661 op_gt_N(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
662 {
663 r->value.number = a->value.number > b->value.number;
664 return 0;
665 }
666
667 static int
op_log_S(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)668 op_log_S(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
669 {
670 r->value.number = b->value.string.size > 0 && b->value.string.data[0] != 0;
671 return 0;
672 }
673
674 static int
op_lt_S(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)675 op_lt_S(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
676 {
677 int c;
678
679 r->value.number = (c = strncmp(a->value.string.data, b->value.string.data, CXMIN(a->value.string.size, b->value.string.size))) < 0 || c == 0 && a->value.string.size < b->value.string.size;
680 return 0;
681 }
682
683 static int
op_le_S(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)684 op_le_S(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
685 {
686 int c;
687
688 r->value.number = (c = strncmp(a->value.string.data, b->value.string.data, CXMIN(a->value.string.size, b->value.string.size))) < 0 || c == 0 && a->value.string.size == b->value.string.size;
689 return 0;
690 }
691
692 static int
op_eq_S(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)693 op_eq_S(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
694 {
695 r->value.number = a->value.string.size == b->value.string.size && strncmp(a->value.string.data, b->value.string.data, a->value.string.size) == 0;
696 return 0;
697 }
698
699 static int
op_ne_S(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)700 op_ne_S(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
701 {
702 r->value.number = a->value.string.size != b->value.string.size || strncmp(a->value.string.data, b->value.string.data, a->value.string.size) != 0;
703 return 0;
704 }
705
706 static int
op_ge_S(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)707 op_ge_S(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
708 {
709 int c;
710
711 r->value.number = (c = strncmp(a->value.string.data, b->value.string.data, CXMIN(a->value.string.size, b->value.string.size))) > 0 || c == 0 && a->value.string.size > b->value.string.size;
712 return 0;
713 }
714
715 static int
op_gt_S(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)716 op_gt_S(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
717 {
718 int c;
719
720 r->value.number = (c = strncmp(a->value.string.data, b->value.string.data, CXMIN(a->value.string.size, b->value.string.size))) > 0 || c == 0 && a->value.string.size > b->value.string.size;
721 return 0;
722 }
723
724 static int
op_not_S(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)725 op_not_S(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
726 {
727 r->value.number = *b->value.string.data == 0;
728 return 0;
729 }
730
731 static int
op_lt_B(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)732 op_lt_B(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
733 {
734 int c;
735
736 r->value.number = (c = memcmp(a->value.buffer.data, b->value.buffer.data, CXMIN(a->value.buffer.size, b->value.buffer.size))) < 0 || c == 0 && a->value.buffer.size < b->value.buffer.size;
737 return 0;
738 }
739
740 static int
op_le_B(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)741 op_le_B(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
742 {
743 int c;
744
745 r->value.number = (c = memcmp(a->value.buffer.data, b->value.buffer.data, CXMIN(a->value.buffer.size, b->value.buffer.size))) < 0 || c == 0 && a->value.buffer.size == b->value.buffer.size;
746 return 0;
747 }
748
749 static int
op_eq_B(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)750 op_eq_B(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
751 {
752 r->value.number = a->value.buffer.size == b->value.buffer.size && memcmp(a->value.buffer.data, b->value.buffer.data, a->value.buffer.size) == 0;
753 return 0;
754 }
755
756 static int
op_ne_B(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)757 op_ne_B(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
758 {
759 r->value.number = a->value.buffer.size != b->value.buffer.size || memcmp(a->value.buffer.data, b->value.buffer.data, a->value.buffer.size) != 0;
760 return 0;
761 }
762
763 static int
op_ge_B(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)764 op_ge_B(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
765 {
766 int c;
767
768 r->value.number = (c = memcmp(a->value.buffer.data, b->value.buffer.data, CXMIN(a->value.buffer.size, b->value.buffer.size))) > 0 || c == 0 && a->value.buffer.size > b->value.buffer.size;
769 return 0;
770 }
771
772 static int
op_gt_B(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)773 op_gt_B(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
774 {
775 int c;
776
777 r->value.number = (c = memcmp(a->value.buffer.data, b->value.buffer.data, CXMIN(a->value.buffer.size, b->value.buffer.size))) > 0 || c == 0 && a->value.buffer.size > b->value.buffer.size;
778 return 0;
779 }
780
781 static int
op_log_B(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)782 op_log_B(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
783 {
784 r->value.number = b->value.buffer.data && b->value.buffer.size;
785 return 0;
786 }
787
788 static int
op_not_B(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)789 op_not_B(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
790 {
791 r->value.number = b->value.buffer.size == 0;
792 return 0;
793 }
794
795 static int
op_eq_T(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)796 op_eq_T(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
797 {
798 r->value.number = a->value.type == b->value.type;
799 return 0;
800 }
801
802 static int
op_ne_T(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)803 op_ne_T(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
804 {
805 r->value.number = a->type != b->type;
806 return 0;
807 }
808
809 static int
op_cast_SN(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)810 op_cast_SN(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
811 {
812 char* e;
813
814 r->value.number = strtod(b->value.string.data, &e);
815 if (*e && cx->disc->errorf)
816 (*cx->disc->errorf)(cx, cx->disc, 2, "%s: invalid number", b->value.string.data);
817 return 0;
818 }
819
820 static int
op_cast_BL(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)821 op_cast_BL(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
822 {
823 r->value.number = b->value.buffer.data && b->value.buffer.size;
824 return 0;
825 }
826
827 static int
op_cast_SL(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)828 op_cast_SL(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
829 {
830 r->value.number = b->value.string.data && b->value.string.size && *b->value.string.data;
831 return 0;
832 }
833
834 static int
op_cast_BN(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)835 op_cast_BN(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
836 {
837 r->value.number = !!b->value.buffer.data;
838 return 0;
839 }
840
841 static int
op_cast_BS(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)842 op_cast_BS(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
843 {
844 r->value.string.data = b->value.buffer.data ? "1" : "0";
845 r->value.string.size = 1;
846 return 0;
847 }
848
849 static int
op_match(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)850 op_match(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
851 {
852 int i;
853
854 if ((i = (*a->type->match->execf)(cx, pc->data.pointer, a->type, &a->value, disc)) < 0)
855 return i;
856 r->value.number = i == 1;
857 return 0;
858 }
859
860 static int
op_nomatch(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)861 op_nomatch(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
862 {
863 int i;
864
865 if ((i = (*a->type->match->execf)(cx, pc->data.pointer, a->type, &a->value, disc)) < 0)
866 return i;
867 r->value.number = i == 0;
868 return 0;
869 }
870
871 static int
re_match(Cx_t * cx,Cxexpr_t * expr,Cxinstruction_t * x,Cxinstruction_t * a,Cxinstruction_t * b,void * data,Cxdisc_t * disc)872 re_match(Cx_t* cx, Cxexpr_t* expr, Cxinstruction_t* x, Cxinstruction_t* a, Cxinstruction_t* b, void* data, Cxdisc_t* disc)
873 {
874 if (!(x->data.pointer = (*a->type->match->compf)(cx, a->type, b->type, &b->data, disc)))
875 return -1;
876 if (a->type->match->freef && cxatfree(cx, expr, a->type->match->freef, x->data.pointer))
877 {
878 (*a->type->match->freef)(cx, x->data.pointer, disc);
879 return -1;
880 }
881 b->type = state.type_void;
882 x->callout = x->op == CX_MATCH ? op_match : op_nomatch;
883 return 0;
884 }
885
886 static Cxcallout_t callouts[] =
887 {
888
889 CXC(CX_CALL, CX_void_t, CX_void_t, op_call_V, 0)
890 CXC(CX_NOP, CX_void_t, CX_void_t, op_nop_V, 0)
891 CXC(CX_POP, CX_void_t, CX_void_t, op_nop_V, 0)
892 CXC(CX_REF, CX_reference_t, CX_void_t, op_const_V, 0)
893 CXC(CX_REF, CX_string_t, CX_void_t, op_ref_V, 0)
894 CXC(CX_SC0, CX_bool_t, CX_void_t, op_sc_V, 0)
895 CXC(CX_SC1, CX_bool_t, CX_void_t, op_sc_V, 0)
896 CXC(CX_SC0, CX_number_t, CX_void_t, op_sc_V, 0)
897 CXC(CX_SC1, CX_number_t, CX_void_t, op_sc_V, 0)
898 CXC(CX_TST, CX_void_t, CX_void_t, op_tst_V, 0)
899 CXC(CX_END, CX_void_t, CX_void_t, op_end_V, 0)
900
901 CXC(CX_NUM, CX_number_t, CX_void_t, op_const_V, 0)
902 CXC(CX_STR, CX_string_t, CX_void_t, op_const_V, 0)
903 CXC(CX_NUM, CX_type_t, CX_void_t, op_const_V, 0)
904
905 CXC(CX_ADD, CX_number_t, CX_number_t, op_add_N, 0)
906 CXC(CX_SUB, CX_number_t, CX_number_t, op_sub_N, 0)
907 CXC(CX_MPY, CX_number_t, CX_number_t, op_mpy_N, 0)
908 CXC(CX_DIV, CX_number_t, CX_number_t, op_div_N, 0)
909 CXC(CX_MOD, CX_number_t, CX_number_t, op_mod_N, 0)
910 CXC(CX_AND, CX_number_t, CX_number_t, op_and_N, 0)
911 CXC(CX_OR, CX_number_t, CX_number_t, op_or_N, 0)
912 CXC(CX_XOR, CX_number_t, CX_number_t, op_xor_N, 0)
913
914 CXC(CX_ANDAND, CX_bool_t, CX_bool_t, op_andand_L, 0)
915 CXC(CX_OROR, CX_bool_t, CX_bool_t, op_oror_L, 0)
916 CXC(CX_INV, CX_bool_t, CX_void_t, op_inv_L, 0)
917 CXC(CX_NOT, CX_bool_t, CX_void_t, op_not_L, 0)
918
919 CXC(CX_ANDAND, CX_number_t, CX_number_t, op_andand_L, 0)
920 CXC(CX_OROR, CX_number_t, CX_number_t, op_oror_L, 0)
921 CXC(CX_INV, CX_number_t, CX_void_t, op_inv_L, 0)
922 CXC(CX_NOT, CX_number_t, CX_void_t, op_not_L, 0)
923
924 CXC(CX_LSH, CX_number_t, CX_number_t, op_lsh_N, 0)
925 CXC(CX_RSH, CX_number_t, CX_number_t, op_rsh_N, 0)
926
927 CXC(CX_UPLUS, CX_number_t, CX_void_t, op_uplus_N, 0)
928 CXC(CX_UMINUS, CX_number_t, CX_void_t, op_uminus_N, 0)
929
930 CXC(CX_LT, CX_number_t, CX_number_t, op_lt_N, 0)
931 CXC(CX_LE, CX_number_t, CX_number_t, op_le_N, 0)
932 CXC(CX_EQ, CX_number_t, CX_number_t, op_eq_N, 0)
933 CXC(CX_NE, CX_number_t, CX_number_t, op_ne_N, 0)
934 CXC(CX_GE, CX_number_t, CX_number_t, op_ge_N, 0)
935 CXC(CX_GT, CX_number_t, CX_number_t, op_gt_N, 0)
936
937 CXC(CX_LT, CX_string_t, CX_string_t, op_lt_S, 0)
938 CXC(CX_LE, CX_string_t, CX_string_t, op_le_S, 0)
939 CXC(CX_EQ, CX_string_t, CX_string_t, op_eq_S, 0)
940 CXC(CX_NE, CX_string_t, CX_string_t, op_ne_S, 0)
941 CXC(CX_GE, CX_string_t, CX_string_t, op_ge_S, 0)
942 CXC(CX_GT, CX_string_t, CX_string_t, op_gt_S, 0)
943
944 CXC(CX_LT, CX_buffer_t, CX_buffer_t, op_lt_B, 0)
945 CXC(CX_LE, CX_buffer_t, CX_buffer_t, op_le_B, 0)
946 CXC(CX_EQ, CX_buffer_t, CX_buffer_t, op_eq_B, 0)
947 CXC(CX_NE, CX_buffer_t, CX_buffer_t, op_ne_B, 0)
948 CXC(CX_GE, CX_buffer_t, CX_buffer_t, op_ge_B, 0)
949 CXC(CX_GT, CX_buffer_t, CX_buffer_t, op_gt_B, 0)
950
951 CXC(CX_EQ, CX_type_t, CX_type_t, op_eq_T, 0)
952 CXC(CX_NE, CX_type_t, CX_type_t, op_ne_T, 0)
953
954 CXC(CX_CAST, CX_string_t, CX_bool_t, op_cast_SL, 0)
955 CXC(CX_CAST, CX_buffer_t, CX_bool_t, op_cast_BL, 0)
956 CXC(CX_CAST, CX_string_t, CX_number_t, op_cast_SN, 0)
957 CXC(CX_CAST, CX_buffer_t, CX_number_t, op_cast_BN, 0)
958 CXC(CX_CAST, CX_buffer_t, CX_string_t, op_cast_BS, 0)
959
960 };
961
962 size_t
cxsizeof(Cx_t * cx,Cxvariable_t * var,Cxtype_t * type,Cxvalue_t * value)963 cxsizeof(Cx_t* cx, Cxvariable_t* var, Cxtype_t* type, Cxvalue_t* value)
964 {
965 size_t size;
966
967 if (var->array)
968 size = var->array->size;
969 else
970 do
971 {
972 if (size = type->size)
973 break;
974 switch (type->representation)
975 {
976 case CX_buffer:
977 if (size = value->buffer.size)
978 {
979 if (value->buffer.elements)
980 size = value->buffer.elements;
981 else if (type->element)
982 size /= type->element;
983 }
984 break;
985 case CX_number:
986 case CX_pointer:
987 size = 8;
988 break;
989 case CX_string:
990 size = value->string.size;
991 break;
992 default:
993 continue;
994 }
995 break;
996 } while (type = type->base);
997 return size;
998 }
999
1000 static int
cx_edit_B(Cx_t * cx,Cxvariable_t * var,Cxoperand_t * ret,Cxoperand_t * arg,int n,void * data,Cxdisc_t * disc)1001 cx_edit_B(Cx_t* cx, Cxvariable_t* var, Cxoperand_t* ret, Cxoperand_t* arg, int n, void* data, Cxdisc_t* disc)
1002 {
1003 Cxedit_t* edit;
1004
1005 if (!(edit = cxedit(cx, arg[0].value.string.data, disc)))
1006 return -1;
1007 ret->value = arg[1].value;
1008 return cxsub(cx, edit, ret);
1009 }
1010
1011 static int
cx_sizeof_B(Cx_t * cx,Cxvariable_t * var,Cxoperand_t * ret,Cxoperand_t * arg,int n,void * data,Cxdisc_t * disc)1012 cx_sizeof_B(Cx_t* cx, Cxvariable_t* var, Cxoperand_t* ret, Cxoperand_t* arg, int n, void* data, Cxdisc_t* disc)
1013 {
1014 ret->value.number = cxsizeof(cx, var, arg->type, &arg->value);
1015 return 0;
1016 }
1017
1018 static int
cx_typeof_B(Cx_t * cx,Cxvariable_t * var,Cxoperand_t * ret,Cxoperand_t * arg,int n,void * data,Cxdisc_t * disc)1019 cx_typeof_B(Cx_t* cx, Cxvariable_t* var, Cxoperand_t* ret, Cxoperand_t* arg, int n, void* data, Cxdisc_t* disc)
1020 {
1021 ret->value.type = arg->type;
1022 return 0;
1023 }
1024
1025 static Cxvariable_t builtins[] =
1026 {
1027 CXF("edit", "string", cx_edit_B, "string,string",
1028 "Returns the result of applying the ed(1) style substitute expression"
1029 " in the first argument to the second argument.")
1030 CXF("sizeof", "number", cx_sizeof_B, "*",
1031 "Returns the size of the \avariable\a argument;"
1032 " the size of an array variable is the number of elements,"
1033 " otherwise the size is in bytes.")
1034 CXF("typeof", "type_t", cx_typeof_B, "*",
1035 "Returns the type of the \avariable\a argument"
1036 " for comparison with other types.")
1037 };
1038
1039 /*
1040 * open a cx session
1041 */
1042
1043 Cx_t*
cxopen(Cxflags_t flags,Cxflags_t test,Cxdisc_t * disc)1044 cxopen(Cxflags_t flags, Cxflags_t test, Cxdisc_t* disc)
1045 {
1046 register Cx_t* cx;
1047 register Vmalloc_t* vm;
1048 register Vmalloc_t* em;
1049 register Vmalloc_t* rm;
1050
1051 if (!(vm = vmopen(Vmdcheap, Vmbest, 0)) || !(em = vmopen(Vmdcheap, Vmlast, 0)) || !(rm = vmopen(Vmdcheap, Vmlast, 0)))
1052 {
1053 if (vm)
1054 {
1055 vmclose(vm);
1056 if (em)
1057 vmclose(em);
1058 }
1059 if (disc->errorf)
1060 (*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
1061 return 0;
1062 }
1063 if (!(cx = vmnewof(vm, 0, Cx_t, 1, 0)) || !(cx->cvtbuf = vmnewof(vm, 0, char, cx->cvtsiz = CX_CVT, 0)))
1064 {
1065 if (disc->errorf)
1066 (*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
1067 goto bad;
1068 }
1069 cx->state = cxstate(disc);
1070 cx->table = &table;
1071 cx->id = CX_ID;
1072 cx->vm = vm;
1073 cx->em = em;
1074 cx->rm = rm;
1075 cx->disc = disc;
1076 cx->flags = flags;
1077 cx->test = test;
1078 cx->redisc.re_version = REG_VERSION;
1079 cx->redisc.re_flags = REG_NOFREE;
1080 cx->redisc.re_errorf = (regerror_t)disc->errorf;
1081 if (!(cx->buf = sfstropen()) || !(cx->tp = sfstropen()))
1082 {
1083 cxclose(cx);
1084 return 0;
1085 }
1086 cx->scoped = 1;
1087 if (!(flags & CX_SCOPE))
1088 {
1089 cx->op = sfstdout;
1090 if (!(cx->fields = dtnew(cx->vm, &state.listdisc, Dtqueue)) || !(cx->buf = sfstropen()) || !(cx->tp = sfstropen()))
1091 {
1092 cxclose(cx);
1093 return 0;
1094 }
1095 cx->callouts = state.callouts;
1096 cx->constraints = state.constraints;
1097 cx->edits = state.edits;
1098 cx->maps = state.maps;
1099 cx->queries = state.queries;
1100 cx->recodes = state.recodes;
1101 cx->types = state.types;
1102 cx->variables = state.variables;
1103 }
1104 cx->ctype = state.ctype;
1105 return cx;
1106 bad:
1107 vmclose(vm);
1108 vmclose(em);
1109 vmclose(rm);
1110 return 0;
1111 }
1112
1113 /*
1114 * scope control
1115 */
1116
1117 Cx_t*
cxscope(Cx_t * top,Cx_t * bot,Cxflags_t flags,Cxflags_t test,Cxdisc_t * disc)1118 cxscope(Cx_t* top, Cx_t* bot, Cxflags_t flags, Cxflags_t test, Cxdisc_t* disc)
1119 {
1120 if (!top)
1121 {
1122 if (!(top = cxopen(CX_SCOPE|flags, test, disc)))
1123 return 0;
1124 top->op = sfstdout;
1125 }
1126 if (top->scoped != 1)
1127 {
1128 if (top->disc->errorf)
1129 (*top->disc->errorf)(NiL, top->disc, 2, "cannot change active scope");
1130 return 0;
1131 }
1132 if (bot)
1133 {
1134 /*
1135 * scope top on bot
1136 */
1137
1138 if (top->scope)
1139 {
1140 if (top->disc->errorf)
1141 (*top->disc->errorf)(NiL, top->disc, 2, "already scoped");
1142 return 0;
1143 }
1144 if (top->view & CX_VIEW_callouts)
1145 dtview(top->callouts, bot->callouts);
1146 else
1147 top->callouts = bot->callouts;
1148 if (top->view & CX_VIEW_constraints)
1149 dtview(top->constraints, bot->constraints);
1150 else
1151 top->constraints = bot->constraints;
1152 if (top->view & CX_VIEW_edits)
1153 dtview(top->edits, bot->edits);
1154 else
1155 top->edits = bot->edits;
1156 if (top->view & CX_VIEW_fields)
1157 dtview(top->fields, bot->fields);
1158 else
1159 top->fields = bot->fields;
1160 if (top->view & CX_VIEW_maps)
1161 dtview(top->maps, bot->maps);
1162 else
1163 top->maps = bot->maps;
1164 if (top->view & CX_VIEW_queries)
1165 dtview(top->queries, bot->queries);
1166 else
1167 top->queries = bot->queries;
1168 if (top->view & CX_VIEW_recodes)
1169 dtview(top->recodes, bot->recodes);
1170 else
1171 top->recodes = bot->recodes;
1172 if (top->view & CX_VIEW_types)
1173 dtview(top->types, bot->types);
1174 else
1175 top->types = bot->types;
1176 if (top->view & CX_VIEW_variables)
1177 dtview(top->variables, bot->variables);
1178 else
1179 top->variables = bot->variables;
1180 bot->scoped++;
1181 top->scope = bot;
1182 bot = top;
1183 }
1184 else if (bot = top->scope)
1185 {
1186 /*
1187 * pop the scope
1188 */
1189
1190 if (top->view & CX_VIEW_callouts)
1191 dtview(top->callouts, NiL);
1192 if (top->view & CX_VIEW_constraints)
1193 dtview(top->constraints, NiL);
1194 if (top->view & CX_VIEW_edits)
1195 dtview(top->edits, NiL);
1196 if (top->view & CX_VIEW_fields)
1197 dtview(top->fields, NiL);
1198 if (top->view & CX_VIEW_maps)
1199 dtview(top->maps, NiL);
1200 if (top->view & CX_VIEW_queries)
1201 dtview(top->queries, NiL);
1202 if (top->view & CX_VIEW_recodes)
1203 dtview(top->recodes, NiL);
1204 if (top->view & CX_VIEW_types)
1205 dtview(top->types, NiL);
1206 if (top->view & CX_VIEW_variables)
1207 dtview(top->variables, NiL);
1208 top->scope = 0;
1209 bot->scoped--;
1210 }
1211 else
1212 bot = top;
1213 return bot;
1214 }
1215
1216 /*
1217 * close a cx session
1218 */
1219
1220 int
cxclose(register Cx_t * cx)1221 cxclose(register Cx_t* cx)
1222 {
1223 if (!cx)
1224 return -1;
1225 if (cx->scope)
1226 cxscope(cx, NiL, 0, 0, cx->disc);
1227 if (--cx->scoped <= 0)
1228 {
1229 if (cx->view & CX_VIEW_callouts)
1230 dtclose(cx->callouts);
1231 if (cx->view & CX_VIEW_constraints)
1232 dtclose(cx->constraints);
1233 if (cx->view & CX_VIEW_edits)
1234 dtclose(cx->edits);
1235 if (cx->view & CX_VIEW_maps)
1236 dtclose(cx->maps);
1237 if (cx->view & CX_VIEW_queries)
1238 dtclose(cx->queries);
1239 if (cx->view & CX_VIEW_recodes)
1240 dtclose(cx->recodes);
1241 if (cx->view & CX_VIEW_types)
1242 dtclose(cx->types);
1243 if (cx->view & CX_VIEW_fields)
1244 dtclose(cx->fields);
1245 if (cx->view & CX_VIEW_variables)
1246 dtclose(cx->variables);
1247 if (cx->scope)
1248 cx->scope->scoped--;
1249 if (cx->buf)
1250 sfclose(cx->buf);
1251 if (cx->tp)
1252 sfclose(cx->tp);
1253 if (cx->em)
1254 vmclose(cx->em);
1255 if (cx->rm)
1256 vmclose(cx->rm);
1257 if (cx->vm)
1258 vmclose(cx->vm);
1259 }
1260 return 0;
1261 }
1262
1263 /*
1264 * add a type
1265 */
1266
1267 int
cxaddtype(Cx_t * cx,register Cxtype_t * type,Cxdisc_t * disc)1268 cxaddtype(Cx_t* cx, register Cxtype_t* type, Cxdisc_t* disc)
1269 {
1270 char* base;
1271 Cxvariable_t* v;
1272 Cxvariable_t* member;
1273 Dt_t* dict;
1274 Cxtype_t* copy;
1275 Cxrecode_t* re;
1276 int i;
1277
1278 if (cx)
1279 {
1280 disc = cx->disc;
1281 if (cx->view & CX_VIEW_types)
1282 dict = cx->types;
1283 else if (!(dict = dtnew(cx->vm, &state.namedisc, Dtoset)))
1284 {
1285 if (disc->errorf)
1286 (*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
1287 return -1;
1288 }
1289 else
1290 {
1291 dtview(dict, cx->types);
1292 cx->types = dict;
1293 cx->view |= CX_VIEW_types;
1294 }
1295 if (!(copy = vmnewof(cx->vm, 0, Cxtype_t, 1, 0)))
1296 {
1297 if (disc->errorf)
1298 (*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
1299 return -1;
1300 }
1301 *copy = *type;
1302 type = copy;
1303 }
1304 else
1305 dict = state.types;
1306 if (dtsearch(dict, type))
1307 {
1308 if (disc->errorf)
1309 (*disc->errorf)(NiL, disc, 2, "%s: type already defined", type->name);
1310 return -1;
1311 }
1312 dtinsert(dict, type);
1313 if (!(type->header.flags & CX_NORMALIZED))
1314 {
1315 type->header.flags |= CX_NORMALIZED;
1316 if ((base = (char*)type->base) && !(type->base = cxtype(cx, base, disc)))
1317 {
1318 if (disc->errorf)
1319 (*disc->errorf)(NiL, disc, 2, "%s: unknown base type", base);
1320 return -1;
1321 }
1322 if ((base = (char*)type->fundamental) && !(type->fundamental = cxtype(cx, base, disc)))
1323 {
1324 if (disc->errorf)
1325 (*disc->errorf)(NiL, disc, 2, "%s: unknown fundamental type", base);
1326 return -1;
1327 }
1328 if (type->member)
1329 {
1330 if (!type->member->getf)
1331 {
1332 if (disc->errorf)
1333 (*disc->errorf)(NiL, disc, 2, "%s: no member get function", type->name);
1334 return -1;
1335 }
1336 if (!(member = (Cxvariable_t*)type->member->members))
1337 {
1338 if (disc->errorf)
1339 (*disc->errorf)(NiL, disc, 2, "%s: no member table", type->name);
1340 return -1;
1341 }
1342 if (type->header.flags & CX_SCHEMA)
1343 type->header.flags |= CX_REFERENCED;
1344 else if (!(type->member->members = cx ? dtnew(cx->vm, &state.namedisc, Dtoset) : dtopen(&state.namedisc, Dtoset)))
1345 {
1346 if (disc->errorf)
1347 (*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
1348 return -1;
1349 }
1350 else
1351 for (i = 0; member->name; member++)
1352 {
1353 v = member;
1354 if (!(v->header.flags & CX_NORMALIZED))
1355 {
1356 v->header.flags |= CX_NORMALIZED;
1357 if ((base = (char*)v->type) && !(v->type = cxtype(cx, base, disc)))
1358 {
1359 if (disc->errorf)
1360 (*disc->errorf)(NiL, disc, 2, "%s: unknown type", base);
1361 return -1;
1362 }
1363 v->member = type;
1364 }
1365 v->header.index = i++;
1366 dtinsert(type->member->members, v);
1367 }
1368 }
1369 if (type->generic)
1370 for (i = 0; base = (char*)type->generic[i]; i++)
1371 if (!(type->generic[i] = cxtype(cx, base, disc)))
1372 {
1373 if (disc->errorf)
1374 (*disc->errorf)(NiL, disc, 2, "%s: unknown type", base);
1375 return -1;
1376 }
1377 }
1378 if (!(type->header.flags & CX_INITIALIZED))
1379 {
1380 type->header.flags |= CX_INITIALIZED;
1381 if (type->fundamental)
1382 {
1383 if (type->base)
1384 type->representation = type->base->representation;
1385 }
1386 else if (!type->base)
1387 type->fundamental = type;
1388 else
1389 {
1390 type->fundamental = type->base->fundamental;
1391 type->representation = type->base->representation;
1392 }
1393 if (type->match)
1394 {
1395 if (!(re = newof(0, Cxrecode_t, 1, 0)))
1396 {
1397 if (disc->errorf)
1398 (*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
1399 return -1;
1400 }
1401 re->header.flags = CX_NORMALIZED;
1402 re->op.code = CX_MATCH;
1403 re->op.type1 = type;
1404 re->op.type2 = state.type_void;
1405 re->recode = re_match;
1406 if (cxaddrecode(cx, re, disc))
1407 return -1;
1408 }
1409 if (type->initf && !(type->data = (*type->initf)(type, disc)))
1410 return -1;
1411 }
1412 return 0;
1413 }
1414
1415 /*
1416 * return type given name
1417 */
1418
1419 Cxtype_t*
cxtype(Cx_t * cx,const char * name,Cxdisc_t * disc)1420 cxtype(Cx_t* cx, const char* name, Cxdisc_t* disc)
1421 {
1422 register char* s;
1423 register char* lib;
1424 Cxtype_t* t;
1425 size_t n;
1426
1427 if ((s = strchr(name, ':')) && *++s == ':')
1428 {
1429 n = s - (char*)name;
1430 lib = fmtbuf(n);
1431 memcpy(lib, name, --n);
1432 lib[n] = 0;
1433 name = (const char*)s + 1;
1434 }
1435 else
1436 lib = (char*)name;
1437 if (!(t = (Cxtype_t*)dtmatch(cx ? cx->types : state.types, name)) && disc->loadf && (*disc->loadf)(lib, disc))
1438 t = (Cxtype_t*)dtmatch(cx ? cx->types : state.types, name);
1439 return t;
1440 }
1441
1442 /*
1443 * add an op callout
1444 */
1445
1446 int
cxaddcallout(Cx_t * cx,register Cxcallout_t * callout,Cxdisc_t * disc)1447 cxaddcallout(Cx_t* cx, register Cxcallout_t* callout, Cxdisc_t* disc)
1448 {
1449 char* name;
1450 Dt_t* dict;
1451 Cxcallout_t* copy;
1452
1453 if (cx)
1454 {
1455 disc = cx->disc;
1456 if (cx->view & CX_VIEW_callouts)
1457 dict = cx->callouts;
1458 else if (!(dict = dtnew(cx->vm, &state.codedisc, Dtoset)))
1459 {
1460 if (disc->errorf)
1461 (*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
1462 return -1;
1463 }
1464 else
1465 {
1466 dtview(dict, cx->callouts);
1467 cx->callouts = dict;
1468 cx->view |= CX_VIEW_callouts;
1469 }
1470 if (!(copy = vmnewof(cx->vm, 0, Cxcallout_t, 1, 0)))
1471 {
1472 if (disc->errorf)
1473 (*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
1474 return -1;
1475 }
1476 *copy = *callout;
1477 callout = copy;
1478 }
1479 else if (callout->op.code == CX_GET || callout->op.code == CX_SET || callout->op.code == CX_DEL || callout->op.code == CX_RET)
1480 {
1481 if (disc->errorf)
1482 (*disc->errorf)(NiL, disc, 2, "%s: callout must be local", cxcodename(callout->op.code));
1483 return -1;
1484 }
1485 else
1486 dict = state.callouts;
1487 if (!(callout->header.flags & CX_NORMALIZED))
1488 {
1489 callout->header.flags |= CX_NORMALIZED;
1490 if (!(name = (char*)callout->op.type1))
1491 callout->op.type1 = state.type_void;
1492 else if (!(callout->op.type1 = cxtype(cx, name, disc)))
1493 {
1494 if (disc->errorf)
1495 (*disc->errorf)(NiL, disc, 2, "%s: unknown type", name);
1496 return -1;
1497 }
1498 if (!(name = (char*)callout->op.type2))
1499 callout->op.type2 = state.type_void;
1500 else if (!(callout->op.type2 = cxtype(cx, name, disc)))
1501 {
1502 if (disc->errorf)
1503 (*disc->errorf)(NiL, disc, 2, "%s: unknown type", name);
1504 return -1;
1505 }
1506 }
1507 if (!(copy = (Cxcallout_t*)dtinsert(dict, callout)) || copy->callout != callout->callout)
1508 {
1509 if (disc->errorf)
1510 (*disc->errorf)(NiL, disc, 2, "callout initialization error");
1511 return -1;
1512 }
1513 return 0;
1514 }
1515
1516 /*
1517 * return callout given <code,type1,type2>
1518 */
1519
1520 Cxcallout_f
cxcallout(Cx_t * cx,int code,Cxtype_t * type1,Cxtype_t * type2,Cxdisc_t * disc)1521 cxcallout(Cx_t* cx, int code, Cxtype_t* type1, Cxtype_t* type2, Cxdisc_t* disc)
1522 {
1523 Cxcallout_t* callout;
1524 Cxop_t op;
1525
1526 memset(&op, 0, sizeof(op));
1527 op.code = code;
1528 if (!(op.type1 = type1))
1529 op.type1 = state.type_void;
1530 if (!(op.type2 = type2))
1531 op.type2 = state.type_void;
1532 while (!(callout = (Cxcallout_t*)dtmatch(cx ? cx->callouts : state.callouts, &op)))
1533 {
1534 if (op.code == CX_NOMATCH)
1535 op.code = CX_MATCH;
1536 else if (op.type2 == state.type_void)
1537 return 0;
1538 else
1539 op.type2 = state.type_void;
1540 }
1541 return callout->callout;
1542 }
1543
1544 /*
1545 * add a query
1546 */
1547
1548 int
cxaddquery(Cx_t * cx,Cxquery_t * query,Cxdisc_t * disc)1549 cxaddquery(Cx_t* cx, Cxquery_t* query, Cxdisc_t* disc)
1550 {
1551 Dt_t* dict;
1552 Cxquery_t* copy;
1553
1554 if (cx)
1555 {
1556 disc = cx->disc;
1557 if (cx->view & CX_VIEW_queries)
1558 dict = cx->queries;
1559 else if (!(dict = dtnew(cx->vm, &state.namedisc, Dtoset)))
1560 {
1561 if (disc->errorf)
1562 (*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
1563 return -1;
1564 }
1565 else
1566 {
1567 dtview(dict, cx->queries);
1568 cx->queries = dict;
1569 cx->view |= CX_VIEW_queries;
1570 }
1571 if (!(copy = vmnewof(cx->vm, 0, Cxquery_t, 1, 0)))
1572 {
1573 if (disc->errorf)
1574 (*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
1575 return -1;
1576 }
1577 *copy = *query;
1578 query = copy;
1579 }
1580 else
1581 dict = state.queries;
1582 if (dtsearch(dict, query))
1583 {
1584 if (disc->errorf)
1585 (*disc->errorf)(NiL, disc, 2, "%s: query already defined", query->name);
1586 return -1;
1587 }
1588 dtinsert(dict, query);
1589 return 0;
1590 }
1591
1592 /*
1593 * return query given name
1594 */
1595
1596 Cxquery_t*
cxquery(Cx_t * cx,const char * name,Cxdisc_t * disc)1597 cxquery(Cx_t* cx, const char* name, Cxdisc_t* disc)
1598 {
1599 register char* s;
1600 register char* lib;
1601 Cxquery_t* q;
1602 size_t n;
1603
1604 if ((s = strchr(name, ':')) && *++s == ':')
1605 {
1606 n = s - (char*)name;
1607 lib = fmtbuf(n);
1608 memcpy(lib, name, --n);
1609 lib[n] = 0;
1610 name = (const char*)s + 1;
1611 }
1612 else
1613 lib = (char*)name;
1614 if (!(q = (Cxquery_t*)dtmatch(cx ? cx->queries : state.queries, name)) && disc->loadf && (*disc->loadf)(lib, disc))
1615 q = (Cxquery_t*)dtmatch(cx ? cx->queries : state.queries, name);
1616 return q;
1617 }
1618
1619 /*
1620 * return function given name
1621 */
1622
1623 Cxvariable_t*
cxfunction(Cx_t * cx,const char * name,Cxdisc_t * disc)1624 cxfunction(Cx_t* cx, const char* name, Cxdisc_t* disc)
1625 {
1626 register char* s;
1627 register char* p;
1628 Cxvariable_t* f;
1629 Cxlib_t* lib;
1630 int i;
1631
1632 if (!cx)
1633 {
1634 if (disc->errorf)
1635 (*disc->errorf)(NiL, disc, 2, "%s: function must be local", name);
1636 return 0;
1637 }
1638 if (f = (Cxvariable_t*)dtmatch(cx->variables, name))
1639 {
1640 if (f->function)
1641 return f;
1642 if (disc->errorf)
1643 (*disc->errorf)(NiL, disc, 2, "%s: not a function", name);
1644 return 0;
1645 }
1646 if (!(s = strchr(name, ':')) || *++s != ':')
1647 {
1648 if (disc->errorf)
1649 (*disc->errorf)(NiL, disc, 2, "%s: function must be local", name);
1650 return 0;
1651 }
1652 i = s - (char*)name;
1653 p = fmtbuf(i);
1654 memcpy(p, name, --i);
1655 p[i] = 0;
1656 if (!disc->loadf || !(lib = (*disc->loadf)(p, disc)))
1657 return 0;
1658 if (lib->functions)
1659 for (i = 0; lib->functions[i].name; i++)
1660 if (cxaddvariable(cx, &lib->functions[i], disc))
1661 return 0;
1662 if (f = (Cxvariable_t*)dtmatch(cx->variables, name))
1663 {
1664 if (f->function)
1665 return f;
1666 if (disc->errorf)
1667 (*disc->errorf)(NiL, disc, 2, "%s: not a function", name);
1668 }
1669 else
1670 {
1671 if (disc->errorf)
1672 (*disc->errorf)(NiL, disc, 2, "%s: undefined function", name);
1673 return 0;
1674 }
1675 return 0;
1676 }
1677
1678 /*
1679 * add a map
1680 */
1681
1682 int
cxaddmap(Cx_t * cx,Cxmap_t * map,Cxdisc_t * disc)1683 cxaddmap(Cx_t* cx, Cxmap_t* map, Cxdisc_t* disc)
1684 {
1685 Dt_t* dict;
1686 Cxmap_t* copy;
1687
1688 if (cx)
1689 {
1690 disc = cx->disc;
1691 if (cx->view & CX_VIEW_maps)
1692 dict = cx->maps;
1693 if (!(dict = dtnew(cx->vm, &state.namedisc, Dtoset)))
1694 {
1695 if (disc->errorf)
1696 (*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
1697 return -1;
1698 }
1699 else
1700 {
1701 dtview(dict, cx->maps);
1702 cx->maps = dict;
1703 cx->view |= CX_VIEW_maps;
1704 }
1705 if (!(copy = vmnewof(cx->vm, 0, Cxmap_t, 1, 0)))
1706 {
1707 if (disc->errorf)
1708 (*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
1709 return -1;
1710 }
1711 *copy = *map;
1712 map = copy;
1713 }
1714 else
1715 dict = state.maps;
1716 if (dtsearch(dict, map))
1717 {
1718 if (disc->errorf)
1719 (*disc->errorf)(NiL, disc, 2, "%s: map already defined", map->name);
1720 return -1;
1721 }
1722 if (cxinitmap(map, disc))
1723 return -1;
1724 dtinsert(dict, map);
1725 return 0;
1726 }
1727
1728 /*
1729 * return map given name
1730 */
1731
1732 Cxmap_t*
cxmap(Cx_t * cx,const char * name,Cxdisc_t * disc)1733 cxmap(Cx_t* cx, const char* name, Cxdisc_t* disc)
1734 {
1735 return (Cxmap_t*)dtmatch(cx ? cx->maps : state.maps, name);
1736 }
1737
1738 /*
1739 * add an op recode
1740 */
1741
1742 int
cxaddrecode(Cx_t * cx,register Cxrecode_t * recode,Cxdisc_t * disc)1743 cxaddrecode(Cx_t* cx, register Cxrecode_t* recode, Cxdisc_t* disc)
1744 {
1745 Cxrecode_t* o;
1746 char* name;
1747 Dt_t* dict;
1748 Cxrecode_t* copy;
1749
1750 if (cx)
1751 {
1752 disc = cx->disc;
1753 if (cx->view & CX_VIEW_recodes)
1754 dict = cx->recodes;
1755 else if (!(dict = dtnew(cx->vm, &state.codedisc, Dtoset)))
1756 {
1757 if (disc->errorf)
1758 (*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
1759 return -1;
1760 }
1761 else
1762 {
1763 dtview(dict, cx->recodes);
1764 cx->recodes = dict;
1765 cx->view |= CX_VIEW_recodes;
1766 }
1767 if (!(copy = vmnewof(cx->vm, 0, Cxrecode_t, 1, 0)))
1768 {
1769 if (disc->errorf)
1770 (*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
1771 return -1;
1772 }
1773 *copy = *recode;
1774 recode = copy;
1775 }
1776 else if (recode->op.code == CX_GET || recode->op.code == CX_SET || recode->op.code == CX_DEL || recode->op.code == CX_RET)
1777 {
1778 if (disc->errorf)
1779 (*disc->errorf)(NiL, disc, 2, "%s: recode must be local", cxcodename(recode->op.code));
1780 return -1;
1781 }
1782 else
1783 dict = state.recodes;
1784 if (!(recode->header.flags & CX_NORMALIZED))
1785 {
1786 recode->header.flags |= CX_NORMALIZED;
1787 if ((name = (char*)recode->op.type1) && !(recode->op.type1 = cxtype(cx, name, disc)))
1788 {
1789 if (disc->errorf)
1790 (*disc->errorf)(NiL, disc, 2, "%s: unknown type", name);
1791 return -1;
1792 }
1793 if ((name = (char*)recode->op.type2) && !(recode->op.type2 = cxtype(cx, name, disc)))
1794 {
1795 if (disc->errorf)
1796 (*disc->errorf)(NiL, disc, 2, "%s: unknown type", name);
1797 return -1;
1798 }
1799 }
1800 if (!(o = (Cxrecode_t*)dtsearch(dict, recode)) || o != recode && dtdelete(dict, o))
1801 dtinsert(dict, recode);
1802 return 0;
1803 }
1804
1805 /*
1806 * return recode given <code,type1,type2>
1807 */
1808
1809 Cxrecode_f
cxrecode(Cx_t * cx,int code,Cxtype_t * type1,Cxtype_t * type2,Cxdisc_t * disc)1810 cxrecode(Cx_t* cx, int code, Cxtype_t* type1, Cxtype_t* type2, Cxdisc_t* disc)
1811 {
1812 Cxrecode_t* recode;
1813 Cxop_t op;
1814
1815 switch (code)
1816 {
1817 case CX_NOMATCH:
1818 code = CX_MATCH;
1819 /*FALLTHROUGH*/
1820 case CX_MATCH:
1821 type2 = 0;
1822 break;
1823 }
1824 memset(&op, 0, sizeof(op));
1825 op.code = code;
1826 if (!(op.type1 = type1))
1827 op.type1 = state.type_void;
1828 if (!(op.type2 = type2))
1829 op.type2 = state.type_void;
1830 return (recode = (Cxrecode_t*)dtmatch(cx ? cx->recodes : state.recodes, &op)) ? recode->recode : (Cxrecode_f)0;
1831 }
1832
1833 /*
1834 * add an edit
1835 */
1836
1837 int
cxaddedit(Cx_t * cx,register Cxedit_t * edit,Cxdisc_t * disc)1838 cxaddedit(Cx_t* cx, register Cxedit_t* edit, Cxdisc_t* disc)
1839 {
1840 Dt_t* dict;
1841 Cxedit_t* copy;
1842
1843 if (cx)
1844 {
1845 disc = cx->disc;
1846 if (cx->view & CX_VIEW_edits)
1847 dict = cx->edits;
1848 else if (!(dict = dtnew(cx->vm, &state.namedisc, Dtoset)))
1849 {
1850 if (disc->errorf)
1851 (*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
1852 return -1;
1853 }
1854 else
1855 {
1856 dtview(dict, cx->edits);
1857 cx->edits = dict;
1858 cx->view |= CX_VIEW_edits;
1859 }
1860 if (!(copy = vmnewof(cx->vm, 0, Cxedit_t, 1, 0)))
1861 {
1862 if (disc->errorf)
1863 (*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
1864 return -1;
1865 }
1866 *copy = *edit;
1867 edit = copy;
1868 }
1869 else
1870 dict = state.edits;
1871 if (dtsearch(dict, edit))
1872 {
1873 if (disc->errorf)
1874 (*disc->errorf)(NiL, disc, 2, "%s: edit already defined", edit->name);
1875 return -1;
1876 }
1877 dtinsert(dict, edit);
1878 if (!(edit->header.flags & CX_INITIALIZED))
1879 {
1880 edit->header.flags |= CX_INITIALIZED;
1881 if (edit->initf && !(edit->data = (*edit->initf)(edit, disc)))
1882 return -1;
1883 }
1884 return 0;
1885 }
1886
1887 /*
1888 * return edit given name
1889 * optional substitute expression instantiated
1890 */
1891
1892 Cxedit_t*
cxedit(Cx_t * cx,const char * data,Cxdisc_t * disc)1893 cxedit(Cx_t* cx, const char* data, Cxdisc_t* disc)
1894 {
1895 Cxedit_t* e;
1896 Cxedit_t* o;
1897 char* s;
1898
1899 e = (Cxedit_t*)dtmatch(cx ? cx->edits : state.edits, data);
1900 if (isalpha(*data))
1901 {
1902 if (!e)
1903 {
1904 if (disc->errorf)
1905 (*disc->errorf)(NiL, disc, 2, "%s: edit not defined", data);
1906 return 0;
1907 }
1908 o = e;
1909 if (!(e = cx ? vmnewof(cx->vm, 0, Cxedit_t, 1, 0) : newof(0, Cxedit_t, 1, 0)))
1910 {
1911 if (disc->errorf)
1912 (*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
1913 return 0;
1914 }
1915 e->name = o->name;
1916 e->description = o->description;
1917 e->initf = o->initf;
1918 e->num2strf = o->num2strf;
1919 e->str2numf = o->str2numf;
1920 }
1921 else if (e)
1922 return e;
1923 else
1924 {
1925 if (!(e = cx ? vmnewof(cx->vm, 0, Cxedit_t, 1, strlen(data) + 1) : newof(0, Cxedit_t, 1, strlen(data) + 1)))
1926 {
1927 if (disc->errorf)
1928 (*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
1929 return 0;
1930 }
1931 e->redisc.re_version = REG_VERSION;
1932 e->redisc.re_errorf = (regerror_t)disc->errorf;
1933 if (cx)
1934 {
1935 e->redisc.re_flags = REG_NOFREE;
1936 e->redisc.re_resizef = (regresize_t)vmgetmem;
1937 e->redisc.re_resizehandle = cx->vm;
1938 }
1939 e->re.re_disc = &e->redisc;
1940 s = (char*)data;
1941 if (regcomp(&e->re, s, REG_DELIMITED|REG_LENIENT|REG_NULL))
1942 return 0;
1943 s += e->re.re_npat;
1944 if (regsubcomp(&e->re, s, NiL, 0, 0))
1945 return 0;
1946 s += e->re.re_npat;
1947 e->re.re_npat = s - (char*)data;
1948 if (*s && disc->errorf)
1949 (*disc->errorf)(NiL, disc, 1, "invalid character after substitution: %s", s);
1950 strcpy((char*)(e->name = (const char*)(e + 1)), data);
1951 if (cx && cxaddedit(cx, e, disc))
1952 return 0;
1953 }
1954 return e;
1955 }
1956
1957 /*
1958 * add a constraint
1959 */
1960
1961 int
cxaddconstraint(Cx_t * cx,register Cxconstraint_t * constraint,Cxdisc_t * disc)1962 cxaddconstraint(Cx_t* cx, register Cxconstraint_t* constraint, Cxdisc_t* disc)
1963 {
1964 Dt_t* dict;
1965 Cxconstraint_t* copy;
1966
1967 if (cx)
1968 {
1969 disc = cx->disc;
1970 if (cx->view & CX_VIEW_constraints)
1971 dict = cx->constraints;
1972 else if (!(dict = dtnew(cx->vm, &state.namedisc, Dtoset)))
1973 {
1974 if (disc->errorf)
1975 (*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
1976 return -1;
1977 }
1978 else
1979 {
1980 dtview(dict, cx->constraints);
1981 cx->constraints = dict;
1982 cx->view |= CX_VIEW_constraints;
1983 }
1984 if (!(copy = vmnewof(cx->vm, 0, Cxconstraint_t, 1, 0)))
1985 {
1986 if (disc->errorf)
1987 (*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
1988 return -1;
1989 }
1990 *copy = *constraint;
1991 constraint = copy;
1992 }
1993 else
1994 dict = state.constraints;
1995 if (dtsearch(dict, constraint))
1996 {
1997 if (disc->errorf)
1998 (*disc->errorf)(NiL, disc, 2, "%s: constraint already defined", constraint->name);
1999 return -1;
2000 }
2001 if (!(constraint->header.flags & CX_INITIALIZED))
2002 {
2003 constraint->header.flags |= CX_INITIALIZED;
2004 if (constraint->initf && !(constraint->data = (*constraint->initf)(constraint, disc)))
2005 return -1;
2006 }
2007 dtinsert(dict, constraint);
2008 return 0;
2009 }
2010
2011 /*
2012 * return constraint given name
2013 */
2014
2015 Cxconstraint_t*
cxconstraint(Cx_t * cx,const char * name,Cxdisc_t * disc)2016 cxconstraint(Cx_t* cx, const char* name, Cxdisc_t* disc)
2017 {
2018 return (Cxconstraint_t*)dtmatch(cx ? cx->constraints : state.constraints, name);
2019 }
2020
2021 /*
2022 * mark type CX_REFERENCED
2023 */
2024
2025 static void
referenced(register Cxtype_t * type)2026 referenced(register Cxtype_t* type)
2027 {
2028 register Cxvariable_t* mp;
2029
2030 if (!(type->header.flags & CX_REFERENCED))
2031 {
2032 type->header.flags |= CX_REFERENCED;
2033 if (type->base)
2034 referenced(type->base);
2035 if (type->member)
2036 for (mp = (Cxvariable_t*)dtfirst(type->member->members); mp; mp = (Cxvariable_t*)dtnext(type->member->members, mp))
2037 referenced(mp->type);
2038 }
2039 }
2040
2041 /*
2042 * add a variable
2043 */
2044
2045 int
cxaddvariable(register Cx_t * cx,register Cxvariable_t * variable,Cxdisc_t * disc)2046 cxaddvariable(register Cx_t* cx, register Cxvariable_t* variable, Cxdisc_t* disc)
2047 {
2048 Dt_t* dict;
2049 Cx_t* sx;
2050 char* name;
2051
2052 if (cx)
2053 {
2054 disc = cx->disc;
2055 if (cx->view & CX_VIEW_variables)
2056 dict = cx->variables;
2057 else if (!(dict = dtnew(cx->vm, &state.namedisc, Dtoset)))
2058 {
2059 if (disc->errorf)
2060 (*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
2061 return -1;
2062 }
2063 else
2064 {
2065 dtview(dict, cx->variables);
2066 cx->variables = dict;
2067 cx->view |= CX_VIEW_variables;
2068 }
2069 }
2070 else
2071 dict = state.variables;
2072 if (!variable)
2073 return 0;
2074 if (dtsearch(dict, variable))
2075 {
2076 if (disc->errorf)
2077 (*disc->errorf)(NiL, disc, 2, "%s: variable already defined", variable->name);
2078 return -1;
2079 }
2080 if (!(variable->header.flags & CX_NORMALIZED))
2081 {
2082 variable->header.flags |= CX_NORMALIZED;
2083 if ((name = (char*)variable->type) && !(variable->type = cxtype(cx, name, disc)))
2084 {
2085 if (disc->errorf)
2086 (*disc->errorf)(NiL, disc, 2, "%s: %s: unknown type", variable->name, name);
2087 return -1;
2088 }
2089 }
2090 dtinsert(dict, variable);
2091 if (cx)
2092 {
2093 if (sx = cx->scope)
2094 {
2095 variable->header.index = sx->index++;
2096 cx->index = sx->index;
2097 }
2098 else
2099 variable->header.index = cx->index++;
2100 }
2101 if (!(variable->header.flags & CX_INITIALIZED))
2102 {
2103 variable->header.flags |= CX_INITIALIZED;
2104 referenced(variable->type);
2105 if (cx)
2106 dtinsert(cx->fields, variable);
2107 }
2108 return 0;
2109 }
2110
2111 /*
2112 * return variable given name
2113 */
2114
2115 Cxvariable_t*
cxvariable(Cx_t * cx,const char * name,register Cxtype_t * m,Cxdisc_t * disc)2116 cxvariable(Cx_t* cx, const char* name, register Cxtype_t* m, Cxdisc_t* disc)
2117 {
2118 register char* s;
2119 register char* t;
2120 Cxvariable_t* v;
2121 Dt_t* dict;
2122 Cxreference_t* ref;
2123 Cxreference_t* head;
2124 Cxreference_t* tail;
2125
2126 if (!cx)
2127 {
2128 if (disc->errorf)
2129 (*disc->errorf)(NiL, disc, 2, "%s: variable must be local", name);
2130 return 0;
2131 }
2132 disc = cx->disc;
2133 if (!m || !m->member)
2134 {
2135 if (!(v = (Cxvariable_t*)dtmatch(cx->variables, name)))
2136 {
2137 if (!(t = strchr(name, '.')))
2138 {
2139 if (disc->errorf)
2140 (*disc->errorf)(NiL, disc, 2, "%s: undefined variable", name);
2141 return 0;
2142 }
2143
2144 /*
2145 * cxparse() never gets here
2146 */
2147
2148 strcpy(s = fmtbuf(strlen(name) + 1), name);
2149 t = s + (t - (char*)name);
2150 m = 0;
2151 dict = cx->variables;
2152 head = 0;
2153 for (;;)
2154 {
2155 if (t)
2156 *t++ = 0;
2157 v = (Cxvariable_t*)dtmatch(dict, *s ? s : ".");
2158 if (!v)
2159 {
2160 if (disc->errorf)
2161 {
2162 if (m)
2163 (*disc->errorf)(NiL, disc, 2, "%s: not a member of %s", s, m->name);
2164
2165 else
2166 (*disc->errorf)(NiL, disc, 2, "%s: undefined variable", s);
2167 }
2168 return 0;
2169 }
2170 if (!(ref = newof(0, Cxreference_t, 1, 0)))
2171 {
2172 if (disc->errorf)
2173 (*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
2174 return 0;
2175 }
2176 ref->variable = v;
2177 if (m)
2178 ref->member = m->member;
2179 if (head)
2180 tail->next = ref;
2181 else
2182 head = ref;
2183 tail = ref;
2184 if (!(s = t))
2185 break;
2186 if ((!(m = v->type) || !m->member || !(dict = m->member->members)) &&
2187 (!(m = v->type->base) || !m->member || !(dict = m->member->members)))
2188 {
2189 if (disc->errorf)
2190 (*disc->errorf)(NiL, disc, 2, "%s: struct or union variable expected", v->name);
2191 return 0;
2192 }
2193 t = strchr(t, '.');
2194 }
2195 if (!(v = newof(0, Cxvariable_t, 1, strlen(name) + 1)))
2196 {
2197 if (disc->errorf)
2198 (*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
2199 return 0;
2200 }
2201 strcpy((char*)(v->name = (const char*)(v + 1)), name);
2202 v->reference = head;
2203 v->type = tail->variable->type;
2204 dtinsert(cx->variables, v);
2205 }
2206 }
2207 else if (!(v = (Cxvariable_t*)dtmatch(m->member->members, name)))
2208 {
2209 if (disc->errorf)
2210 (*disc->errorf)(cx, disc, 2, "%s: not a member of %s", name, m->name);
2211 return 0;
2212 }
2213 return v;
2214 }
2215
2216 /*
2217 * cast var value to type
2218 * if var==0 or data==0 then the value is already in ret
2219 */
2220
2221 int
cxcast(Cx_t * cx,Cxoperand_t * ret,Cxvariable_t * var,Cxtype_t * type,void * data,const char * format)2222 cxcast(Cx_t* cx, Cxoperand_t* ret, Cxvariable_t* var, Cxtype_t* type, void* data, const char* format)
2223 {
2224 Cxinstruction_t x;
2225 Cxoperand_t val;
2226 Cxreference_t* ref;
2227 Cxtype_t* from;
2228 unsigned char* map;
2229 Cxbuf_t* cvt;
2230 char* s;
2231 void* d;
2232 ssize_t n;
2233 Cxunsigned_t m;
2234 int c;
2235 Cxoperand_t a;
2236 Cxoperand_t b;
2237 Cxexternal_f e;
2238
2239 x.callout = 0;
2240 if (x.data.variable = var)
2241 {
2242 from = var->type;
2243 if (!type)
2244 type = from;
2245 if (data)
2246 {
2247 if (!cx->getf && !(cx->getf = cxcallout(cx, CX_GET, 0, 0, cx->disc)))
2248 {
2249 if (cx->disc->errorf)
2250 (*cx->disc->errorf)(NiL, cx->disc, 3, "%s: cx CX_GET callout must be defined", var->name);
2251 return -1;
2252 }
2253 a.type = state.type_string;
2254 a.refs = 0;
2255 a.value.string.size = (a.value.string.data = (char*)format) ? strlen(format) : 0;
2256 ret->type = var->type;
2257 ret->value.number = 0;
2258 if (ref = var->reference)
2259 {
2260 b.type = var->type;
2261 b.refs = 0;
2262 b.value.number = 0;
2263 x.data.variable = ref->variable;
2264 x.type = ret->type = ref->variable->type;
2265 if (var->name != var->type->name && (*cx->getf)(cx, &x, ret, &a, &b, data, cx->disc))
2266 return -1;
2267 while (ref = ref->next)
2268 {
2269 b.type = x.data.variable->type;
2270 x.data.variable = ref->variable;
2271 ret->type = x.data.variable->type;
2272 if ((*ref->member->getf)(cx, &x, ret, &a, &b, (ref->member->flags & CX_VIRTUAL) ? data : (void*)0, cx->disc))
2273 return -1;
2274 }
2275 }
2276 else if ((*cx->getf)(cx, &x, ret, &a, NiL, data, cx->disc))
2277 return -1;
2278 if (type == state.type_void)
2279 return 0;
2280 from = ret->type;
2281 }
2282 }
2283 else
2284 from = 0;
2285 if (var && var->format.map && var->format.map->part && var->format.map->part->edit)
2286 cxsuball(cx, var->format.map->part, ret);
2287 if ((var && (c = var->format.code) || (c = type->format.code)) &&
2288 c != CC_NATIVE &&
2289 (CCCONVERT(c) || !(type->format.flags & CX_BINARY) && (c = CCOP(c, CC_NATIVE))) &&
2290 (map = ccmap(CCIN(c), CCOUT(c))))
2291 {
2292 if (ret->value.string.size > cx->ccsiz)
2293 {
2294 n = roundof(ret->value.string.size + 1, CX_CVT);
2295 if (!(cx->ccbuf = vmoldof(cx->vm, cx->ccbuf, char, n, 0)))
2296 {
2297 if (cx->disc->errorf)
2298 (*cx->disc->errorf)(NiL, cx->disc, ERROR_SYSTEM|2, "out of space");
2299 return -1;
2300 }
2301 cx->ccsiz = n;
2302 }
2303 ret->value.string.data = (char*)ccmapcpy(map, cx->ccbuf, ret->value.string.data, ret->value.string.size);
2304 }
2305 if (ret->type->representation != type->representation)
2306 {
2307 val = *ret;
2308 if (cxisstring(type))
2309 {
2310 if (!var || !cxisnumber(from) || !var->format.map || format || cxnum2str(cx, &var->format, (Cxinteger_t)ret->value.number, &s))
2311 {
2312 if (!(e = ret->type->externalf) && var && var->type->member)
2313 e = cxmembers;
2314 if (e)
2315 {
2316 if (!(cvt = cx->cvt))
2317 {
2318 if (!cx->top)
2319 {
2320 if (!(cx->top = vmnewof(cx->vm, 0, Cxbuf_t, 1, 0)) || !(cx->top->data = vmoldof(cx->vm, 0, char, CX_CVT, 0)))
2321 {
2322 if (cx->disc->errorf)
2323 (*cx->disc->errorf)(NiL, cx->disc, ERROR_SYSTEM|2, "out of space");
2324 return -1;
2325 }
2326 cx->top->size = CX_CVT;
2327 }
2328 cx->cvt = cx->top;
2329 }
2330 else
2331 {
2332 if (!cx->cvt->next)
2333 {
2334 if (!(cx->cvt->next = vmnewof(cx->vm, 0, Cxbuf_t, 1, 0)) || !(cx->cvt->next->data = vmoldof(cx->vm, 0, char, CX_CVT, 0)))
2335 {
2336 if (cx->disc->errorf)
2337 (*cx->disc->errorf)(NiL, cx->disc, ERROR_SYSTEM|2, "out of space");
2338 return -1;
2339 }
2340 cx->cvt->next->size = CX_CVT;
2341 }
2342 cx->cvt = cx->cvt->next;
2343 }
2344 while ((n = (*e)(cx, ret->type, format, var ? &var->format : (Cxformat_t*)0, &ret->value, cx->cvt->data, cx->cvt->size, cx->disc)) > cx->cvt->size)
2345 {
2346 n = roundof(n + 1, CX_CVT);
2347 if (!(cx->cvt->data = vmoldof(cx->vm, cx->cvt->data, char, n, 0)))
2348 {
2349 if (cx->disc->errorf)
2350 (*cx->disc->errorf)(NiL, cx->disc, ERROR_SYSTEM|2, "out of space");
2351 cx->cvt = cvt;
2352 return -1;
2353 }
2354 cx->cvt->size = n;
2355 }
2356 if (n < 0)
2357 {
2358 cx->cvt = cvt;
2359 return -1;
2360 }
2361 ret->value.string.data = cx->cvt->data;
2362 ret->value.string.size = n;
2363 cx->cvt = cvt;
2364 }
2365 else if (!cxisnumber(ret->type))
2366 goto bad;
2367 else
2368 ret->value.string.size = strlen(ret->value.string.data = sfprints("%Lg", val.value.number));
2369 }
2370 else
2371 ret->value.string.size = strlen(ret->value.string.data = s);
2372 }
2373 else if (var && data)
2374 goto bad;
2375 else if (cxisnumber(type) && var && cxisstring(from) && var->format.map && !cxstr2num(cx, &var->format, val.value.string.data, val.value.string.size, &m))
2376 ret->value.number = (Cxinteger_t)m;
2377 #if 0
2378 else if (ret->type->representation != type->representation)
2379 goto bad;
2380 #endif
2381 else if (!type->internalf || (*type->internalf)(cx, type, format, var ? &var->format : (Cxformat_t*)0, ret, val.value.string.data, val.value.string.size, cx->em, cx->disc) < 0)
2382 goto bad;
2383 ret->type = type;
2384 }
2385 return 0;
2386 bad:
2387 if (((x.callout = cxcallout(cx, CX_CAST, ret->type, type, cx->disc)) || ret->type->fundamental && (x.callout = cxcallout(cx, CX_CAST, ret->type->fundamental, type, cx->disc))) && !(*x.callout)(cx, &x, ret, NiL, &val, data, cx->disc))
2388 return 0;
2389 if (cx->disc->errorf)
2390 (*cx->disc->errorf)(cx, cx->disc, 2, "cannot cast %s to %s", ret->type->name, type->name);
2391 return -1;
2392 }
2393
2394 /*
2395 * generic struct type externalf that lists defined members in ksh93u compound notation
2396 */
2397
2398 ssize_t
cxmembers(Cx_t * cx,Cxtype_t * type,const char * details,Cxformat_t * format,Cxvalue_t * value,char * buf,size_t size,Cxdisc_t * disc)2399 cxmembers(Cx_t* cx, Cxtype_t* type, const char* details, Cxformat_t* format, Cxvalue_t* value, char* buf, size_t size, Cxdisc_t* disc)
2400 {
2401 Cxvariable_t* v;
2402 unsigned char* p;
2403 unsigned char* e;
2404 char* b;
2405 char* m;
2406 char* s;
2407 size_t n;
2408 int i;
2409 Cxoperand_t o;
2410 Cxinstruction_t x;
2411
2412 if (!type->member || !value->buffer.data)
2413 return 0;
2414 b = buf;
2415 m = b + size;
2416 b += sfsprintf(b, m - b, "( ");
2417 for (v = (Cxvariable_t*)dtfirst(type->member->members); v; v = (Cxvariable_t*)dtnext(type->member->members, v))
2418 {
2419 if (!v->type->generic)
2420 {
2421 x.data.variable = v;
2422 o.type = v->type;
2423 o.value.buffer.data = value->buffer.data;
2424 if (!type->member->getf(cx, &x, &o, NiL, NiL, NiL, disc))
2425 {
2426 switch (cxrepresentation(v->type))
2427 {
2428 case CX_buffer:
2429 if (!o.value.buffer.size)
2430 continue;
2431 p = (unsigned char*)o.value.buffer.data;
2432 e = p + o.value.buffer.size;
2433 while (p < e && !*p)
2434 p++;
2435 if (p >= e)
2436 continue;
2437 break;
2438 case CX_number:
2439 if (!o.value.number)
2440 continue;
2441 break;
2442 case CX_string:
2443 if (!o.value.string.size)
2444 continue;
2445 break;
2446 case CX_void:
2447 continue;
2448 }
2449 if (!cxcast(cx, &o, v, cx->state->type_string, NiL, NiL))
2450 b += sfsprintf(b, m > b ? m - b : 0, "%s=%s ", v->name, o.value.string.data);
2451 }
2452 }
2453 }
2454 if ((n = b - buf) <= 2)
2455 n = 0;
2456 else
2457 {
2458 b += sfsprintf(b, m > b ? m - b : 0, ")");
2459 n++;
2460 if (n >= size)
2461 return n + 1;
2462 *b = 0;
2463 }
2464 return n;
2465 }
2466
2467 /*
2468 * initialize the global state
2469 */
2470
2471 static void
initialize(Cxdisc_t * disc)2472 initialize(Cxdisc_t* disc)
2473 {
2474 register int i;
2475
2476 static const char cx_alpha[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_$";
2477 static const char cx_digit[] = "0123456789";
2478 static const char cx_float[] = "_.#";
2479 static const char cx_space[] = " \f\n\t\r\v";
2480
2481 if (!state.initialized++)
2482 {
2483 table.opcode['+'] = CX_ADD;
2484 table.opcode['&'] = CX_AND;
2485 table.opcode['/'] = CX_DIV;
2486 table.opcode['>'] = CX_GT;
2487 table.opcode['~'] = CX_INV;
2488 table.opcode['<'] = CX_LT;
2489 table.opcode['%'] = CX_MOD;
2490 table.opcode['*'] = CX_MPY;
2491 table.opcode['!'] = CX_NOT;
2492 table.opcode['|'] = CX_OR;
2493 table.opcode['='] = CX_SET;
2494 table.opcode['-'] = CX_SUB;
2495 table.opcode['^'] = CX_XOR;
2496
2497 table.comparison[CX_LOG] =
2498 table.comparison[CX_LT] =
2499 table.comparison[CX_LE] =
2500 table.comparison[CX_EQ] =
2501 table.comparison[CX_NE] =
2502 table.comparison[CX_MATCH] =
2503 table.comparison[CX_NOMATCH] =
2504 table.comparison[CX_GE] =
2505 table.comparison[CX_GT] = 1;
2506
2507 table.logical[CX_ANDAND] =
2508 table.logical[CX_LOG] =
2509 table.logical[CX_OROR] =
2510 table.logical[CX_NOT] = 1;
2511
2512 table.precedence[CX_INV] =
2513 table.precedence[CX_LOG] =
2514 table.precedence[CX_NOT] =
2515 table.precedence[CX_UMINUS] =
2516 table.precedence[CX_UPLUS] = 15;
2517 table.precedence[CX_DIV] =
2518 table.precedence[CX_MOD] =
2519 table.precedence[CX_MPY] = 14;
2520 table.precedence[CX_ADD] =
2521 table.precedence[CX_SUB] = 13;
2522 table.precedence[CX_LSH] =
2523 table.precedence[CX_RSH] = 12;
2524 table.precedence[CX_GE] =
2525 table.precedence[CX_GT] =
2526 table.precedence[CX_LE] =
2527 table.precedence[CX_LT] = 11;
2528 table.precedence[CX_EQ] =
2529 table.precedence[CX_NE] =
2530 table.precedence[CX_MATCH] =
2531 table.precedence[CX_NOMATCH] = 10;
2532 table.precedence[CX_AND] = 9;
2533 table.precedence[CX_XOR] = 8;
2534 table.precedence[CX_AND] =
2535 table.precedence[CX_OR] = 7;
2536 table.precedence[CX_ANDAND] = 6;
2537 table.precedence[CX_OROR] = 5;
2538 table.precedence[CX_TST] = 4;
2539 table.precedence[CX_SET] = 3;
2540 table.precedence[CX_PAREN] = 2;
2541 table.precedence[CX_CALL] = 1;
2542
2543 state.codedisc.key = offsetof(Cxcodeheader_t, op);
2544 state.codedisc.size = sizeof(Cxop_t);
2545 state.codedisc.link = offsetof(Cxcodeheader_t, header.link);
2546 state.listdisc.key = offsetof(Cxlistheader_t, name);
2547 state.listdisc.size = -1;
2548 state.listdisc.link = offsetof(Cxlistheader_t, header.list);
2549 state.namedisc.key = offsetof(Cxnameheader_t, name);
2550 state.namedisc.size = -1;
2551 state.namedisc.link = offsetof(Cxnameheader_t, header.link);
2552
2553 if (!(state.libraries = dtopen(&state.namedisc, Dtqueue)) ||
2554 !(state.methods = dtopen(&state.namedisc, Dtoset)) ||
2555 !(state.types = dtopen(&state.namedisc, Dtoset)) ||
2556 !(state.callouts = dtopen(&state.codedisc, Dtoset)) ||
2557 !(state.recodes = dtopen(&state.codedisc, Dtoset)) ||
2558 !(state.maps = dtopen(&state.namedisc, Dtoset)) ||
2559 !(state.queries = dtopen(&state.namedisc, Dtoset)) ||
2560 !(state.constraints = dtopen(&state.namedisc, Dtoset)) ||
2561 !(state.edits = dtopen(&state.namedisc, Dtoset)) ||
2562 !(state.variables = dtopen(&state.namedisc, Dtoset)))
2563 {
2564 if (disc->errorf)
2565 (*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
2566 goto panic;
2567 }
2568
2569 for (i = 0; i < elementsof(types); i++)
2570 {
2571 if (cxaddtype(NiL, &types[i].type, disc))
2572 goto panic;
2573 if (types[i].state)
2574 *types[i].state = cxtype(NiL, types[i].type.name, disc);
2575 }
2576 for (i = 0; i < elementsof(callouts); i++)
2577 if (cxaddcallout(NiL, &callouts[i], disc))
2578 goto panic;
2579 for (i = 0; i < elementsof(builtins); i++)
2580 if (cxaddvariable(NiL, &builtins[i], disc))
2581 goto panic;
2582
2583 for (i = 0; i < (sizeof(cx_alpha) - 1); i++)
2584 state.ctype[cx_alpha[i]] |= CX_CTYPE_ALPHA;
2585 for (i = 0; i < (sizeof(cx_digit) - 1); i++)
2586 state.ctype[cx_digit[i]] |= CX_CTYPE_DIGIT;
2587 for (i = 0; i < (sizeof(cx_float) - 1); i++)
2588 state.ctype[cx_float[i]] |= CX_CTYPE_FLOAT;
2589 for (i = 0; i < (sizeof(cx_space) - 1); i++)
2590 state.ctype[cx_space[i]] |= CX_CTYPE_SPACE;
2591 }
2592 return;
2593 panic:
2594 error(ERROR_PANIC, "%s library initialization error", CX_ID);
2595 }
2596
2597 /*
2598 * return initialized global state pointer
2599 */
2600
2601 Cxstate_t*
cxstate(Cxdisc_t * disc)2602 cxstate(Cxdisc_t* disc)
2603 {
2604 if (!state.initialized)
2605 initialize(disc);
2606 return &state;
2607 }
2608
2609 /*
2610 * return the input location (path,record,offset) or the empty string
2611 */
2612
2613 char*
cxlocation(Cx_t * cx,void * data)2614 cxlocation(Cx_t* cx, void* data)
2615 {
2616 char* s;
2617
2618 return cx->disc->locationf && (s = (*cx->disc->locationf)(cx, data, cx->disc)) ? s : "";
2619 }
2620
2621 /*
2622 * for when only a 0-terminated string will do
2623 * copy n bytes of s to cvt buffer and 0-terminate it
2624 * pointer to cvt buf returned
2625 * data ok until the next cvtbuf() call
2626 */
2627
2628 char*
cxcvt(register Cx_t * cx,const char * s,size_t n)2629 cxcvt(register Cx_t* cx, const char* s, size_t n)
2630 {
2631 if (cx->cvtsiz <= n || !cx->cvtbuf)
2632 {
2633 cx->cvtsiz = roundof(n + 1, CX_CVT);
2634 if (!(cx->cvtbuf = vmoldof(cx->vm, cx->cvtbuf, char, cx->cvtsiz, 0)))
2635 {
2636 if (cx->disc->errorf)
2637 (*cx->disc->errorf)(NiL, cx->disc, ERROR_SYSTEM|2, "out of space");
2638 return (char*)s;
2639 }
2640 }
2641 memcpy(cx->cvtbuf, s, n);
2642 cx->cvtbuf[n] = 0;
2643 return cx->cvtbuf;
2644 }
2645