GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: bin/csh/exp.c Lines: 0 266 0.0 %
Date: 2016-12-06 Branches: 0 202 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: exp.c,v 1.16 2015/12/26 13:48:38 mestre Exp $	*/
2
/*	$NetBSD: exp.c,v 1.6 1995/03/21 09:02:51 cgd Exp $	*/
3
4
/*-
5
 * Copyright (c) 1980, 1991, 1993
6
 *	The Regents of the University of California.  All rights reserved.
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 * 3. Neither the name of the University nor the names of its contributors
17
 *    may be used to endorse or promote products derived from this software
18
 *    without specific prior written permission.
19
 *
20
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30
 * SUCH DAMAGE.
31
 */
32
33
#include <sys/types.h>
34
#include <sys/stat.h>
35
#include <limits.h>
36
#include <stdlib.h>
37
#include <unistd.h>
38
#include <stdarg.h>
39
40
#include "csh.h"
41
#include "extern.h"
42
43
#define IGNORE	1	/* in ignore, it means to ignore value, just parse */
44
#define NOGLOB	2	/* in ignore, it means not to globone */
45
46
#define	ADDOP	1
47
#define	MULOP	2
48
#define	EQOP	4
49
#define	RELOP	8
50
#define	RESTOP	16
51
#define	ANYOP	31
52
53
#define	EQEQ	1
54
#define	GTR	2
55
#define	LSS	4
56
#define	NOTEQ	6
57
#define EQMATCH 7
58
#define NOTEQMATCH 8
59
60
static int	exp1(Char ***, bool);
61
static int	exp2_(Char ***, bool);
62
static int	exp2a(Char ***, bool);
63
static int	exp2b(Char ***, bool);
64
static int	exp2c(Char ***, bool);
65
static Char *	exp3(Char ***, bool);
66
static Char *	exp3a(Char ***, bool);
67
static Char *	exp4(Char ***, bool);
68
static Char *	exp5(Char ***, bool);
69
static Char *	exp6(Char ***, bool);
70
static void	evalav(Char **);
71
static int	isa(Char *, int);
72
static int	egetn(Char *);
73
74
int
75
expr(Char ***vp)
76
{
77
    return (exp0(vp, 0));
78
}
79
80
int
81
exp0(Char ***vp, bool ignore)
82
{
83
    int p1 = exp1(vp, ignore);
84
85
    if (**vp && eq(**vp, STRor2)) {
86
	int p2;
87
88
	(*vp)++;
89
	p2 = exp0(vp, (ignore & IGNORE) || p1);
90
	return (p1 || p2);
91
    }
92
    return (p1);
93
}
94
95
static int
96
exp1(Char ***vp, bool ignore)
97
{
98
    int p1 = exp2_(vp, ignore);
99
100
    if (**vp && eq(**vp, STRand2)) {
101
	int p2;
102
103
	(*vp)++;
104
	p2 = exp1(vp, (ignore & IGNORE) || !p1);
105
	return (p1 && p2);
106
    }
107
    return (p1);
108
}
109
110
static int
111
exp2_(Char ***vp, bool ignore)
112
{
113
    int p1 = exp2a(vp, ignore);
114
115
    if (**vp && eq(**vp, STRor)) {
116
	int p2;
117
118
	(*vp)++;
119
	p2 = exp2_(vp, ignore);
120
	return (p1 | p2);
121
    }
122
    return (p1);
123
}
124
125
static int
126
exp2a(Char ***vp, bool ignore)
127
{
128
    int p1 = exp2b(vp, ignore);
129
130
    if (**vp && eq(**vp, STRcaret)) {
131
	int p2;
132
133
	(*vp)++;
134
	p2 = exp2a(vp, ignore);
135
	return (p1 ^ p2);
136
    }
137
    return (p1);
138
}
139
140
static int
141
exp2b(Char ***vp, bool ignore)
142
{
143
    int p1 = exp2c(vp, ignore);
144
145
    if (**vp && eq(**vp, STRand)) {
146
	int p2;
147
148
	(*vp)++;
149
	p2 = exp2b(vp, ignore);
150
	return (p1 & p2);
151
    }
152
    return (p1);
153
}
154
155
static int
156
exp2c(Char ***vp, bool ignore)
157
{
158
    Char *p1 = exp3(vp, ignore);
159
    Char *p2;
160
    int i;
161
162
    if ((i = isa(**vp, EQOP)) != 0) {
163
	(*vp)++;
164
	if (i == EQMATCH || i == NOTEQMATCH)
165
	    ignore |= NOGLOB;
166
	p2 = exp3(vp, ignore);
167
	if (!(ignore & IGNORE))
168
	    switch (i) {
169
170
	    case EQEQ:
171
		i = eq(p1, p2);
172
		break;
173
174
	    case NOTEQ:
175
		i = !eq(p1, p2);
176
		break;
177
178
	    case EQMATCH:
179
		i = Gmatch(p1, p2);
180
		break;
181
182
	    case NOTEQMATCH:
183
		i = !Gmatch(p1, p2);
184
		break;
185
	    }
186
	free(p1);
187
	free(p2);
188
	return (i);
189
    }
190
    i = egetn(p1);
191
    free(p1);
192
    return (i);
193
}
194
195
static Char *
196
exp3(Char ***vp, bool ignore)
197
{
198
    Char *p1, *p2;
199
    int i;
200
201
    p1 = exp3a(vp, ignore);
202
    if ((i = isa(**vp, RELOP)) != 0) {
203
	(*vp)++;
204
	if (**vp && eq(**vp, STRequal))
205
	    i |= 1, (*vp)++;
206
	p2 = exp3(vp, ignore);
207
	if (!(ignore & IGNORE))
208
	    switch (i) {
209
210
	    case GTR:
211
		i = egetn(p1) > egetn(p2);
212
		break;
213
214
	    case GTR | 1:
215
		i = egetn(p1) >= egetn(p2);
216
		break;
217
218
	    case LSS:
219
		i = egetn(p1) < egetn(p2);
220
		break;
221
222
	    case LSS | 1:
223
		i = egetn(p1) <= egetn(p2);
224
		break;
225
	    }
226
	free(p1);
227
	free(p2);
228
	return (putn(i));
229
    }
230
    return (p1);
231
}
232
233
static Char *
234
exp3a(Char ***vp, bool ignore)
235
{
236
    Char *p1, *p2, *op;
237
    int i;
238
239
    p1 = exp4(vp, ignore);
240
    op = **vp;
241
    if (op && any("<>", op[0]) && op[0] == op[1]) {
242
	(*vp)++;
243
	p2 = exp3a(vp, ignore);
244
	if (op[0] == '<')
245
	    i = egetn(p1) << egetn(p2);
246
	else
247
	    i = egetn(p1) >> egetn(p2);
248
	free(p1);
249
	free(p2);
250
	return (putn(i));
251
    }
252
    return (p1);
253
}
254
255
static Char *
256
exp4(Char ***vp, bool ignore)
257
{
258
    Char *p1, *p2;
259
    int i = 0;
260
261
    p1 = exp5(vp, ignore);
262
    if (isa(**vp, ADDOP)) {
263
	Char *op = *(*vp)++;
264
265
	p2 = exp4(vp, ignore);
266
	if (!(ignore & IGNORE))
267
	    switch (op[0]) {
268
269
	    case '+':
270
		i = egetn(p1) + egetn(p2);
271
		break;
272
273
	    case '-':
274
		i = egetn(p1) - egetn(p2);
275
		break;
276
	    }
277
	free(p1);
278
	free(p2);
279
	return (putn(i));
280
    }
281
    return (p1);
282
}
283
284
static Char *
285
exp5(Char ***vp, bool ignore)
286
{
287
    Char *p1, *p2;
288
    int i = 0, l;
289
290
    p1 = exp6(vp, ignore);
291
    if (isa(**vp, MULOP)) {
292
	Char *op = *(*vp)++;
293
294
	p2 = exp5(vp, ignore);
295
	if (!(ignore & IGNORE))
296
	    switch (op[0]) {
297
298
	    case '*':
299
		i = egetn(p1) * egetn(p2);
300
		break;
301
302
	    case '/':
303
		i = egetn(p2);
304
		if (i == 0)
305
		    stderror(ERR_DIV0);
306
		l = egetn(p1);
307
		if (l == INT_MIN && i == -1)
308
			i = INT_MIN;
309
		else
310
			i = l / i;
311
		break;
312
313
	    case '%':
314
		i = egetn(p2);
315
		if (i == 0)
316
		    stderror(ERR_MOD0);
317
		l = egetn(p1);
318
		if (l == INT_MIN && i == -1)
319
			i = 0;
320
		else
321
			i = l % i;
322
		break;
323
	    }
324
	free(p1);
325
	free(p2);
326
	return (putn(i));
327
    }
328
    return (p1);
329
}
330
331
static Char *
332
exp6(Char ***vp, bool ignore)
333
{
334
    int     ccode, i = 0;
335
    Char *cp, *dp, *ep;
336
337
    if (**vp == 0)
338
	stderror(ERR_NAME | ERR_EXPRESSION);
339
    if (eq(**vp, STRbang)) {
340
	(*vp)++;
341
	cp = exp6(vp, ignore);
342
	i = egetn(cp);
343
	free(cp);
344
	return (putn(!i));
345
    }
346
    if (eq(**vp, STRtilde)) {
347
	(*vp)++;
348
	cp = exp6(vp, ignore);
349
	i = egetn(cp);
350
	free(cp);
351
	return (putn(~i));
352
    }
353
    if (eq(**vp, STRLparen)) {
354
	(*vp)++;
355
	ccode = exp0(vp, ignore);
356
	if (*vp == 0 || **vp == 0 || ***vp != ')')
357
	    stderror(ERR_NAME | ERR_EXPRESSION);
358
	(*vp)++;
359
	return (putn(ccode));
360
    }
361
    if (eq(**vp, STRLbrace)) {
362
	Char **v;
363
	struct command faket;
364
	Char   *fakecom[2];
365
366
	faket.t_dtyp = NODE_COMMAND;
367
	faket.t_dflg = 0;
368
	faket.t_dcar = faket.t_dcdr = faket.t_dspr = NULL;
369
	faket.t_dcom = fakecom;
370
	fakecom[0] = STRfakecom;
371
	fakecom[1] = NULL;
372
	(*vp)++;
373
	v = *vp;
374
	for (;;) {
375
	    if (!**vp)
376
		stderror(ERR_NAME | ERR_MISSING, '}');
377
	    if (eq(*(*vp)++, STRRbrace))
378
		break;
379
	}
380
	if (ignore & IGNORE)
381
	    return (Strsave(STRNULL));
382
	psavejob();
383
	if (pfork(&faket, -1) == 0) {
384
	    *--(*vp) = 0;
385
	    evalav(v);
386
	    exitstat();
387
	}
388
	pwait();
389
	prestjob();
390
	return (putn(egetn(value(STRstatus)) == 0));
391
    }
392
    if (isa(**vp, ANYOP))
393
	return (Strsave(STRNULL));
394
    cp = *(*vp)++;
395
    if (*cp == '-' && any("erwxfdzopls", cp[1])) {
396
	struct stat stb;
397
398
	if (cp[2] != '\0')
399
	    stderror(ERR_NAME | ERR_FILEINQ);
400
	/*
401
	 * Detect missing file names by checking for operator in the file name
402
	 * position.  However, if an operator name appears there, we must make
403
	 * sure that there's no file by that name (e.g., "/") before announcing
404
	 * an error.  Even this check isn't quite right, since it doesn't take
405
	 * globbing into account.
406
	 */
407
	if (isa(**vp, ANYOP) && stat(short2str(**vp), &stb))
408
	    stderror(ERR_NAME | ERR_FILENAME);
409
410
	dp = *(*vp)++;
411
	if (ignore & IGNORE)
412
	    return (Strsave(STRNULL));
413
	ep = globone(dp, G_ERROR);
414
	switch (cp[1]) {
415
416
	case 'r':
417
	    i = !access(short2str(ep), R_OK);
418
	    break;
419
420
	case 'w':
421
	    i = !access(short2str(ep), W_OK);
422
	    break;
423
424
	case 'x':
425
	    i = !access(short2str(ep), X_OK);
426
	    break;
427
428
	default:
429
	    if (cp[1] == 'l' ? lstat(short2str(ep), &stb) :
430
		stat(short2str(ep), &stb)) {
431
		free(ep);
432
		return (Strsave(STR0));
433
	    }
434
	    switch (cp[1]) {
435
436
	    case 'f':
437
		i = S_ISREG(stb.st_mode);
438
		break;
439
440
	    case 'd':
441
		i = S_ISDIR(stb.st_mode);
442
		break;
443
444
	    case 'p':
445
		i = S_ISFIFO(stb.st_mode);
446
		break;
447
448
	    case 'l':
449
		i = S_ISLNK(stb.st_mode);
450
		break;
451
452
	    case 's':
453
		i = S_ISSOCK(stb.st_mode);
454
		break;
455
456
	    case 'z':
457
		i = stb.st_size == 0;
458
		break;
459
460
	    case 'e':
461
		i = 1;
462
		break;
463
464
	    case 'o':
465
		i = stb.st_uid == uid;
466
		break;
467
	    }
468
	}
469
	free(ep);
470
	return (putn(i));
471
    }
472
    return (ignore & NOGLOB ? Strsave(cp) : globone(cp, G_ERROR));
473
}
474
475
static void
476
evalav(Char **v)
477
{
478
    struct wordent paraml1;
479
    struct wordent *hp = &paraml1;
480
    struct command *t;
481
    struct wordent *wdp = hp;
482
483
    set(STRstatus, Strsave(STR0));
484
    hp->prev = hp->next = hp;
485
    hp->word = STRNULL;
486
    while (*v) {
487
	struct wordent *new = xcalloc(1, sizeof *wdp);
488
489
	new->prev = wdp;
490
	new->next = hp;
491
	wdp->next = new;
492
	wdp = new;
493
	wdp->word = Strsave(*v++);
494
    }
495
    hp->prev = wdp;
496
    alias(&paraml1);
497
    t = syntax(paraml1.next, &paraml1, 0);
498
    if (seterr)
499
	stderror(ERR_OLD);
500
    execute(t, -1, NULL, NULL);
501
    freelex(&paraml1), freesyn(t);
502
}
503
504
static int
505
isa(Char *cp, int what)
506
{
507
    if (cp == 0)
508
	return ((what & RESTOP) != 0);
509
    if (cp[1] == 0) {
510
	if (what & ADDOP && (*cp == '+' || *cp == '-'))
511
	    return (1);
512
	if (what & MULOP && (*cp == '*' || *cp == '/' || *cp == '%'))
513
	    return (1);
514
	if (what & RESTOP && (*cp == '(' || *cp == ')' || *cp == '!' ||
515
			      *cp == '~' || *cp == '^' || *cp == '"'))
516
	    return (1);
517
    }
518
    else if (cp[2] == 0) {
519
	if (what & RESTOP) {
520
	    if (cp[0] == '|' && cp[1] == '&')
521
		return (1);
522
	    if (cp[0] == '<' && cp[1] == '<')
523
		return (1);
524
	    if (cp[0] == '>' && cp[1] == '>')
525
		return (1);
526
	}
527
	if (what & EQOP) {
528
	    if (cp[0] == '=') {
529
		if (cp[1] == '=')
530
		    return (EQEQ);
531
		if (cp[1] == '~')
532
		    return (EQMATCH);
533
	    }
534
	    else if (cp[0] == '!') {
535
		if (cp[1] == '=')
536
		    return (NOTEQ);
537
		if (cp[1] == '~')
538
		    return (NOTEQMATCH);
539
	    }
540
	}
541
    }
542
    if (what & RELOP) {
543
	if (*cp == '<')
544
	    return (LSS);
545
	if (*cp == '>')
546
	    return (GTR);
547
    }
548
    return (0);
549
}
550
551
static int
552
egetn(Char *cp)
553
{
554
    if (*cp && *cp != '-' && !Isdigit(*cp))
555
	stderror(ERR_NAME | ERR_EXPRESSION);
556
    return (getn(cp));
557
}
558
559
/* Phew! */