/***********************************************************************
* *
* This software is part of the ast package *
* Copyright (c) 1982-2012 AT&T Intellectual Property *
* and is licensed under the *
* Eclipse Public License, Version 1.0 *
* by AT&T Intellectual Property *
* *
* A copy of the License is available at *
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
* *
* Information and Software Systems Research *
* AT&T Research *
* Florham Park NJ *
* *
* David Korn <dgk@research.att.com> *
* *
***********************************************************************/
#pragma prototyped
/*
* test expression
* [ expression ]
*
* David Korn
* AT&T Labs
*
*/
#include "defs.h"
#include <error.h>
#include <ls.h>
#include <regex.h>
#include "io.h"
#include "terminal.h"
#include "test.h"
#include "builtins.h"
#include <tmx.h>
#if !_lib_setregid
#endif /* _lib_setregid */
#ifdef S_ISSOCK
# if _pipe_socketpair
# define isapipe(f,p) (test_stat(f,p)>=0&&S_ISFIFO((p)->st_mode)||S_ISSOCK((p)->st_mode)&&(p)->st_ino&&((p)->st_mode&(S_IRUSR|S_IWUSR))!=(S_IRUSR|S_IWUSR))
# else
# define isapipe(f,p) (test_stat(f,p)>=0&&S_ISFIFO((p)->st_mode)||S_ISSOCK((p)->st_mode)&&(p)->st_ino)
# endif
# else
# define isapipe(f,p) (test_stat(f,p)>=0&&S_ISFIFO((p)->st_mode)||S_ISSOCK((p)->st_mode)&&(p)->st_ino)
# endif
#else
# define isasock(f,p) (0)
#endif
static int test_mode(const char*);
/* single char string compare */
/* two character string compare */
struct test
{
int ap;
int ac;
char **av;
};
{
register int c, m=0;
while(c = *cp++)
{
if(c=='(')
m++;
if(c=='\\' && *cp)
cp++;
}
if(m)
m++;
else
match[0] = 0;
if(m==0 && n==1)
if(n)
return(n);
}
{
register int not;
{
}
if(argc <= 1)
return(1);
{
/* special case ( binop ) to conform with standard */
{
argc -= 2;
}
}
/* posix portion for test */
switch(argc)
{
case 5:
if(!not)
break;
argv++;
/* fall through */
case 4:
{
if(op&TEST_BINOP)
break;
if(!op)
{
if(argc==5)
break;
return(*argv[3]==0);
}
}
case 3:
if(not)
return(*argv[2]!=0);
{
{
av[2] = 0;
return(2);
}
break;
}
case 2:
return(*cp==0);
}
}
/*
* evaluate a test expression.
* flag is 0 on outer level
* flag is 1 when in parenthesis
* flag is 2 when evaluating -a
*/
{
register int r;
register char *p;
{
/* check for -o and -a */
{
break;
}
if(*p=='-' && *(p+2)==0)
{
if(*++p == 'o')
{
if(flag==2)
{
break;
}
continue;
}
else if(*p == 'a')
{
continue;
}
}
if(flag==0)
break;
}
return(r);
}
{
{
if(mt)
{
return(0);
}
}
}
{
register int op;
char *binop;
{
return(op);
}
goto skip;
{
if(cp)
{
}
else
{
/* test -t with no arguments */
return(tty_check(1));
}
}
{
if(!cp)
{
/* for backward compatibility with new flags */
return(1);
}
}
if(!cp)
{
return(*arg!=0);
}
skip:
if(!(op&TEST_BINOP))
if(!op)
}
{
int f;
switch(op)
{
case 'r':
case 'w':
case 'x':
case 'V':
#if SHOPT_FS_3D
{
return(0);
/* add trailing / */
stakputc('/');
stakputc(0);
/* FALL THRU */
}
#else
return(0);
#endif /* SHOPT_FS_3D */
case 'd':
case 'c':
case 'b':
case 'f':
case 'u':
case 'g':
case 'k':
#ifdef S_ISVTX
#else
return(0);
#endif /* S_ISVTX */
#if SHOPT_TEST_L
case 'l':
#endif
case 'L':
case 'h': /* undocumented, and hopefully will disappear */
return(0);
case 'C':
#ifdef S_ISCTG
#else
return(0);
#endif /* S_ISCTG */
case 'H':
#ifdef S_ISCDF
{
return(1);
stakputc('+');
stakputc(0);
}
#else
return(0);
#endif /* S_ISCDF */
case 'S':
case 'N':
case 'p':
case 'n':
return(*arg != 0);
case 'z':
return(*arg == 0);
case 's':
case 'O':
case 'G':
return(0);
if(op=='s')
else if(op=='O')
case 'a':
case 'e':
return(1);
case 'o':
f=1;
if(*arg=='?')
case 't':
{
char *last;
}
case 'v':
case 'R':
{
int isref;
return(0);
if(op=='R')
return(isref);
if(isref)
{
else
return(0);
}
}
default:
{
static char a[3] = "-?";
a[1]= op;
/* NOTREACHED */
return(0);
}
}
}
{
if(op&TEST_ARITH)
{
while(*left=='0')
left++;
while(*right=='0')
right++;
}
switch(op)
{
/* op must be one of the following values */
case TEST_AND:
case TEST_OR:
return(*left!=0);
case TEST_PEQ:
case TEST_PNE:
case TEST_SGT:
case TEST_SLT:
case TEST_SEQ:
case TEST_SNE:
case TEST_EF:
case TEST_NT:
case TEST_OT:
case TEST_EQ:
case TEST_NE:
case TEST_GT:
case TEST_LT:
case TEST_GE:
case TEST_LE:
}
/* NOTREACHED */
return(0);
}
/*
* returns the modification time of f1 - modification time of f2
*/
{
return(r<0?0:-1);
if(r<0)
return(1);
return(1);
return(-1);
return(0);
}
/*
* return true if inode of two files are the same
*/
{
return(1);
return(0);
}
/*
* The static buffer statb is shared with test_mode.
*/
{
if(*name==0)
return(-1);
if(sh_isdevfd(name))
/* can't use access function for execute permission with root */
goto skip;
#ifdef _lib_setreuid
/* swap the real uid to effective, check access then restore */
/* first swap real and effective gid, if different */
{
/* next swap real and effective uid, if needed */
{
/* restore ids */
return(mode);
}
}
#endif /* _lib_setreuid */
skip:
{
return(mode);
{
return(0);
/* root needs execute permission for someone */
}
mode <<= 6;
mode <<= 3;
#ifdef _lib_getgroups
/* on some systems you can be in several groups */
else
{
static int maxgroups;
register int n;
if(maxgroups==0)
{
/* first time */
{
/* pre-POSIX system */
}
}
while(--n >= 0)
{
{
mode <<= 3;
break;
}
}
}
# endif /* _lib_getgroups */
return(0);
}
return(-1);
}
/*
* Return the mode bits of file <file>
* If <file> is null, then the previous stat buffer is used.
* The mode bits are zero if the file doesn't exist.
*/
{
return(0);
}
/*
*/
{
if(*name==0)
{
return(-1);
}
if(sh_isdevfd(name))
else
}