GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
/* $OpenBSD: c_ksh.c,v 1.50 2016/03/21 13:35:00 tb Exp $ */ |
||
2 |
|||
3 |
/* |
||
4 |
* built-in Korn commands: c_* |
||
5 |
*/ |
||
6 |
|||
7 |
#include <sys/stat.h> |
||
8 |
|||
9 |
#include <ctype.h> |
||
10 |
#include <errno.h> |
||
11 |
#include <string.h> |
||
12 |
#include <unistd.h> |
||
13 |
|||
14 |
#include "sh.h" |
||
15 |
|||
16 |
int |
||
17 |
c_cd(char **wp) |
||
18 |
426 |
{ |
|
19 |
int optc; |
||
20 |
426 |
int physical = Flag(FPHYSICAL); |
|
21 |
int cdnode; /* was a node from cdpath added in? */ |
||
22 |
426 |
int printpath = 0; /* print where we cd'd? */ |
|
23 |
int rval; |
||
24 |
struct tbl *pwd_s, *oldpwd_s; |
||
25 |
XString xs; |
||
26 |
char *xp; |
||
27 |
char *dir, *try, *pwd; |
||
28 |
int phys_path; |
||
29 |
char *cdpath; |
||
30 |
426 |
char *fdir = NULL; |
|
31 |
|||
32 |
✗✓ | 852 |
while ((optc = ksh_getopt(wp, &builtin_opt, "LP")) != -1) |
33 |
switch (optc) { |
||
34 |
case 'L': |
||
35 |
physical = 0; |
||
36 |
break; |
||
37 |
case 'P': |
||
38 |
physical = 1; |
||
39 |
break; |
||
40 |
case '?': |
||
41 |
return 1; |
||
42 |
} |
||
43 |
426 |
wp += builtin_opt.optind; |
|
44 |
|||
45 |
✗✓ | 426 |
if (Flag(FRESTRICTED)) { |
46 |
bi_errorf("restricted shell - can't cd"); |
||
47 |
return 1; |
||
48 |
} |
||
49 |
|||
50 |
426 |
pwd_s = global("PWD"); |
|
51 |
426 |
oldpwd_s = global("OLDPWD"); |
|
52 |
|||
53 |
✗✓ | 426 |
if (!wp[0]) { |
54 |
/* No arguments - go home */ |
||
55 |
if ((dir = str_val(global("HOME"))) == null) { |
||
56 |
bi_errorf("no home directory (HOME not set)"); |
||
57 |
return 1; |
||
58 |
} |
||
59 |
✓✗ | 426 |
} else if (!wp[1]) { |
60 |
/* One argument: - or dir */ |
||
61 |
426 |
dir = wp[0]; |
|
62 |
✗✓ | 426 |
if (strcmp(dir, "-") == 0) { |
63 |
dir = str_val(oldpwd_s); |
||
64 |
if (dir == null) { |
||
65 |
bi_errorf("no OLDPWD"); |
||
66 |
return 1; |
||
67 |
} |
||
68 |
printpath++; |
||
69 |
} |
||
70 |
} else if (!wp[2]) { |
||
71 |
/* Two arguments - substitute arg1 in PWD for arg2 */ |
||
72 |
int ilen, olen, nlen, elen; |
||
73 |
char *cp; |
||
74 |
|||
75 |
if (!current_wd[0]) { |
||
76 |
bi_errorf("don't know current directory"); |
||
77 |
return 1; |
||
78 |
} |
||
79 |
/* substitute arg1 for arg2 in current path. |
||
80 |
* if the first substitution fails because the cd fails |
||
81 |
* we could try to find another substitution. For now |
||
82 |
* we don't |
||
83 |
*/ |
||
84 |
if ((cp = strstr(current_wd, wp[0])) == NULL) { |
||
85 |
bi_errorf("bad substitution"); |
||
86 |
return 1; |
||
87 |
} |
||
88 |
ilen = cp - current_wd; |
||
89 |
olen = strlen(wp[0]); |
||
90 |
nlen = strlen(wp[1]); |
||
91 |
elen = strlen(current_wd + ilen + olen) + 1; |
||
92 |
fdir = dir = alloc(ilen + nlen + elen, ATEMP); |
||
93 |
memcpy(dir, current_wd, ilen); |
||
94 |
memcpy(dir + ilen, wp[1], nlen); |
||
95 |
memcpy(dir + ilen + nlen, current_wd + ilen + olen, elen); |
||
96 |
printpath++; |
||
97 |
} else { |
||
98 |
bi_errorf("too many arguments"); |
||
99 |
return 1; |
||
100 |
} |
||
101 |
|||
102 |
426 |
Xinit(xs, xp, PATH, ATEMP); |
|
103 |
/* xp will have a bogus value after make_path() - set it to 0 |
||
104 |
* so that if it's used, it will cause a dump |
||
105 |
*/ |
||
106 |
426 |
xp = NULL; |
|
107 |
|||
108 |
426 |
cdpath = str_val(global("CDPATH")); |
|
109 |
do { |
||
110 |
426 |
cdnode = make_path(current_wd, dir, &cdpath, &xs, &phys_path); |
|
111 |
✗✓ | 426 |
if (physical) |
112 |
rval = chdir(try = Xstring(xs, xp) + phys_path); |
||
113 |
else { |
||
114 |
426 |
simplify_path(Xstring(xs, xp)); |
|
115 |
426 |
rval = chdir(try = Xstring(xs, xp)); |
|
116 |
} |
||
117 |
✗✓✗✗ |
426 |
} while (rval < 0 && cdpath != NULL); |
118 |
|||
119 |
✗✓ | 426 |
if (rval < 0) { |
120 |
if (cdnode) |
||
121 |
bi_errorf("%s: bad directory", dir); |
||
122 |
else |
||
123 |
bi_errorf("%s - %s", try, strerror(errno)); |
||
124 |
afree(fdir, ATEMP); |
||
125 |
return 1; |
||
126 |
} |
||
127 |
|||
128 |
/* Clear out tracked aliases with relative paths */ |
||
129 |
426 |
flushcom(0); |
|
130 |
|||
131 |
/* Set OLDPWD (note: unsetting OLDPWD does not disable this |
||
132 |
* setting in at&t ksh) |
||
133 |
*/ |
||
134 |
✓✗ | 426 |
if (current_wd[0]) |
135 |
/* Ignore failure (happens if readonly or integer) */ |
||
136 |
426 |
setstr(oldpwd_s, current_wd, KSH_RETURN_ERROR); |
|
137 |
|||
138 |
✗✓ | 426 |
if (Xstring(xs, xp)[0] != '/') { |
139 |
pwd = NULL; |
||
140 |
} else |
||
141 |
✗✓✗✗ |
426 |
if (!physical || !(pwd = get_phys_path(Xstring(xs, xp)))) |
142 |
426 |
pwd = Xstring(xs, xp); |
|
143 |
|||
144 |
/* Set PWD */ |
||
145 |
✓✗ | 426 |
if (pwd) { |
146 |
426 |
char *ptmp = pwd; |
|
147 |
426 |
set_current_wd(ptmp); |
|
148 |
/* Ignore failure (happens if readonly or integer) */ |
||
149 |
426 |
setstr(pwd_s, ptmp, KSH_RETURN_ERROR); |
|
150 |
} else { |
||
151 |
set_current_wd(null); |
||
152 |
pwd = Xstring(xs, xp); |
||
153 |
/* XXX unset $PWD? */ |
||
154 |
} |
||
155 |
✗✓ | 426 |
if (printpath || cdnode) |
156 |
shprintf("%s\n", pwd); |
||
157 |
|||
158 |
426 |
afree(fdir, ATEMP); |
|
159 |
|||
160 |
426 |
return 0; |
|
161 |
} |
||
162 |
|||
163 |
int |
||
164 |
c_pwd(char **wp) |
||
165 |
46 |
{ |
|
166 |
int optc; |
||
167 |
46 |
int physical = Flag(FPHYSICAL); |
|
168 |
46 |
char *p, *freep = NULL; |
|
169 |
|||
170 |
✗✓ | 92 |
while ((optc = ksh_getopt(wp, &builtin_opt, "LP")) != -1) |
171 |
switch (optc) { |
||
172 |
case 'L': |
||
173 |
physical = 0; |
||
174 |
break; |
||
175 |
case 'P': |
||
176 |
physical = 1; |
||
177 |
break; |
||
178 |
case '?': |
||
179 |
return 1; |
||
180 |
} |
||
181 |
46 |
wp += builtin_opt.optind; |
|
182 |
|||
183 |
✗✓ | 46 |
if (wp[0]) { |
184 |
bi_errorf("too many arguments"); |
||
185 |
return 1; |
||
186 |
} |
||
187 |
✓✗✗✓ |
46 |
p = current_wd[0] ? (physical ? get_phys_path(current_wd) : current_wd) : |
188 |
NULL; |
||
189 |
✓✗✗✓ |
46 |
if (p && access(p, R_OK) < 0) |
190 |
p = NULL; |
||
191 |
✗✓ | 46 |
if (!p) { |
192 |
freep = p = ksh_get_wd(NULL, 0); |
||
193 |
if (!p) { |
||
194 |
bi_errorf("can't get current directory - %s", |
||
195 |
strerror(errno)); |
||
196 |
return 1; |
||
197 |
} |
||
198 |
} |
||
199 |
46 |
shprintf("%s\n", p); |
|
200 |
46 |
afree(freep, ATEMP); |
|
201 |
46 |
return 0; |
|
202 |
} |
||
203 |
|||
204 |
int |
||
205 |
c_print(char **wp) |
||
206 |
113638 |
{ |
|
207 |
#define PO_NL BIT(0) /* print newline */ |
||
208 |
#define PO_EXPAND BIT(1) /* expand backslash sequences */ |
||
209 |
#define PO_PMINUSMINUS BIT(2) /* print a -- argument */ |
||
210 |
#define PO_HIST BIT(3) /* print to history instead of stdout */ |
||
211 |
#define PO_COPROC BIT(4) /* printing to coprocess: block SIGPIPE */ |
||
212 |
113638 |
int fd = 1; |
|
213 |
113638 |
int flags = PO_EXPAND|PO_NL; |
|
214 |
char *s; |
||
215 |
const char *emsg; |
||
216 |
XString xs; |
||
217 |
char *xp; |
||
218 |
|||
219 |
✓✓ | 113638 |
if (wp[0][0] == 'e') { /* echo command */ |
220 |
112007 |
int nflags = flags; |
|
221 |
|||
222 |
/* A compromise between sysV and BSD echo commands: |
||
223 |
* escape sequences are enabled by default, and |
||
224 |
* -n, -e and -E are recognized if they appear |
||
225 |
* in arguments with no illegal options (ie, echo -nq |
||
226 |
* will print -nq). |
||
227 |
* Different from sysV echo since options are recognized, |
||
228 |
* different from BSD echo since escape sequences are enabled |
||
229 |
* by default. |
||
230 |
*/ |
||
231 |
112007 |
wp += 1; |
|
232 |
✓✓ | 112007 |
if (Flag(FPOSIX)) { |
233 |
✓✓✓✓ |
1466 |
if (*wp && strcmp(*wp, "-n") == 0) { |
234 |
156 |
flags &= ~PO_NL; |
|
235 |
156 |
wp++; |
|
236 |
} |
||
237 |
} else { |
||
238 |
✓✓✓✓ ✓✗ |
111186 |
while ((s = *wp) && *s == '-' && s[1]) { |
239 |
✓✓ | 1320 |
while (*++s) |
240 |
✓✓ | 675 |
if (*s == 'n') |
241 |
645 |
nflags &= ~PO_NL; |
|
242 |
✗✓ | 30 |
else if (*s == 'e') |
243 |
nflags |= PO_EXPAND; |
||
244 |
✓✗ | 30 |
else if (*s == 'E') |
245 |
nflags &= ~PO_EXPAND; |
||
246 |
else |
||
247 |
/* bad option: don't use |
||
248 |
* nflags, print argument |
||
249 |
*/ |
||
250 |
30 |
break; |
|
251 |
✓✓ | 675 |
if (*s) |
252 |
30 |
break; |
|
253 |
645 |
wp++; |
|
254 |
645 |
flags = nflags; |
|
255 |
} |
||
256 |
} |
||
257 |
} else { |
||
258 |
int optc; |
||
259 |
1631 |
const char *options = "Rnprsu,"; |
|
260 |
✓✓ | 5133 |
while ((optc = ksh_getopt(wp, &builtin_opt, options)) != -1) |
261 |
✗✗✓✗ ✓✗✗✗ ✗ |
1871 |
switch (optc) { |
262 |
case 'R': /* fake BSD echo command */ |
||
263 |
flags |= PO_PMINUSMINUS; |
||
264 |
flags &= ~PO_EXPAND; |
||
265 |
options = "ne"; |
||
266 |
break; |
||
267 |
case 'e': |
||
268 |
flags |= PO_EXPAND; |
||
269 |
break; |
||
270 |
case 'n': |
||
271 |
242 |
flags &= ~PO_NL; |
|
272 |
242 |
break; |
|
273 |
case 'p': |
||
274 |
if ((fd = coproc_getfd(W_OK, &emsg)) < 0) { |
||
275 |
bi_errorf("-p: %s", emsg); |
||
276 |
return 1; |
||
277 |
} |
||
278 |
break; |
||
279 |
case 'r': |
||
280 |
1629 |
flags &= ~PO_EXPAND; |
|
281 |
1629 |
break; |
|
282 |
case 's': |
||
283 |
flags |= PO_HIST; |
||
284 |
break; |
||
285 |
case 'u': |
||
286 |
if (!*(s = builtin_opt.optarg)) |
||
287 |
fd = 0; |
||
288 |
else if ((fd = check_fd(s, W_OK, &emsg)) < 0) { |
||
289 |
bi_errorf("-u: %s: %s", s, emsg); |
||
290 |
return 1; |
||
291 |
} |
||
292 |
break; |
||
293 |
case '?': |
||
294 |
return 1; |
||
295 |
} |
||
296 |
✓✓ | 1631 |
if (!(builtin_opt.info & GI_MINUSMINUS)) { |
297 |
/* treat a lone - like -- */ |
||
298 |
✓✗✗✓ |
2 |
if (wp[builtin_opt.optind] && |
299 |
strcmp(wp[builtin_opt.optind], "-") == 0) |
||
300 |
builtin_opt.optind++; |
||
301 |
✗✓ | 1629 |
} else if (flags & PO_PMINUSMINUS) |
302 |
builtin_opt.optind--; |
||
303 |
1631 |
wp += builtin_opt.optind; |
|
304 |
} |
||
305 |
|||
306 |
113638 |
Xinit(xs, xp, 128, ATEMP); |
|
307 |
|||
308 |
✓✓ | 341563 |
while (*wp != NULL) { |
309 |
int c; |
||
310 |
114281 |
s = *wp; |
|
311 |
✓✓ | 1456040 |
while ((c = *s++) != '\0') { |
312 |
✓✓ | 1227478 |
Xcheck(xs, xp); |
313 |
✓✓ | 1227478 |
if ((flags & PO_EXPAND) && c == '\\') { |
314 |
int i; |
||
315 |
|||
316 |
✓✓✗✗ ✓✓✓✗ ✓✗✓✗ |
1729 |
switch ((c = *s++)) { |
317 |
/* Oddly enough, \007 seems more portable than |
||
318 |
* \a (due to HP-UX cc, Ultrix cc, old pcc's, |
||
319 |
* etc.). |
||
320 |
*/ |
||
321 |
3 |
case 'a': c = '\007'; break; |
|
322 |
1069 |
case 'b': c = '\b'; break; |
|
323 |
case 'c': flags &= ~PO_NL; |
||
324 |
continue; /* AT&T brain damage */ |
||
325 |
case 'f': c = '\f'; break; |
||
326 |
199 |
case 'n': c = '\n'; break; |
|
327 |
220 |
case 'r': c = '\r'; break; |
|
328 |
2 |
case 't': c = '\t'; break; |
|
329 |
case 'v': c = 0x0B; break; |
||
330 |
case '0': |
||
331 |
/* Look for an octal number: can have |
||
332 |
* three digits (not counting the |
||
333 |
* leading 0). Truly burnt. |
||
334 |
*/ |
||
335 |
174 |
c = 0; |
|
336 |
✓✓ | 694 |
for (i = 0; i < 3; i++) { |
337 |
✓✓ | 522 |
if (*s >= '0' && *s <= '7') |
338 |
520 |
c = c*8 + *s++ - '0'; |
|
339 |
else |
||
340 |
2 |
break; |
|
341 |
} |
||
342 |
break; |
||
343 |
case '\0': s--; c = '\\'; break; |
||
344 |
case '\\': break; |
||
345 |
default: |
||
346 |
62 |
Xput(xs, xp, '\\'); |
|
347 |
} |
||
348 |
} |
||
349 |
1227478 |
Xput(xs, xp, c); |
|
350 |
} |
||
351 |
✓✓ | 114281 |
if (*++wp != NULL) |
352 |
760 |
Xput(xs, xp, ' '); |
|
353 |
} |
||
354 |
✓✓ | 113641 |
if (flags & PO_NL) |
355 |
112598 |
Xput(xs, xp, '\n'); |
|
356 |
|||
357 |
✗✓ | 113641 |
if (flags & PO_HIST) { |
358 |
Xput(xs, xp, '\0'); |
||
359 |
source->line++; |
||
360 |
histsave(source->line, Xstring(xs, xp), 1); |
||
361 |
Xfree(xs, xp); |
||
362 |
} else { |
||
363 |
113641 |
int n, len = Xlength(xs, xp); |
|
364 |
113641 |
int opipe = 0; |
|
365 |
|||
366 |
/* Ensure we aren't killed by a SIGPIPE while writing to |
||
367 |
* a coprocess. at&t ksh doesn't seem to do this (seems |
||
368 |
* to just check that the co-process is alive, which is |
||
369 |
* not enough). |
||
370 |
*/ |
||
371 |
✗✓✗✗ |
113641 |
if (coproc.write >= 0 && coproc.write == fd) { |
372 |
flags |= PO_COPROC; |
||
373 |
opipe = block_pipe(); |
||
374 |
} |
||
375 |
✓✓ | 340920 |
for (s = Xstring(xs, xp); len > 0; ) { |
376 |
113638 |
n = write(fd, s, len); |
|
377 |
✗✓ | 113638 |
if (n < 0) { |
378 |
if (flags & PO_COPROC) |
||
379 |
restore_pipe(opipe); |
||
380 |
if (errno == EINTR) { |
||
381 |
/* allow user to ^C out */ |
||
382 |
intrcheck(); |
||
383 |
if (flags & PO_COPROC) |
||
384 |
opipe = block_pipe(); |
||
385 |
continue; |
||
386 |
} |
||
387 |
/* This doesn't really make sense - could |
||
388 |
* break scripts (print -p generates |
||
389 |
* error message). |
||
390 |
*if (errno == EPIPE) |
||
391 |
* coproc_write_close(fd); |
||
392 |
*/ |
||
393 |
return 1; |
||
394 |
} |
||
395 |
113638 |
s += n; |
|
396 |
113638 |
len -= n; |
|
397 |
} |
||
398 |
✗✓ | 113641 |
if (flags & PO_COPROC) |
399 |
restore_pipe(opipe); |
||
400 |
} |
||
401 |
|||
402 |
113641 |
return 0; |
|
403 |
} |
||
404 |
|||
405 |
int |
||
406 |
c_whence(char **wp) |
||
407 |
103 |
{ |
|
408 |
struct tbl *tp; |
||
409 |
char *id; |
||
410 |
103 |
int pflag = 0, vflag = 0, Vflag = 0; |
|
411 |
103 |
int ret = 0; |
|
412 |
int optc; |
||
413 |
103 |
int iam_whence = wp[0][0] == 'w'; |
|
414 |
int fcflags; |
||
415 |
✓✓ | 103 |
const char *options = iam_whence ? "pv" : "pvV"; |
416 |
|||
417 |
✓✓ | 327 |
while ((optc = ksh_getopt(wp, &builtin_opt, options)) != -1) |
418 |
✓✓✓✗ ✗ |
121 |
switch (optc) { |
419 |
case 'p': |
||
420 |
48 |
pflag = 1; |
|
421 |
48 |
break; |
|
422 |
case 'v': |
||
423 |
49 |
vflag = 1; |
|
424 |
49 |
break; |
|
425 |
case 'V': |
||
426 |
24 |
Vflag = 1; |
|
427 |
24 |
break; |
|
428 |
case '?': |
||
429 |
return 1; |
||
430 |
} |
||
431 |
103 |
wp += builtin_opt.optind; |
|
432 |
|||
433 |
|||
434 |
103 |
fcflags = FC_BI | FC_PATH | FC_FUNC; |
|
435 |
✓✓ | 103 |
if (!iam_whence) { |
436 |
/* Note that -p on its own is dealt with in comexec() */ |
||
437 |
✓✓ | 48 |
if (pflag) |
438 |
24 |
fcflags |= FC_DEFPATH; |
|
439 |
/* Convert command options to whence options. Note that |
||
440 |
* command -pV and command -pv use a different path search |
||
441 |
* than whence -v or whence -pv. This should be considered |
||
442 |
* a feature. |
||
443 |
*/ |
||
444 |
48 |
vflag = Vflag; |
|
445 |
✓✓ | 55 |
} else if (pflag) |
446 |
24 |
fcflags &= ~(FC_BI | FC_FUNC); |
|
447 |
|||
448 |
✓✓✓✓ |
206 |
while ((vflag || ret == 0) && (id = *wp++) != NULL) { |
449 |
103 |
tp = NULL; |
|
450 |
✓✓ | 103 |
if (!iam_whence || !pflag) |
451 |
79 |
tp = ktsearch(&keywords, id, hash(id)); |
|
452 |
✓✓✓✓ |
103 |
if (!tp && (!iam_whence || !pflag)) { |
453 |
67 |
tp = ktsearch(&aliases, id, hash(id)); |
|
454 |
✓✓✗✓ |
67 |
if (tp && !(tp->flag & ISSET)) |
455 |
tp = NULL; |
||
456 |
} |
||
457 |
✓✓ | 103 |
if (!tp) |
458 |
79 |
tp = findcom(id, fcflags); |
|
459 |
✓✓✓✓ |
103 |
if (vflag || (tp->type != CALIAS && tp->type != CEXEC && |
460 |
tp->type != CTALIAS)) |
||
461 |
73 |
shprintf("%s", id); |
|
462 |
✓✓✓✓ ✓✗ |
103 |
switch (tp->type) { |
463 |
case CKEYWD: |
||
464 |
✓✓ | 12 |
if (vflag) |
465 |
6 |
shprintf(" is a reserved word"); |
|
466 |
break; |
||
467 |
case CALIAS: |
||
468 |
✓✓ | 12 |
if (vflag) |
469 |
✗✓ | 6 |
shprintf(" is an %salias for ", |
470 |
(tp->flag & EXPORT) ? "exported " : ""); |
||
471 |
✓✓ | 12 |
if (!iam_whence && !vflag) |
472 |
4 |
shprintf("alias %s=", id); |
|
473 |
12 |
print_value_quoted(tp->val.s); |
|
474 |
12 |
break; |
|
475 |
case CFUNC: |
||
476 |
✓✓ | 12 |
if (vflag) { |
477 |
6 |
shprintf(" is a"); |
|
478 |
✗✓ | 6 |
if (tp->flag & EXPORT) |
479 |
shprintf("n exported"); |
||
480 |
✗✓ | 6 |
if (tp->flag & TRACE) |
481 |
shprintf(" traced"); |
||
482 |
✗✓ | 6 |
if (!(tp->flag & ISSET)) { |
483 |
shprintf(" undefined"); |
||
484 |
if (tp->u.fpath) |
||
485 |
shprintf(" (autoload from %s)", |
||
486 |
tp->u.fpath); |
||
487 |
} |
||
488 |
6 |
shprintf(" function"); |
|
489 |
} |
||
490 |
break; |
||
491 |
case CSHELL: |
||
492 |
✓✓ | 24 |
if (vflag) |
493 |
✓✓ | 12 |
shprintf(" is a%s shell builtin", |
494 |
(tp->flag & SPEC_BI) ? " special" : ""); |
||
495 |
break; |
||
496 |
case CTALIAS: |
||
497 |
case CEXEC: |
||
498 |
✓✓ | 43 |
if (tp->flag & ISSET) { |
499 |
✓✓ | 21 |
if (vflag) { |
500 |
11 |
shprintf(" is "); |
|
501 |
✓✓ | 11 |
if (tp->type == CTALIAS) |
502 |
✗✓ | 9 |
shprintf("a tracked %salias for ", |
503 |
(tp->flag & EXPORT) ? |
||
504 |
"exported " : ""); |
||
505 |
} |
||
506 |
21 |
shprintf("%s", tp->val.s); |
|
507 |
} else { |
||
508 |
✓✓ | 22 |
if (vflag) |
509 |
8 |
shprintf(" not found"); |
|
510 |
22 |
ret = 1; |
|
511 |
} |
||
512 |
break; |
||
513 |
default: |
||
514 |
shprintf("%s is *GOK*", id); |
||
515 |
break; |
||
516 |
} |
||
517 |
✓✓ | 103 |
if (vflag || !ret) |
518 |
89 |
shprintf("\n"); |
|
519 |
} |
||
520 |
103 |
return ret; |
|
521 |
} |
||
522 |
|||
523 |
/* Deal with command -vV - command -p dealt with in comexec() */ |
||
524 |
int |
||
525 |
c_command(char **wp) |
||
526 |
48 |
{ |
|
527 |
/* Let c_whence do the work. Note that c_command() must be |
||
528 |
* a distinct function from c_whence() (tested in comexec()). |
||
529 |
*/ |
||
530 |
48 |
return c_whence(wp); |
|
531 |
} |
||
532 |
|||
533 |
/* typeset, export, and readonly */ |
||
534 |
int |
||
535 |
c_typeset(char **wp) |
||
536 |
17905 |
{ |
|
537 |
struct block *l; |
||
538 |
struct tbl *vp, **p; |
||
539 |
17905 |
int fset = 0, fclr = 0, thing = 0, func = 0, local = 0, pflag = 0; |
|
540 |
17905 |
const char *options = "L#R#UZ#fi#lprtux"; /* see comment below */ |
|
541 |
char *fieldstr, *basestr; |
||
542 |
int field, base, optc, flag; |
||
543 |
|||
544 |
✓✓✓✓ |
17905 |
switch (**wp) { |
545 |
case 'e': /* export */ |
||
546 |
157 |
fset |= EXPORT; |
|
547 |
157 |
options = "p"; |
|
548 |
157 |
break; |
|
549 |
case 'r': /* readonly */ |
||
550 |
2 |
fset |= RDONLY; |
|
551 |
2 |
options = "p"; |
|
552 |
2 |
break; |
|
553 |
case 's': /* set */ |
||
554 |
/* called with 'typeset -' */ |
||
555 |
break; |
||
556 |
case 't': /* typeset */ |
||
557 |
17728 |
local = 1; |
|
558 |
break; |
||
559 |
} |
||
560 |
|||
561 |
17905 |
fieldstr = basestr = NULL; |
|
562 |
17905 |
builtin_opt.flags |= GF_PLUSOPT; |
|
563 |
/* at&t ksh seems to have 0-9 as options, which are multiplied |
||
564 |
* to get a number that is used with -L, -R, -Z or -i (eg, -1R2 |
||
565 |
* sets right justify in a field of 12). This allows options |
||
566 |
* to be grouped in an order (eg, -Lu12), but disallows -i8 -L3 and |
||
567 |
* does not allow the number to be specified as a separate argument |
||
568 |
* Here, the number must follow the RLZi option, but is optional |
||
569 |
* (see the # kludge in ksh_getopt()). |
||
570 |
*/ |
||
571 |
✓✓ | 53493 |
while ((optc = ksh_getopt(wp, &builtin_opt, options)) != -1) { |
572 |
17683 |
flag = 0; |
|
573 |
✗✗✗✗ ✗✓✗✗ ✓✗✗✓ ✗✗ |
17683 |
switch (optc) { |
574 |
case 'L': |
||
575 |
flag = LJUST; |
||
576 |
fieldstr = builtin_opt.optarg; |
||
577 |
break; |
||
578 |
case 'R': |
||
579 |
flag = RJUST; |
||
580 |
fieldstr = builtin_opt.optarg; |
||
581 |
break; |
||
582 |
case 'U': |
||
583 |
/* at&t ksh uses u, but this conflicts with |
||
584 |
* upper/lower case. If this option is changed, |
||
585 |
* need to change the -U below as well |
||
586 |
*/ |
||
587 |
flag = INT_U; |
||
588 |
break; |
||
589 |
case 'Z': |
||
590 |
flag = ZEROFIL; |
||
591 |
fieldstr = builtin_opt.optarg; |
||
592 |
break; |
||
593 |
case 'f': |
||
594 |
func = 1; |
||
595 |
break; |
||
596 |
case 'i': |
||
597 |
10641 |
flag = INTEGER; |
|
598 |
10641 |
basestr = builtin_opt.optarg; |
|
599 |
10641 |
break; |
|
600 |
case 'l': |
||
601 |
flag = LCASEV; |
||
602 |
break; |
||
603 |
case 'p': |
||
604 |
/* posix export/readonly -p flag. |
||
605 |
* typeset -p is the same as typeset (in pdksh); |
||
606 |
* here for compatibility with ksh93. |
||
607 |
*/ |
||
608 |
pflag = 1; |
||
609 |
break; |
||
610 |
case 'r': |
||
611 |
3521 |
flag = RDONLY; |
|
612 |
3521 |
break; |
|
613 |
case 't': |
||
614 |
flag = TRACE; |
||
615 |
break; |
||
616 |
case 'u': |
||
617 |
flag = UCASEV_AL; /* upper case / autoload */ |
||
618 |
break; |
||
619 |
case 'x': |
||
620 |
3521 |
flag = EXPORT; |
|
621 |
3521 |
break; |
|
622 |
case '?': |
||
623 |
return 1; |
||
624 |
} |
||
625 |
✗✓ | 17683 |
if (builtin_opt.info & GI_PLUS) { |
626 |
fclr |= flag; |
||
627 |
fset &= ~flag; |
||
628 |
thing = '+'; |
||
629 |
} else { |
||
630 |
17683 |
fset |= flag; |
|
631 |
17683 |
fclr &= ~flag; |
|
632 |
17683 |
thing = '-'; |
|
633 |
} |
||
634 |
} |
||
635 |
|||
636 |
17905 |
field = 0; |
|
637 |
✗✓✗✗ |
17905 |
if (fieldstr && !bi_getn(fieldstr, &field)) |
638 |
return 1; |
||
639 |
17905 |
base = 0; |
|
640 |
✓✓✗✓ |
17905 |
if (basestr && !bi_getn(basestr, &base)) |
641 |
return 1; |
||
642 |
|||
643 |
✓✗✓✓ ✓✓✓✗ |
17905 |
if (!(builtin_opt.info & GI_MINUSMINUS) && wp[builtin_opt.optind] && |
644 |
(wp[builtin_opt.optind][0] == '-' || |
||
645 |
wp[builtin_opt.optind][0] == '+') && |
||
646 |
wp[builtin_opt.optind][1] == '\0') { |
||
647 |
18 |
thing = wp[builtin_opt.optind][0]; |
|
648 |
18 |
builtin_opt.optind++; |
|
649 |
} |
||
650 |
|||
651 |
✗✓✗✗ |
17905 |
if (func && ((fset|fclr) & ~(TRACE|UCASEV_AL|EXPORT))) { |
652 |
bi_errorf("only -t, -u and -x options may be used with -f"); |
||
653 |
return 1; |
||
654 |
} |
||
655 |
✓✓ | 17905 |
if (wp[builtin_opt.optind]) { |
656 |
/* Take care of exclusions. |
||
657 |
* At this point, flags in fset are cleared in fclr and vise |
||
658 |
* versa. This property should be preserved. |
||
659 |
*/ |
||
660 |
✗✓ | 17877 |
if (fset & LCASEV) /* LCASEV has priority over UCASEV_AL */ |
661 |
fset &= ~UCASEV_AL; |
||
662 |
✗✓ | 17877 |
if (fset & LJUST) /* LJUST has priority over RJUST */ |
663 |
fset &= ~RJUST; |
||
664 |
✗✓ | 17877 |
if ((fset & (ZEROFIL|LJUST)) == ZEROFIL) { /* -Z implies -ZR */ |
665 |
fset |= RJUST; |
||
666 |
fclr &= ~RJUST; |
||
667 |
} |
||
668 |
/* Setting these attributes clears the others, unless they |
||
669 |
* are also set in this command |
||
670 |
*/ |
||
671 |
✓✓ | 17877 |
if (fset & (LJUST | RJUST | ZEROFIL | UCASEV_AL | LCASEV | |
672 |
INTEGER | INT_U | INT_L)) |
||
673 |
10635 |
fclr |= ~fset & (LJUST | RJUST | ZEROFIL | UCASEV_AL | |
|
674 |
LCASEV | INTEGER | INT_U | INT_L); |
||
675 |
} |
||
676 |
|||
677 |
/* set variables and attributes */ |
||
678 |
✓✓ | 17905 |
if (wp[builtin_opt.optind]) { |
679 |
int i; |
||
680 |
17877 |
int rval = 0; |
|
681 |
struct tbl *f; |
||
682 |
|||
683 |
✓✓ | 17877 |
if (local && !func) |
684 |
17718 |
fset |= LOCAL; |
|
685 |
✓✓ | 53445 |
for (i = builtin_opt.optind; wp[i]; i++) { |
686 |
✗✓ | 35572 |
if (func) { |
687 |
f = findfunc(wp[i], hash(wp[i]), |
||
688 |
(fset&UCASEV_AL) ? true : false); |
||
689 |
if (!f) { |
||
690 |
/* at&t ksh does ++rval: bogus */ |
||
691 |
rval = 1; |
||
692 |
continue; |
||
693 |
} |
||
694 |
if (fset | fclr) { |
||
695 |
f->flag |= fset; |
||
696 |
f->flag &= ~fclr; |
||
697 |
} else |
||
698 |
fptreef(shl_stdout, 0, |
||
699 |
f->flag & FKSH ? |
||
700 |
"function %s %T\n" : |
||
701 |
"%s() %T\n", wp[i], f->val.t); |
||
702 |
✗✓ | 35572 |
} else if (!typeset(wp[i], fset, fclr, field, base)) { |
703 |
bi_errorf("%s: not identifier", wp[i]); |
||
704 |
return 1; |
||
705 |
} |
||
706 |
} |
||
707 |
17873 |
return rval; |
|
708 |
} |
||
709 |
|||
710 |
/* list variables and attributes */ |
||
711 |
28 |
flag = fset | fclr; /* no difference at this point.. */ |
|
712 |
✗✓ | 28 |
if (func) { |
713 |
for (l = genv->loc; l; l = l->next) { |
||
714 |
for (p = ktsort(&l->funs); (vp = *p++); ) { |
||
715 |
if (flag && (vp->flag & flag) == 0) |
||
716 |
continue; |
||
717 |
if (thing == '-') |
||
718 |
fptreef(shl_stdout, 0, vp->flag & FKSH ? |
||
719 |
"function %s %T\n" : "%s() %T\n", |
||
720 |
vp->name, vp->val.t); |
||
721 |
else |
||
722 |
shprintf("%s\n", vp->name); |
||
723 |
} |
||
724 |
} |
||
725 |
} else { |
||
726 |
✓✓ | 56 |
for (l = genv->loc; l; l = l->next) { |
727 |
✓✓ | 7178 |
for (p = ktsort(&l->vars); (vp = *p++); ) { |
728 |
struct tbl *tvp; |
||
729 |
7122 |
int any_set = 0; |
|
730 |
/* |
||
731 |
* See if the parameter is set (for arrays, if any |
||
732 |
* element is set). |
||
733 |
*/ |
||
734 |
✓✓ | 7679 |
for (tvp = vp; tvp; tvp = tvp->u.array) |
735 |
✓✓ | 7130 |
if (tvp->flag & ISSET) { |
736 |
6573 |
any_set = 1; |
|
737 |
6573 |
break; |
|
738 |
} |
||
739 |
|||
740 |
/* |
||
741 |
* Check attributes - note that all array elements |
||
742 |
* have (should have?) the same attributes, so checking |
||
743 |
* the first is sufficient. |
||
744 |
* |
||
745 |
* Report an unset param only if the user has |
||
746 |
* explicitly given it some attribute (like export); |
||
747 |
* otherwise, after "echo $FOO", we would report FOO... |
||
748 |
*/ |
||
749 |
✓✓✓✓ |
7122 |
if (!any_set && !(vp->flag & USERATTRIB)) |
750 |
505 |
continue; |
|
751 |
✓✓✓✓ |
6617 |
if (flag && (vp->flag & flag) == 0) |
752 |
74 |
continue; |
|
753 |
✓✓ | 6503 |
for (; vp; vp = vp->u.array) { |
754 |
/* Ignore array elements that aren't |
||
755 |
* set unless there are no set elements, |
||
756 |
* in which case the first is reported on */ |
||
757 |
✓✓✓✓ |
6549 |
if ((vp->flag&ARRAY) && any_set && |
758 |
!(vp->flag & ISSET)) |
||
759 |
6 |
continue; |
|
760 |
/* no arguments */ |
||
761 |
✓✓ | 6543 |
if (thing == 0 && flag == 0) { |
762 |
/* at&t ksh prints things |
||
763 |
* like export, integer, |
||
764 |
* leftadj, zerofill, etc., |
||
765 |
* but POSIX says must |
||
766 |
* be suitable for re-entry... |
||
767 |
*/ |
||
768 |
76 |
shprintf("typeset "); |
|
769 |
✓✓ | 76 |
if ((vp->flag&INTEGER)) |
770 |
28 |
shprintf("-i "); |
|
771 |
✓✓ | 76 |
if ((vp->flag&EXPORT)) |
772 |
20 |
shprintf("-x "); |
|
773 |
✓✓ | 76 |
if ((vp->flag&RDONLY)) |
774 |
4 |
shprintf("-r "); |
|
775 |
✗✓ | 76 |
if ((vp->flag&TRACE)) |
776 |
shprintf("-t "); |
||
777 |
✗✓ | 76 |
if ((vp->flag&LJUST)) |
778 |
shprintf("-L%d ", vp->u2.field); |
||
779 |
✗✓ | 76 |
if ((vp->flag&RJUST)) |
780 |
shprintf("-R%d ", vp->u2.field); |
||
781 |
✗✓ | 76 |
if ((vp->flag&ZEROFIL)) |
782 |
shprintf("-Z "); |
||
783 |
✗✓ | 76 |
if ((vp->flag&LCASEV)) |
784 |
shprintf("-l "); |
||
785 |
✗✓ | 76 |
if ((vp->flag&UCASEV_AL)) |
786 |
shprintf("-u "); |
||
787 |
✗✓ | 76 |
if ((vp->flag&INT_U)) |
788 |
shprintf("-U "); |
||
789 |
76 |
shprintf("%s\n", vp->name); |
|
790 |
✓✓ | 76 |
if (vp->flag&ARRAY) |
791 |
4 |
break; |
|
792 |
} else { |
||
793 |
✗✓ | 6467 |
if (pflag) |
794 |
shprintf("%s ", |
||
795 |
(flag & EXPORT) ? |
||
796 |
"export" : "readonly"); |
||
797 |
✓✓ | 6467 |
if ((vp->flag&ARRAY) && any_set) |
798 |
2 |
shprintf("%s[%d]", |
|
799 |
vp->name, vp->index); |
||
800 |
else |
||
801 |
6465 |
shprintf("%s", vp->name); |
|
802 |
✓✗✓✓ |
6467 |
if (thing == '-' && (vp->flag&ISSET)) { |
803 |
6429 |
char *s = str_val(vp); |
|
804 |
|||
805 |
6429 |
shprintf("="); |
|
806 |
/* at&t ksh can't have |
||
807 |
* justified integers.. */ |
||
808 |
✓✓ | 6429 |
if ((vp->flag & |
809 |
(INTEGER|LJUST|RJUST)) == |
||
810 |
INTEGER) |
||
811 |
122 |
shprintf("%s", s); |
|
812 |
else |
||
813 |
6307 |
print_value_quoted(s); |
|
814 |
} |
||
815 |
6467 |
shprintf("\n"); |
|
816 |
} |
||
817 |
/* Only report first `element' of an array with |
||
818 |
* no set elements. |
||
819 |
*/ |
||
820 |
✓✓ | 6539 |
if (!any_set) |
821 |
42 |
break; |
|
822 |
} |
||
823 |
} |
||
824 |
} |
||
825 |
} |
||
826 |
28 |
return 0; |
|
827 |
} |
||
828 |
|||
829 |
int |
||
830 |
c_alias(char **wp) |
||
831 |
7098 |
{ |
|
832 |
7098 |
struct table *t = &aliases; |
|
833 |
7098 |
int rv = 0, rflag = 0, tflag, Uflag = 0, pflag = 0, prefix = 0; |
|
834 |
7098 |
int xflag = 0; |
|
835 |
int optc; |
||
836 |
|||
837 |
7098 |
builtin_opt.flags |= GF_PLUSOPT; |
|
838 |
✓✓ | 21238 |
while ((optc = ksh_getopt(wp, &builtin_opt, "dprtUx")) != -1) { |
839 |
✗✓ | 7042 |
prefix = builtin_opt.info & GI_PLUS ? '+' : '-'; |
840 |
✗✗✗✓ ✓✗✗✗ |
7042 |
switch (optc) { |
841 |
case 'd': |
||
842 |
t = &homedirs; |
||
843 |
break; |
||
844 |
case 'p': |
||
845 |
pflag = 1; |
||
846 |
break; |
||
847 |
case 'r': |
||
848 |
rflag = 1; |
||
849 |
break; |
||
850 |
case 't': |
||
851 |
3521 |
t = &taliases; |
|
852 |
3521 |
break; |
|
853 |
case 'U': |
||
854 |
/* |
||
855 |
* kludge for tracked alias initialization |
||
856 |
* (don't do a path search, just make an entry) |
||
857 |
*/ |
||
858 |
3521 |
Uflag = 1; |
|
859 |
3521 |
break; |
|
860 |
case 'x': |
||
861 |
xflag = EXPORT; |
||
862 |
break; |
||
863 |
case '?': |
||
864 |
return 1; |
||
865 |
} |
||
866 |
} |
||
867 |
7098 |
wp += builtin_opt.optind; |
|
868 |
|||
869 |
✓✗✓✗ ✗✓✗✗ |
7098 |
if (!(builtin_opt.info & GI_MINUSMINUS) && *wp && |
870 |
(wp[0][0] == '-' || wp[0][0] == '+') && wp[0][1] == '\0') { |
||
871 |
prefix = wp[0][0]; |
||
872 |
wp++; |
||
873 |
} |
||
874 |
|||
875 |
7098 |
tflag = t == &taliases; |
|
876 |
|||
877 |
/* "hash -r" means reset all the tracked aliases.. */ |
||
878 |
✗✓ | 7098 |
if (rflag) { |
879 |
static const char *const args[] = { |
||
880 |
"unalias", "-ta", NULL |
||
881 |
}; |
||
882 |
|||
883 |
if (!tflag || *wp) { |
||
884 |
shprintf("alias: -r flag can only be used with -t" |
||
885 |
" and without arguments\n"); |
||
886 |
return 1; |
||
887 |
} |
||
888 |
ksh_getopt_reset(&builtin_opt, GF_ERROR); |
||
889 |
return c_unalias((char **) args); |
||
890 |
} |
||
891 |
|||
892 |
✗✓ | 7098 |
if (*wp == NULL) { |
893 |
struct tbl *ap, **p; |
||
894 |
|||
895 |
for (p = ktsort(t); (ap = *p++) != NULL; ) |
||
896 |
if ((ap->flag & (ISSET|xflag)) == (ISSET|xflag)) { |
||
897 |
if (pflag) |
||
898 |
shf_puts("alias ", shl_stdout); |
||
899 |
shf_puts(ap->name, shl_stdout); |
||
900 |
if (prefix != '+') { |
||
901 |
shf_putc('=', shl_stdout); |
||
902 |
print_value_quoted(ap->val.s); |
||
903 |
} |
||
904 |
shprintf("\n"); |
||
905 |
} |
||
906 |
} |
||
907 |
|||
908 |
✓✓ | 102167 |
for (; *wp != NULL; wp++) { |
909 |
102167 |
char *alias = *wp; |
|
910 |
102167 |
char *val = strchr(alias, '='); |
|
911 |
char *newval; |
||
912 |
struct tbl *ap; |
||
913 |
int h; |
||
914 |
|||
915 |
✓✓ | 102167 |
if (val) |
916 |
38789 |
alias = str_nsave(alias, val++ - alias, ATEMP); |
|
917 |
102167 |
h = hash(alias); |
|
918 |
✗✓✗✗ |
102167 |
if (val == NULL && !tflag && !xflag) { |
919 |
ap = ktsearch(t, alias, h); |
||
920 |
if (ap != NULL && (ap->flag&ISSET)) { |
||
921 |
if (pflag) |
||
922 |
shf_puts("alias ", shl_stdout); |
||
923 |
shf_puts(ap->name, shl_stdout); |
||
924 |
if (prefix != '+') { |
||
925 |
shf_putc('=', shl_stdout); |
||
926 |
print_value_quoted(ap->val.s); |
||
927 |
} |
||
928 |
shprintf("\n"); |
||
929 |
} else { |
||
930 |
shprintf("%s alias not found\n", alias); |
||
931 |
rv = 1; |
||
932 |
} |
||
933 |
continue; |
||
934 |
} |
||
935 |
102167 |
ap = ktenter(t, alias, h); |
|
936 |
✓✓ | 102167 |
ap->type = tflag ? CTALIAS : CALIAS; |
937 |
/* Are we setting the value or just some flags? */ |
||
938 |
✓✓✓✗ ✗✓ |
102167 |
if ((val && !tflag) || (!val && tflag && !Uflag)) { |
939 |
✗✓ | 38789 |
if (ap->flag&ALLOC) { |
940 |
ap->flag &= ~(ALLOC|ISSET); |
||
941 |
afree(ap->val.s, APERM); |
||
942 |
} |
||
943 |
/* ignore values for -t (at&t ksh does this) */ |
||
944 |
✗✓ | 38789 |
newval = tflag ? search(alias, path, X_OK, NULL) : |
945 |
val; |
||
946 |
✓✗ | 38789 |
if (newval) { |
947 |
38789 |
ap->val.s = str_save(newval, APERM); |
|
948 |
38789 |
ap->flag |= ALLOC|ISSET; |
|
949 |
} else |
||
950 |
ap->flag &= ~ISSET; |
||
951 |
} |
||
952 |
102167 |
ap->flag |= DEFINED; |
|
953 |
✗✓ | 102167 |
if (prefix == '+') |
954 |
ap->flag &= ~xflag; |
||
955 |
else |
||
956 |
102167 |
ap->flag |= xflag; |
|
957 |
✓✓ | 102167 |
if (val) |
958 |
38789 |
afree(alias, ATEMP); |
|
959 |
} |
||
960 |
|||
961 |
7098 |
return rv; |
|
962 |
} |
||
963 |
|||
964 |
int |
||
965 |
c_unalias(char **wp) |
||
966 |
2 |
{ |
|
967 |
2 |
struct table *t = &aliases; |
|
968 |
struct tbl *ap; |
||
969 |
2 |
int rv = 0, all = 0; |
|
970 |
int optc; |
||
971 |
|||
972 |
✗✓ | 4 |
while ((optc = ksh_getopt(wp, &builtin_opt, "adt")) != -1) |
973 |
switch (optc) { |
||
974 |
case 'a': |
||
975 |
all = 1; |
||
976 |
break; |
||
977 |
case 'd': |
||
978 |
t = &homedirs; |
||
979 |
break; |
||
980 |
case 't': |
||
981 |
t = &taliases; |
||
982 |
break; |
||
983 |
case '?': |
||
984 |
return 1; |
||
985 |
} |
||
986 |
2 |
wp += builtin_opt.optind; |
|
987 |
|||
988 |
✓✓ | 4 |
for (; *wp != NULL; wp++) { |
989 |
2 |
ap = ktsearch(t, *wp, hash(*wp)); |
|
990 |
✗✓ | 2 |
if (ap == NULL) { |
991 |
rv = 1; /* POSIX */ |
||
992 |
continue; |
||
993 |
} |
||
994 |
✓✗ | 2 |
if (ap->flag&ALLOC) { |
995 |
2 |
ap->flag &= ~(ALLOC|ISSET); |
|
996 |
2 |
afree(ap->val.s, APERM); |
|
997 |
} |
||
998 |
2 |
ap->flag &= ~(DEFINED|ISSET|EXPORT); |
|
999 |
} |
||
1000 |
|||
1001 |
✗✓ | 2 |
if (all) { |
1002 |
struct tstate ts; |
||
1003 |
|||
1004 |
for (ktwalk(&ts, t); (ap = ktnext(&ts)); ) { |
||
1005 |
if (ap->flag&ALLOC) { |
||
1006 |
ap->flag &= ~(ALLOC|ISSET); |
||
1007 |
afree(ap->val.s, APERM); |
||
1008 |
} |
||
1009 |
ap->flag &= ~(DEFINED|ISSET|EXPORT); |
||
1010 |
} |
||
1011 |
} |
||
1012 |
|||
1013 |
2 |
return rv; |
|
1014 |
} |
||
1015 |
|||
1016 |
int |
||
1017 |
c_let(char **wp) |
||
1018 |
8 |
{ |
|
1019 |
8 |
int rv = 1; |
|
1020 |
long val; |
||
1021 |
|||
1022 |
✗✓ | 8 |
if (wp[1] == NULL) /* at&t ksh does this */ |
1023 |
bi_errorf("no arguments"); |
||
1024 |
else |
||
1025 |
✓✓ | 16 |
for (wp++; *wp; wp++) |
1026 |
✗✓ | 8 |
if (!evaluate(*wp, &val, KSH_RETURN_ERROR, true)) { |
1027 |
rv = 2; /* distinguish error from zero result */ |
||
1028 |
break; |
||
1029 |
} else |
||
1030 |
8 |
rv = val == 0; |
|
1031 |
8 |
return rv; |
|
1032 |
} |
||
1033 |
|||
1034 |
int |
||
1035 |
c_jobs(char **wp) |
||
1036 |
{ |
||
1037 |
int optc; |
||
1038 |
int flag = 0; |
||
1039 |
int nflag = 0; |
||
1040 |
int rv = 0; |
||
1041 |
|||
1042 |
while ((optc = ksh_getopt(wp, &builtin_opt, "lpnz")) != -1) |
||
1043 |
switch (optc) { |
||
1044 |
case 'l': |
||
1045 |
flag = 1; |
||
1046 |
break; |
||
1047 |
case 'p': |
||
1048 |
flag = 2; |
||
1049 |
break; |
||
1050 |
case 'n': |
||
1051 |
nflag = 1; |
||
1052 |
break; |
||
1053 |
case 'z': /* debugging: print zombies */ |
||
1054 |
nflag = -1; |
||
1055 |
break; |
||
1056 |
case '?': |
||
1057 |
return 1; |
||
1058 |
} |
||
1059 |
wp += builtin_opt.optind; |
||
1060 |
if (!*wp) { |
||
1061 |
if (j_jobs(NULL, flag, nflag)) |
||
1062 |
rv = 1; |
||
1063 |
} else { |
||
1064 |
for (; *wp; wp++) |
||
1065 |
if (j_jobs(*wp, flag, nflag)) |
||
1066 |
rv = 1; |
||
1067 |
} |
||
1068 |
return rv; |
||
1069 |
} |
||
1070 |
|||
1071 |
#ifdef JOBS |
||
1072 |
int |
||
1073 |
c_fgbg(char **wp) |
||
1074 |
{ |
||
1075 |
int bg = strcmp(*wp, "bg") == 0; |
||
1076 |
int rv = 0; |
||
1077 |
|||
1078 |
if (!Flag(FMONITOR)) { |
||
1079 |
bi_errorf("job control not enabled"); |
||
1080 |
return 1; |
||
1081 |
} |
||
1082 |
if (ksh_getopt(wp, &builtin_opt, null) == '?') |
||
1083 |
return 1; |
||
1084 |
wp += builtin_opt.optind; |
||
1085 |
if (*wp) |
||
1086 |
for (; *wp; wp++) |
||
1087 |
rv = j_resume(*wp, bg); |
||
1088 |
else |
||
1089 |
rv = j_resume("%%", bg); |
||
1090 |
/* POSIX says fg shall return 0 (unless an error occurs). |
||
1091 |
* at&t ksh returns the exit value of the job... |
||
1092 |
*/ |
||
1093 |
return (bg || Flag(FPOSIX)) ? 0 : rv; |
||
1094 |
} |
||
1095 |
#endif |
||
1096 |
|||
1097 |
struct kill_info { |
||
1098 |
int num_width; |
||
1099 |
int name_width; |
||
1100 |
}; |
||
1101 |
static char *kill_fmt_entry(void *arg, int i, char *buf, int buflen); |
||
1102 |
|||
1103 |
/* format a single kill item */ |
||
1104 |
static char * |
||
1105 |
kill_fmt_entry(void *arg, int i, char *buf, int buflen) |
||
1106 |
{ |
||
1107 |
struct kill_info *ki = (struct kill_info *) arg; |
||
1108 |
|||
1109 |
i++; |
||
1110 |
if (sigtraps[i].name) |
||
1111 |
shf_snprintf(buf, buflen, "%*d %*s %s", |
||
1112 |
ki->num_width, i, |
||
1113 |
ki->name_width, sigtraps[i].name, |
||
1114 |
sigtraps[i].mess); |
||
1115 |
else |
||
1116 |
shf_snprintf(buf, buflen, "%*d %*d %s", |
||
1117 |
ki->num_width, i, |
||
1118 |
ki->name_width, sigtraps[i].signal, |
||
1119 |
sigtraps[i].mess); |
||
1120 |
return buf; |
||
1121 |
} |
||
1122 |
|||
1123 |
|||
1124 |
int |
||
1125 |
c_kill(char **wp) |
||
1126 |
95 |
{ |
|
1127 |
95 |
Trap *t = NULL; |
|
1128 |
char *p; |
||
1129 |
95 |
int lflag = 0; |
|
1130 |
int i, n, rv, sig; |
||
1131 |
|||
1132 |
/* assume old style options if -digits or -UPPERCASE */ |
||
1133 |
✓✗✗✓ ✗✗✗✗ |
95 |
if ((p = wp[1]) && *p == '-' && |
1134 |
(digit(p[1]) || isupper((unsigned char)p[1]))) { |
||
1135 |
if (!(t = gettrap(p + 1, true))) { |
||
1136 |
bi_errorf("bad signal `%s'", p + 1); |
||
1137 |
return 1; |
||
1138 |
} |
||
1139 |
i = (wp[2] && strcmp(wp[2], "--") == 0) ? 3 : 2; |
||
1140 |
} else { |
||
1141 |
int optc; |
||
1142 |
|||
1143 |
✗✓ | 95 |
while ((optc = ksh_getopt(wp, &builtin_opt, "ls:")) != -1) |
1144 |
switch (optc) { |
||
1145 |
case 'l': |
||
1146 |
lflag = 1; |
||
1147 |
break; |
||
1148 |
case 's': |
||
1149 |
if (!(t = gettrap(builtin_opt.optarg, true))) { |
||
1150 |
bi_errorf("bad signal `%s'", |
||
1151 |
builtin_opt.optarg); |
||
1152 |
return 1; |
||
1153 |
} |
||
1154 |
break; |
||
1155 |
case '?': |
||
1156 |
return 1; |
||
1157 |
} |
||
1158 |
95 |
i = builtin_opt.optind; |
|
1159 |
} |
||
1160 |
✓✗✗✓ |
95 |
if ((lflag && t) || (!wp[i] && !lflag)) { |
1161 |
shf_fprintf(shl_out, |
||
1162 |
"usage: kill [-s signame | -signum | -signame] { job | pid | pgrp } ...\n" |
||
1163 |
" kill -l [exit_status ...]\n"); |
||
1164 |
bi_errorf(NULL); |
||
1165 |
return 1; |
||
1166 |
} |
||
1167 |
|||
1168 |
✗✓ | 95 |
if (lflag) { |
1169 |
if (wp[i]) { |
||
1170 |
for (; wp[i]; i++) { |
||
1171 |
if (!bi_getn(wp[i], &n)) |
||
1172 |
return 1; |
||
1173 |
if (n > 128 && n < 128 + NSIG) |
||
1174 |
n -= 128; |
||
1175 |
if (n > 0 && n < NSIG && sigtraps[n].name) |
||
1176 |
shprintf("%s\n", sigtraps[n].name); |
||
1177 |
else |
||
1178 |
shprintf("%d\n", n); |
||
1179 |
} |
||
1180 |
} else if (Flag(FPOSIX)) { |
||
1181 |
p = null; |
||
1182 |
for (i = 1; i < NSIG; i++, p = " ") |
||
1183 |
if (sigtraps[i].name) |
||
1184 |
shprintf("%s%s", p, sigtraps[i].name); |
||
1185 |
shprintf("\n"); |
||
1186 |
} else { |
||
1187 |
int mess_width = 0, w, i; |
||
1188 |
struct kill_info ki = { |
||
1189 |
.num_width = 1, |
||
1190 |
.name_width = 0, |
||
1191 |
}; |
||
1192 |
|||
1193 |
for (i = NSIG; i >= 10; i /= 10) |
||
1194 |
ki.num_width++; |
||
1195 |
|||
1196 |
for (i = 0; i < NSIG; i++) { |
||
1197 |
w = sigtraps[i].name ? strlen(sigtraps[i].name) : |
||
1198 |
ki.num_width; |
||
1199 |
if (w > ki.name_width) |
||
1200 |
ki.name_width = w; |
||
1201 |
w = strlen(sigtraps[i].mess); |
||
1202 |
if (w > mess_width) |
||
1203 |
mess_width = w; |
||
1204 |
} |
||
1205 |
|||
1206 |
print_columns(shl_stdout, NSIG - 1, |
||
1207 |
kill_fmt_entry, (void *) &ki, |
||
1208 |
ki.num_width + ki.name_width + mess_width + 3, 1); |
||
1209 |
} |
||
1210 |
return 0; |
||
1211 |
} |
||
1212 |
95 |
rv = 0; |
|
1213 |
✗✓ | 95 |
sig = t ? t->signal : SIGTERM; |
1214 |
✓✓ | 190 |
for (; (p = wp[i]); i++) { |
1215 |
✗✓ | 95 |
if (*p == '%') { |
1216 |
if (j_kill(p, sig)) |
||
1217 |
rv = 1; |
||
1218 |
✗✓ | 95 |
} else if (!getn(p, &n)) { |
1219 |
bi_errorf("%s: arguments must be jobs or process IDs", |
||
1220 |
p); |
||
1221 |
rv = 1; |
||
1222 |
} else { |
||
1223 |
/* use killpg if < -1 since -1 does special things for |
||
1224 |
* some non-killpg-endowed kills |
||
1225 |
*/ |
||
1226 |
✗✓✗✓ |
95 |
if ((n < -1 ? killpg(-n, sig) : kill(n, sig)) < 0) { |
1227 |
bi_errorf("%s: %s", p, strerror(errno)); |
||
1228 |
rv = 1; |
||
1229 |
} |
||
1230 |
} |
||
1231 |
} |
||
1232 |
95 |
return rv; |
|
1233 |
} |
||
1234 |
|||
1235 |
void |
||
1236 |
getopts_reset(int val) |
||
1237 |
10575 |
{ |
|
1238 |
✓✗ | 10575 |
if (val >= 1) { |
1239 |
✗✓ | 10575 |
ksh_getopt_reset(&user_opt, |
1240 |
GF_NONAME | (Flag(FPOSIX) ? 0 : GF_PLUSOPT)); |
||
1241 |
10575 |
user_opt.optind = user_opt.uoptind = val; |
|
1242 |
} |
||
1243 |
10575 |
} |
|
1244 |
|||
1245 |
int |
||
1246 |
c_getopts(char **wp) |
||
1247 |
48 |
{ |
|
1248 |
int argc; |
||
1249 |
const char *options; |
||
1250 |
const char *var; |
||
1251 |
int optc; |
||
1252 |
int ret; |
||
1253 |
char buf[3]; |
||
1254 |
struct tbl *vq, *voptarg; |
||
1255 |
|||
1256 |
✗✓ | 48 |
if (ksh_getopt(wp, &builtin_opt, null) == '?') |
1257 |
return 1; |
||
1258 |
48 |
wp += builtin_opt.optind; |
|
1259 |
|||
1260 |
48 |
options = *wp++; |
|
1261 |
✗✓ | 48 |
if (!options) { |
1262 |
bi_errorf("missing options argument"); |
||
1263 |
return 1; |
||
1264 |
} |
||
1265 |
|||
1266 |
48 |
var = *wp++; |
|
1267 |
✗✓ | 48 |
if (!var) { |
1268 |
bi_errorf("missing name argument"); |
||
1269 |
return 1; |
||
1270 |
} |
||
1271 |
✓✗✗✓ |
48 |
if (!*var || *skip_varname(var, true)) { |
1272 |
bi_errorf("%s: is not an identifier", var); |
||
1273 |
return 1; |
||
1274 |
} |
||
1275 |
|||
1276 |
✗✓ | 48 |
if (genv->loc->next == NULL) { |
1277 |
internal_errorf(0, "c_getopts: no argv"); |
||
1278 |
return 1; |
||
1279 |
} |
||
1280 |
/* Which arguments are we parsing... */ |
||
1281 |
✓✗ | 48 |
if (*wp == NULL) |
1282 |
48 |
wp = genv->loc->next->argv; |
|
1283 |
else |
||
1284 |
*--wp = genv->loc->next->argv[0]; |
||
1285 |
|||
1286 |
/* Check that our saved state won't cause a core dump... */ |
||
1287 |
✓✓ | 48 |
for (argc = 0; wp[argc]; argc++) |
1288 |
; |
||
1289 |
✓✗✓✓ ✗✓ |
48 |
if (user_opt.optind > argc || |
1290 |
(user_opt.p != 0 && |
||
1291 |
user_opt.p > strlen(wp[user_opt.optind - 1]))) { |
||
1292 |
bi_errorf("arguments changed since last call"); |
||
1293 |
return 1; |
||
1294 |
} |
||
1295 |
|||
1296 |
48 |
user_opt.optarg = NULL; |
|
1297 |
48 |
optc = ksh_getopt(wp, &user_opt, options); |
|
1298 |
|||
1299 |
✓✓✗✓ |
48 |
if (optc >= 0 && optc != '?' && (user_opt.info & GI_PLUS)) { |
1300 |
buf[0] = '+'; |
||
1301 |
buf[1] = optc; |
||
1302 |
buf[2] = '\0'; |
||
1303 |
} else { |
||
1304 |
/* POSIX says var is set to ? at end-of-options, at&t ksh |
||
1305 |
* sets it to null - we go with POSIX... |
||
1306 |
*/ |
||
1307 |
✓✓ | 48 |
buf[0] = optc < 0 ? '?' : optc; |
1308 |
48 |
buf[1] = '\0'; |
|
1309 |
} |
||
1310 |
|||
1311 |
/* at&t ksh does not change OPTIND if it was an unknown option. |
||
1312 |
* Scripts counting on this are prone to break... (ie, don't count |
||
1313 |
* on this staying). |
||
1314 |
*/ |
||
1315 |
✓✓ | 48 |
if (optc != '?') { |
1316 |
46 |
user_opt.uoptind = user_opt.optind; |
|
1317 |
} |
||
1318 |
|||
1319 |
48 |
voptarg = global("OPTARG"); |
|
1320 |
48 |
voptarg->flag &= ~RDONLY; /* at&t ksh clears ro and int */ |
|
1321 |
/* Paranoia: ensure no bizarre results. */ |
||
1322 |
✗✓ | 48 |
if (voptarg->flag & INTEGER) |
1323 |
typeset("OPTARG", 0, INTEGER, 0, 0); |
||
1324 |
✓✓ | 48 |
if (user_opt.optarg == NULL) |
1325 |
46 |
unset(voptarg, 0); |
|
1326 |
else |
||
1327 |
/* This can't fail (have cleared readonly/integer) */ |
||
1328 |
2 |
setstr(voptarg, user_opt.optarg, KSH_RETURN_ERROR); |
|
1329 |
|||
1330 |
48 |
ret = 0; |
|
1331 |
|||
1332 |
48 |
vq = global(var); |
|
1333 |
/* Error message already printed (integer, readonly) */ |
||
1334 |
✗✓ | 48 |
if (!setstr(vq, buf, KSH_RETURN_ERROR)) |
1335 |
ret = 1; |
||
1336 |
✗✓ | 48 |
if (Flag(FEXPORT)) |
1337 |
typeset(var, EXPORT, 0, 0, 0); |
||
1338 |
|||
1339 |
✓✓ | 48 |
return optc < 0 ? 1 : ret; |
1340 |
} |
||
1341 |
|||
1342 |
#ifdef EMACS |
||
1343 |
int |
||
1344 |
c_bind(char **wp) |
||
1345 |
{ |
||
1346 |
int optc, rv = 0, macro = 0, list = 0; |
||
1347 |
char *cp; |
||
1348 |
|||
1349 |
while ((optc = ksh_getopt(wp, &builtin_opt, "lm")) != -1) |
||
1350 |
switch (optc) { |
||
1351 |
case 'l': |
||
1352 |
list = 1; |
||
1353 |
break; |
||
1354 |
case 'm': |
||
1355 |
macro = 1; |
||
1356 |
break; |
||
1357 |
case '?': |
||
1358 |
return 1; |
||
1359 |
} |
||
1360 |
wp += builtin_opt.optind; |
||
1361 |
|||
1362 |
if (*wp == NULL) /* list all */ |
||
1363 |
rv = x_bind(NULL, NULL, 0, list); |
||
1364 |
|||
1365 |
for (; *wp != NULL; wp++) { |
||
1366 |
cp = strchr(*wp, '='); |
||
1367 |
if (cp != NULL) |
||
1368 |
*cp++ = '\0'; |
||
1369 |
if (x_bind(*wp, cp, macro, 0)) |
||
1370 |
rv = 1; |
||
1371 |
} |
||
1372 |
|||
1373 |
return rv; |
||
1374 |
} |
||
1375 |
#endif |
||
1376 |
|||
1377 |
/* A leading = means assignments before command are kept; |
||
1378 |
* a leading * means a POSIX special builtin; |
||
1379 |
* a leading + means a POSIX regular builtin |
||
1380 |
* (* and + should not be combined). |
||
1381 |
*/ |
||
1382 |
const struct builtin kshbuiltins [] = { |
||
1383 |
{"+alias", c_alias}, /* no =: at&t manual wrong */ |
||
1384 |
{"+cd", c_cd}, |
||
1385 |
{"+command", c_command}, |
||
1386 |
{"echo", c_print}, |
||
1387 |
{"*=export", c_typeset}, |
||
1388 |
#ifdef HISTORY |
||
1389 |
{"+fc", c_fc}, |
||
1390 |
#endif /* HISTORY */ |
||
1391 |
{"+getopts", c_getopts}, |
||
1392 |
{"+jobs", c_jobs}, |
||
1393 |
{"+kill", c_kill}, |
||
1394 |
{"let", c_let}, |
||
1395 |
{"print", c_print}, |
||
1396 |
{"pwd", c_pwd}, |
||
1397 |
{"*=readonly", c_typeset}, |
||
1398 |
{"=typeset", c_typeset}, |
||
1399 |
{"+unalias", c_unalias}, |
||
1400 |
{"whence", c_whence}, |
||
1401 |
#ifdef JOBS |
||
1402 |
{"+bg", c_fgbg}, |
||
1403 |
{"+fg", c_fgbg}, |
||
1404 |
#endif |
||
1405 |
#ifdef EMACS |
||
1406 |
{"bind", c_bind}, |
||
1407 |
#endif |
||
1408 |
{NULL, NULL} |
||
1409 |
}; |
Generated by: GCOVR (Version 3.3) |