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