Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/jcl/jcl.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 deck interpreter
24
*
25
* Glenn Fowler
26
* AT&T Research
27
*/
28
29
#include "jcl.h"
30
31
#include <tm.h>
32
33
static const char usage[] =
34
"[-?\n@(#)$Id: jcl (AT&T Research) 2006-11-11 $\n]"
35
USAGE_LICENSE
36
"[+NAME?jcl - jcl deck interpreter]"
37
"[+DESCRIPTION?\bjcl\b interprets the JCL decks named by the \afile\a"
38
" operands. The standard input is read if no \afile\a operands"
39
" are specified. If \b--map\b is not specified then"
40
" \b--map=" JCL_MAPFILE "\b is assumed. The \aname\a=\avalue\a"
41
" operands override any values specified JCL decks.]"
42
"[+?control-M scheduler auto edit variable \b%%\b\aname\a values"
43
" may be initialized by exporting \b" JCL_AUTO "\b\aname\a=\avalue\a"
44
" or by \b%%\b\aname\a=\avalue\a on the command line.]"
45
"[d:debug?Set the debug trace level. Higher levels produce more"
46
" output.]#[level]"
47
"[g:global?Like \b--map\b=\afile\a except that the default "
48
JCL_MAPFILE ", if it exists, is still read after the command"
49
" line options are processed.]:[file]"
50
"[i:import?Environment variable definitions take precedence over"
51
" corresponding \b--map\b file definitions.]"
52
"[I:include?Search \adirectory\a for DSN names. More than one"
53
" \b--include\b option may be specified.]:[directory]"
54
"[k:marklength?Mark fixed length record file names by appending"
55
" \b%\b\alrecl\a to the names.]"
56
"[l:list?List all referenced \aitem\as. Only the last \b--list\b"
57
" \aitem\a is listed. \aitem\a may be:]:[item]{"
58
" [a:autoedit?List the %%\aname\a autoedit variables.]"
59
" [c:count?List the \aitem\a dup counts too.]"
60
" [e:exec?List the EXEC job and command names.]"
61
" [i:inputs?List the DD input data file paths.]"
62
" [o:outputs?List the DD output data file paths.]"
63
" [p:programs?List the EXEC PGM=\aprogram\a program names.]"
64
" [s:scripts?List the EXEC [PROC=]]\ascript\a script names.]"
65
" [v:variables?List the &\aname\a variables.]"
66
"}"
67
"[m:map?Read the dataset file path prefix map \afile\a. Each line in \afile\a"
68
" contains an operation followed by 0 or more space separated fields."
69
" \b#\b in the first column denotes a comment; comments and blank lines"
70
" are ignored. If \afile\a is \b-\b then \b/dev/null\b is assumed."
71
" If \afile\a is not found and contains no \b/\b then"
72
" \b../lib/jcl/\b\afile\a is searched for on \b$PATH\b. If no \b--map\b"
73
" option is specified then the default " JCL_MAPFILE ", if it exists,"
74
" is read after the command line options are processed. The operations"
75
" are:]:[file]{"
76
" [+export \aname\a=\avalue ...?Set export variable values."
77
" Export variable expansions are preserved in the"
78
" generated scripts.]"
79
" [+map \aprefix\a \amap\a [\asuffix\a]]?Dataset paths are"
80
" mapped by doing a longest prefix match on the"
81
" prefixes. The matching dataset prefix is replaced"
82
" by \amap\a, and \asuffix\a, if specified, is"
83
" appended. The prefix \b\"\"\b matches when no other"
84
" prefix matches. Leading \b*.\b and trailing \b.*\b"
85
" match any \b.\b-separated component. \b${\b\an\a\b}\b"
86
" in \amap\a expands to the component matched by the"
87
" \an\a-th \b*\b in \aprefix\a, counting from 1, left"
88
" to right.]"
89
" [+set --[no]]\aoption\a[=\avalue]] ...?Set command line options.]"
90
" [+set %%\aname\a=\avalue ...?Set auto edit variable values.]"
91
" [+set \aname\a=\avalue ...?Set variable values.]"
92
" }"
93
"[n!:exec?Enable command execution. \b--noexec\b disables.]"
94
"[N:never?Disable all command and recursive script execution.]"
95
"[p:parameterize?Parameterize simple &\aname\a variable references by"
96
" substituting the \bsh\b(1) equivalent ${\aname\a}.]"
97
"[r:resolve?Resolve each operand as a path name using the \b--map\b files"
98
" and print the resulting path on the standard output, one path per line.]"
99
"[s:subdir?Execute each job in a separate subdirectory named"
100
" \ajobname\a.\ayy-mm-dd.n\a]]. \an\a starts at \b1\b and"
101
" is incremeted by \b1\b for each run of \ajobname\a within"
102
" the same day.]"
103
"[v:verbose?For \b--noexec\b the equivalent \bsh\b(1) script is listed"
104
" on the standard output. For \b--exec\b verbose execution output,"
105
" like start and completion times, is enabled.]"
106
"[w:warn?Enable verbose warning messages.]"
107
"[x:trace?Enable command execution trace.]"
108
"[O:odate?Set the control-M original date to \adate\a.]:[date:=now]"
109
"[R:rdate?Set the control-M current run date to \adate\a.]:[date:=now]"
110
"[S:date?Set the control-M system date to \adate\a.]:[date:=now]"
111
"\n"
112
"\n[ name=value ... ] [ file ... ]\n"
113
"\n"
114
"[+FILES]{"
115
" [+../lib/jcl/prefix?Default \b--map\b file, found on \b$PATH\b.]"
116
"}"
117
"[+SEE ALSO?\bsh\b(1)]"
118
;
119
120
#include <tm.h>
121
122
struct Map_s; typedef struct Map_s Map_t;
123
124
struct Map_s
125
{
126
Map_t* next;
127
char* arg;
128
int map;
129
};
130
131
typedef struct State_s
132
{
133
Jcldisc_t disc;
134
int resolve;
135
Map_t* map;
136
Map_t* lastmap;
137
} State_t;
138
139
static int
140
optset(Jcl_t* jcl, int c, Jcldisc_t* disc)
141
{
142
State_t* state = (State_t*)disc;
143
unsigned long f;
144
char* s;
145
time_t* t;
146
Map_t* p;
147
148
switch (c)
149
{
150
case 'd':
151
error_info.trace = -opt_info.number;
152
return 1;
153
case 'g':
154
case 'm':
155
if (!(p = newof(0, Map_t, 1, 0)))
156
{
157
error(ERROR_SYSTEM|2, "out of space");
158
return 0;
159
}
160
p->arg = opt_info.arg;
161
p->map = c == 'm';
162
if (!state->map)
163
state->map = p;
164
else
165
state->lastmap->next = p;
166
state->lastmap = p;
167
return 1;
168
case 'i':
169
f = JCL_IMPORT;
170
break;
171
case 'I':
172
jclinclude(NiL, opt_info.arg, JCL_JOB|JCL_PROC, disc);
173
return 1;
174
case 'k':
175
f = JCL_MARKLENGTH;
176
break;
177
case 'l':
178
switch (opt_info.num)
179
{
180
case 'a':
181
jcl->flags |= JCL_LISTAUTOEDITS;
182
break;
183
case 'c':
184
jcl->flags |= JCL_LISTCOUNTS;
185
break;
186
case 'e':
187
jcl->flags |= JCL_LISTEXEC;
188
break;
189
case 'i':
190
jcl->flags |= JCL_LISTINPUTS;
191
break;
192
case 'o':
193
jcl->flags |= JCL_LISTOUTPUTS;
194
break;
195
case 'p':
196
jcl->flags |= JCL_LISTPROGRAMS;
197
break;
198
case 's':
199
jcl->flags |= JCL_LISTSCRIPTS;
200
break;
201
case 'v':
202
jcl->flags |= JCL_LISTVARIABLES;
203
break;
204
}
205
return 1;
206
case 'n':
207
jcl->roflags |= JCL_EXEC;
208
if (!opt_info.number)
209
jcl->flags &= ~JCL_EXEC;
210
return 1;
211
case 'N':
212
jcl->roflags |= JCL_RECURSE;
213
if (!opt_info.number)
214
jcl->flags &= ~JCL_RECURSE;
215
return 1;
216
case 'O':
217
t = &jcl->disc->odate;
218
date:
219
*t = tmdate(opt_info.arg, &s, NiL);
220
if (*s)
221
{
222
error(2, "%s: %s: invalid date", opt_info.name, opt_info.arg);
223
return 0;
224
}
225
return 1;
226
case 'p':
227
f = JCL_PARAMETERIZE;
228
break;
229
case 'r':
230
((State_t*)disc)->resolve = !!opt_info.number;
231
return 1;
232
case 'R':
233
t = &jcl->disc->rdate;
234
goto date;
235
case 's':
236
f = JCL_SUBDIR;
237
break;
238
case 'S':
239
t = &jcl->disc->date;
240
goto date;
241
case 'v':
242
f = JCL_VERBOSE;
243
break;
244
case 'w':
245
f = JCL_WARN;
246
break;
247
case 'x':
248
f = JCL_TRACE;
249
break;
250
case ':':
251
error(2, "%s", opt_info.arg);
252
return 0;
253
case '?':
254
error(ERROR_USAGE|4, "%s", opt_info.arg);
255
return 0;
256
}
257
if ((jcl->roflags & (JCL_MAPPED|f)) != (JCL_MAPPED|f))
258
{
259
if (!(jcl->roflags & JCL_MAPPED))
260
jcl->roflags |= f;
261
if (opt_info.number)
262
jcl->flags |= f;
263
else
264
jcl->flags &= ~f;
265
}
266
return 1;
267
}
268
269
int
270
main(int argc, char** argv)
271
{
272
char* s;
273
char* t;
274
Jcl_t* jcl;
275
Map_t* p;
276
int c;
277
State_t state;
278
279
error_info.id = "jcl";
280
memset(&state, 0, sizeof(state));
281
jclinit(&state.disc, errorf);
282
state.disc.usage = usage;
283
state.disc.optsetf = optset;
284
if (jcl = jclopen(NiL, NiL, JCL_EXEC|JCL_JOB|JCL_RECURSE|JCL_STANDARD|JCL_SCOPE, &state.disc))
285
{
286
while ((c = optget(argv, usage)) && optset(jcl, c, &state.disc));
287
argv += opt_info.index;
288
if (error_info.errors)
289
error(ERROR_USAGE|4, "%s", optusage(NiL));
290
while (jclsym(jcl, *argv, NiL, JCL_SYM_READONLY))
291
argv++;
292
c = 0;
293
while (p = state.map)
294
{
295
state.map = state.map->next;
296
if (jclmap(jcl, p->arg, &state.disc))
297
return 1;
298
c |= p->map;
299
free(p);
300
}
301
if (!c && jclmap(jcl, NiL, &state.disc))
302
return 1;
303
if (state.resolve)
304
{
305
while (s = *argv++)
306
if (t = jclpath(jcl, s))
307
sfprintf(sfstdout, "%s\n", t);
308
else
309
error(2, "%s: cannot resolve", s);
310
}
311
else
312
{
313
jcl->step->command = *argv;
314
while (!jclrun(jcl) && jcl->step->command && (jcl->step->command = *++argv));
315
}
316
}
317
if (!(c = jclclose(jcl)) && error_info.errors)
318
c = 1;
319
return c;
320
}
321
322