Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/jcl/jcm.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
static const char usage[] =
23
"[-?\n@(#)$Id: jcm (AT&T Research) 2006-08-16 $\n]"
24
USAGE_LICENSE
25
"[+NAME?jcm - job control-M deck converter]"
26
"[+DESCRIPTION?\bjcm\b converts the control-M job scheduler decks named by"
27
" the \afile\a operands to an \bnmake\b(1) makefile on the"
28
" standard output. The standard input is read if no \afile\a"
29
" operands are specified.]"
30
"[c:cards?List control card lines instead of the generated makefile on the"
31
" standard output.]"
32
"[d:debug?Set the debug trace level. Higher levels produce more"
33
" output.]#[level]"
34
"[h:comment?Include H card comments in the generated output.]"
35
"[i:initialize?Initialize variable values from \aidentifier\a=\avalue\a "
36
"lines in \afile\a. \afile\a may contain # style comments.]:[file]"
37
"[I:index?Expand the first input condition to the condition plus "
38
"\aindex\a-1 conditions suffixed by \b-%02d\b from 1 through "
39
"\aindex\a-1.]#[index]"
40
"[l:lowercase?Convert job and library names to lower case.]"
41
"[p:portable?Convert event names for \b/bin/make\b portability.]"
42
"[v:verbose?Enable verbose tracing.]"
43
"[T:test?Implementation-specific test and tracing bitmask.]#[test-mask]{"
44
" [+0x0010?List `-' OUT dependents (these are marked for delete).]"
45
"}"
46
"\n"
47
"\n[ file ... ]\n"
48
"\n"
49
"[+SEE ALSO?\bjcl\b(1), \bnmake\b(1)]"
50
;
51
52
#include <ast.h>
53
#include <cdt.h>
54
#include <ccode.h>
55
#include <ctype.h>
56
#include <error.h>
57
#include <jcl.h>
58
#include <vmalloc.h>
59
60
#define CARD 80
61
62
#define circular(p) (strneq((p)->value, "$(", 2) && strneq((p)->value + 2, JCL_AUTO, sizeof(JCL_AUTO) - 1) && strneq((p)->value + sizeof(JCL_AUTO) + 1, (p)->name, strlen((p)->name)) && streq((p)->value + sizeof(JCL_AUTO) + strlen((p)->name) + 1, ")"))
63
64
struct Jcmcard_s; typedef struct Jcmcard_s Jcmcard_t;
65
struct Jcmevent_s; typedef struct Jcmevent_s Jcmevent_t;
66
struct Jcmjob_s; typedef struct Jcmjob_s Jcmjob_t;
67
struct Jcmlib_s; typedef struct Jcmlib_s Jcmlib_t;
68
struct Jcmlist_s; typedef struct Jcmlist_s Jcmlist_t;
69
struct Jcmset_s; typedef struct Jcmset_s Jcmset_t;
70
struct Jcmshout_s; typedef struct Jcmshout_s Jcmshout_t;
71
struct Jcmvar_s; typedef struct Jcmvar_s Jcmvar_t;
72
73
struct Jcmcard_s
74
{
75
Jcmcard_t* next;
76
char data[1];
77
};
78
79
struct Jcmvar_s
80
{
81
Dtlink_t link;
82
unsigned long dup;
83
int init;
84
char* value;
85
char name[64];
86
};
87
88
struct Jcmlib_s
89
{
90
Dtlink_t link;
91
Jcmvar_t* var;
92
char name[64];
93
};
94
95
struct Jcmset_s
96
{
97
Dtlink_t link;
98
Jcmset_t* next;
99
char* value;
100
char name[1];
101
};
102
103
struct Jcmshout_s
104
{
105
Jcmshout_t* next;
106
int when;
107
int pri;
108
char data[17];
109
char to[17];
110
char text[71];
111
};
112
113
struct Jcmjob_s
114
{
115
Jcmlib_t* memlib;
116
Jcmlib_t* overlib;
117
Jcmlib_t* doclib;
118
Jcmset_t* set;
119
Jcmshout_t* shout;
120
int namelen;
121
int relationship;
122
char* docmem;
123
char* name;
124
char* tag;
125
char base[1];
126
};
127
128
struct Jcmlist_s
129
{
130
Jcmlist_t* next;
131
Jcmevent_t* event;
132
};
133
134
struct Jcmevent_s
135
{
136
Dtlink_t link;
137
unsigned long dup;
138
int mark;
139
char date[5];
140
Jcmlist_t* reqs;
141
Jcmlist_t* deps;
142
Jcmjob_t* job;
143
char name[1];
144
};
145
146
static struct State_s
147
{
148
Vmalloc_t* vm;
149
Dt_t* events;
150
Dt_t* libs;
151
Dt_t* set;
152
Dt_t* vars;
153
Dtdisc_t eventdisc;
154
Dtdisc_t libdisc;
155
Dtdisc_t setdisc;
156
Dtdisc_t vardisc;
157
char* data;
158
char* last;
159
Jcmlib_t* dummy;
160
Jcmevent_t* all;
161
Sfio_t* tmp;
162
unsigned long pseudo;
163
unsigned long test;
164
int cards;
165
int comment;
166
int index;
167
int lowercase;
168
int portable;
169
int verbose;
170
} state;
171
172
static void
173
nospace(void)
174
{
175
error(ERROR_SYSTEM|3, "out of space");
176
}
177
178
static char*
179
stash(const char* s)
180
{
181
char* r;
182
183
if (!(r = strdup(s)))
184
nospace();
185
return r;
186
}
187
188
static void
189
lower(register char* s)
190
{
191
for (; *s; s++)
192
if (isupper(*s))
193
*s = tolower(*s);
194
}
195
196
static void
197
upper(register char* s)
198
{
199
for (; *s; s++)
200
if (islower(*s))
201
*s = toupper(*s);
202
}
203
204
static char*
205
copy(register char* t, register const char* s, size_t n)
206
{
207
register const char* e = s + n;
208
209
while (s < e && *s && *s != ' ')
210
*t++ = *s++;
211
*t = 0;
212
return t;
213
}
214
215
static char*
216
card(Sfio_t* sp, register unsigned char* map)
217
{
218
register char* s;
219
register char* t;
220
register int c;
221
register int o;
222
size_t z;
223
size_t n;
224
size_t m;
225
226
s = state.data;
227
z = CARD;
228
for (;;)
229
{
230
if (s >= state.last)
231
{
232
n = s - state.data;
233
m = (state.last - state.data) + 32 * CARD;
234
if (!(state.data = newof(state.data, char, m, 0)))
235
nospace();
236
state.last = state.data + m - CARD - 1;
237
s = state.data + n;
238
}
239
if (sfread(sp, s, z) != z)
240
break;
241
error_info.line++;
242
if (s == state.data)
243
o = *(unsigned char*)s;
244
ccmapstr(map, s, z);
245
for (t = s, s += z; s > t && (*(s - 1) == ' ' || *(s - 1) == 0 || !isprint(*(s - 1))); s--);
246
if ((c = sfgetc(sp)) == EOF)
247
break;
248
if (c != o)
249
{
250
sfungetc(sp, c);
251
break;
252
}
253
if (ccmapchr(map, c) == 'T')
254
{
255
if ((c = sfgetc(sp)) == EOF)
256
{
257
sfungetc(sp, o);
258
break;
259
}
260
if (ccmapchr(map, c) == '%')
261
{
262
sfungetc(sp, c);
263
sfungetc(sp, o);
264
break;
265
}
266
}
267
z = CARD - 1;
268
}
269
if (s == state.data)
270
return 0;
271
*s = 0;
272
while (s > state.data)
273
if (!*--s)
274
*s = ' ';
275
return state.data;
276
}
277
278
static const char*
279
prefix(const char* s, const char* e, int d)
280
{
281
register Jcmvar_t* v;
282
register int n;
283
Jcmvar_t var;
284
285
n = (e ? (e - s) : strlen(s)) + 1;
286
if (n >= sizeof(var.name))
287
n = sizeof(var.name);
288
strlcpy(var.name, s, n);
289
if (!(v = (Jcmvar_t*)dtprev(state.vars, &var)))
290
v = (Jcmvar_t*)dtsearch(state.vars, &var);
291
if (*v->name != *s)
292
v = (Jcmvar_t*)dtnext(state.vars, v);
293
for (; v && *v->name == *s; v = (Jcmvar_t*)dtnext(state.vars, v))
294
{
295
n = strlen(v->name);
296
if (strneq(s, v->name, n))
297
return s + n;
298
}
299
while (s < e && *s != d && isalnum(*s))
300
s++;
301
return s;
302
}
303
304
static char*
305
parameterize(register Sfio_t* sp, register const char* s, register const char* e, int append, int index)
306
{
307
register int c;
308
register int d;
309
register const char* t;
310
311
if (e)
312
d = ' ';
313
else
314
{
315
e = s + strlen(s);
316
d = 0;
317
}
318
while (s < e && (c = *s++) != d)
319
{
320
if (c == '~' && s < e && *s != d)
321
{
322
sfputr(sp, "$(" JCL_AUTO, -1);
323
switch (c = *s++)
324
{
325
case '#':
326
sfputr(sp, "pound", -1);
327
break;
328
case '@':
329
sfputr(sp, "at", -1);
330
break;
331
case '&':
332
sfputr(sp, "and", -1);
333
break;
334
case '!':
335
sfputr(sp, "bang", -1);
336
break;
337
default:
338
if (isalnum(c) && (t = prefix(s - 1, e, d)))
339
{
340
sfwrite(sp, s - 1, t - s + 1);
341
s = t;
342
}
343
else
344
sfprintf(sp, "special_%02x", c);
345
break;
346
}
347
c = ')';
348
}
349
else if (c == '%' && s < e && *s == c)
350
{
351
sfputr(sp, "$(" JCL_AUTO, -1);
352
for (s++; s < e && (c = *s) != d && (isalnum(c) || c == '$' && (c = '_')); s++)
353
sfputc(sp, c);
354
c = ')';
355
}
356
else if (state.portable && (c == '#' || c == '$' || c == ':'))
357
c = '_';
358
sfputc(sp, c);
359
}
360
if (index)
361
sfprintf(sp, "-%02d", index);
362
if (append)
363
{
364
if (sfputc(sp, 0) < 0)
365
nospace();
366
sfstrseek(sp, -1, SEEK_CUR);
367
return sfstrbase(sp);
368
}
369
if (!(s = (const char*)sfstruse(sp)))
370
nospace();
371
return (char*)s;
372
}
373
374
static Jcmevent_t*
375
getevent(const char* s, const char* d, int uniq, int string, int index)
376
{
377
register Jcmevent_t* event;
378
379
if (s)
380
{
381
s = (const char*)parameterize(state.tmp, s, string ? (const char*)0 : s + 20, 1, index);
382
if (event = (Jcmevent_t*)dtmatch(state.events, s))
383
{
384
if (!uniq)
385
{
386
sfstrseek(state.tmp, 0, SEEK_SET);
387
return event;
388
}
389
sfprintf(state.tmp, "{%lu}", ++event->dup);
390
}
391
}
392
else
393
sfprintf(state.tmp, "{%lu}", ++state.pseudo);
394
if (!(s = (const char*)sfstruse(state.tmp)) || !(event = newof(0, Jcmevent_t, 1, strlen(s))))
395
nospace();
396
strcpy(event->name, s);
397
dtinsert(state.events, event);
398
if (d)
399
copy(event->date, d, 4);
400
return event;
401
}
402
403
static Jcmjob_t*
404
getjob(const char* s)
405
{
406
register Jcmjob_t* job;
407
408
s = (const char*)parameterize(state.tmp, s, s + 8, 0, 0);
409
if (!(job = newof(0, Jcmjob_t, 1, strlen(s))))
410
nospace();
411
strcpy(job->base, s);
412
if (state.lowercase)
413
lower(job->base);
414
job->name = stash(parameterize(state.tmp, s, s + 27, 0, 0));
415
if (state.lowercase)
416
lower(job->name);
417
return job;
418
}
419
420
static Jcmvar_t*
421
setvar(const char* s, const char* v, int init)
422
{
423
register Jcmvar_t* var;
424
425
if (var = (Jcmvar_t*)dtmatch(state.vars, s))
426
{
427
if (!v || !init && var->init)
428
return var;
429
free(var->value);
430
}
431
else
432
{
433
if (!(var = newof(0, Jcmvar_t, 1, 0)))
434
nospace();
435
var->dup = 1;
436
strcpy(var->name, s);
437
dtinsert(state.vars, var);
438
}
439
var->init = init;
440
var->value = stash(v ? v : "");
441
return var;
442
}
443
444
static Jcmlib_t*
445
getlib(const char* s)
446
{
447
register Jcmlib_t* lib;
448
register Jcmvar_t* var;
449
register char* t;
450
char name[64];
451
452
copy(name, s, 44);
453
if (!*name)
454
return 0;
455
if (state.lowercase)
456
lower(name);
457
if (!(lib = (Jcmlib_t*)dtmatch(state.libs, name)))
458
{
459
if (!(lib = newof(0, Jcmlib_t, 1, 0)))
460
nospace();
461
strcpy(lib->name, name);
462
dtinsert(state.libs, lib);
463
if (!(t = strchr(lib->name, '%')) || *++t != '%')
464
{
465
if (!(t = strrchr(lib->name, '.')) || !*++t)
466
t = lib->name;
467
sfsprintf(name, sizeof(name), "lib_%s", t);
468
if (state.lowercase)
469
upper(name);
470
if (var = (Jcmvar_t*)dtmatch(state.vars, name))
471
do
472
{
473
sfsprintf(name, sizeof(name), "lib_%s_%lu", t, ++var->dup);
474
if (state.lowercase)
475
upper(name);
476
} while (dtmatch(state.vars, name));
477
lib->var = setvar(name, lib->name, 0);
478
}
479
}
480
return lib;
481
}
482
483
static Jcmlist_t*
484
append(Jcmlist_t* list, Jcmevent_t* event)
485
{
486
register Jcmlist_t* p;
487
register Jcmlist_t* q;
488
489
for (p = list; p; p = p->next)
490
{
491
if (p->event == event)
492
return list;
493
if (!p->next)
494
break;
495
}
496
if (!(q = newof(0, Jcmlist_t, 1, 0)))
497
nospace();
498
q->event = event;
499
if (p)
500
{
501
p->next = q;
502
return list;
503
}
504
return q;
505
}
506
507
static void
508
assert(register Jcmjob_t* job, register Jcmlist_t* reqs, register Jcmlist_t* deps, Jcmevent_t* group)
509
{
510
register Jcmevent_t* event;
511
512
event = getevent(job ? sfprints("JOB-%s", job->name) : NiL, NiL, 1, 1, 0);
513
event->job = job;
514
event->reqs = reqs;
515
event->deps = deps;
516
if (group)
517
group->reqs = append(group->reqs, event);
518
}
519
520
static int
521
init(const char* path)
522
{
523
register char* s;
524
register char* t;
525
register char* e;
526
register int i;
527
Sfio_t* sp;
528
char* file;
529
size_t line;
530
531
if (!(sp = sfopen(NiL, path, "r")))
532
{
533
error(ERROR_SYSTEM|2, "%s: cannot read initialization file", path);
534
return -1;
535
}
536
file = error_info.file;
537
error_info.file = (char*)path;
538
line = error_info.line;
539
error_info.line = 0;
540
while (s = sfgetr(sp, '\n', 1))
541
{
542
error_info.line++;
543
e = s + sfvalue(sp) - 1;
544
while (isspace(*s))
545
s++;
546
if (!*s || *s == '#')
547
continue;
548
i = 0;
549
for (t = s; *s; s++)
550
if (*s == '=')
551
{
552
i = 1;
553
*s++ = 0;
554
break;
555
}
556
else if (isspace(*s) && !i)
557
{
558
i = -1;
559
*s = 0;
560
}
561
if (i > 0 && isalpha(*t))
562
{
563
while (isspace(*s))
564
s++;
565
while (e > s && isspace(*(e - 1)))
566
e--;
567
*e = 0;
568
if (strneq(t, JCL_AUTO, sizeof(JCL_AUTO) - 1))
569
t += sizeof(JCL_AUTO) - 1;
570
if (*t)
571
setvar(t, s, 1);
572
}
573
else
574
error(1, "invalid initialization line ignored: %s", t);
575
}
576
sfclose(sp);
577
error_info.file = file;
578
error_info.line = line;
579
return 0;
580
}
581
582
static void
583
dump(Sfio_t* sp, register Jcmevent_t* event)
584
{
585
register Jcmlist_t* p;
586
register Jcmset_t* v;
587
588
event->mark = 1;
589
sfprintf(sp, "%s : .VIRTUAL", event->name);
590
if (event->job)
591
{
592
if (event->job->overlib && streq(event->job->overlib->name, "DUMMY"))
593
{
594
sfprintf(sp, " .DO.NOTHING");
595
for (p = event->reqs; p; p = p->next)
596
sfprintf(sp, " %s", p->event->name);
597
}
598
else
599
{
600
sfprintf(sp, " .JOB");
601
for (v = event->job->set; v; v = v->next)
602
if (v->value)
603
sfprintf(sp, " %s%s=%s", JCL_AUTO, v->name, fmtquote(v->value, "$'", "'", strlen(v->value), 0));
604
else
605
sfprintf(sp, " (%s%s)", JCL_AUTO, v->name);
606
for (p = event->reqs; p; p = p->next)
607
sfprintf(sp, " %s", p->event->name);
608
sfprintf(sp, " %s", event->job->base);
609
}
610
}
611
else if (!event->reqs)
612
sfprintf(sp, " .EVENT.WAIT");
613
else
614
for (p = event->reqs; p; p = p->next)
615
sfprintf(sp, " %s", p->event->name);
616
if (event->deps)
617
for (p = event->deps; p; p = p->next)
618
sfprintf(sp, " %s.RAISE", p->event->name);
619
sfprintf(sp, "\n");
620
if (event->deps)
621
{
622
for (p = event->deps; p; p = p->next)
623
sfprintf(sp, "%s.RAISE ", p->event->name);
624
sfprintf(sp, ": .AFTER .EVENT.RAISE\n");
625
}
626
for (p = event->reqs; p; p = p->next)
627
if (!p->event->mark)
628
dump(sp, p->event);
629
}
630
631
int
632
main(int argc, char** argv)
633
{
634
register char* file;
635
register char* s;
636
register char* t;
637
register Jcmcard_t* cp;
638
register Jcmevent_t* appl;
639
register Jcmevent_t* base;
640
register Jcmevent_t* group;
641
register Jcmjob_t* job;
642
register Jcmlist_t* deps;
643
register Jcmlist_t* reqs;
644
Jcmcard_t* firstcard;
645
Jcmcard_t* lastcard;
646
Jcmset_t* set;
647
Jcmset_t* lastset;
648
Jcmset_t* global;
649
Jcmshout_t* shout;
650
Jcmshout_t* lastshout;
651
Jcmvar_t* var;
652
unsigned char* map;
653
Sfio_t* sp;
654
int n;
655
int index;
656
657
error_info.id = "jcm";
658
if (!(state.vm = vmopen(Vmdcheap, Vmlast, 0)) || !(state.tmp = sfstropen()))
659
nospace();
660
state.eventdisc.link = offsetof(Jcmevent_t, link);
661
state.eventdisc.key = offsetof(Jcmevent_t, name);
662
state.libdisc.link = offsetof(Jcmlib_t, link);
663
state.libdisc.key = offsetof(Jcmlib_t, name);
664
state.setdisc.link = offsetof(Jcmset_t, link);
665
state.setdisc.key = offsetof(Jcmset_t, name);
666
state.vardisc.link = offsetof(Jcmvar_t, link);
667
state.vardisc.key = offsetof(Jcmvar_t, name);
668
if (!(state.events = dtopen(&state.eventdisc, Dtoset)) ||
669
!(state.libs = dtopen(&state.libdisc, Dtoset)) ||
670
!(state.set = dtopen(&state.setdisc, Dtoset)) ||
671
!(state.vars = dtopen(&state.vardisc, Dtoset)))
672
nospace();
673
index = 0;
674
for (;;)
675
{
676
switch (optget(argv, usage))
677
{
678
case 'c':
679
state.cards = opt_info.number;
680
continue;
681
case 'd':
682
error_info.trace = -opt_info.number;
683
continue;
684
case 'h':
685
state.comment = 1;
686
continue;
687
case 'i':
688
if (init(opt_info.arg))
689
return 1;
690
continue;
691
case 'I':
692
index = opt_info.number;
693
continue;
694
case 'l':
695
state.lowercase = opt_info.number;
696
continue;
697
case 'p':
698
state.portable = opt_info.number;
699
continue;
700
case 'v':
701
state.verbose = opt_info.number;
702
continue;
703
case 'T':
704
state.test |= opt_info.number;
705
continue;
706
case ':':
707
error(2, "%s", opt_info.arg);
708
break;
709
case '?':
710
error(ERROR_USAGE|4, "%s", opt_info.arg);
711
break;
712
}
713
break;
714
}
715
argv += opt_info.index;
716
if (error_info.errors)
717
error(ERROR_USAGE, "%s", optusage(NiL));
718
state.dummy = getlib("DUMMY");
719
state.all = getevent("all", NiL, 0, 1, 0);
720
file = *argv;
721
if (!state.cards)
722
{
723
sfprintf(sfstdout, ":JCL:\n\n");
724
n = 0;
725
for (var = (Jcmvar_t*)dtfirst(state.vars); var; var = (Jcmvar_t*)dtnext(state.vars, var))
726
if (var->init)
727
{
728
sfprintf(sfstdout, "%s%s == %s\n", JCL_AUTO, var->name, var->value);
729
n = 1;
730
}
731
if (n)
732
sfprintf(sfstdout, "\n");
733
}
734
do
735
{
736
if (!file)
737
sp = sfstdin;
738
else if (!(sp = sfopen(NiL, file, "r")))
739
{
740
error(ERROR_SYSTEM|2, "%s: cannot read", file);
741
continue;
742
}
743
else if (state.cards || state.verbose)
744
sfprintf(sfstdout, "=== %s ===\n", file);
745
n = sfgetc(sp);
746
sfungetc(sp, n);
747
map = isupper(n) ? (unsigned char*)0 : ccmap(CC_EBCDIC_O, CC_NATIVE);
748
error_info.file = file;
749
error_info.line = 0;
750
vmclear(state.vm);
751
firstcard = lastcard = 0;
752
while (s = card(sp, map))
753
{
754
if (state.cards || state.verbose)
755
{
756
sfprintf(sfstdout, "%s\n", s);
757
if (state.cards)
758
continue;
759
}
760
if (*s == 'T' && (t = strchr(s + 3, '=')) && *++t == '~')
761
setvar(t + 1, NiL, 0);
762
if (!(cp = vmnewof(state.vm, 0, Jcmcard_t, 1, strlen(s))))
763
nospace();
764
strcpy(cp->data, s);
765
if (lastcard)
766
lastcard = lastcard->next = cp;
767
else
768
lastcard = firstcard = cp;
769
}
770
if (cp = firstcard)
771
{
772
appl = base = group = 0;
773
job = 0;
774
deps = reqs = 0;
775
cp = firstcard;
776
do
777
{
778
s = cp->data;
779
if (state.cards || state.verbose)
780
{
781
sfprintf(sfstdout, "%s\n", s);
782
if (state.cards)
783
continue;
784
}
785
switch (s[0])
786
{
787
case 'B':
788
/* XXX: unknown per-job sparse */
789
break;
790
case 'C':
791
/* XXX: event control */
792
break;
793
case 'D':
794
case 'J':
795
case 'K':
796
case 'W':
797
/* XXX: cron info */
798
break;
799
case 'E':
800
/* XXX: event relationships */
801
break;
802
case 'G':
803
/* XXX: group info */
804
break;
805
case 'H':
806
if (state.comment)
807
sfprintf(sfstdout, "# %s\n\n", parameterize(state.tmp, s+1, NiL, 0, 0));
808
break;
809
case 'I':
810
if (job)
811
{
812
if (index)
813
{
814
s++;
815
for (n = 0; n < index; n++)
816
reqs = append(reqs, getevent(s, s+20, 0, 0, n));
817
s += 23;
818
}
819
for (s++; *s; s += 24)
820
reqs = append(reqs, getevent(s, s+20, 0, 0, 0));
821
}
822
break;
823
case 'L':
824
if (job)
825
job->memlib = getlib(s+1);
826
break;
827
case 'M':
828
if (job || deps || reqs)
829
assert(job, reqs, deps, group);
830
deps = reqs = 0;
831
appl = getevent(s+9, 0, 0, 0, 0);
832
state.all->reqs = append(state.all->reqs, appl);
833
if (s[60] == 'G')
834
{
835
base = appl;
836
group = getevent(s+1, NiL, 1, 0, 0);
837
appl->reqs = append(appl->reqs, group);
838
job = 0;
839
}
840
else
841
{
842
group = appl;
843
job = getjob(s+1);
844
job->relationship = s[64];
845
if (base && base != appl)
846
appl->reqs = append(appl->reqs, base);
847
}
848
break;
849
case 'N':
850
if (job)
851
job->tag = stash(parameterize(state.tmp, s+1, s+21, 0, 0));
852
break;
853
case 'O':
854
if (job)
855
{
856
if (*(s + 4) == '-')
857
{
858
job->name = stash(parameterize(state.tmp, s+5, s+13, 0, 0));
859
if (t = strchr(job->name, '-'))
860
*t = 0;
861
if (state.lowercase)
862
lower(job->name);
863
}
864
for (s++; *s; s += 25)
865
if ((state.test & 0x0010) || s[24] != '-')
866
deps = append(deps, getevent(s, s+20, 0, 0, 0));
867
}
868
break;
869
case 'Q':
870
if (state.verbose)
871
for (s++; *s; s += 24)
872
sfprintf(sfstdout, "Q='%-20.20s'\n", s);
873
break;
874
case 'R':
875
/* XXX: unknown per-job sparse */
876
break;
877
case 'S':
878
if (job)
879
{
880
if (lastshout = job->shout)
881
while (lastshout->next)
882
lastshout = lastshout->next;
883
s++;
884
while (*s)
885
{
886
if (!(shout = newof(0, Jcmshout_t, 1, 0)))
887
nospace();
888
if (lastshout)
889
lastshout->next = shout;
890
else
891
job->shout = shout;
892
lastshout = shout;
893
shout->when = *s++;
894
for (t = shout->data; !isalpha(*s); s++)
895
if (t < &shout->data[sizeof(shout->data)-1])
896
*t++ = *s;
897
*t = 0;
898
for (s += (copy(shout->to, s, 16) - shout->to); *s == ' '; s++);
899
shout->pri = *s++;
900
n = 0;
901
while (*s >= '0' && *s <= '9')
902
n = n * 10 + (*s++ - '0');
903
if (n >= sizeof(shout->text))
904
n = sizeof(shout->text) - 1;
905
memcpy(shout->text, s, n);
906
s += n;
907
}
908
}
909
break;
910
case 'T':
911
if (job)
912
{
913
s = parameterize(state.tmp, s + 3, NiL, 0, 0);
914
n = strlen(s) + 2;
915
if (!(set = newof(0, Jcmset_t, 1, n)))
916
nospace();
917
strcpy(set->name, s);
918
if (s = strchr(set->name, '='))
919
{
920
*s++ = 0;
921
set->value = s;
922
}
923
else
924
set->value = "";
925
var = (Jcmvar_t*)dtmatch(state.vars, set->name);
926
if ((!(var = (Jcmvar_t*)dtmatch(state.vars, set->name)) || !var->init) && (!(global = (Jcmset_t*)dtmatch(state.set, set->name)) || streq(global->value, set->value) || circular(set)))
927
{
928
if (!global)
929
{
930
if (!state.cards)
931
sfprintf(sfstdout, "%s%s == %s\n", JCL_AUTO, set->name, circular(set) ? "1" : set->value);
932
dtinsert(state.set, global = set);
933
if (!(set = newof(0, Jcmset_t, 1, n)))
934
nospace();
935
memcpy(set, global, sizeof(Jcmset_t) + n);
936
}
937
set->value = 0;
938
}
939
if (lastset = job->set)
940
{
941
while (lastset->next)
942
lastset = lastset->next;
943
lastset->next = set;
944
}
945
else
946
job->set = set;
947
}
948
break;
949
case 'V':
950
if (job)
951
job->overlib = getlib(s+1);
952
break;
953
case 'Z':
954
if (job)
955
{
956
job->docmem = stash(parameterize(state.tmp, s+1, s+9, 0, 0));
957
job->doclib = getlib(s+9);
958
}
959
break;
960
default:
961
error(1, "%c: unknown op", s[0]);
962
break;
963
}
964
} while (cp = cp->next);
965
if (job || deps || reqs)
966
assert(job, reqs, deps, group);
967
}
968
if (sp != sfstdin)
969
sfclose(sp);
970
error_info.file = 0;
971
error_info.line = 0;
972
} while (file && (file = *++argv));
973
if (!state.cards)
974
{
975
sfprintf(sfstdout, "\n");
976
dump(sfstdout, state.all);
977
}
978
return error_info.errors != 0;
979
}
980
981