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 <glenn.s.fowler@gmail.com>                *
18 *                                                                      *
19 ***********************************************************************/
20 #pragma prototyped
21 
22 /*
23  * jcl private library support
24  */
25 
26 #include "jcllib.h"
27 
28 #include <tm.h>
29 
30 static char*
internal(register Jcl_t * jcl,const char * name)31 internal(register Jcl_t* jcl, const char* name)
32 {
33 	register char*	s;
34 	register char*	t;
35 
36 	if (streq(name, "CYCLE"))
37 		return tmmake(NiL)->tm_mday <= 10 ? "10" : "31";
38 	else if (streq(name, "JOBNAME"))
39 		return jcl->name;
40 	else if (streq(name, "USERID"))
41 		return getlogin();
42 	else if (streq(name, "VDATE"))
43 	{
44 		for (t = s = fmttime("%h%y", time(NiL)); *t; t++)
45 			if (islower(*t))
46 				*t = toupper(*t);
47 		return s;
48 	}
49 	return 0;
50 }
51 
52 /*
53  * return value for &name. variable
54  * if value!=0 then value is set
55  * if (set&DEFAULT) then no set if already defined
56  * if (set&MUST) then error message if not found
57  * no provision for delete
58  */
59 
60 char*
lookup(register Jcl_t * jcl,const char * name,const char * value,int flags,int set)61 lookup(register Jcl_t* jcl, const char* name, const char* value, int flags, int set)
62 {
63 	register Jclsym_t*	v;
64 	register Jcl_t*		scope;
65 	char*			s;
66 	char*			b;
67 	time_t			t;
68 	int			j;
69 	int			f;
70 
71 	if (!value)
72 	{
73 		if (jcl->step->syms && (v = (Jclsym_t*)dtmatch(jcl->step->syms, name)))
74 			goto found;
75 		for (scope = jcl; scope; scope = scope->scope)
76 		{
77 			if (scope->scope && scope->scope->step->syms && (v = (Jclsym_t*)dtmatch(scope->scope->step->syms, name)))
78 				goto found;
79 			if (scope->syms && (v = (Jclsym_t*)dtmatch(scope->syms, name)))
80 				goto found;
81 		}
82 	}
83 	else if (!jcl->syms)
84 		return 0;
85 	else if ((v = (Jclsym_t*)dtmatch(jcl->syms, name)) && (!(flags & (JCL_SYM_EXPORT|JCL_SYM_SET)) || (v->flags & (JCL_SYM_EXPORT|JCL_SYM_SET))))
86 	{
87 		if (!(set & DEFAULT))
88 			v->value = stash(jcl, jcl->vm, value, 0);
89 		goto found;
90 	}
91 	if (!value)
92 	{
93 		if (strneq(name, JCL_AUTO, sizeof(JCL_AUTO) - 1))
94 		{
95 			b = (char*)name + sizeof(JCL_AUTO) - 1;
96 			if ((s = getenv(name)) || (s = internal(jcl, b)))
97 				return s;
98 			s = b;
99 			if (*s == '$')
100 			{
101 				s++;
102 				f = 1;
103 			}
104 			else
105 				f = 0;
106 			switch (*s)
107 			{
108 			case 'O':
109 				s++;
110 				t = jcl->disc->odate;
111 				break;
112 			case 'R':
113 				s++;
114 				t = jcl->disc->rdate;
115 				break;
116 			default:
117 				t = jcl->disc->date;
118 				break;
119 			}
120 			if (s[0] == 'J' && s[1] == 'U' && s[2] == 'L')
121 			{
122 				s += 3;
123 				j = 1;
124 			}
125 			else
126 				j = 0;
127 			switch (*s)
128 			{
129 			case 'C':
130 				if (!strcmp(s, "CENT"))
131 					return fmttime("%C", t);
132 				break;
133 			case 'D':
134 				if (!strcmp(s, "DATE"))
135 					return fmttime(f ? (j ? "%Y%j" : "%Y%m%d") : (j ? "%y%j" : "%y%m%d"), t);
136 				else if (!strcmp(s, "DAY"))
137 					return fmttime(j ? "%j" : "%d", t);
138 				break;
139 			case 'M':
140 				if (!strcmp(s, "MONTH"))
141 					return fmttime("%m", t);
142 				break;
143 			case 'W':
144 				if (!strcmp(s, "WDAY"))
145 					return fmttime("%u", t);
146 				else if (!strcmp(s, "WEEK"))
147 					return fmttime("%U", t);
148 				break;
149 			case 'Y':
150 				if (!strcmp(s, "YEAR"))
151 					return fmttime(f ? "%Y" : "%y", t);
152 				break;
153 			}
154 			switch (*b)
155 			{
156 			case 'B':
157 				if (!strncmp(b, "BLANK", 5))
158 				{
159 					if (!(j = (int)strtol(b, &s, 10)))
160 						j = 1;
161 					if (!*s)
162 					{
163 						s = fmtbuf(j + 1);
164 						memset(s, ' ', j);
165 						s[j] = 0;
166 						return s;
167 					}
168 				}
169 				break;
170 			case 'R':
171 				if (!strcmp(b, "RN"))
172 					return "1";
173 				break;
174 			case 'T':
175 				if (!strcmp(b, "TIME"))
176 					return fmttime("%H%M%S", t);
177 				break;
178 			}
179 			if ((set & MUST) && jcl->disc->errorf)
180 				(*jcl->disc->errorf)(NiL, jcl->disc, 1, "%%%%%s operand value or %s environment value expected", b, name);
181 		}
182 		else if (s = internal(jcl, name))
183 			return s;
184 		else if ((set & MUST) && jcl->disc->errorf)
185 			(*jcl->disc->errorf)(NiL, jcl->disc, 1, "&%s: undefined variable", name);
186 		return 0;
187 	}
188 	if (!(v = vmnewof(jcl->vm, 0, Jclsym_t, 1, strlen(name))))
189 	{
190 		nospace(jcl, NiL);
191 		return 0;
192 	}
193 	strcpy(v->name, name);
194 	if (!(v->value = stash(jcl, jcl->vm, value, 0)))
195 		return 0;
196 	dtinsert(jcl->syms, v);
197  found:
198 	if (jcl->flags & (JCL_PARAMETERIZE|JCL_LISTVARIABLES))
199 	{
200 		register char*	s;
201 
202 		for (s = v->name; isalnum(*s) || *s == '_'; s++);
203 		if (!*s)
204 		{
205 			if (jcl->flags & JCL_LISTVARIABLES)
206 				uniq(v->name, NiL, 0, jcl->disc);
207 			if (jcl->flags & JCL_PARAMETERIZE)
208 			{
209 #if 0
210 				if (diff(v->name, v->value))
211 					sfprintf(sfstdout, "%s=%s\t# global\n", v->name, fmtquote(v->value, "$'", "'", strlen(v->value), 0));
212 #endif
213 				sfprintf(jcl->vp, "${%s}", v->name);
214 				if (!(s = sfstruse(jcl->vp)))
215 					nospace(jcl, NiL);
216 				return s;
217 			}
218 		}
219 	}
220 	return v->value;
221 }
222 
223 /*
224  * save string in vm
225  * path==1 enables mvs => unix path conversion
226  */
227 
228 char*
stash(Jcl_t * jcl,Vmalloc_t * vm,const char * str,int path)229 stash(Jcl_t* jcl, Vmalloc_t* vm, const char* str, int path)
230 {
231 	char*	s;
232 	char*	t;
233 	char*	e;
234 	int	n;
235 
236 	n = strlen(str);
237 	if (!(s = vmnewof(vm, NiL, char, n, 1)))
238 		nospace(jcl, NiL);
239 	strcpy(s, str);
240 	if (path && (*s != '$' || *(s + 1) != '(') && (t = strchr(s, '(')) && *(s + n - 1) == ')')
241 	{
242 		strtol(t + 1, &e, 10);
243 		if (e == (s + n - 1))
244 			*t = 0;
245 		else
246 		{
247 			*t = '/';
248 			*(s + n - 1) = 0;
249 		}
250 	}
251 	return s;
252 }
253 
254 /*
255  * out of space message
256  */
257 
258 void
nospace(Jcl_t * jcl,Jcldisc_t * disc)259 nospace(Jcl_t* jcl, Jcldisc_t* disc)
260 {
261 	if (!disc)
262 		disc = jcl->disc;
263 	if (disc->errorf)
264 		(*disc->errorf)(jcl, disc, ERROR_SYSTEM|2, "out of space");
265 }
266