openenvutils/commandshell/shell/src/cond.c
changeset 0 2e3d3ce01487
equal deleted inserted replaced
-1:000000000000 0:2e3d3ce01487
       
     1 /*
       
     2  * cond.c - evaluate conditional expressions
       
     3  *
       
     4  * This file is part of zsh, the Z shell.
       
     5  *
       
     6  * Copyright (c) 1992-1997 Paul Falstad
       
     7  * All rights reserved.
       
     8  *
       
     9  * Permission is hereby granted, without written agreement and without
       
    10  * license or royalty fees, to use, copy, modify, and distribute this
       
    11  * software and to distribute modified versions of this software for any
       
    12  * purpose, provided that the above copyright notice and the following
       
    13  * two paragraphs appear in all copies of this software.
       
    14  *
       
    15  * In no event shall Paul Falstad or the Zsh Development Group be liable
       
    16  * to any party for direct, indirect, special, incidental, or consequential
       
    17  * damages arising out of the use of this software and its documentation,
       
    18  * even if Paul Falstad and the Zsh Development Group have been advised of
       
    19  * the possibility of such damage.
       
    20  *
       
    21  * Paul Falstad and the Zsh Development Group specifically disclaim any
       
    22  * warranties, including, but not limited to, the implied warranties of
       
    23  * merchantability and fitness for a particular purpose.  The software
       
    24  * provided hereunder is on an "as is" basis, and Paul Falstad and the
       
    25  * Zsh Development Group have no obligation to provide maintenance,
       
    26  * support, updates, enhancements, or modifications.
       
    27  *
       
    28  */
       
    29 
       
    30 #include "zsh.mdh"
       
    31 #include "cond.pro"
       
    32 
       
    33 int tracingcond;
       
    34 
       
    35 static char *condstr[COND_MOD] = {
       
    36     "!", "&&", "||", "==", "!=", "<", ">", "-nt", "-ot", "-ef", "-eq",
       
    37     "-ne", "-lt", "-gt", "-le", "-ge"
       
    38 };
       
    39 
       
    40 /*
       
    41  * Evaluate a conditional expression given the arguments.
       
    42  * If fromtest is set, the caller is the test or [ builtin;
       
    43  * with the pointer giving the name of the command.
       
    44  * for POSIX conformance this supports a more limited range
       
    45  * of functionality.
       
    46  *
       
    47  * Return status is the final shell status, i.e. 0 for true,
       
    48  * 1 for false and 2 for error.
       
    49  */
       
    50 
       
    51 /**/
       
    52 int
       
    53 evalcond(Estate state, char *fromtest)
       
    54 {
       
    55     struct stat *st;
       
    56     char *left, *right;
       
    57     Wordcode pcode;
       
    58     wordcode code;
       
    59     int ctype, htok = 0, ret;
       
    60 
       
    61  rec:
       
    62 
       
    63     left = right = NULL;
       
    64     pcode = state->pc++;
       
    65     code = *pcode;
       
    66     ctype = WC_COND_TYPE(code);
       
    67 
       
    68     switch (ctype) {
       
    69     case COND_NOT:
       
    70 	if (tracingcond)
       
    71 	    fprintf(xtrerr, " %s", condstr[ctype]);
       
    72 	ret = evalcond(state, fromtest);
       
    73 	if (ret == 2)
       
    74 	    return ret;
       
    75 	else
       
    76 	    return !ret;
       
    77     case COND_AND:
       
    78 	if (!(ret = evalcond(state, fromtest))) {
       
    79 	    if (tracingcond)
       
    80 		fprintf(xtrerr, " %s", condstr[ctype]);
       
    81 	    goto rec;
       
    82 	} else {
       
    83 	    state->pc = pcode + (WC_COND_SKIP(code) + 1);
       
    84 	    return ret;
       
    85 	}
       
    86     case COND_OR:
       
    87 	if ((ret = evalcond(state, fromtest)) == 1) {
       
    88 	    if (tracingcond)
       
    89 		fprintf(xtrerr, " %s", condstr[ctype]);
       
    90 	    goto rec;
       
    91 	} else {
       
    92 	    state->pc = pcode + (WC_COND_SKIP(code) + 1);
       
    93 	    return ret;
       
    94 	}
       
    95     case COND_MOD:
       
    96     case COND_MODI:
       
    97 	{
       
    98 	    Conddef cd;
       
    99 	    char *name = ecgetstr(state, EC_NODUP, NULL), **strs;
       
   100 	    int l = WC_COND_SKIP(code);
       
   101 
       
   102 	    if (ctype == COND_MOD)
       
   103 		strs = ecgetarr(state, l, EC_DUP, NULL);
       
   104 	    else {
       
   105 		char *sbuf[3];
       
   106 
       
   107 		sbuf[0] = ecgetstr(state, EC_NODUP, NULL);
       
   108 		sbuf[1] = ecgetstr(state, EC_NODUP, NULL);
       
   109 		sbuf[2] = NULL;
       
   110 
       
   111 		strs = arrdup(sbuf);
       
   112 		l = 2;
       
   113 	    }
       
   114 	    if ((cd = getconddef((ctype == COND_MODI), name + 1, 1))) {
       
   115 		if (ctype == COND_MOD &&
       
   116 		    (l < cd->min || (cd->max >= 0 && l > cd->max))) {
       
   117 		    zwarnnam(fromtest, "unrecognized condition: `%s'",
       
   118 			     name, 0);
       
   119 		    return 2;
       
   120 		}
       
   121 		if (tracingcond)
       
   122 		    tracemodcond(name, strs, ctype == COND_MODI);
       
   123 		return !cd->handler(strs, cd->condid);
       
   124 	    }
       
   125 	    else {
       
   126 		char *s = strs[0];
       
   127 
       
   128 		strs[0] = dupstring(name);
       
   129 		name = s;
       
   130 
       
   131 		if (name && name[0] == '-' &&
       
   132 		    (cd = getconddef(0, name + 1, 1))) {
       
   133 		    if (l < cd->min || (cd->max >= 0 && l > cd->max)) {
       
   134 			zwarnnam(fromtest, "unrecognized condition: `%s'",
       
   135 				 name, 0);
       
   136 			return 2;
       
   137 		    }
       
   138 		    if (tracingcond)
       
   139 			tracemodcond(name, strs, ctype == COND_MODI);
       
   140 		    return !cd->handler(strs, cd->condid);
       
   141 		} else {
       
   142 		    zwarnnam(fromtest,
       
   143 			     "unrecognized condition: `%s'", name, 0);
       
   144 		}
       
   145 	    }
       
   146 	    /* module not found, error */
       
   147 	    return 2;
       
   148 	}
       
   149     }
       
   150     left = ecgetstr(state, EC_DUPTOK, &htok);
       
   151     if (htok) {
       
   152 	singsub(&left);
       
   153 	untokenize(left);
       
   154     }
       
   155     if (ctype <= COND_GE && ctype != COND_STREQ && ctype != COND_STRNEQ) {
       
   156 	right = ecgetstr(state, EC_DUPTOK, &htok);
       
   157 	if (htok) {
       
   158 	    singsub(&right);
       
   159 	    untokenize(right);
       
   160 	}
       
   161     }
       
   162     if (tracingcond) {
       
   163 	if (ctype < COND_MOD) {
       
   164 	    char *rt = (char *) right;
       
   165 	    if (ctype == COND_STREQ || ctype == COND_STRNEQ) {
       
   166 		rt = dupstring(ecrawstr(state->prog, state->pc, NULL));
       
   167 		singsub(&rt);
       
   168 		untokenize(rt);
       
   169 	    }
       
   170 	    fputc(' ',xtrerr);
       
   171 	    quotedzputs(left, xtrerr);
       
   172 	    fprintf(xtrerr, " %s ", condstr[ctype]);
       
   173 	    quotedzputs(rt, xtrerr);
       
   174 	} else {
       
   175 	    fprintf(xtrerr, " -%c ", ctype);
       
   176 	    quotedzputs(left, xtrerr);
       
   177 	}
       
   178     }
       
   179 
       
   180     if (ctype >= COND_EQ && ctype <= COND_GE) {
       
   181 	mnumber mn1, mn2;
       
   182 	if (fromtest) {
       
   183 	    /*
       
   184 	     * For test and [, the expressions must be base 10 integers,
       
   185 	     * not integer expressions.
       
   186 	     */
       
   187 	    char *eptr, *err;
       
   188 
       
   189 	    mn1.u.l = zstrtol(left, &eptr, 10);
       
   190 	    if (!*eptr)
       
   191 	    {
       
   192 		mn2.u.l = zstrtol(right, &eptr, 10);
       
   193 		err = right;
       
   194 	    }
       
   195 	    else
       
   196 		err = left;
       
   197 
       
   198 	    if (*eptr)
       
   199 	    {
       
   200 		zwarnnam(fromtest, "integer expression expected: %s",
       
   201 			 err, 0);
       
   202 		return 2;
       
   203 	    }
       
   204 
       
   205 	    mn1.type = mn2.type = MN_INTEGER;
       
   206 	} else {
       
   207 	    mn1 = matheval(left);
       
   208 	    mn2 = matheval(right);
       
   209 	}
       
   210 
       
   211 	if (((mn1.type|mn2.type) & (MN_INTEGER|MN_FLOAT)) ==
       
   212 	    (MN_INTEGER|MN_FLOAT)) {
       
   213 	    /* promote to float */
       
   214 	    if (mn1.type & MN_INTEGER) {
       
   215 		mn1.type = MN_FLOAT;
       
   216 		mn1.u.d = (double)mn1.u.l;
       
   217 	    }
       
   218 	    if (mn2.type & MN_INTEGER) {
       
   219 		mn2.type = MN_FLOAT;
       
   220 		mn2.u.d = (double)mn2.u.l;
       
   221 	    }
       
   222 	}
       
   223 	switch(ctype) {
       
   224 	case COND_EQ:
       
   225 	    return !((mn1.type & MN_FLOAT) ? (mn1.u.d == mn2.u.d) :
       
   226 		     (mn1.u.l == mn2.u.l));
       
   227 	case COND_NE:
       
   228 	    return !((mn1.type & MN_FLOAT) ? (mn1.u.d != mn2.u.d) :
       
   229 		     (mn1.u.l != mn2.u.l));
       
   230 	case COND_LT:
       
   231 	    return !((mn1.type & MN_FLOAT) ? (mn1.u.d < mn2.u.d) :
       
   232 		     (mn1.u.l < mn2.u.l));
       
   233 	case COND_GT:
       
   234 	    return !((mn1.type & MN_FLOAT) ? (mn1.u.d > mn2.u.d) :
       
   235 		     (mn1.u.l > mn2.u.l));
       
   236 	case COND_LE:
       
   237 	    return !((mn1.type & MN_FLOAT) ? (mn1.u.d <= mn2.u.d) :
       
   238 		     (mn1.u.l <= mn2.u.l));
       
   239 	case COND_GE:
       
   240 	    return !((mn1.type & MN_FLOAT) ? (mn1.u.d >= mn2.u.d) :
       
   241 		     (mn1.u.l >= mn2.u.l));
       
   242 	}
       
   243     }
       
   244 
       
   245     switch (ctype) {
       
   246     case COND_STREQ:
       
   247     case COND_STRNEQ:
       
   248 	{
       
   249 	    int test, npat = state->pc[1];
       
   250 	    Patprog pprog = state->prog->pats[npat];
       
   251 
       
   252 	    if (pprog == dummy_patprog1 || pprog == dummy_patprog2) {
       
   253 		char *opat;
       
   254 		int save;
       
   255 
       
   256 		right = dupstring(opat = ecrawstr(state->prog, state->pc,
       
   257 						  &htok));
       
   258 		if (htok)
       
   259 		    singsub(&right);
       
   260 		save = (!(state->prog->flags & EF_HEAP) &&
       
   261 			!strcmp(opat, right) && pprog != dummy_patprog2);
       
   262 
       
   263 		if (!(pprog = patcompile(right, (save ? PAT_ZDUP : PAT_STATIC),
       
   264 					 NULL))) {
       
   265 		    zwarnnam(fromtest, "bad pattern: %s", right, 0);
       
   266 		    return 2;
       
   267 		}
       
   268 		else if (save)
       
   269 		    state->prog->pats[npat] = pprog;
       
   270 	    }
       
   271 	    state->pc += 2;
       
   272 	    test = (pprog && pattry(pprog, left));
       
   273 
       
   274 	    return !(ctype == COND_STREQ ? test : !test);
       
   275 	}
       
   276     case COND_STRLT:
       
   277 	return !(strcmp(left, right) < 0);
       
   278     case COND_STRGTR:
       
   279 	return !(strcmp(left, right) > 0);
       
   280     case 'e':
       
   281     case 'a':
       
   282 	return (!doaccess(left, F_OK));
       
   283     case 'b':
       
   284 	return (!S_ISBLK(dostat(left)));
       
   285     case 'c':
       
   286 	return (!S_ISCHR(dostat(left)));
       
   287     case 'd':
       
   288 	return (!S_ISDIR(dostat(left)));
       
   289     case 'f':
       
   290 	return (!S_ISREG(dostat(left)));
       
   291     case 'g':
       
   292 	return (!(dostat(left) & S_ISGID));
       
   293     case 'k':
       
   294 	return (!(dostat(left) & S_ISVTX));
       
   295     case 'n':
       
   296 	return (!strlen(left));
       
   297     case 'o':
       
   298 	return (optison(fromtest, left));
       
   299     case 'p':
       
   300 	return (!S_ISFIFO(dostat(left)));
       
   301     case 'r':
       
   302 	return (!doaccess(left, R_OK));
       
   303     case 's':
       
   304 	return !((st = getstat(left)) && !!(st->st_size));
       
   305     case 'S':
       
   306 	return (!S_ISSOCK(dostat(left)));
       
   307     case 'u':
       
   308 	return (!(dostat(left) & S_ISUID));
       
   309     case 'w':
       
   310 	return (!doaccess(left, W_OK));
       
   311     case 'x':
       
   312 	if (privasserted()) {
       
   313 	    mode_t mode = dostat(left);
       
   314 	    return !((mode & S_IXUGO) || S_ISDIR(mode));
       
   315 	}
       
   316 	return !doaccess(left, X_OK);
       
   317     case 'z':
       
   318 	return !!(strlen(left));
       
   319     case 'h':
       
   320     case 'L':
       
   321 	return (!S_ISLNK(dolstat(left)));
       
   322     case 'O':
       
   323 	return !((st = getstat(left)) && st->st_uid == geteuid());
       
   324     case 'G':
       
   325 	return !((st = getstat(left)) && st->st_gid == getegid());
       
   326     case 'N':
       
   327 	return !((st = getstat(left)) && st->st_atime <= st->st_mtime);
       
   328     case 't':
       
   329 	return !isatty(mathevali(left));
       
   330     case COND_NT:
       
   331     case COND_OT:
       
   332 	{
       
   333 	    time_t a;
       
   334 
       
   335 	    if (!(st = getstat(left)))
       
   336 		return 1;
       
   337 	    a = st->st_mtime;
       
   338 	    if (!(st = getstat(right)))
       
   339 		return 1;
       
   340 	    return !((ctype == COND_NT) ? a > st->st_mtime : a < st->st_mtime);
       
   341 	}
       
   342     case COND_EF:
       
   343 	{
       
   344 	    dev_t d;
       
   345 	    ino_t i;
       
   346 
       
   347 	    if (!(st = getstat(left)))
       
   348 		return 1;
       
   349 	    d = st->st_dev;
       
   350 	    i = st->st_ino;
       
   351 	    if (!(st = getstat(right)))
       
   352 		return 1;
       
   353 	    return !(d == st->st_dev && i == st->st_ino);
       
   354 	}
       
   355     default:
       
   356 	zwarnnam(fromtest, "bad cond code", NULL, 0);
       
   357 	return 2;
       
   358     }
       
   359     return 1;
       
   360 }
       
   361 
       
   362 
       
   363 /**/
       
   364 static int
       
   365 doaccess(char *s, int c)
       
   366 {
       
   367 #ifdef HAVE_FACCESSX
       
   368     if (!strncmp(s, "/dev/fd/", 8))
       
   369 	return !faccessx(atoi(s + 8), c, ACC_SELF);
       
   370 #endif
       
   371     return !access(unmeta(s), c);
       
   372 }
       
   373 
       
   374 
       
   375 static struct stat st;
       
   376 
       
   377 /**/
       
   378 static struct stat *
       
   379 getstat(char *s)
       
   380 {
       
   381     char *us;
       
   382 
       
   383 /* /dev/fd/n refers to the open file descriptor n.  We always use fstat *
       
   384  * in this case since on Solaris /dev/fd/n is a device special file     */
       
   385     if (!strncmp(s, "/dev/fd/", 8)) {
       
   386 	if (fstat(atoi(s + 8), &st))
       
   387 	    return NULL;
       
   388         return &st;
       
   389     }
       
   390 
       
   391     if (!(us = unmeta(s)))
       
   392         return NULL;
       
   393     if (stat(us, &st))
       
   394 	return NULL;
       
   395     return &st;
       
   396 }
       
   397 
       
   398 
       
   399 /**/
       
   400 static mode_t
       
   401 dostat(char *s)
       
   402 {
       
   403     struct stat *statp;
       
   404 
       
   405     if (!(statp = getstat(s)))
       
   406 	return 0;
       
   407     return statp->st_mode;
       
   408 }
       
   409 
       
   410 
       
   411 /* pem@aaii.oz; needed since dostat now uses "stat" */
       
   412 
       
   413 /**/
       
   414 static mode_t
       
   415 dolstat(char *s)
       
   416 {
       
   417     if (lstat(unmeta(s), &st) < 0)
       
   418 	return 0;
       
   419     return st.st_mode;
       
   420 }
       
   421 
       
   422 
       
   423 /*
       
   424  * optison returns evalcond-friendly statuses (true, false, error).
       
   425  */
       
   426 
       
   427 /**/
       
   428 static int
       
   429 optison(char *name, char *s)
       
   430 {
       
   431     int i;
       
   432 
       
   433     if (strlen(s) == 1)
       
   434 	i = optlookupc(*s);
       
   435     else
       
   436 	i = optlookup(s);
       
   437     if (!i) {
       
   438 	zwarnnam(name, "no such option: %s", s, 0);
       
   439 	return 2;
       
   440     } else if(i < 0)
       
   441 	return !unset(-i);
       
   442     else
       
   443 	return !isset(i);
       
   444 }
       
   445 
       
   446 /**/
       
   447 mod_export char *
       
   448 cond_str(char **args, int num, int raw)
       
   449 {
       
   450     char *s = args[num];
       
   451 
       
   452     if (has_token(s)) {
       
   453 	singsub(&s);
       
   454 	if (!raw)
       
   455 	    untokenize(s);
       
   456     }
       
   457     return s;
       
   458 }
       
   459 
       
   460 /**/
       
   461 mod_export zlong
       
   462 cond_val(char **args, int num)
       
   463 {
       
   464     char *s = args[num];
       
   465 
       
   466     if (has_token(s)) {
       
   467 	singsub(&s);
       
   468 	untokenize(s);
       
   469     }
       
   470     return mathevali(s);
       
   471 }
       
   472 
       
   473 /**/
       
   474 mod_export int
       
   475 cond_match(char **args, int num, char *str)
       
   476 {
       
   477     char *s = args[num];
       
   478 
       
   479     singsub(&s);
       
   480 
       
   481     return matchpat(str, s);
       
   482 }
       
   483 
       
   484 /**/
       
   485 static void
       
   486 tracemodcond(char *name, char **args, int inf)
       
   487 {
       
   488     char **aptr;
       
   489 
       
   490     args = arrdup(args);
       
   491     for (aptr = args; *aptr; aptr++)
       
   492 	untokenize(*aptr);
       
   493     if (inf) {
       
   494 	fprintf(xtrerr, " %s %s %s", args[0], name, args[1]);
       
   495     } else {
       
   496 	fprintf(xtrerr, " %s", name);
       
   497 	while (*args)
       
   498 	    fprintf(xtrerr, " %s", *args++);
       
   499     }
       
   500 }