Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/lib/libcodex/codex.c
1808 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 2003-2011 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
* David Korn <[email protected]> *
19
* Phong Vo <[email protected]> *
20
* *
21
***********************************************************************/
22
#pragma prototyped
23
24
/*
25
* sfio decode/encode discipline wrapper
26
*/
27
28
static const char id[] = "codex";
29
30
#include <sfio_t.h>
31
#include <codex.h>
32
#include <namval.h>
33
34
static int
35
copy_close(Codex_t* code)
36
{
37
return 0;
38
}
39
40
static Codexmeth_t codex_copy =
41
{
42
"copy",
43
"No-op copy.",
44
0,
45
CODEX_DECODE|CODEX_ENCODE,
46
0,
47
0,
48
0,
49
copy_close,
50
0,
51
0,
52
0,
53
0,
54
0,
55
0,
56
0,
57
};
58
59
Codexstate_t codexstate =
60
{
61
"codex",
62
codex_first,
63
{ CODEX_VERSION },
64
{ {0}, 0, 0, -1, 0, &codex_copy, 0},
65
};
66
67
static int
68
codex_except(Sfio_t* sp, int op, void* data, Sfdisc_t* disc)
69
{
70
register Codex_t* code = CODEX(disc);
71
int f;
72
int r;
73
74
r = 0;
75
switch (op)
76
{
77
case SF_ATEXIT:
78
sfdisc(sp, SF_POPDISC);
79
break;
80
case SF_CLOSING:
81
case SF_DPOP:
82
case SF_FINAL:
83
if (code->meth->syncf)
84
{
85
SFDCNEXT(sp, f);
86
if (r = (*code->meth->syncf)(code))
87
sp->_flags |= SF_ERROR;
88
SFDCPREV(sp, f);
89
}
90
if (op != SF_CLOSING)
91
{
92
if (code->meth->donef)
93
{
94
SFDCNEXT(sp, f);
95
r = (*code->meth->donef)(code);
96
SFDCPREV(sp, f);
97
}
98
if (code->dp)
99
{
100
sfclose(code->dp);
101
code->dp = 0;
102
}
103
if (code->flags & CODEX_ACTIVE)
104
code->flags &= ~CODEX_ACTIVE;
105
else if (!(code->flags & CODEX_CACHED))
106
{
107
if (code->meth->closef)
108
r = (*code->meth->closef)(code);
109
else if (code->data)
110
free(code->data);
111
if (code->op)
112
{
113
sfswap(code->op, code->sp);
114
sfclose(code->op);
115
code->op = 0;
116
}
117
free(code);
118
}
119
}
120
break;
121
case SF_DBUFFER:
122
r = 1;
123
break;
124
case SF_SYNC:
125
if (code->meth->syncf && !(code->flags & CODEX_FLUSH))
126
{
127
SFDCNEXT(sp, f);
128
if ((r = (*code->meth->syncf)(code)) < 0)
129
sp->_flags |= SF_ERROR;
130
SFDCPREV(sp, f);
131
}
132
break;
133
case CODEX_DATA:
134
code->flags |= CODEX_FLUSH;
135
sfsync(sp);
136
code->flags &= ~CODEX_FLUSH;
137
if (data && code->meth->dataf && !(r = (*code->meth->dataf)(code, (Codexdata_t*)data)) && ((Codexdata_t*)data)->size)
138
r = 1;
139
break;
140
case CODEX_GETPOS:
141
if (!code->meth->seekf || (*((Sfoff_t*)data) = (*code->meth->seekf)(code, (Sfoff_t)0, SEEK_CUR)) < 0)
142
r = -1;
143
break;
144
case CODEX_SETPOS:
145
if (!code->meth->seekf || (*code->meth->seekf)(code, *((Sfoff_t*)data), SEEK_SET) < 0)
146
r = -1;
147
break;
148
case CODEX_SIZE:
149
if (!data)
150
r = -1;
151
else
152
code->size = *((Sfoff_t*)data);
153
break;
154
}
155
return r;
156
}
157
158
static int
159
trace_close(Codex_t* code)
160
{
161
Codexmeth_t* meth = code->meth->next;
162
int r;
163
164
if (!meth->closef)
165
return 0;
166
r = (*meth->closef)(code);
167
sfprintf(sfstderr, "codex: %d: %s: close()=%d\n", code->index, meth->name, r);
168
free(meth);
169
return r;
170
}
171
172
static int
173
trace_init(Codex_t* code)
174
{
175
Codexmeth_t* meth = code->meth->next;
176
int r;
177
178
if (!meth->initf)
179
return 0;
180
r = (*meth->initf)(code);
181
sfprintf(sfstderr, "codex: %d: %s: init()=%d\n", code->index, meth->name, r);
182
return r;
183
}
184
185
static int
186
trace_done(Codex_t* code)
187
{
188
Codexmeth_t* meth = code->meth->next;
189
int r;
190
191
if (!meth->donef)
192
return 0;
193
r = (*meth->donef)(code);
194
sfprintf(sfstderr, "codex: %d: %s: done()=%d\n", code->index, meth->name, r);
195
return r;
196
}
197
198
static ssize_t
199
trace_read(Sfio_t* f, void* buf, size_t n, Sfdisc_t* disc)
200
{
201
Codexmeth_t* meth = CODEX(disc)->meth->next;
202
ssize_t r;
203
204
if (!meth->readf)
205
return 0;
206
r = (*meth->readf)(f, buf, n, disc);
207
sfprintf(sfstderr, "codex: %d: %s: read(%I*u,%s)=%I*d\n", CODEX(disc)->index, meth->name, sizeof(n), n, (CODEX(disc)->flags & CODEX_VERBOSE) ? fmtquote(buf, "\"", "\"", r, 0) : "''", sizeof(r), r, buf);
208
return r;
209
}
210
211
static ssize_t
212
trace_write(Sfio_t* f, const void* buf, size_t n, Sfdisc_t* disc)
213
{
214
Codexmeth_t* meth = CODEX(disc)->meth->next;
215
ssize_t r;
216
217
if (!meth->writef)
218
return 0;
219
r = (*meth->writef)(f, buf, n, disc);
220
sfprintf(sfstderr, "codex: %d: %s: write(%I*u,%s)=%I*d\n", CODEX(disc)->index, meth->name, sizeof(n), n, (CODEX(disc)->flags & CODEX_VERBOSE) ? fmtquote(buf, "\"", "\"", r, 0) : "''", sizeof(r), r);
221
return r;
222
}
223
224
static int
225
trace_except(Sfio_t* f, int op, void* data, Sfdisc_t* disc)
226
{
227
Codexmeth_t* meth = CODEX(disc)->meth->next;
228
char* event;
229
int r;
230
char tmp[8];
231
232
r = codex_except(f, op, data, disc);
233
switch (op)
234
{
235
case SF_ATEXIT:
236
event = "ATEXIT";
237
break;
238
case SF_CLOSING:
239
event = "CLOSING";
240
break;
241
case SF_DBUFFER:
242
event = "DBUFFER";
243
break;
244
case SF_DPOLL:
245
event = "DPOLL";
246
break;
247
case SF_DPOP:
248
event = "DPOP";
249
break;
250
case SF_DPUSH:
251
event = "DPUSH";
252
break;
253
case SF_FINAL:
254
event = "FINAL";
255
break;
256
case SF_LOCKED:
257
event = "LOCKED";
258
break;
259
case SF_NEW:
260
event = "NEW";
261
break;
262
case SF_PURGE:
263
event = "PURGE";
264
break;
265
case SF_READ:
266
event = "READ";
267
break;
268
case SF_READY:
269
event = "READY";
270
break;
271
case SF_SEEK:
272
event = "SEEK";
273
break;
274
case SF_SYNC:
275
event = "SYNC";
276
break;
277
case SF_WRITE:
278
event = "WRITE";
279
break;
280
case CODEX_DATA:
281
event = "CODEX_DATA";
282
break;
283
case CODEX_GETPOS:
284
event = "CODEX_GETPOS";
285
break;
286
case CODEX_SETPOS:
287
event = "CODEX_SETPOS";
288
break;
289
case CODEX_SIZE:
290
event = "CODEX_SIZE";
291
break;
292
default:
293
sfsprintf(event = tmp, sizeof(tmp), "%d", op);
294
break;
295
}
296
sfprintf(sfstderr, "codex: %d: %s: except(%s,%p%s%s)=%d\n", CODEX(disc)->index, meth->name, event, data, (CODEX(disc)->flags & CODEX_ACTIVE) ? "|ACTIVE" : "", (CODEX(disc)->flags & CODEX_CACHED) ? "|CACHED" : "", r);
297
return r;
298
}
299
300
static int
301
trace_sync(Codex_t* code)
302
{
303
Codexmeth_t* meth = code->meth->next;
304
int r;
305
306
if (!meth->syncf)
307
return 0;
308
r = (*meth->syncf)(code);
309
sfprintf(sfstderr, "codex: %d: %s: sync()=%d\n", code->index, meth->name, r);
310
return r;
311
}
312
313
static Sfoff_t
314
trace_seek(Codex_t* code, Sfoff_t pos, int op)
315
{
316
Codexmeth_t* meth = code->meth->next;
317
Sfoff_t r;
318
319
if (!meth->seekf)
320
return 0;
321
r = (*meth->seekf)(code, pos, op);
322
sfprintf(sfstderr, "codex: %d: %s: seek(%I*d,%d)=%I*d\n", code->index, meth->name, sizeof(pos), pos, op, sizeof(r), r);
323
return r;
324
}
325
326
static int
327
trace_data(Codex_t* code, Codexdata_t* data)
328
{
329
Codexmeth_t* meth = code->meth->next;
330
int r;
331
unsigned char* e;
332
unsigned char* u;
333
334
if (!meth->dataf)
335
{
336
data->size = 0;
337
return 0;
338
}
339
r = (*meth->dataf)(code, data);
340
sfprintf(sfstderr, "codex: %d: %s: data()=%d", code->index, meth->name, r);
341
if (r >= 0)
342
{
343
if (data->buf)
344
for (e = (u = (unsigned char*)data->buf) + data->size; u < e; u++)
345
sfprintf(sfstderr, "%02x", *u);
346
else
347
sfprintf(sfstderr, "%0*I*x", data->size * 2, sizeof(data->num), data->num);
348
}
349
sfprintf(sfstderr, "\n");
350
return r;
351
}
352
353
static Codexmeth_t codex_trace =
354
{
355
"trace",
356
"Debug trace wrapper.",
357
0,
358
CODEX_DECODE|CODEX_ENCODE,
359
0,
360
0,
361
0,
362
trace_close,
363
trace_init,
364
trace_done,
365
trace_read,
366
trace_write,
367
trace_sync,
368
trace_seek,
369
trace_data,
370
};
371
372
#define OPT_TRACE 1
373
#define OPT_VERBOSE 2
374
375
static const Namval_t options[] =
376
{
377
"trace", OPT_TRACE,
378
"verbose", OPT_VERBOSE,
379
0, 0
380
};
381
382
/*
383
* called by stropt() to set options
384
*/
385
386
static int
387
setopt(void* a, const void* p, register int n, register const char* v)
388
{
389
NoP(a);
390
if (p)
391
switch (((Namval_t*)p)->value)
392
{
393
case OPT_TRACE:
394
codexstate.trace = n ? strdup(v) : (char*)0;
395
break;
396
case OPT_VERBOSE:
397
codexstate.verbose = n ? strdup(v) : (char*)0;
398
break;
399
}
400
return 0;
401
}
402
403
static void
404
save(Codexcache_t* cache, Codex_t* code, const char* name, int namelen, Codexnum_t flags)
405
{
406
if (cache->code && cache->code != CODEXERROR)
407
{
408
if (cache->code->meth->closef)
409
(*cache->code->meth->closef)(cache->code);
410
else if (cache->code->data)
411
free(cache->code->data);
412
if (cache->code->dp)
413
sfclose(cache->code->dp);
414
free(cache->code);
415
}
416
cache->code = code;
417
cache->flags = flags;
418
strncopy(cache->name, name, namelen < sizeof(cache->name) ? (namelen + 1) : sizeof(cache->name));
419
cache->cached = ++codexstate.cached;
420
}
421
422
/*
423
* single sfio method discipline push of meth!=0 onto sp
424
*/
425
426
static int
427
push(Sfio_t* sp, const char* name, Codexnum_t flags, Codexdisc_t* disc, Codexmeth_t* meth)
428
{
429
register char** a;
430
register char* s;
431
register char* b;
432
register int c;
433
register int q;
434
char* v;
435
int f;
436
int namelen;
437
int serial;
438
Codexnum_t deen;
439
Sfoff_t size;
440
Codex_t* code;
441
Codexcache_t* cache;
442
Codexcache_t* cp;
443
Codexmeth_t* trace;
444
char* arg[CODEX_ARGS];
445
char can[CODEX_NAME+CODEX_ARGS];
446
447
/*
448
* check for matching inactive method in the cache
449
* this avoids openf/closef thrashing
450
*/
451
452
code = 0;
453
cache = 0;
454
deen = flags & (CODEX_DECODE|CODEX_ENCODE);
455
s = (char*)name;
456
q = 0;
457
b = s;
458
while (c = *b++)
459
if (c == q)
460
q = 0;
461
else if (c == '"' || c == '\'')
462
q = c;
463
else if (!q && c == '+')
464
break;
465
namelen = b - s - 1;
466
for (cp = codexstate.cache; cp < &codexstate.cache[elementsof(codexstate.cache)]; cp++)
467
if (!cp->code)
468
(cache = cp)->cached = 0;
469
else if (!(cp->code->flags & CODEX_ACTIVE))
470
{
471
if (strneq(s, cp->name, namelen) && (cp->flags & deen) && (!cp->name[namelen] || cp->name[namelen] == '-' || cp->name[namelen] == '+'))
472
{
473
cp->cached = ++codexstate.cached;
474
if ((code = (cache = cp)->code) == CODEXERROR)
475
{
476
if (disc->errorf)
477
(*disc->errorf)(NiL, disc, 2, "%s: invalid method", s);
478
goto bad;
479
}
480
break;
481
}
482
else if (!cache || cp->cached < cache->cached)
483
cache = cp;
484
}
485
sfset(sp, SF_SHARE|SF_PUBLIC, 0);
486
size = -1;
487
if (!code)
488
{
489
if (!(code = newof(0, Codex_t, 1, 0)))
490
{
491
if (disc->errorf)
492
(*disc->errorf)(NiL, disc, 2, "out of space");
493
goto bad;
494
}
495
code->flags = deen;
496
code->index = ++codexstate.index;
497
code->sp = sp;
498
code->disc = disc;
499
code->meth = meth;
500
a = arg;
501
*a++ = (char*)s;
502
*a++ = b = can;
503
q = -1;
504
do
505
{
506
c = *s++;
507
if (c == q)
508
q = -1;
509
else if (c == '"' || c == '\'')
510
q = c;
511
else if (c == 0 || q < 0 && (c == '-' || c == '+'))
512
{
513
*b++ = 0;
514
v = *(a - 1);
515
if (strneq(v, "PASSPHRASE=", 11))
516
{
517
disc->passphrase = v + 11;
518
b = v;
519
}
520
else if (streq(v, "RETAIN"))
521
{
522
flags |= CODEX_RETAIN;
523
b = v;
524
}
525
else if (strneq(v, "SIZE=", 5))
526
{
527
size = strtoll(v + 5, NiL, 0);
528
b = v;
529
}
530
else if (strneq(v, "SOURCE=", 7))
531
{
532
if (!(code->dp = sfopen(NiL, v + 7, "r")))
533
{
534
if (disc->errorf)
535
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "%s: cannot read delta source", v + 7);
536
goto bad;
537
}
538
b = v;
539
}
540
else if (streq(v, "TRACE"))
541
{
542
flags |= CODEX_TRACE;
543
b = v;
544
}
545
else if (streq(v, "VERBOSE"))
546
{
547
flags |= CODEX_VERBOSE;
548
b = v;
549
}
550
else
551
{
552
if (a >= &arg[elementsof(arg)-1] || b >= &can[sizeof(can)-1])
553
break;
554
*a++ = b;
555
}
556
}
557
else
558
*b++ = c;
559
} while (c && b < &can[sizeof(can)-1]);
560
*b = 0;
561
if (!**(a - 1))
562
a--;
563
*a = 0;
564
s = arg[1];
565
if ((*meth->openf)(code, arg, deen))
566
{
567
if (code->op)
568
{
569
sfswap(code->op, code->sp);
570
sfclose(code->op);
571
code->op = 0;
572
}
573
free(code);
574
code = 0;
575
}
576
if ((flags & (CODEX_TRACE|CODEX_VERBOSE)) != (CODEX_TRACE|CODEX_VERBOSE))
577
{
578
if (codexstate.trace && strmatch(name, codexstate.trace))
579
flags |= CODEX_TRACE;
580
if (codexstate.verbose && strmatch(name, codexstate.verbose))
581
flags |= CODEX_VERBOSE;
582
}
583
if ((flags & (CODEX_TRACE|CODEX_VERBOSE)) && (trace = memdup(&codex_trace, sizeof(codex_trace))))
584
sfprintf(sfstderr, "codex: %d: %s: open(\"%s\",%s,%s)\n", code ? code->index : 0, meth->name, arg[0], (sp->_flags & SF_READ) ? "READ" : "WRITE", (deen & CODEX_DECODE) ? "DECODE" : "ENCODE");
585
else
586
trace = 0;
587
if (!code)
588
{
589
if (cache)
590
save(cache, CODEXERROR, name, namelen, deen);
591
goto bad;
592
}
593
if (!(meth = code->meth))
594
meth = code->meth = &codex_copy;
595
code->flags = deen | (code->meth->flags & ~(CODEX_DECODE|CODEX_ENCODE));
596
if (trace)
597
{
598
trace->next = meth;
599
code->meth = meth = trace;
600
code->sfdisc.readf = trace_read;
601
code->sfdisc.writef = trace_write;
602
code->sfdisc.exceptf = (flags & CODEX_VERBOSE) ? trace_except : codex_except;
603
}
604
else
605
{
606
code->sfdisc.readf = meth->readf;
607
code->sfdisc.writef = meth->writef;
608
code->sfdisc.exceptf = codex_except;
609
}
610
if (cache)
611
save(cache, code, name, namelen, deen);
612
}
613
else if (b)
614
while (*b++)
615
{
616
v = b;
617
for (v = b; *b && *b != '-' && *b != '+'; b++);
618
if (strneq(v, "SIZE=", 5))
619
size = strtoll(v + 5, NiL, 0);
620
else if (strneq(v, "SOURCE=", 7))
621
{
622
v += 7;
623
if ((b - v) >= sizeof(can))
624
{
625
if (disc->errorf)
626
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "%-.*s: cannot delta source pathname too long", b - v, v);
627
goto bad;
628
}
629
else
630
{
631
strncopy(can, v, b - v);
632
if (!(code->dp = sfopen(NiL, can, "r")))
633
{
634
if (disc->errorf)
635
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "%s: cannot read delta source", can);
636
goto bad;
637
}
638
}
639
}
640
}
641
if (cache)
642
code->flags |= CODEX_CACHED|CODEX_ACTIVE;
643
if (code->meth == &codex_copy)
644
{
645
c = 0;
646
goto done;
647
}
648
code->sp = sp;
649
code->size = size;
650
code->disc = disc;
651
code->flags |= CODEX_FLUSH;
652
if (sfdisc(sp, &code->sfdisc) != &code->sfdisc)
653
{
654
if (disc->errorf)
655
(*disc->errorf)(NiL, disc, 2, "%s: sfio discipline push error", name);
656
goto bad;
657
}
658
code->serial = serial = codexstate.serial;
659
code->flags &= ~CODEX_FLUSH;
660
if (!(sp->_flags & SF_READ))
661
sfset(sp, SF_IOCHECK, 1);
662
if (code->meth->initf)
663
{
664
SFDCNEXT(sp, f);
665
c = (*code->meth->initf)(code);
666
SFDCPREV(sp, f);
667
if (c)
668
goto bad;
669
}
670
code->flags |= flags & (CODEX_RETAIN|CODEX_TRACE|CODEX_VERBOSE);
671
return serial;
672
bad:
673
c = -1;
674
codexpop(sp, NiL, serial);
675
done:
676
if (code)
677
{
678
if (cache)
679
code->flags &= ~CODEX_ACTIVE;
680
else
681
{
682
if (meth->closef)
683
(*meth->closef)(code);
684
else if (code->data)
685
free(code->data);
686
if (code->dp)
687
sfclose(code->dp);
688
if (code->op)
689
{
690
sfswap(code->op, code->sp);
691
sfclose(code->op);
692
code->op = 0;
693
}
694
free(code);
695
}
696
}
697
return c;
698
}
699
700
/*
701
* recursively identify and push sfcode() disciplines
702
* to decode the SF_READ stream ip
703
*
704
* return:
705
* -1 error
706
* 0 no discipline pushed
707
* >0 discipline serial number
708
*/
709
710
static int
711
decodex(Sfio_t* ip, Codexnum_t flags, Codexdisc_t* disc)
712
{
713
register Codexmeth_t* meth;
714
void* hdr;
715
size_t siz;
716
int serial;
717
int i;
718
char buf[CODEX_NAME];
719
720
sfset(ip, SF_SHARE|SF_PUBLIC, 0);
721
serial = 0;
722
for (;;)
723
{
724
siz = CODEX_IDENT;
725
if (!(hdr = sfreserve(ip, siz, 1)) && (!(siz = sfvalue(ip)) || !(hdr = sfreserve(ip, siz, 1))))
726
break;
727
meth = codexid(hdr, siz, buf, sizeof(buf));
728
sfread(ip, hdr, 0);
729
if (!meth)
730
break;
731
if ((i = codex(ip, NiL, buf, flags, disc, meth)) < 0)
732
{
733
if (serial)
734
codexpop(ip, NiL, serial);
735
return -1;
736
}
737
if (i)
738
{
739
serial = i;
740
if (disc->version >= 20090704L && disc->identify)
741
sfprintf(disc->identify, "<%s", meth->name);
742
}
743
}
744
return serial;
745
}
746
747
typedef struct Part_s
748
{
749
char* name;
750
Codexmeth_t* meth;
751
Codexnum_t flags;
752
} Part_t;
753
754
/*
755
* push the codex method composition name onto ip/op
756
*/
757
758
int
759
codex(Sfio_t* ip, Sfio_t* op, const char* name, Codexnum_t flags, Codexdisc_t* disc, Codexmeth_t* meth)
760
{
761
register char* s;
762
register Part_t* p;
763
register int c;
764
register int q;
765
char* m;
766
Part_t* b;
767
Part_t* e;
768
Codexnum_t f;
769
Codexnum_t decode;
770
Codexnum_t encode;
771
int invert;
772
Part_t part[256];
773
774
if (!codexstate.initialized)
775
{
776
codexstate.initialized = 1;
777
stropt(getenv("CODEX_OPTIONS"), options, sizeof(*options), setopt, NiL);
778
}
779
flags &= CODEX_INVERT|CODEX_RETAIN|CODEX_SERIAL|CODEX_TRACE|CODEX_VERBOSE;
780
if (!(flags & CODEX_SERIAL))
781
{
782
flags |= CODEX_SERIAL;
783
if (++codexstate.serial < 0)
784
codexstate.serial = 1;
785
}
786
if (!disc)
787
disc = &codexstate.disc;
788
if (!(s = (char*)name) || !s[0] || s[0] == '-' && !s[1])
789
{
790
if (!meth)
791
return ip ? decodex(ip, flags, disc) : -1;
792
s = (char*)(name = meth->name);
793
}
794
795
/*
796
* split the method name into component parts
797
* and verify that each part is a known method
798
* CODEX_INVERT is dispatched here
799
*/
800
801
if (!(s = strdup(s)))
802
{
803
if (disc->errorf)
804
(*disc->errorf)(NiL, disc, 2, "out of space");
805
return -1;
806
}
807
m = s;
808
if (flags & CODEX_INVERT)
809
{
810
flags &= ~CODEX_INVERT;
811
invert = -1;
812
decode = CODEX_ENCODE;
813
encode = CODEX_DECODE;
814
b = &part[elementsof(part)-1];
815
e = &part[0];
816
}
817
else
818
{
819
invert = 1;
820
decode = CODEX_DECODE;
821
encode = CODEX_ENCODE;
822
b = &part[0];
823
e = &part[elementsof(part)-1];
824
}
825
p = b;
826
if (*s == '<')
827
{
828
s++;
829
p->flags = decode;
830
}
831
else if (*s == '>')
832
{
833
s++;
834
p->flags = encode;
835
}
836
else
837
p->flags = 0;
838
p->name = s;
839
q = 0;
840
do
841
{
842
if (!(c = *s++))
843
;
844
else if (c == q)
845
{
846
q = 0;
847
continue;
848
}
849
else if (q)
850
continue;
851
else if (c == '"' || c == '\'')
852
{
853
q = c;
854
continue;
855
}
856
else if (c == '<')
857
f = decode;
858
else if (c == '>')
859
f = encode;
860
else if (c == '|' || c == '^')
861
f = 0;
862
else
863
continue;
864
*(s - 1) = 0;
865
if (codexcmp(p->name, "copy"))
866
{
867
if (!(p->meth = codexmeth(p->name)))
868
{
869
if (disc->errorf)
870
(*disc->errorf)(NiL, disc, 2, "%s: unknown coder", p->name);
871
free(m);
872
return -1;
873
}
874
if (!c)
875
break;
876
if (p == e)
877
{
878
if (disc->errorf)
879
(*disc->errorf)(NiL, disc, 2, "%s: too many method components -- %d max", name, elementsof(part));
880
free(m);
881
return -1;
882
}
883
p += invert;
884
}
885
p->flags = f;
886
p->name = s;
887
} while (c);
888
if (!*b->name)
889
{
890
free(m);
891
return 0;
892
}
893
if (invert < 0)
894
{
895
e = b;
896
b = p;
897
}
898
else
899
e = p;
900
901
/*
902
* assign CODEX_DECODE or CODEX_ENCODE to each part and
903
* verfy that the method supports the assignment
904
* vcodex methods give us some leeway here
905
* otherwise CODEX_DECODE must be on the left and
906
* CODEX_ENCODE must be on the right
907
* CODEX_INVERT has already been handled in the previous loop
908
*/
909
910
f = 0;
911
if (ip)
912
f |= CODEX_DECODE;
913
if (op)
914
f |= CODEX_ENCODE;
915
p = b;
916
for (;;)
917
{
918
if (p->flags == CODEX_ENCODE || p->flags != CODEX_DECODE && !(f & CODEX_DECODE))
919
{
920
p->flags = CODEX_ENCODE;
921
f &= ~CODEX_DECODE;
922
}
923
else
924
p->flags = CODEX_DECODE;
925
if (!(p->flags & p->meth->flags) || !p->meth->vcmeth && !(p->flags & f))
926
{
927
if (disc->errorf)
928
{
929
if (e != &part[0])
930
(*disc->errorf)(NiL, disc, 2, "%s: %s: cannot %s", name, p->name, p->flags == CODEX_DECODE ? ERROR_translate(NiL, NiL, id, "decode") : ERROR_translate(NiL, NiL, id, "encode"));
931
else
932
(*disc->errorf)(NiL, disc, 2, "%s: cannot %s", p->name, p->flags == CODEX_DECODE ? ERROR_translate(NiL, NiL, id, "decode") : ERROR_translate(NiL, NiL, id, "encode"));
933
}
934
free(m);
935
return -1;
936
}
937
if (p == e)
938
break;
939
p++;
940
}
941
#if 0
942
p = b;
943
for (;;)
944
{
945
error(-1, "AHA codex [%d] %u %s \"%s\"", p - b, p->flags, p->meth->name, p->name);
946
if (p == e)
947
break;
948
p++;
949
}
950
#endif
951
952
/*
953
* input decode method sfio disciplines pushed from left to right
954
*/
955
956
p = b;
957
for (;;)
958
{
959
if (p->flags == CODEX_ENCODE)
960
break;
961
if (push(ip, p->name, CODEX_DECODE|flags, disc, p->meth) < 0)
962
{
963
free(m);
964
codexpop(ip, op, codexstate.serial);
965
return -1;
966
}
967
if (p == e)
968
break;
969
p++;
970
}
971
972
/*
973
* output encode method sfio disciplines pushed from right to left
974
*/
975
976
p = e;
977
for (;;)
978
{
979
if (p->flags == CODEX_DECODE)
980
break;
981
if (push(op, p->name, CODEX_ENCODE|flags, disc, p->meth) < 0)
982
{
983
free(m);
984
codexpop(ip, op, codexstate.serial);
985
return -1;
986
}
987
if (p == b)
988
break;
989
p--;
990
}
991
free(m);
992
return codexstate.serial;
993
}
994
995
/*
996
* pop contiguous ip and op codex disciplines matching serial number
997
* serial==0 pops all contiguous codex disciplines
998
*/
999
1000
int
1001
codexpop(register Sfio_t* ip, register Sfio_t* op, int serial)
1002
{
1003
int pop;
1004
1005
pop = 0;
1006
if (serial >= 0)
1007
{
1008
if (ip)
1009
while (ip->disc && (ip->disc->exceptf == codex_except || ip->disc->exceptf == trace_except) && (!serial || CODEX(ip->disc)->serial == serial))
1010
if (sfdisc(ip, SF_POPDISC))
1011
pop++;
1012
if (op)
1013
while (op->disc && (op->disc->exceptf == codex_except || op->disc->exceptf == trace_except) && (!serial || CODEX(op->disc)->serial == serial))
1014
if (sfdisc(op, SF_POPDISC))
1015
pop++;
1016
}
1017
return pop;
1018
}
1019
1020