Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/lib/libdss/dssopen.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
* dss open/close/library/method implementation
23
*
24
* Glenn Fowler
25
* AT&T Research
26
*/
27
28
static const char usage[] =
29
"[-1ls5P?\n@(#)$Id: dss library (AT&T Research) 2012-05-31 $\n]"
30
USAGE_LICENSE
31
"[+PLUGIN?\findex\f]"
32
"[+DESCRIPTION?The \bdss\b default method provides types, global "
33
"variables, and a schema available for all other methods.]"
34
"{\fvariables\f}"
35
"[+?The schema is a pure XML (tags "
36
"only) file that specifies the \bdss\b method and optional field value "
37
"maps and constraints. Public schemas are usually placed in a "
38
"\b../lib/dss\b sibling directory on \b$PATH\b. The supported tags are:]"
39
"{"
40
;
41
42
#include "dsshdr.h"
43
44
#include <dlldefs.h>
45
#include <pzip.h>
46
#include <stak.h>
47
48
typedef Dsslib_t* (*Dsslib_f)(const char*, Dssdisc_t*);
49
50
static const char id[] = DSS_ID;
51
52
static Dssstate_t state;
53
54
#define DSS_MEM_file 1
55
#define DSS_MEM_format 2
56
#define DSS_MEM_length 3
57
#define DSS_MEM_offset 4
58
#define DSS_MEM_queried 5
59
#define DSS_MEM_record 6
60
#define DSS_MEM_selected 7
61
62
static Cxvariable_t dss_mem_struct[] =
63
{
64
CXV("file", "string", DSS_MEM_file, "Current record file name.")
65
CXV("format", "string", DSS_MEM_format, "Current record format.")
66
CXV("length", "number", DSS_MEM_length, "Current record length (always 0 for some formats.)")
67
CXV("offset", "number", DSS_MEM_offset, "Current record offset (always 0 for some formats.).")
68
CXV("queried", "number", DSS_MEM_queried, "Current queried record count.")
69
CXV("record", "number", DSS_MEM_record, "Current record number.")
70
CXV("selected", "number", DSS_MEM_selected, "Current selected record count.")
71
{0}
72
};
73
74
/*
75
* find and open file for read
76
*/
77
78
Sfio_t*
79
dssfind(const char* name, const char* suffix, Dssflags_t flags, char* path, size_t size, Dssdisc_t* disc)
80
{
81
Sfio_t* sp;
82
83
if (!suffix)
84
suffix = id;
85
if (*name == ':')
86
{
87
sfsprintf(path, size, "%s", "schema-string");
88
sp = sfnew(NiL, (char*)name + 1, strlen(name) - 1, -1, SF_READ|SF_STRING);
89
}
90
else if (!pathfind(name, id, suffix, path, size))
91
{
92
if ((flags & DSS_VERBOSE) && disc->errorf)
93
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "%s: %s file not found", name, suffix);
94
return 0;
95
}
96
else
97
sp = sfopen(NiL, path, "r");
98
if (!sp)
99
{
100
if ((flags & DSS_VERBOSE) && disc->errorf)
101
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "%s: cannot read %s file", path, suffix);
102
return 0;
103
}
104
return sp;
105
}
106
107
/*
108
* load tags file
109
*/
110
111
static Dssmeth_t*
112
loadtags(const char* name, const char* suffix, Dssdisc_t* disc, Dssmeth_t* meth)
113
{
114
Sfio_t* sp;
115
char path[PATH_MAX];
116
117
if (streq(name, DSS_ID))
118
return meth;
119
if (!(sp = dssfind(name, suffix, DSS_VERBOSE, path, sizeof(path), disc)))
120
return 0;
121
return dsstags(sp, path, 1, 0, disc, meth);
122
}
123
124
/*
125
* dss identf
126
*/
127
128
static int
129
dssidentf(Dssfile_t* file, void* buf, size_t size, Dssdisc_t* disc)
130
{
131
register char* s;
132
register char* e;
133
134
s = (char*)buf;
135
e = s + size;
136
while (s < e && isspace(*s))
137
s++;
138
if (*s++ != '<')
139
return 0;
140
if (*s == '!')
141
while (s < e && *s++ != '!');
142
else
143
while (s < e && isalpha(*s))
144
s++;
145
return s < e && *s == '>';
146
}
147
148
/*
149
* dss openf
150
*/
151
152
static int
153
dssopenf(Dssfile_t* file, Dssdisc_t* disc)
154
{
155
return 0;
156
}
157
158
/*
159
* dss readf
160
*/
161
162
static int
163
dssreadf(Dssfile_t* file, Dssrecord_t* record, Dssdisc_t* disc)
164
{
165
return 0;
166
}
167
168
/*
169
* dss writef
170
*/
171
172
static int
173
dsswritef(Dssfile_t* file, Dssrecord_t* record, Dssdisc_t* disc)
174
{
175
return 0;
176
}
177
178
/*
179
* dss seekf
180
*/
181
182
static Sfoff_t
183
dssseekf(Dssfile_t* file, Sfoff_t offset, Dssdisc_t* disc)
184
{
185
return 0;
186
}
187
188
/*
189
* dss closef
190
*/
191
192
static int
193
dssclosef(Dssfile_t* file, Dssdisc_t* disc)
194
{
195
return 0;
196
}
197
198
static Dssformat_t dss_format =
199
{
200
&id[0],
201
"pseudo-format that treats all files as /dev/null",
202
CXH,
203
dssidentf,
204
dssopenf,
205
dssreadf,
206
dsswritef,
207
dssseekf,
208
dssclosef
209
};
210
211
static Dssmeth_t* dssmethf(const char*, const char*, const char*, Dssdisc_t*, Dssmeth_t*);
212
213
static Dssmeth_t dss_method =
214
{
215
&id[0],
216
"meta-method that specifies a method, value maps and constraints",
217
CXH,
218
dssmethf
219
};
220
221
/*
222
* dss methf
223
*/
224
225
static Dssmeth_t*
226
dssmethf(const char* name, const char* options, const char* schema, Dssdisc_t* disc, Dssmeth_t* meth)
227
{
228
Sfio_t* up;
229
char* us;
230
Tagdisc_t tagdisc;
231
232
if (options)
233
{
234
if (!(up = sfstropen()))
235
{
236
if (disc->errorf)
237
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
238
return 0;
239
}
240
sfprintf(up, "%s", usage);
241
taginit(&tagdisc, disc->errorf);
242
if (tagusage(dss_tags, up, &tagdisc))
243
{
244
sfclose(up);
245
return 0;
246
}
247
sfputc(up, '}');
248
sfputc(up, '\n');
249
if (!(us = sfstruse(up)))
250
{
251
sfclose(up);
252
return 0;
253
}
254
dss_method.data = dss_mem_struct;
255
state.global = &dss_method;
256
for (;;)
257
{
258
switch (optstr(options, us))
259
{
260
case '?':
261
if (disc->errorf)
262
(*disc->errorf)(NiL, disc, ERROR_USAGE|4, "%s", opt_info.arg);
263
return 0;
264
case ':':
265
if (disc->errorf)
266
(*disc->errorf)(NiL, disc, 2, "%s", opt_info.arg);
267
return 0;
268
}
269
break;
270
}
271
state.global = 0;
272
sfclose(up);
273
}
274
if (schema)
275
return loadtags(schema, NiL, disc, meth);
276
dtinsert(meth->formats, &dss_format);
277
return meth;
278
}
279
280
#include "dss-compress.h"
281
#include "dss-count.h"
282
#include "dss-null.h"
283
#include "dss-print.h"
284
#include "dss-return.h"
285
#include "dss-scan.h"
286
#include "dss-write.h"
287
288
static Cxquery_t queries[] =
289
{
290
QUERY_compress,
291
QUERY_count,
292
QUERY_null,
293
QUERY_print,
294
QUERY_return,
295
QUERY_scan,
296
QUERY_write,
297
{0},
298
};
299
300
static Dsslib_t dss_library =
301
{
302
&id[0],
303
"dss method",
304
CXH,
305
0,
306
&dss_method,
307
0,
308
0,
309
0,
310
0,
311
&queries[0],
312
0,
313
0,
314
0
315
};
316
317
/*
318
* initialize library given name and dlopen() handle
319
*/
320
321
static Dsslib_t*
322
init(void* dll, Dsslib_t* lib, const char* path, Dssflags_t flags, Dssdisc_t* disc)
323
{
324
Dsslib_f libf;
325
char buf[64];
326
327
/*
328
* check for the Dsslib_t* function
329
*/
330
331
if (dll)
332
{
333
sfsprintf(buf, sizeof(buf), "%s_lib", id);
334
lib = (libf = (Dsslib_f)dlllook(dll, buf)) ? (*libf)(path, disc) : (Dsslib_t*)0;
335
}
336
if (lib)
337
{
338
if (!(lib->path = (const char*)strdup(path)))
339
{
340
if (disc && disc->errorf)
341
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
342
return 0;
343
}
344
if (!dtsearch(state.cx->libraries, lib))
345
dtinsert(state.cx->libraries, lib);
346
return lib;
347
}
348
if ((flags & DSS_VERBOSE) && disc && disc->errorf)
349
(*disc->errorf)(NiL, disc, 2, "%s: %s: initialization function not found in library", path, buf);
350
return 0;
351
}
352
353
/*
354
* open and return library info for name
355
* name==0 scans for all related libraries on $PATH
356
*/
357
358
Dsslib_t*
359
dsslib(const char* name, Dssflags_t flags, Dssdisc_t* disc)
360
{
361
register Dsslib_t* lib;
362
Dllscan_t* dls;
363
Dllent_t* dle;
364
void* dll;
365
Dllnames_t names;
366
367
dssstate(disc);
368
if (!name)
369
{
370
if (!state.scanned)
371
{
372
state.scanned++;
373
if (dtsize(state.cx->libraries) == 1 && (dls = dllsopen(id, NiL, NiL)))
374
{
375
while (dle = dllsread(dls))
376
if (dll = dlopen(dle->path, RTLD_LAZY))
377
init(dll, NiL, dle->path, 0, disc);
378
else if (disc && disc->errorf)
379
(*disc->errorf)(NiL, disc, 1, "%s: %s", dle->path, dlerror());
380
dllsclose(dls);
381
}
382
}
383
return (Dsslib_t*)dtfirst(state.cx->libraries);
384
}
385
if (!dllnames(id, name, &names))
386
return 0;
387
if ((lib = (Dsslib_t*)dtmatch(state.cx->libraries, names.base)) ||
388
(lib = (Dsslib_t*)dll_lib(&names, DSS_PLUGIN_VERSION, (flags & DSS_VERBOSE) ? (Error_f)disc->errorf : (Error_f)0, disc)))
389
init(NiL, lib, names.path, flags|DSS_VERBOSE, disc);
390
return lib;
391
}
392
393
/*
394
* add lib tables
395
*/
396
397
int
398
dssadd(register Dsslib_t* lib, Dssdisc_t* disc)
399
{
400
register int i;
401
402
if (lib->header.flags & CX_INITIALIZED)
403
return 0;
404
lib->header.flags |= CX_INITIALIZED;
405
if (lib->libraries)
406
for (i = 0; lib->libraries[i]; i++)
407
if (!dssload(lib->libraries[i], disc))
408
return -1;
409
if (lib->types)
410
for (i = 0; lib->types[i].name; i++)
411
if (cxaddtype(NiL, &lib->types[i], disc))
412
return -1;
413
if (lib->callouts)
414
for (i = 0; lib->callouts[i].callout; i++)
415
if (cxaddcallout(NiL, &lib->callouts[i], disc))
416
return -1;
417
if (lib->recodes)
418
for (i = 0; lib->recodes[i].recode; i++)
419
if (cxaddrecode(NiL, &lib->recodes[i], disc))
420
return -1;
421
if (lib->maps)
422
for (i = 0; lib->maps[i]; i++)
423
if (cxaddmap(NiL, lib->maps[i], disc))
424
return -1;
425
if (lib->queries)
426
for (i = 0; lib->queries[i].name; i++)
427
if (cxaddquery(NiL, &lib->queries[i], disc))
428
return -1;
429
if (lib->constraints)
430
for (i = 0; lib->constraints[i].name; i++)
431
if (cxaddconstraint(NiL, &lib->constraints[i], disc))
432
return -1;
433
if (lib->edits)
434
for (i = 0; lib->edits[i].name; i++)
435
if (cxaddedit(NiL, &lib->edits[i], disc))
436
return -1;
437
if (!dtsearch(state.cx->libraries, lib))
438
dtinsert(state.cx->libraries, lib);
439
return 0;
440
}
441
442
/*
443
* find and add library name
444
*/
445
446
Dsslib_t*
447
dssload(const char* name, Dssdisc_t* disc)
448
{
449
Dsslib_t* lib;
450
451
if (!(lib = dsslib(name, DSS_VERBOSE, disc)))
452
return 0;
453
return dssadd(lib, disc) ? 0 : lib;
454
}
455
456
/*
457
* return the input location string for data
458
* suitable for errorf
459
*/
460
461
static char*
462
location(Cx_t* cx, void* data, Cxdisc_t* disc)
463
{
464
register Dssfile_t* file = DSSRECORD(data)->file;
465
char* path;
466
char* sep;
467
char* loc;
468
char* nxt;
469
char* end;
470
size_t n;
471
472
if (!file)
473
return "";
474
if (path = strrchr(file->path, '/'))
475
path++;
476
else
477
path = file->path;
478
n = strlen(path) + 3;
479
sep = ": ";
480
if (file->count || file->offset)
481
{
482
sep = ", ";
483
n += 64;
484
}
485
loc = nxt = fmtbuf(n);
486
end = loc + n;
487
nxt += sfsprintf(nxt, end - nxt, "%s%s", path, sep);
488
if (file->count || file->offset)
489
sfsprintf(nxt, end - nxt, "%s %I*u, %s %I*d: ", ERROR_translate(NiL, NiL, id, "record"), sizeof(file->count), file->count, ERROR_translate(NiL, NiL, id, "offset"), sizeof(file->offset), file->offset);
490
return loc;
491
}
492
493
static int
494
dss_mem_get(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
495
{
496
Dssfile_t* file = DSSRECORD(data)->file;
497
498
switch (pc->data.variable->index)
499
{
500
case DSS_MEM_file:
501
r->value.string.data = (char*)file->path;
502
r->value.string.size = strlen(file->path);
503
break;
504
case DSS_MEM_format:
505
r->value.string.data = (char*)file->format->name;
506
r->value.string.size = strlen(file->format->name);
507
break;
508
case DSS_MEM_length:
509
r->value.number = file->length;
510
break;
511
case DSS_MEM_offset:
512
r->value.number = file->offset;
513
break;
514
case DSS_MEM_queried:
515
r->value.number = cx->expr ? cx->expr->parent->queried : 0;
516
break;
517
case DSS_MEM_record:
518
r->value.number = file->count;
519
break;
520
case DSS_MEM_selected:
521
r->value.number = cx->expr ? cx->expr->parent->selected : 0;
522
break;
523
default:
524
return -1;
525
}
526
return 0;
527
}
528
529
static Cxmember_t dss_mem =
530
{
531
dss_mem_get,
532
0,
533
(Dt_t*)&dss_mem_struct[0]
534
};
535
536
static Cxtype_t dss_type[] =
537
{
538
{ DSS_ID "_s", "Global state struct.", CXH, (Cxtype_t*)"void", 0, 0, 0, 0, 0, 0, 0, {0}, 0, &dss_mem },
539
{ DSS_ID "_t", "Global state.", CXH, (Cxtype_t*)DSS_ID "_s" },
540
};
541
542
static Cxvariable_t dss_var[] =
543
{
544
CXV(".", DSS_ID "_t", 0, "Global State.")
545
CXV(DSS_ID, DSS_ID "_t", 0, "Global State.")
546
};
547
548
/*
549
* open a dss session
550
*/
551
552
Dss_t*
553
dssopen(Dssflags_t flags, Dssflags_t test, Dssdisc_t* disc, Dssmeth_t* meth)
554
{
555
register Dss_t* dss;
556
register Vmalloc_t* vm;
557
Cxvariable_t* var;
558
Dsslib_t* lib;
559
int i;
560
561
if (!disc)
562
return 0;
563
dssstate(disc);
564
if (!meth)
565
{
566
/*
567
* find the first user library that defines a method
568
*/
569
570
lib = (Dsslib_t*)dtfirst(state.cx->libraries);
571
while ((lib = (Dsslib_t*)dtnext(state.cx->libraries, lib)) && !lib->meth);
572
if (lib)
573
meth = lib->meth;
574
else
575
{
576
if (!(flags & DSS_QUIET) && disc->errorf)
577
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "a method must be specified");
578
return 0;
579
}
580
}
581
if (!(vm = vmopen(Vmdcheap, Vmbest, 0)))
582
{
583
if (disc->errorf)
584
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
585
return 0;
586
}
587
if (!(dss = vmnewof(vm, 0, Dss_t, 1, 0)))
588
{
589
if (disc->errorf)
590
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
591
vmclose(vm);
592
return 0;
593
}
594
if (!disc->loadf)
595
disc->loadf = dssload;
596
if (!disc->locationf)
597
disc->locationf = location;
598
dss->id = id;
599
dss->vm = vm;
600
dss->disc = disc;
601
if (!meth->cx || (meth->flags & DSS_BASE))
602
meth = dssmethinit(NiL, NiL, NiL, disc, meth);
603
dss->meth = meth;
604
dss->flags = flags;
605
dss->test = test;
606
dss->state = &state;
607
if (!(dss->cx = cxscope(NiL, meth->cx, flags & DSS_CX_FLAGS, test, disc)) || disc->map && !loadtags(disc->map, "map", disc, meth))
608
goto bad;
609
dss->cx->caller = dss;
610
if (meth->openf && (*meth->openf)(dss, dss->disc))
611
goto bad;
612
for (var = (Cxvariable_t*)dtfirst(dss->cx->variables); var; var = (Cxvariable_t*)dtnext(dss->cx->variables, var))
613
if (var->format.map)
614
var->format.map->header.flags |= CX_REFERENCED;
615
for (i = 0; i < elementsof(dss_type); i++)
616
if (!cxtype(NiL, dss_type[i].name, disc) && cxaddtype(NiL, &dss_type[i], disc))
617
goto bad;
618
for (i = 0; i < elementsof(dss_var); i++)
619
{
620
if (!(var = vmnewof(vm, 0, Cxvariable_t, 1, 0)))
621
goto bad;
622
*var = dss_var[i];
623
var->header.flags |= CX_INITIALIZED;
624
if (cxaddvariable(dss->cx, var, disc))
625
goto bad;
626
}
627
return state.dss = dss;
628
bad:
629
dssclose(dss);
630
return 0;
631
}
632
633
/*
634
* close a dss session
635
*/
636
637
int
638
dssclose(register Dss_t* dss)
639
{
640
int r;
641
642
if (!dss)
643
return -1;
644
if (dss->meth->closef)
645
r = (*dss->meth->closef)(dss, dss->disc);
646
else
647
r = 0;
648
if (dss == state.dss)
649
state.dss = 0;
650
if (!dss->vm)
651
r = -1;
652
else
653
vmclose(dss->vm);
654
return r;
655
}
656
657
/*
658
* initialize method given pointer
659
* this is a library private global for dssmeth() and dssstatic()
660
*/
661
662
Dssmeth_t*
663
dssmethinit(const char* name, const char* options, const char* schema, Dssdisc_t* disc, Dssmeth_t* meth)
664
{
665
Dssmeth_t* ometh;
666
Opt_t opt;
667
668
if (meth->flags & DSS_BASE)
669
{
670
if (!(ometh = newof(0, Dssmeth_t, 1, 0)))
671
{
672
if (disc->errorf)
673
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
674
return 0;
675
}
676
*ometh = *meth;
677
meth = ometh;
678
meth->flags &= ~DSS_BASE;
679
meth->cx = 0;
680
}
681
if (!meth->cx && !(meth->cx = cxopen(0, 0, disc)))
682
return 0;
683
if (!meth->formats && !(meth->formats = dtopen(&state.cx->namedisc, Dtoset)))
684
{
685
cxclose(meth->cx);
686
if (disc->errorf)
687
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
688
return 0;
689
}
690
if (name)
691
{
692
if (meth->methf)
693
{
694
ometh = meth;
695
opt = opt_info;
696
state.cx->header = (Cxheader_t*)meth;
697
state.meth = meth;
698
meth = (*meth->methf)(name, options, schema, disc, meth);
699
opt_info = opt;
700
if (!meth)
701
return 0;
702
if (meth != ometh)
703
meth->reference++;
704
}
705
else if (options)
706
return 0;
707
}
708
return state.meth = meth;
709
}
710
711
/*
712
* return method given name
713
*/
714
715
Dssmeth_t*
716
dssmeth(const char* name, Dssdisc_t* disc)
717
{
718
register char* s;
719
const char* options;
720
const char* schema;
721
Dsslib_t* lib;
722
Dssmeth_t* meth;
723
char buf[1024];
724
char path[1024];
725
726
buf[sfsprintf(buf, sizeof(buf) - 1, "%s", name)] = 0;
727
options = schema = 0;
728
for (s = buf; *s; s++)
729
if (*s == ',' || *s == '\t' || *s == '\r' || *s == '\n')
730
{
731
if (!options)
732
{
733
*s++ = 0;
734
options = (char*)s;
735
}
736
}
737
else if (*s == ':')
738
{
739
*s++ = 0;
740
schema = name + (s - buf);
741
break;
742
}
743
name = (const char*)buf;
744
if (!*name)
745
name = id;
746
if (!(meth = (Dssmeth_t*)dtmatch(state.cx->methods, name)))
747
{
748
if (pathfind(name, id, id, path, sizeof(path)))
749
{
750
meth = &dss_method;
751
name = id;
752
schema = path;
753
}
754
else if (!(lib = dsslib(name, 0, disc)) || !(meth = lib->meth) || dssadd(lib, disc))
755
return 0;
756
}
757
return dssmethinit(name, options, schema, disc, meth);
758
}
759
760
/*
761
* return initialized global state pointer
762
*/
763
764
Dssstate_t*
765
dssstate(Dssdisc_t* disc)
766
{
767
if (!state.initialized && !state.initialized++)
768
{
769
error(-1, "%s", fmtident(usage));
770
state.cx = cxstate(disc);
771
dtinsert(state.cx->libraries, &dss_library);
772
if (dssadd(&dss_library, disc))
773
error(ERROR_PANIC, "%s library initialization error", id);
774
}
775
return &state;
776
}
777
778
/*
779
* return 1 if expr contains a query
780
*/
781
782
static int
783
hasquery(register Dssexpr_t* expr)
784
{
785
do
786
{
787
if (!expr->query->prog)
788
return 1;
789
if (expr->pass && hasquery(expr->pass))
790
return 1;
791
if (expr->fail && hasquery(expr->fail))
792
return 1;
793
if (expr->group && hasquery(expr->group))
794
return 1;
795
} while (expr = expr->next);
796
return 0;
797
}
798
799
/*
800
* apply expression with optional head and tail queries to files in argv
801
*/
802
803
int
804
dssrun(Dss_t* dss, const char* expression, const char* head, const char* tail, char** argv)
805
{
806
register Dssexpr_t* x;
807
Dssexpr_t* expr;
808
Dssexpr_t* xh;
809
Dssexpr_t* xt;
810
int errors;
811
int r;
812
813
errors = error_info.errors;
814
if (!expression || !*expression || *expression == '-' && !*(expression + 1))
815
expression = tail ? tail : "{write}";
816
if (!(expr = dsscomp(dss, expression, NiL)))
817
return -1;
818
xh = xt = 0;
819
r = -1;
820
if (expression == tail)
821
tail = 0;
822
else if (!tail && !hasquery(expr))
823
tail = "{write}";
824
if (tail)
825
{
826
if (!(xt = dsscomp(dss, tail, NiL)))
827
goto bad;
828
if (xt->query->beg == null_beg)
829
{
830
dssfree(dss, xt);
831
xt = 0;
832
}
833
}
834
for (x = expr; x->group; x = x->group);
835
if (!x->query->head)
836
{
837
if (!head)
838
head = "{scan}";
839
if (!(xh = dsscomp(dss, head, NiL)))
840
goto bad;
841
if (!xh->query->head)
842
{
843
if (dss->disc->errorf)
844
(*dss->disc->errorf)(dss, dss->disc, 2, "%s: not a head query", head);
845
goto bad;
846
}
847
xh->files = argv;
848
}
849
else if (head)
850
{
851
if (dss->disc->errorf)
852
(*dss->disc->errorf)(dss, dss->disc, 2, "%s: expression already has %s head", head, x->query->name);
853
goto bad;
854
}
855
else
856
x->files = argv;
857
if (xh || xt)
858
{
859
if (expr->pass || expr->fail || expr->next)
860
{
861
if (!(x = vmnewof(expr->vm, 0, Cxexpr_t, 1, sizeof(Cxquery_t))))
862
{
863
if (dss->disc->errorf)
864
(*dss->disc->errorf)(dss, dss->disc, ERROR_SYSTEM|2, "out of space");
865
goto bad;
866
}
867
x->vm = expr->vm;
868
x->done = expr->done;
869
x->stack = expr->stack;
870
x->op = expr->op;
871
x->query = (Cxquery_t*)(x + 1);
872
x->group = expr;
873
expr = x;
874
}
875
if (xt)
876
{
877
expr->pass = xt;
878
xt->parent = expr;
879
}
880
if (xh)
881
{
882
x = xh->pass = expr;
883
expr = xh;
884
xh = x;
885
}
886
}
887
if (expr->pass)
888
expr->pass->parent = expr->pass;
889
if (dss->test & 0x00000100)
890
dsslist(dss, expr, sfstdout);
891
if (dssbeg(dss, expr) || dssend(dss, expr))
892
goto bad;
893
dssfree(dss, expr);
894
r = error_info.errors != errors ? -1 : 0;
895
bad:
896
if (xh)
897
dssfree(dss, xh);
898
if (xt)
899
dssfree(dss, xt);
900
dssfree(dss, expr);
901
return r;
902
}
903
904