Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/lib/libjcl/path.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
* *
19
***********************************************************************/
20
#pragma prototyped
21
22
/*
23
* jcl path map
24
*/
25
26
#include "jcllib.h"
27
28
#include <tok.h>
29
30
typedef struct Map_s
31
{
32
Dtlink_t link;
33
char* prefix;
34
char* map;
35
char* tail;
36
char* suffix;
37
int length;
38
int same;
39
} Map_t;
40
41
typedef struct Match_s
42
{
43
Dt_t* map;
44
Map_t* all;
45
const char* string;
46
int length;
47
} Match_t;
48
49
typedef struct Suf_s
50
{
51
Dtlink_t link;
52
int length;
53
char name[1];
54
} Suf_t;
55
56
typedef struct State_s
57
{
58
Dtdisc_t mapdisc;
59
Dtdisc_t sufdisc;
60
Dt_t* suf;
61
Match_t match[7];
62
int mapped;
63
int matched;
64
int matches;
65
} State_t;
66
67
static State_t state;
68
69
static const char usage[] =
70
"[-?\n@(#)$Id: libjcl (AT&T Research) 2007-12-10 $\n]"
71
"[i:import]"
72
"[I:include]:[directory]"
73
"[k:marklength]"
74
"[p:parameterize]"
75
"[s:subdirectory]"
76
"[w:warn]"
77
;
78
79
static int
80
optset(Jcl_t* jcl, int c, Jcldisc_t* disc)
81
{
82
unsigned long f;
83
84
switch (c)
85
{
86
case 'i':
87
f = JCL_IMPORT;
88
break;
89
case 'I':
90
jclinclude(NiL, opt_info.arg, JCL_JOB|JCL_PROC, disc);
91
return 1;
92
case 'k':
93
f = JCL_MARKLENGTH;
94
break;
95
case 'p':
96
f = JCL_PARAMETERIZE;
97
break;
98
case 's':
99
f = JCL_SUBDIR;
100
break;
101
case 'w':
102
f = JCL_WARN;
103
break;
104
case ':':
105
error(2, "%s", opt_info.arg);
106
return 0;
107
case '?':
108
error(ERROR_USAGE|4, "%s", opt_info.arg);
109
return 0;
110
}
111
if ((jcl->roflags & (JCL_MAPPED|f)) != (JCL_MAPPED|f))
112
{
113
if (!(jcl->roflags & JCL_MAPPED))
114
jcl->roflags |= f;
115
if (opt_info.number)
116
jcl->flags |= f;
117
else
118
jcl->flags &= ~f;
119
}
120
return 1;
121
}
122
123
#define delimiter(c) ((c)=='.'||(c)=='/')
124
125
/*
126
* return a pointer to the next delimiter
127
* 0 if no more delimiters
128
*/
129
130
static const char*
131
nextdelim(register const char* s)
132
{
133
register int c;
134
135
while (c = *s++)
136
if (delimiter(c))
137
return s - 1;
138
return 0;
139
}
140
141
/*
142
* return a pointer to the last delimiter
143
* 0 if no more delimiters
144
*/
145
146
static const char*
147
lastdelim(register const char* s)
148
{
149
register int c;
150
register const char* r;
151
152
r = 0;
153
while (c = *s++)
154
if (delimiter(c) && (!r || *r == '.' || c == '/'))
155
r = s - 1;
156
return r;
157
}
158
159
/*
160
* return the pointer to the matched subexpression n
161
* string length returned in *z
162
*/
163
164
char*
165
matched(int n, size_t* z, Jcldisc_t* disc)
166
{
167
if (n > state.matched)
168
{
169
if (disc->errorf)
170
(*disc->errorf)(NiL, disc, 2, "${%d}: not defined for this pattern", n);
171
return 0;
172
}
173
*z = state.match[n].length;
174
return (char*)state.match[n].string;
175
}
176
177
/*
178
* match tail pattern t to s
179
* set sets state.matched
180
*/
181
182
static int
183
tail(register const char* t, register const char* s, int set)
184
{
185
register const char* u;
186
const char* b;
187
188
b = s;
189
for (;;)
190
{
191
if (*t == '*')
192
{
193
if (!*++t)
194
{
195
if (set)
196
{
197
state.matched++;
198
return (s - b) + (state.match[state.matched].length = strlen(state.match[state.matched].string = s));
199
}
200
return 1;
201
}
202
else
203
{
204
t++;
205
if (!(u = nextdelim(s)))
206
break;
207
if (set)
208
{
209
state.matched++;
210
state.match[state.matched].length = u - s;
211
state.match[state.matched].string = s;
212
}
213
s = u + 1;
214
}
215
}
216
else if (*t != *s++)
217
break;
218
else if (!*t++)
219
return s - b - 1;
220
}
221
return 0;
222
}
223
224
/*
225
* longest matching prefix match function
226
* we don't expect many map entries
227
*/
228
229
static Map_t*
230
match(const char* name)
231
{
232
register Map_t* mp;
233
register Map_t* lp;
234
register int i;
235
register int j;
236
register int n;
237
int all;
238
const char* s;
239
Map_t map;
240
char buf[2];
241
242
buf[1] = 0;
243
map.prefix = buf;
244
n = 0;
245
all = -1;
246
state.match[0].string = name;
247
state.matched = 0;
248
for (;;)
249
{
250
lp = 0;
251
if (state.match[state.matched].map)
252
{
253
i = 0;
254
buf[0] = name[0];
255
if (!(mp = (Map_t*)dtprev(state.match[state.matched].map, &map)))
256
mp = (Map_t*)dtfirst(state.match[state.matched].map);
257
for (; mp && mp->same >= i; mp = (Map_t*)dtnext(state.match[state.matched].map, mp))
258
{
259
for (j = i; name[j] == mp->prefix[j]; j++)
260
if (!name[j])
261
{
262
if (mp->tail)
263
break;
264
mp->length = j + n;
265
message((-9, "match[%d] %s %s %d", state.matched, name, mp->prefix, mp->length));
266
return mp;
267
}
268
if (!mp->prefix[j] && (!mp->tail || tail(mp->tail, &name[j], 0)))
269
{
270
i = j;
271
lp = mp;
272
lp->length = j + n;
273
message((-9, "maybe[%d] %s %s %d", state.matched, name, mp->prefix, mp->length));
274
}
275
}
276
}
277
if (lp)
278
{
279
if (lp->tail)
280
lp->length += tail(lp->tail, &name[i], 1);
281
return lp;
282
}
283
if (state.match[state.matched].all)
284
all = state.matched;
285
if (state.matched >= state.matches)
286
break;
287
state.matched++;
288
if (!(s = nextdelim(name)))
289
{
290
if (state.match[state.matched].all)
291
all = state.matched;
292
break;
293
}
294
state.match[state.matched].string = name;
295
n += (state.match[state.matched].length = s - name) + 1;
296
name = s + 1;
297
}
298
if (all >= 0)
299
{
300
state.match[0].length = strlen(state.match[0].string);
301
mp = state.match[all].all;
302
switch (all)
303
{
304
case 0:
305
all++;
306
state.match[1].string = state.match[0].string;
307
state.match[1].length = state.match[0].length;
308
mp->length = 0;
309
break;
310
case 1:
311
state.match[1].string = state.match[0].string;
312
mp->length = state.match[1].length = state.match[0].length;
313
break;
314
default:
315
state.match[all].length = strlen(state.match[all].string = state.match[all-1].string + state.match[all-1].length + 1);
316
mp->length = n + strlen(name);
317
break;
318
}
319
state.matched = all;
320
return mp;
321
}
322
return 0;
323
}
324
325
/*
326
* add s to the mapped suffix dictionary
327
*/
328
329
static int
330
suffix(Sfio_t* sp, const char* s, Jcldisc_t* disc)
331
{
332
Suf_t* xp;
333
int n;
334
335
if (!state.suf)
336
{
337
state.sufdisc.link = offsetof(Suf_t, link);
338
state.sufdisc.key = offsetof(Suf_t, name);
339
state.sufdisc.size = 0;
340
if (!(state.suf = dtopen(&state.sufdisc, Dtoset)))
341
{
342
sfclose(sp);
343
nospace(NiL, disc);
344
return -1;
345
}
346
}
347
if (!dtmatch(state.suf, s))
348
{
349
n = strlen(s);
350
if (!(xp = newof(0, Suf_t, 1, n)))
351
{
352
sfclose(sp);
353
nospace(NiL, disc);
354
return -1;
355
}
356
strcpy(xp->name, s);
357
xp->length = n;
358
dtinsert(state.suf, xp);
359
}
360
return 0;
361
}
362
363
/*
364
* add maps in file to dataset map
365
*/
366
367
int
368
jclmap(Jcl_t* jcl, const char* file, Jcldisc_t* disc)
369
{
370
register Sfio_t* sp;
371
register Map_t* mp;
372
register Map_t* pp;
373
register char* s;
374
register char* t;
375
char* op;
376
char* arg[32];
377
char* ofile;
378
char* tail;
379
long oline;
380
int c;
381
int n;
382
int k;
383
int dontcare;
384
Opt_t opt;
385
char buf[PATH_MAX];
386
char tmp[PATH_MAX];
387
388
jcl->flags |= JCL_MAPPED;
389
if (!file || !*file)
390
{
391
file = JCL_MAPFILE;
392
dontcare = 1;
393
}
394
else if (streq(file, "-"))
395
return 0;
396
else
397
dontcare = 0;
398
if (!(sp = sfopen(NiL, file, "r")))
399
{
400
sp = 0;
401
if (!strchr(file, '/'))
402
{
403
sfsprintf(tmp, sizeof(tmp), "lib/jcl/%s", file);
404
if (!pathpath(tmp, "", PATH_REGULAR, buf, sizeof(buf)))
405
{
406
if (dontcare)
407
return 0;
408
if (disc->errorf)
409
(*disc->errorf)(NiL, disc, 2, "%s: cannot find map file", file);
410
return -1;
411
}
412
sp = sfopen(NiL, file = (char*)buf, "r");
413
}
414
if (!sp)
415
{
416
if (disc->errorf)
417
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "%s: cannot read map file", file);
418
return -1;
419
}
420
}
421
ofile = error_info.file;
422
error_info.file = (char*)file;
423
oline = error_info.line;
424
error_info.line = 0;
425
while (s = sfgetr(sp, '\n', 1))
426
{
427
error_info.line++;
428
if (*s != '#' && tokscan(s, NiL, " %s %v ", &op, arg, elementsof(arg)) >= 1)
429
{
430
if (streq(op, "export"))
431
{
432
n = 0;
433
while (s = arg[n++])
434
if (!jclsym(jcl, s, NiL, JCL_SYM_EXPORT) && disc->errorf)
435
(*disc->errorf)(NiL, disc, 1, "%s: invalid assignment", s);
436
}
437
else if (streq(op, "map"))
438
{
439
if (!(s = arg[0]) || !arg[1])
440
{
441
if (disc->errorf)
442
(*disc->errorf)(NiL, disc, 2, "%s: prefix map [suffix] expected", op);
443
continue;
444
}
445
k = 0;
446
while (*s == '*' && delimiter(*(s + 1)))
447
{
448
s += 2;
449
k++;
450
}
451
if (*s == '*')
452
{
453
if (*(s + 1))
454
{
455
if (disc->errorf)
456
(*disc->errorf)(NiL, disc, 2, "%s: %s: only \"*.\" at beginning, \".*.\" in middle, or \".*\" at end supported", op, s);
457
sfclose(sp);
458
return -1;
459
}
460
s++;
461
k++;
462
}
463
if (k >= elementsof(state.match))
464
{
465
if (disc->errorf)
466
(*disc->errorf)(NiL, disc, 2, "%s: %s: only %d *. prefixes supported", op, arg[0], elementsof(state.match) - 1);
467
sfclose(sp);
468
return -1;
469
}
470
if (state.matches < k)
471
state.matches = k;
472
tail = 0;
473
for (t = s; *t; t++)
474
if (*t == '*')
475
{
476
if (!delimiter(*(t - 1)) && --t || *(t + 1) && !delimiter(*(t + 1)))
477
{
478
if (disc->errorf)
479
(*disc->errorf)(NiL, disc, 2, "%s: %s: only \"*[./]\" at beginning, \"[./]*[./]\" in middle, or \"[./]*\" at end supported", op, s);
480
sfclose(sp);
481
return -1;
482
}
483
if (!tail)
484
tail = t;
485
}
486
if (n = t - s)
487
{
488
if (!state.match[k].map)
489
{
490
state.mapped |= (1<<k);
491
state.mapdisc.link = offsetof(Map_t, link);
492
state.mapdisc.key = offsetof(Map_t, prefix);
493
state.mapdisc.size = -1;
494
if (!(state.match[k].map = dtopen(&state.mapdisc, Dtoset)))
495
{
496
nospace(NiL, disc);
497
return -1;
498
}
499
}
500
if (tail)
501
*tail = 0;
502
c = dtmatch(state.match[k].map, s) != 0;
503
if (tail)
504
*tail = '*';
505
if (c)
506
{
507
if (disc->errorf)
508
(*disc->errorf)(NiL, disc, 2, "%s: duplicate map prefix", arg[0]);
509
continue;
510
}
511
}
512
else
513
{
514
if (!*(s = arg[0]))
515
s = "*";
516
if (state.match[k].all)
517
{
518
if (disc->errorf)
519
(*disc->errorf)(NiL, disc, 2, "%s: duplicate map prefix", s);
520
continue;
521
}
522
}
523
if (!(mp = newof(0, Map_t, 1, n + strlen(arg[1]) + (arg[2] ? strlen(arg[2]) : 0) + 8)))
524
{
525
sfclose(sp);
526
nospace(NiL, disc);
527
return -1;
528
}
529
if (tail)
530
n = tail - s;
531
mp->length = n;
532
memcpy(mp->prefix = (char*)(mp + 1), s, n);
533
s = mp->prefix + n;
534
*s++ = 0;
535
s = strcopy(mp->map = s, arg[1]);
536
if (tail)
537
s = strcopy(mp->tail = s + 1, tail);
538
if (arg[2])
539
strcpy(mp->suffix = s + 1, arg[2]);
540
else
541
mp->suffix = s;
542
if (mp->length)
543
dtinsert(state.match[k].map, mp);
544
else
545
state.match[k].all = mp;
546
if ((s = (char*)nextdelim(mp->suffix)) && suffix(sp, s, disc))
547
return -1;
548
}
549
else if (streq(op, "set"))
550
{
551
const char* use;
552
Jcloptset_f set;
553
554
if (!(use = disc->usage) || !(set = disc->optsetf))
555
{
556
use = usage;
557
set = optset;
558
}
559
jcl->roflags |= JCL_MAPPED;
560
opt = opt_info;
561
n = 0;
562
while (s = arg[n++])
563
if (*s == '-' || *s == '+')
564
{
565
s = expand(jcl, s, JCL_SYM_EXPORT|JCL_SYM_SET);
566
while (c = optstr(s, use))
567
(*set)(jcl, c, disc);
568
}
569
else if (!jclsym(jcl, s, NiL, JCL_SYM_SET) && disc->errorf)
570
(*disc->errorf)(NiL, disc, 1, "%s: invalid assignment", s);
571
opt_info = opt;
572
jcl->roflags &= ~JCL_MAPPED;
573
}
574
else if (streq(op, "suf") || streq(op, "suffix"))
575
{
576
n = 0;
577
while (s = arg[n++])
578
if (!delimiter(*s))
579
{
580
if (disc->errorf)
581
(*disc->errorf)(NiL, disc, 1, "%s: invalid suffix", s);
582
}
583
else if (suffix(sp, s, disc))
584
return -1;
585
}
586
else if (disc->errorf)
587
(*disc->errorf)(NiL, disc, 1, "%s: unknown op", op);
588
}
589
}
590
sfclose(sp);
591
error_info.file = ofile;
592
error_info.line = oline;
593
for (k = 0; k <= state.matches; k++)
594
{
595
if (state.match[k].map)
596
for (pp = 0, mp = (Map_t*)dtfirst(state.match[k].map); mp; pp = mp, mp = (Map_t*)dtnext(state.match[k].map, mp))
597
{
598
mp->same = 0;
599
if (pp)
600
while (mp->prefix[mp->same] == pp->prefix[mp->same])
601
mp->same++;
602
message((-9, "map[%d] %2d %2d %s%s%s", k, mp->length, mp->same, mp->prefix, mp->tail ? " " : "", mp->tail ? mp->tail : ""));
603
}
604
if (mp = state.match[k].all)
605
message((-9, "map[%d] %2d %2d %s", k, mp->length, mp->same, mp->prefix));
606
}
607
return 0;
608
}
609
610
/*
611
* return the length of the mapped suffix in path
612
* 0 returned if path has no mapped suffix
613
*/
614
615
int
616
suflen(const char* path)
617
{
618
Suf_t* xp;
619
const char* s;
620
621
return (state.suf && (s = strrchr(path, '.')) && (xp = (Suf_t*)dtmatch(state.suf, s))) ? xp->length : 0;
622
}
623
624
/*
625
* dataset library(member) => library/member
626
* converted name returned in jcl->vp
627
* jcl->tp may be clobbered
628
*/
629
630
char*
631
jclpath(Jcl_t* jcl, const char* name)
632
{
633
register char* s;
634
register char* t;
635
register Map_t* m;
636
char* e;
637
const char* oname = name;
638
int n;
639
Sfio_t* pp;
640
641
if (s = mark(name, 0, 0, jcl->disc))
642
name = (const char*)s;
643
if (*name != '/' && (*name != '.' || *(name + 1) != '/') && state.mapped && (m = match(name)))
644
{
645
name += m->length;
646
if (*m->suffix && *name && (n = suflen(name)))
647
{
648
n = strlen(name) - n;
649
sfprintf(jcl->vp, "%s%-.*s%s%s", m->map, n, name, m->suffix, name + n);
650
}
651
else if (*m->suffix && *m->map && (n = suflen(m->map)))
652
{
653
n = strlen(m->map) - n;
654
sfprintf(jcl->vp, "%-.*s%s%s%s", n, m->map, name, m->suffix, m->map + n);
655
}
656
else
657
sfprintf(jcl->vp, "%s%s%s", m->map, name, m->suffix);
658
if (!(name = sfstruse(jcl->vp)))
659
nospace(jcl, NiL);
660
name = (const char*)expand(jcl, name, JCL_SYM_SET);
661
message((-7, "match %s => %s", oname, name));
662
}
663
else
664
m = 0;
665
if ((s = strrchr(name, '(')) && (t = strrchr(s, ')')) && !*(t + 1))
666
{
667
if (name != (const char*)sfstrbase(jcl->vp))
668
{
669
sfprintf(jcl->vp, "%s", name);
670
if (!(name = (const char*)sfstruse(jcl->vp)))
671
nospace(jcl, NiL);
672
s = strrchr(name, '(');
673
}
674
strtol(s + 1, &e, 0);
675
if (*e == ')' && !*(e + 1))
676
{
677
jcl->flags |= JCL_GDG;
678
*s++ = '/';
679
if (*(s + 1) == '0' && (s + 2) == e || *(s + 1) == '+' && *(s + 2) == '0' && (s + 3) == e)
680
{
681
*s++ = '0';
682
*s = 0;
683
}
684
else
685
{
686
*e = 0;
687
sfprintf(jcl->tp, "$(gdginstance %s)", name);
688
if (!(s = sfstruse(jcl->tp)))
689
nospace(jcl, NiL);
690
if (jcl->flags & JCL_EXEC)
691
{
692
if (!(pp = sfpopen(NiL, s, "r")) || !(t = sfgetr(pp, '\n', 0)) || sfprintf(jcl->vp, "%s", t) || sfclose(pp))
693
{
694
if (jcl->disc->errorf)
695
(*jcl->disc->errorf)(NiL, jcl->disc, 1, "%s: cannot map generation data group", s);
696
}
697
else if (!(name = (const char*)sfstruse(jcl->vp)))
698
nospace(jcl, NiL);
699
}
700
else
701
{
702
sfprintf(jcl->vp, "%s", s);
703
if (!(name = (const char*)sfstruse(jcl->vp)))
704
nospace(jcl, NiL);
705
}
706
}
707
}
708
else
709
{
710
*s = '/';
711
*strrchr(s, ')') = 0;
712
}
713
}
714
if (s = mark(name, 0, 0, jcl->disc))
715
name = (const char*)s;
716
if (name != oname)
717
message((-7, "map %s => %s", oname, name));
718
return (char*)name;
719
}
720
721