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 * 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-09-04 $\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*
dssfind(const char * name,const char * suffix,Dssflags_t flags,char * path,size_t size,Dssdisc_t * disc)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*
loadtags(const char * name,const char * suffix,Dssdisc_t * disc,Dssmeth_t * meth)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
dssidentf(Dssfile_t * file,void * buf,size_t size,Dssdisc_t * disc)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
dssopenf(Dssfile_t * file,Dssdisc_t * disc)153 dssopenf(Dssfile_t* file, Dssdisc_t* disc)
154 {
155 return 0;
156 }
157
158 /*
159 * dss readf
160 */
161
162 static int
dssreadf(Dssfile_t * file,Dssrecord_t * record,Dssdisc_t * disc)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
dsswritef(Dssfile_t * file,Dssrecord_t * record,Dssdisc_t * disc)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
dssseekf(Dssfile_t * file,Sfoff_t offset,Dssdisc_t * disc)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
dssclosef(Dssfile_t * file,Dssdisc_t * disc)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*
dssmethf(const char * name,const char * options,const char * schema,Dssdisc_t * disc,Dssmeth_t * meth)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*
init(void * dll,Dsslib_t * lib,const char * path,Dssflags_t flags,Dssdisc_t * disc)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*
dsslib(const char * name,Dssflags_t flags,Dssdisc_t * disc)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
dssadd(register Dsslib_t * lib,Dssdisc_t * disc)398 dssadd(register Dsslib_t* lib, Dssdisc_t* disc)
399 {
400 register int i;
401 int schema;
402
403 if (lib->header.flags & CX_INITIALIZED)
404 return 0;
405 lib->header.flags |= CX_INITIALIZED;
406 if (lib->libraries)
407 for (i = 0; lib->libraries[i]; i++)
408 if (!dssload(lib->libraries[i], disc))
409 return -1;
410 if (lib->types)
411 {
412 schema = -1;
413 for (i = 0; lib->types[i].name; i++)
414 {
415 if (cxaddtype(NiL, &lib->types[i], disc))
416 return -1;
417 if (lib->types[i].header.flags & CX_SCHEMA)
418 schema = i;
419 }
420 for (i = 0; i <= schema; i++)
421 if ((lib->types[i].header.flags & (CX_INITIALIZED|CX_SCHEMA)) == CX_SCHEMA)
422 {
423 lib->types[i].header.flags |= CX_INITIALIZED;
424 lib->types[i].member->members = state.cx->variables;
425 }
426 }
427 if (lib->callouts)
428 for (i = 0; lib->callouts[i].callout; i++)
429 if (cxaddcallout(NiL, &lib->callouts[i], disc))
430 return -1;
431 if (lib->recodes)
432 for (i = 0; lib->recodes[i].recode; i++)
433 if (cxaddrecode(NiL, &lib->recodes[i], disc))
434 return -1;
435 if (lib->maps)
436 for (i = 0; lib->maps[i]; i++)
437 if (cxaddmap(NiL, lib->maps[i], disc))
438 return -1;
439 if (lib->queries)
440 for (i = 0; lib->queries[i].name; i++)
441 if (cxaddquery(NiL, &lib->queries[i], disc))
442 return -1;
443 if (lib->constraints)
444 for (i = 0; lib->constraints[i].name; i++)
445 if (cxaddconstraint(NiL, &lib->constraints[i], disc))
446 return -1;
447 if (lib->edits)
448 for (i = 0; lib->edits[i].name; i++)
449 if (cxaddedit(NiL, &lib->edits[i], disc))
450 return -1;
451 if (!dtsearch(state.cx->libraries, lib))
452 dtinsert(state.cx->libraries, lib);
453 return 0;
454 }
455
456 /*
457 * find and add library name
458 */
459
460 Dsslib_t*
dssload(const char * name,Dssdisc_t * disc)461 dssload(const char* name, Dssdisc_t* disc)
462 {
463 Dsslib_t* lib;
464
465 if (!(lib = dsslib(name, DSS_VERBOSE, disc)))
466 return 0;
467 return dssadd(lib, disc) ? 0 : lib;
468 }
469
470 /*
471 * return the input location string for data
472 * suitable for errorf
473 */
474
475 static char*
location(Cx_t * cx,void * data,Cxdisc_t * disc)476 location(Cx_t* cx, void* data, Cxdisc_t* disc)
477 {
478 register Dssfile_t* file = DSSRECORD(data)->file;
479 char* path;
480 char* sep;
481 char* loc;
482 char* nxt;
483 char* end;
484 size_t n;
485
486 if (!file)
487 return "";
488 if (path = strrchr(file->path, '/'))
489 path++;
490 else
491 path = file->path;
492 n = strlen(path) + 3;
493 sep = ": ";
494 if (file->count || file->offset)
495 {
496 sep = ", ";
497 n += 64;
498 }
499 loc = nxt = fmtbuf(n);
500 end = loc + n;
501 nxt += sfsprintf(nxt, end - nxt, "%s%s", path, sep);
502 if (file->count || file->offset)
503 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);
504 return loc;
505 }
506
507 static int
dss_mem_get(Cx_t * cx,Cxinstruction_t * pc,Cxoperand_t * r,Cxoperand_t * a,Cxoperand_t * b,void * data,Cxdisc_t * disc)508 dss_mem_get(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
509 {
510 Dssfile_t* file = DSSRECORD(data)->file;
511
512 switch (pc->data.variable->index)
513 {
514 case DSS_MEM_file:
515 r->value.string.data = (char*)file->path;
516 r->value.string.size = strlen(file->path);
517 break;
518 case DSS_MEM_format:
519 r->value.string.data = (char*)file->format->name;
520 r->value.string.size = strlen(file->format->name);
521 break;
522 case DSS_MEM_length:
523 r->value.number = file->length;
524 break;
525 case DSS_MEM_offset:
526 r->value.number = file->offset;
527 break;
528 case DSS_MEM_queried:
529 r->value.number = cx->expr ? cx->expr->parent->queried : 0;
530 break;
531 case DSS_MEM_record:
532 r->value.number = file->count;
533 break;
534 case DSS_MEM_selected:
535 r->value.number = cx->expr ? cx->expr->parent->selected : 0;
536 break;
537 default:
538 return -1;
539 }
540 return 0;
541 }
542
543 static Cxmember_t dss_mem =
544 {
545 dss_mem_get,
546 0,
547 (Dt_t*)&dss_mem_struct[0],
548 CX_VIRTUAL
549 };
550
551 static Cxtype_t dss_type[] =
552 {
553 { DSS_ID "_s", "Global state struct.", CXH, (Cxtype_t*)"void", 0, 0, 0, 0, 0, 0, 0, {0}, 0, &dss_mem },
554 { DSS_ID "_t", "Global state.", CXH, (Cxtype_t*)DSS_ID "_s" },
555 };
556
557 static Cxvariable_t dss_var[] =
558 {
559 CXV(".", DSS_ID "_t", 0, "Global State.")
560 CXV(DSS_ID, DSS_ID "_t", 0, "Global State.")
561 };
562
563 /*
564 * open a dss session
565 */
566
567 Dss_t*
dssopen(Dssflags_t flags,Dssflags_t test,Dssdisc_t * disc,Dssmeth_t * meth)568 dssopen(Dssflags_t flags, Dssflags_t test, Dssdisc_t* disc, Dssmeth_t* meth)
569 {
570 register Dss_t* dss;
571 register Vmalloc_t* vm;
572 Cxvariable_t* var;
573 Dsslib_t* lib;
574 int i;
575
576 if (!disc)
577 return 0;
578 dssstate(disc);
579 if (!meth)
580 {
581 /*
582 * find the first user library that defines a method
583 */
584
585 lib = (Dsslib_t*)dtfirst(state.cx->libraries);
586 while ((lib = (Dsslib_t*)dtnext(state.cx->libraries, lib)) && !lib->meth);
587 if (lib)
588 meth = lib->meth;
589 else
590 {
591 if (!(flags & DSS_QUIET) && disc->errorf)
592 (*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "a method must be specified");
593 return 0;
594 }
595 }
596 if (!(vm = vmopen(Vmdcheap, Vmbest, 0)))
597 {
598 if (disc->errorf)
599 (*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
600 return 0;
601 }
602 if (!(dss = vmnewof(vm, 0, Dss_t, 1, 0)))
603 {
604 if (disc->errorf)
605 (*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
606 vmclose(vm);
607 return 0;
608 }
609 if (!disc->loadf)
610 disc->loadf = dssload;
611 if (!disc->locationf)
612 disc->locationf = location;
613 dss->id = id;
614 dss->vm = vm;
615 dss->disc = disc;
616 if (!meth->cx || (meth->flags & DSS_BASE))
617 meth = dssmethinit(NiL, NiL, NiL, disc, meth);
618 dss->meth = meth;
619 dss->flags = flags;
620 dss->test = test;
621 dss->state = &state;
622 if (!(dss->cx = cxscope(NiL, meth->cx, flags & DSS_CX_FLAGS, test, disc)) || disc->map && !loadtags(disc->map, "map", disc, meth))
623 goto bad;
624 dss->cx->caller = dss;
625 if (meth->openf && (*meth->openf)(dss, dss->disc))
626 goto bad;
627 for (var = (Cxvariable_t*)dtfirst(dss->cx->variables); var; var = (Cxvariable_t*)dtnext(dss->cx->variables, var))
628 if (var->format.map)
629 var->format.map->header.flags |= CX_REFERENCED;
630 for (i = 0; i < elementsof(dss_type); i++)
631 if (!cxtype(NiL, dss_type[i].name, disc) && cxaddtype(NiL, &dss_type[i], disc))
632 goto bad;
633 for (i = 0; i < elementsof(dss_var); i++)
634 {
635 if (!(var = vmnewof(vm, 0, Cxvariable_t, 1, 0)))
636 goto bad;
637 *var = dss_var[i];
638 var->header.flags |= CX_INITIALIZED;
639 if (cxaddvariable(dss->cx, var, disc))
640 goto bad;
641 }
642 return state.dss = dss;
643 bad:
644 dssclose(dss);
645 return 0;
646 }
647
648 /*
649 * close a dss session
650 */
651
652 int
dssclose(register Dss_t * dss)653 dssclose(register Dss_t* dss)
654 {
655 int r;
656
657 if (!dss)
658 return -1;
659 if (dss->meth->closef)
660 r = (*dss->meth->closef)(dss, dss->disc);
661 else
662 r = 0;
663 if (dss == state.dss)
664 state.dss = 0;
665 if (!dss->vm)
666 r = -1;
667 else
668 vmclose(dss->vm);
669 return r;
670 }
671
672 /*
673 * initialize method given pointer
674 * this is a library private global for dssmeth() and dssstatic()
675 */
676
677 Dssmeth_t*
dssmethinit(const char * name,const char * options,const char * schema,Dssdisc_t * disc,Dssmeth_t * meth)678 dssmethinit(const char* name, const char* options, const char* schema, Dssdisc_t* disc, Dssmeth_t* meth)
679 {
680 Dssmeth_t* ometh;
681 Opt_t opt;
682
683 if (meth->flags & DSS_BASE)
684 {
685 if (!(ometh = newof(0, Dssmeth_t, 1, 0)))
686 {
687 if (disc->errorf)
688 (*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
689 return 0;
690 }
691 *ometh = *meth;
692 meth = ometh;
693 meth->flags &= ~DSS_BASE;
694 meth->cx = 0;
695 }
696 if (!meth->cx && !(meth->cx = cxopen(0, 0, disc)))
697 return 0;
698 if (!meth->formats && !(meth->formats = dtopen(&state.cx->namedisc, Dtoset)))
699 {
700 cxclose(meth->cx);
701 if (disc->errorf)
702 (*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
703 return 0;
704 }
705 if (name)
706 {
707 if (meth->methf)
708 {
709 ometh = meth;
710 opt = opt_info;
711 state.cx->header = (Cxheader_t*)meth;
712 state.meth = meth;
713 meth = (*meth->methf)(name, options, schema, disc, meth);
714 opt_info = opt;
715 if (!meth)
716 return 0;
717 if (meth != ometh)
718 meth->reference++;
719 }
720 else if (options)
721 return 0;
722 }
723 return state.meth = meth;
724 }
725
726 /*
727 * return method given name
728 */
729
730 Dssmeth_t*
dssmeth(const char * name,Dssdisc_t * disc)731 dssmeth(const char* name, Dssdisc_t* disc)
732 {
733 register char* s;
734 const char* options;
735 const char* schema;
736 Dsslib_t* lib;
737 Dssmeth_t* meth;
738 char buf[1024];
739 char path[1024];
740
741 buf[sfsprintf(buf, sizeof(buf) - 1, "%s", name)] = 0;
742 options = schema = 0;
743 for (s = buf; *s; s++)
744 if (*s == ',' || *s == '\t' || *s == '\r' || *s == '\n')
745 {
746 if (!options)
747 {
748 *s++ = 0;
749 options = (char*)s;
750 }
751 }
752 else if (*s == ':')
753 {
754 *s++ = 0;
755 schema = name + (s - buf);
756 break;
757 }
758 name = (const char*)buf;
759 if (!*name)
760 name = id;
761 if (!(meth = (Dssmeth_t*)dtmatch(state.cx->methods, name)))
762 {
763 if (pathfind(name, id, id, path, sizeof(path)))
764 {
765 meth = &dss_method;
766 name = id;
767 schema = path;
768 }
769 else if (!(lib = dsslib(name, 0, disc)) || !(meth = lib->meth) || dssadd(lib, disc))
770 return 0;
771 }
772 return dssmethinit(name, options, schema, disc, meth);
773 }
774
775 /*
776 * return initialized global state pointer
777 */
778
779 Dssstate_t*
dssstate(Dssdisc_t * disc)780 dssstate(Dssdisc_t* disc)
781 {
782 if (!state.initialized && !state.initialized++)
783 {
784 error(-1, "%s", fmtident(usage));
785 state.cx = cxstate(disc);
786 dtinsert(state.cx->libraries, &dss_library);
787 if (dssadd(&dss_library, disc))
788 error(ERROR_PANIC, "%s library initialization error", id);
789 }
790 return &state;
791 }
792
793 /*
794 * return 1 if expr contains a query
795 */
796
797 static int
hasquery(register Dssexpr_t * expr)798 hasquery(register Dssexpr_t* expr)
799 {
800 do
801 {
802 if (!expr->query->prog)
803 return 1;
804 if (expr->pass && hasquery(expr->pass))
805 return 1;
806 if (expr->fail && hasquery(expr->fail))
807 return 1;
808 if (expr->group && hasquery(expr->group))
809 return 1;
810 } while (expr = expr->next);
811 return 0;
812 }
813
814 /*
815 * apply expression with optional head and tail queries to files in argv
816 */
817
818 int
dssrun(Dss_t * dss,const char * expression,const char * head,const char * tail,char ** argv)819 dssrun(Dss_t* dss, const char* expression, const char* head, const char* tail, char** argv)
820 {
821 register Dssexpr_t* x;
822 Dssexpr_t* expr;
823 Dssexpr_t* xh;
824 Dssexpr_t* xt;
825 int errors;
826 int r;
827
828 errors = error_info.errors;
829 if (!expression || !*expression || *expression == '-' && !*(expression + 1))
830 expression = tail ? tail : "{write}";
831 if (!(expr = dsscomp(dss, expression, NiL)))
832 return -1;
833 xh = xt = 0;
834 r = -1;
835 if (expression == tail)
836 tail = 0;
837 else if (!tail && !hasquery(expr))
838 tail = "{write}";
839 if (tail)
840 {
841 if (!(xt = dsscomp(dss, tail, NiL)))
842 goto bad;
843 if (xt->query->beg == null_beg)
844 {
845 dssfree(dss, xt);
846 xt = 0;
847 }
848 }
849 for (x = expr; x->group; x = x->group);
850 if (!x->query->head)
851 {
852 if (!head)
853 head = "{scan}";
854 if (!(xh = dsscomp(dss, head, NiL)))
855 goto bad;
856 if (!xh->query->head)
857 {
858 if (dss->disc->errorf)
859 (*dss->disc->errorf)(dss, dss->disc, 2, "%s: not a head query", head);
860 goto bad;
861 }
862 xh->files = argv;
863 }
864 else if (head)
865 {
866 if (dss->disc->errorf)
867 (*dss->disc->errorf)(dss, dss->disc, 2, "%s: expression already has %s head", head, x->query->name);
868 goto bad;
869 }
870 else
871 x->files = argv;
872 if (xh || xt)
873 {
874 if (expr->pass || expr->fail || expr->next)
875 {
876 if (!(x = vmnewof(expr->vm, 0, Cxexpr_t, 1, sizeof(Cxquery_t))))
877 {
878 if (dss->disc->errorf)
879 (*dss->disc->errorf)(dss, dss->disc, ERROR_SYSTEM|2, "out of space");
880 goto bad;
881 }
882 x->vm = expr->vm;
883 x->done = expr->done;
884 x->stack = expr->stack;
885 x->op = expr->op;
886 x->query = (Cxquery_t*)(x + 1);
887 x->group = expr;
888 expr = x;
889 }
890 if (xt)
891 {
892 expr->pass = xt;
893 xt->parent = expr;
894 }
895 if (xh)
896 {
897 x = xh->pass = expr;
898 expr = xh;
899 xh = x;
900 }
901 }
902 if (expr->pass)
903 expr->pass->parent = expr->pass;
904 if (dss->test & 0x00000100)
905 dsslist(dss, expr, sfstdout);
906 if (dssbeg(dss, expr) || dssend(dss, expr))
907 goto bad;
908 dssfree(dss, expr);
909 r = error_info.errors != errors ? -1 : 0;
910 bad:
911 if (xh)
912 dssfree(dss, xh);
913 if (xt)
914 dssfree(dss, xt);
915 dssfree(dss, expr);
916 return r;
917 }
918