Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/lib/libjcl/find.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 file search
24
*/
25
26
#include "jcllib.h"
27
28
#include <ctype.h>
29
#include <ls.h>
30
31
#define directory(p,s) (stat((p),(s))>=0&&S_ISDIR((s)->st_mode))
32
#define REGULAR(p,s) (stat((p),(s))>=0&&(S_ISREG((s)->st_mode)||streq(p,"/dev/null")))
33
34
static struct /* directory list state */
35
{
36
Dirlist_t dirs; /* global directory list */
37
} state;
38
39
/*
40
* return >0 if path is a regular file
41
*/
42
43
static int
44
regular(Jcl_t* jcl, char* path, struct stat* st)
45
{
46
register char* s;
47
register char* t;
48
register Include_t* ip;
49
50
if (REGULAR(path, st))
51
goto found;
52
if (s = strrchr(path, '/'))
53
s++;
54
else
55
s = path;
56
while (*s && !isupper(*s))
57
s++;
58
if (*s)
59
{
60
t = sfprints("%s", path);
61
for (s = t + (s - path); *s; s++)
62
if (isupper(*s))
63
*s = tolower(*s);
64
if (REGULAR(t, st))
65
{
66
strcpy(path, t);
67
goto found;
68
}
69
}
70
return 0;
71
found:
72
73
/*
74
* catch recursive includes
75
*/
76
77
do
78
{
79
for (ip = jcl->include; ip; ip = ip->prev)
80
if (streq(path, ip->path))
81
return 0;
82
} while (jcl = jcl->scope);
83
return 1;
84
}
85
86
/*
87
* expand ${...} in name
88
* return expanded value returned in jcl->vp
89
* jcl->tp may be clobbered
90
*/
91
92
char*
93
expand(Jcl_t* jcl, const char* name, int flags)
94
{
95
register char* s;
96
register char* t;
97
register int c;
98
char* b;
99
char* v;
100
size_t n;
101
size_t p;
102
Sfio_t* vp;
103
104
if (jcl)
105
for (s = (char*)name; *s; s++)
106
if (*s == '$' && *(s + 1) == '{')
107
{
108
p = sfstrtell(jcl->tp);
109
if (n = s - (char*)name)
110
sfwrite(jcl->tp, name, n);
111
while (c = *s++)
112
if (c == '$' && *s == '{')
113
{
114
b = s;
115
n = sfstrtell(jcl->tp);
116
s++;
117
if (*s == '%' && *(s + 1) == '%')
118
{
119
s += 2;
120
sfputr(jcl->tp, JCL_AUTO, -1);
121
}
122
while ((c = *s++) && c != '}')
123
sfputc(jcl->tp, c);
124
sfputc(jcl->tp, 0);
125
v = sfstrseek(jcl->tp, n, SEEK_SET);
126
if (isdigit(*v) && !*(v + 1))
127
{
128
if (t = matched(*v - '0', &n, jcl->disc))
129
sfwrite(jcl->tp, t, n);
130
}
131
else if (t = lookup(jcl, v, NiL, flags, DEFAULT))
132
{
133
if ((flags & JCL_SYM_SET) && jcl->vp != jcl->xp)
134
{
135
vp = jcl->vp;
136
jcl->vp = jcl->xp;
137
t = expand(jcl, t, flags);
138
sfputr(jcl->tp, t, -1);
139
jcl->vp = vp;
140
}
141
else
142
sfputr(jcl->tp, t, -1);
143
}
144
else if (((flags & JCL_SYM_EXPORT) || !(flags & JCL_SYM_SET)) && (t = getenv(v)))
145
sfputr(jcl->tp, t, -1);
146
else if (flags & JCL_SYM_SET)
147
{
148
sfputc(jcl->tp, '$');
149
s = b;
150
}
151
}
152
else
153
sfputc(jcl->tp, c);
154
sfputc(jcl->tp, 0);
155
s = sfstrseek(jcl->tp, p, SEEK_SET);
156
message((-7, "expand %s => %s", name, s));
157
sfputr(jcl->vp, s, -1);
158
if (!(s = sfstruse(jcl->vp)))
159
nospace(jcl, NiL);
160
return s;
161
}
162
return (char*)name;
163
}
164
165
/*
166
* append dir to jclfind() include list
167
*/
168
169
int
170
jclinclude(Jcl_t* jcl, const char* dir, unsigned long flags, Jcldisc_t* disc)
171
{
172
register Dirlist_t* lp;
173
register Dir_t* dp;
174
struct stat st;
175
176
if (dir && *(dir = (const char*)expand(jcl, dir, 0)) && !streq(dir, ".") && directory(dir, &st))
177
{
178
lp = jcl ? &jcl->dirs : &state.dirs;
179
for (dp = lp->head; dp; dp = dp->next)
180
if (streq(dir, dp->dir))
181
return 0;
182
if (!(dp = oldof(0, Dir_t, 1, strlen(dir))))
183
{
184
nospace(jcl, disc);
185
return -1;
186
}
187
strcpy(dp->dir, dir);
188
dp->next = 0;
189
dp->flags = flags;
190
if (lp->tail)
191
lp->tail = lp->tail->next = dp;
192
else
193
lp->head = lp->tail = dp;
194
}
195
return 0;
196
}
197
198
/*
199
* check the jclinclude() directories
200
*/
201
202
static char*
203
search(Jcl_t* jcl, const char* dir, const char* name, unsigned long flags, struct stat* st)
204
{
205
register char* s;
206
register Dir_t* dp;
207
Jcl_t* top;
208
209
if (!dir || !(flags & JCL_STANDARD) || strchr(name, '/'))
210
{
211
if (dir && *name != '/')
212
sfprintf(jcl->tp, "%s/", dir);
213
sfprintf(jcl->vp, "%s", name);
214
if (!(s = sfstruse(jcl->vp)))
215
nospace(jcl, NiL);
216
if (regular(jcl, s, st))
217
return s;
218
}
219
if (*name != '/')
220
{
221
top = jcl;
222
dp = jcl->dirs.head;
223
for (;;)
224
{
225
for (; dp; dp = dp->next)
226
if (flags & dp->flags)
227
{
228
if (dir && *dp->dir != '/')
229
sfprintf(top->tp, "%s/", dir);
230
sfprintf(top->tp, "%s/%s", dp->dir, name);
231
if (!(s = sfstruse(top->tp)))
232
nospace(jcl, NiL);
233
if (regular(top, s, st))
234
return s;
235
}
236
if (!jcl)
237
break;
238
dp = (jcl = jcl->scope) ? jcl->dirs.head : state.dirs.head;
239
}
240
}
241
return 0;
242
}
243
244
/*
245
* return path to name using jclinclude() list
246
* path allocated in jcl->vs
247
* !(flags&JCL_STANDARD) checks . and dir of including file
248
* level>0 is not found error message level
249
* { jcl->tp jcl->vp jcl->xp } may be clobbered
250
*/
251
252
char*
253
jclfind(Jcl_t* jcl, const char* name, unsigned long flags, int level, Sfio_t** spp)
254
{
255
register char* s;
256
struct stat st;
257
258
if (flags & JCL_PROC)
259
{
260
sfprintf(jcl->vp, "(PROC)%s", name);
261
if (!(s = sfstruse(jcl->vp)))
262
nospace(jcl, NiL);
263
if (s = lookup(jcl, s, NiL, 0, 0))
264
{
265
if (spp && !(*spp = sfstropen()) || sfstrbuf(*spp, s, strlen(s), 0))
266
{
267
if (*spp)
268
sfclose(*spp);
269
nospace(jcl, NiL);
270
return 0;
271
}
272
s = (char*)name;
273
goto save;
274
}
275
}
276
name = (const char*)expand(jcl, jclpath(jcl, name), 0);
277
278
/*
279
* check the unadorned path first
280
* this handles . and absolute paths
281
*/
282
283
if (s = search(jcl, NiL, name, flags, &st))
284
goto found;
285
if (*name != '/')
286
{
287
/*
288
* check the directory of the including file
289
* on the assumption that error_info.file is properly stacked
290
*/
291
292
if (!(flags & JCL_STANDARD) && error_info.file && (s = strrchr(error_info.file, '/')))
293
{
294
sfprintf(jcl->tp, "%-.*s%s", s - error_info.file + 1, error_info.file, name);
295
if (!(s = sfstruse(jcl->tp)))
296
nospace(jcl, NiL);
297
if (regular(jcl, s, &st))
298
goto found;
299
}
300
}
301
if (flags & JCL_CREATE)
302
{
303
if (spp)
304
*spp = 0;
305
s = (char*)name;
306
goto save;
307
}
308
if (level && jcl->disc->errorf)
309
(*jcl->disc->errorf)(NiL, jcl->disc, ERROR_SYSTEM|level, "%s: not found", name);
310
return 0;
311
found:
312
if (spp && !(*spp = sfopen(NiL, s, "r")) && level > 0 && jcl->disc->errorf)
313
(*jcl->disc->errorf)(NiL, jcl->disc, ERROR_SYSTEM|level, "%s: cannot read", s);
314
message((-4, "find %s => %s", name, s));
315
save:
316
return stash(jcl, jcl->vs, s, 0);
317
}
318
319