149884Ssheldonh/* $NetBSD: test.c,v 1.21 1999/04/05 09:48:38 kleink Exp $ */ 249884Ssheldonh 3139969Simp/*- 449884Ssheldonh * test(1); version 7-like -- author Erik Baalbergen 549884Ssheldonh * modified by Eric Gisin to be used as built-in. 649884Ssheldonh * modified by Arnold Robbins to add SVR3 compatibility 749884Ssheldonh * (-x -c -b -p -u -g -k) plus Korn's -L -nt -ot -ef and new -S (socket). 849884Ssheldonh * modified by J.T. Conklin for NetBSD. 91556Srgrimes * 1049884Ssheldonh * This program is in the Public Domain. 111556Srgrimes */ 12218724Sjilles/* 13218724Sjilles * Important: This file is used both as a standalone program /bin/test and 14218724Sjilles * as a builtin for /bin/sh (#define SHELL). 15218724Sjilles */ 161556Srgrimes 1799110Sobrien#include <sys/cdefs.h> 1899110Sobrien__FBSDID("$FreeBSD$"); 191556Srgrimes 2049884Ssheldonh#include <sys/types.h> 211556Srgrimes#include <sys/stat.h> 221556Srgrimes 231556Srgrimes#include <ctype.h> 241556Srgrimes#include <err.h> 251556Srgrimes#include <errno.h> 2693345Sache#include <inttypes.h> 2776883Skris#include <limits.h> 2886619Sknu#include <stdarg.h> 291556Srgrimes#include <stdio.h> 301556Srgrimes#include <stdlib.h> 311556Srgrimes#include <string.h> 321556Srgrimes#include <unistd.h> 331556Srgrimes 3486505Sknu#ifdef SHELL 3586505Sknu#define main testcmd 3686505Sknu#include "bltin/bltin.h" 3786618Sknu#else 3888084Sache#include <locale.h> 3988084Sache 4096376Salfredstatic void error(const char *, ...) __dead2 __printf0like(1, 2); 4186618Sknu 4286618Sknustatic void 4386618Sknuerror(const char *msg, ...) 4486618Sknu{ 4586618Sknu va_list ap; 4686618Sknu va_start(ap, msg); 4786618Sknu verrx(2, msg, ap); 4886618Sknu /*NOTREACHED*/ 4986618Sknu va_end(ap); 5086618Sknu} 5186618Sknu#endif 5286618Sknu 5349884Ssheldonh/* test(1) accepts the following grammar: 5449884Ssheldonh oexpr ::= aexpr | aexpr "-o" oexpr ; 5549884Ssheldonh aexpr ::= nexpr | nexpr "-a" aexpr ; 5649884Ssheldonh nexpr ::= primary | "!" primary 5749884Ssheldonh primary ::= unary-operator operand 5849884Ssheldonh | operand binary-operator operand 5949884Ssheldonh | operand 6049884Ssheldonh | "(" oexpr ")" 6149884Ssheldonh ; 6249884Ssheldonh unary-operator ::= "-r"|"-w"|"-x"|"-f"|"-d"|"-c"|"-b"|"-p"| 6349884Ssheldonh "-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"|"-L"|"-S"; 641556Srgrimes 6549884Ssheldonh binary-operator ::= "="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"| 66251208Sjilles "-nt"|"-ot"|"-ef"; 6749884Ssheldonh operand ::= <any legal UNIX file name> 6849884Ssheldonh*/ 691556Srgrimes 70297766Sjillesenum token_types { 71297766Sjilles UNOP = 0x100, 72297766Sjilles BINOP = 0x200, 73297766Sjilles BUNOP = 0x300, 74297766Sjilles BBINOP = 0x400, 75297766Sjilles PAREN = 0x500 76297766Sjilles}; 77297766Sjilles 7849884Ssheldonhenum token { 7949884Ssheldonh EOI, 80297766Sjilles OPERAND, 81297766Sjilles FILRD = UNOP + 1, 8249884Ssheldonh FILWR, 8349884Ssheldonh FILEX, 8449884Ssheldonh FILEXIST, 8549884Ssheldonh FILREG, 8649884Ssheldonh FILDIR, 8749884Ssheldonh FILCDEV, 8849884Ssheldonh FILBDEV, 8949884Ssheldonh FILFIFO, 9049884Ssheldonh FILSOCK, 9149884Ssheldonh FILSYM, 9249884Ssheldonh FILGZ, 9349884Ssheldonh FILTT, 9449884Ssheldonh FILSUID, 9549884Ssheldonh FILSGID, 9649884Ssheldonh FILSTCK, 97297766Sjilles STREZ, 98297766Sjilles STRNZ, 99297766Sjilles FILUID, 100297766Sjilles FILGID, 101297766Sjilles FILNT = BINOP + 1, 102251208Sjilles FILOT, 10349884Ssheldonh FILEQ, 10449884Ssheldonh STREQ, 10549884Ssheldonh STRNE, 10649884Ssheldonh STRLT, 10749884Ssheldonh STRGT, 10849884Ssheldonh INTEQ, 10949884Ssheldonh INTNE, 11049884Ssheldonh INTGE, 11149884Ssheldonh INTGT, 11249884Ssheldonh INTLE, 11349884Ssheldonh INTLT, 114297766Sjilles UNOT = BUNOP + 1, 115297766Sjilles BAND = BBINOP + 1, 11649884Ssheldonh BOR, 117297766Sjilles LPAREN = PAREN + 1, 118297766Sjilles RPAREN 1191556Srgrimes}; 1201556Srgrimes 121297766Sjilles#define TOKEN_TYPE(token) ((token) & 0xff00) 1221556Srgrimes 123226961Sedstatic struct t_op { 124251208Sjilles char op_text[4]; 125297766Sjilles short op_num; 12649884Ssheldonh} const ops [] = { 127297766Sjilles {"-r", FILRD}, 128297766Sjilles {"-w", FILWR}, 129297766Sjilles {"-x", FILEX}, 130297766Sjilles {"-e", FILEXIST}, 131297766Sjilles {"-f", FILREG}, 132297766Sjilles {"-d", FILDIR}, 133297766Sjilles {"-c", FILCDEV}, 134297766Sjilles {"-b", FILBDEV}, 135297766Sjilles {"-p", FILFIFO}, 136297766Sjilles {"-u", FILSUID}, 137297766Sjilles {"-g", FILSGID}, 138297766Sjilles {"-k", FILSTCK}, 139297766Sjilles {"-s", FILGZ}, 140297766Sjilles {"-t", FILTT}, 141297766Sjilles {"-z", STREZ}, 142297766Sjilles {"-n", STRNZ}, 143297766Sjilles {"-h", FILSYM}, /* for backwards compat */ 144297766Sjilles {"-O", FILUID}, 145297766Sjilles {"-G", FILGID}, 146297766Sjilles {"-L", FILSYM}, 147297766Sjilles {"-S", FILSOCK}, 148297766Sjilles {"=", STREQ}, 149297766Sjilles {"==", STREQ}, 150297766Sjilles {"!=", STRNE}, 151297766Sjilles {"<", STRLT}, 152297766Sjilles {">", STRGT}, 153297766Sjilles {"-eq", INTEQ}, 154297766Sjilles {"-ne", INTNE}, 155297766Sjilles {"-ge", INTGE}, 156297766Sjilles {"-gt", INTGT}, 157297766Sjilles {"-le", INTLE}, 158297766Sjilles {"-lt", INTLT}, 159297766Sjilles {"-nt", FILNT}, 160297766Sjilles {"-ot", FILOT}, 161297766Sjilles {"-ef", FILEQ}, 162297766Sjilles {"!", UNOT}, 163297766Sjilles {"-a", BAND}, 164297766Sjilles {"-o", BOR}, 165297766Sjilles {"(", LPAREN}, 166297766Sjilles {")", RPAREN}, 167297766Sjilles {"", 0} 1681556Srgrimes}; 1691556Srgrimes 170226961Sedstatic int nargc; 171226961Sedstatic char **t_wp; 172226961Sedstatic int parenlevel; 1731556Srgrimes 17490111Simpstatic int aexpr(enum token); 175297767Sjillesstatic int binop(enum token); 17690111Simpstatic int equalf(const char *, const char *); 17790111Simpstatic int filstat(char *, enum token); 17890111Simpstatic int getn(const char *); 17993345Sachestatic intmax_t getq(const char *); 18090111Simpstatic int intcmp(const char *, const char *); 181192862Sjillesstatic int isunopoperand(void); 182192862Sjillesstatic int islparenoperand(void); 183192862Sjillesstatic int isrparenoperand(void); 184251208Sjillesstatic int newerf(const char *, const char *); 18590111Simpstatic int nexpr(enum token); 18690111Simpstatic int oexpr(enum token); 187251208Sjillesstatic int olderf(const char *, const char *); 18890111Simpstatic int primary(enum token); 18990111Simpstatic void syntax(const char *, const char *); 19090111Simpstatic enum token t_lex(char *); 19149884Ssheldonh 1921556Srgrimesint 19390111Simpmain(int argc, char **argv) 1941556Srgrimes{ 195101923Smaxim int res; 19655179Ssheldonh char *p; 1971556Srgrimes 198219680Sjilles if ((p = strrchr(argv[0], '/')) == NULL) 19955179Ssheldonh p = argv[0]; 20055179Ssheldonh else 20155179Ssheldonh p++; 20255179Ssheldonh if (strcmp(p, "[") == 0) { 20386622Sknu if (strcmp(argv[--argc], "]") != 0) 20486618Sknu error("missing ]"); 2051556Srgrimes argv[argc] = NULL; 2061556Srgrimes } 2071556Srgrimes 208101923Smaxim /* no expression => false */ 209101923Smaxim if (--argc <= 0) 210101923Smaxim return 1; 211101923Smaxim 21288084Sache#ifndef SHELL 21388084Sache (void)setlocale(LC_CTYPE, ""); 21488084Sache#endif 215101923Smaxim nargc = argc; 21649884Ssheldonh t_wp = &argv[1]; 217192862Sjilles parenlevel = 0; 218192862Sjilles if (nargc == 4 && strcmp(*t_wp, "!") == 0) { 219192862Sjilles /* Things like ! "" -o x do not fit in the normal grammar. */ 220192862Sjilles --nargc; 221192862Sjilles ++t_wp; 222192862Sjilles res = oexpr(t_lex(*t_wp)); 223192862Sjilles } else 224192862Sjilles res = !oexpr(t_lex(*t_wp)); 2251556Srgrimes 226101923Smaxim if (--nargc > 0) 22749884Ssheldonh syntax(*t_wp, "unexpected operator"); 22849884Ssheldonh 22949884Ssheldonh return res; 2301556Srgrimes} 2311556Srgrimes 23249884Ssheldonhstatic void 23390111Simpsyntax(const char *op, const char *msg) 2341556Srgrimes{ 2351556Srgrimes 23649884Ssheldonh if (op && *op) 23786618Sknu error("%s: %s", op, msg); 23849884Ssheldonh else 23986618Sknu error("%s", msg); 2401556Srgrimes} 2411556Srgrimes 24249884Ssheldonhstatic int 24390111Simpoexpr(enum token n) 2441556Srgrimes{ 24549884Ssheldonh int res; 2461556Srgrimes 24749884Ssheldonh res = aexpr(n); 248101923Smaxim if (t_lex(nargc > 0 ? (--nargc, *++t_wp) : NULL) == BOR) 249101923Smaxim return oexpr(t_lex(nargc > 0 ? (--nargc, *++t_wp) : NULL)) || 250101923Smaxim res; 25149884Ssheldonh t_wp--; 252101923Smaxim nargc++; 25349884Ssheldonh return res; 25449884Ssheldonh} 2554171Sache 25649884Ssheldonhstatic int 25790111Simpaexpr(enum token n) 25849884Ssheldonh{ 25949884Ssheldonh int res; 2601556Srgrimes 26149884Ssheldonh res = nexpr(n); 262101923Smaxim if (t_lex(nargc > 0 ? (--nargc, *++t_wp) : NULL) == BAND) 263101923Smaxim return aexpr(t_lex(nargc > 0 ? (--nargc, *++t_wp) : NULL)) && 264101923Smaxim res; 26549884Ssheldonh t_wp--; 266101923Smaxim nargc++; 26749884Ssheldonh return res; 2681556Srgrimes} 2691556Srgrimes 2701556Srgrimesstatic int 27190111Simpnexpr(enum token n) 2721556Srgrimes{ 27349884Ssheldonh if (n == UNOT) 274101923Smaxim return !nexpr(t_lex(nargc > 0 ? (--nargc, *++t_wp) : NULL)); 27549884Ssheldonh return primary(n); 2761556Srgrimes} 2771556Srgrimes 2781556Srgrimesstatic int 27990111Simpprimary(enum token n) 2801556Srgrimes{ 28149884Ssheldonh enum token nn; 28249884Ssheldonh int res; 2831556Srgrimes 28449884Ssheldonh if (n == EOI) 28549884Ssheldonh return 0; /* missing expression */ 28649884Ssheldonh if (n == LPAREN) { 287192862Sjilles parenlevel++; 288101923Smaxim if ((nn = t_lex(nargc > 0 ? (--nargc, *++t_wp) : NULL)) == 289192862Sjilles RPAREN) { 290192862Sjilles parenlevel--; 29149884Ssheldonh return 0; /* missing expression */ 292192862Sjilles } 29349884Ssheldonh res = oexpr(nn); 294101923Smaxim if (t_lex(nargc > 0 ? (--nargc, *++t_wp) : NULL) != RPAREN) 29549884Ssheldonh syntax(NULL, "closing paren expected"); 296192862Sjilles parenlevel--; 29749884Ssheldonh return res; 29849884Ssheldonh } 299297766Sjilles if (TOKEN_TYPE(n) == UNOP) { 30049884Ssheldonh /* unary expression */ 301101923Smaxim if (--nargc == 0) 302297766Sjilles syntax(NULL, "argument expected"); /* impossible */ 30349884Ssheldonh switch (n) { 30449884Ssheldonh case STREZ: 305101923Smaxim return strlen(*++t_wp) == 0; 30649884Ssheldonh case STRNZ: 307101923Smaxim return strlen(*++t_wp) != 0; 30849884Ssheldonh case FILTT: 309101923Smaxim return isatty(getn(*++t_wp)); 31049884Ssheldonh default: 311101923Smaxim return filstat(*++t_wp, n); 31249884Ssheldonh } 31349884Ssheldonh } 3141556Srgrimes 315297767Sjilles nn = t_lex(nargc > 0 ? t_wp[1] : NULL); 316297767Sjilles if (TOKEN_TYPE(nn) == BINOP) 317297767Sjilles return binop(nn); 31849884Ssheldonh 31949884Ssheldonh return strlen(*t_wp) > 0; 3201556Srgrimes} 3211556Srgrimes 3221556Srgrimesstatic int 323297767Sjillesbinop(enum token n) 3241556Srgrimes{ 325297766Sjilles const char *opnd1, *op, *opnd2; 3261556Srgrimes 32749884Ssheldonh opnd1 = *t_wp; 328297767Sjilles op = nargc > 0 ? (--nargc, *++t_wp) : NULL; 3291556Srgrimes 330101923Smaxim if ((opnd2 = nargc > 0 ? (--nargc, *++t_wp) : NULL) == NULL) 331297766Sjilles syntax(op, "argument expected"); 33249884Ssheldonh 333297766Sjilles switch (n) { 33449884Ssheldonh case STREQ: 33549884Ssheldonh return strcmp(opnd1, opnd2) == 0; 33649884Ssheldonh case STRNE: 33749884Ssheldonh return strcmp(opnd1, opnd2) != 0; 33849884Ssheldonh case STRLT: 33949884Ssheldonh return strcmp(opnd1, opnd2) < 0; 34049884Ssheldonh case STRGT: 34149884Ssheldonh return strcmp(opnd1, opnd2) > 0; 34249884Ssheldonh case INTEQ: 34362925Sse return intcmp(opnd1, opnd2) == 0; 34449884Ssheldonh case INTNE: 34562925Sse return intcmp(opnd1, opnd2) != 0; 34649884Ssheldonh case INTGE: 34762925Sse return intcmp(opnd1, opnd2) >= 0; 34849884Ssheldonh case INTGT: 34962925Sse return intcmp(opnd1, opnd2) > 0; 35049884Ssheldonh case INTLE: 35162925Sse return intcmp(opnd1, opnd2) <= 0; 35249884Ssheldonh case INTLT: 35362925Sse return intcmp(opnd1, opnd2) < 0; 354251208Sjilles case FILNT: 355251208Sjilles return newerf (opnd1, opnd2); 356251208Sjilles case FILOT: 357251208Sjilles return olderf (opnd1, opnd2); 35849884Ssheldonh case FILEQ: 35949884Ssheldonh return equalf (opnd1, opnd2); 36049884Ssheldonh default: 36149884Ssheldonh abort(); 36249884Ssheldonh /* NOTREACHED */ 3631556Srgrimes } 3641556Srgrimes} 3651556Srgrimes 36649884Ssheldonhstatic int 36790111Simpfilstat(char *nm, enum token mode) 3681556Srgrimes{ 36949884Ssheldonh struct stat s; 3701556Srgrimes 37149884Ssheldonh if (mode == FILSYM ? lstat(nm, &s) : stat(nm, &s)) 37249884Ssheldonh return 0; 3732664Scsgr 37449884Ssheldonh switch (mode) { 37549884Ssheldonh case FILRD: 37691737Smaxim return (eaccess(nm, R_OK) == 0); 37749884Ssheldonh case FILWR: 37891737Smaxim return (eaccess(nm, W_OK) == 0); 37949884Ssheldonh case FILEX: 38091737Smaxim /* XXX work around eaccess(2) false positives for superuser */ 38191737Smaxim if (eaccess(nm, X_OK) != 0) 38250087Sgreen return 0; 38391737Smaxim if (S_ISDIR(s.st_mode) || geteuid() != 0) 38450087Sgreen return 1; 38550087Sgreen return (s.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0; 38649884Ssheldonh case FILEXIST: 38791737Smaxim return (eaccess(nm, F_OK) == 0); 38849884Ssheldonh case FILREG: 38949884Ssheldonh return S_ISREG(s.st_mode); 39049884Ssheldonh case FILDIR: 39149884Ssheldonh return S_ISDIR(s.st_mode); 39249884Ssheldonh case FILCDEV: 39349884Ssheldonh return S_ISCHR(s.st_mode); 39449884Ssheldonh case FILBDEV: 39549884Ssheldonh return S_ISBLK(s.st_mode); 39649884Ssheldonh case FILFIFO: 39749884Ssheldonh return S_ISFIFO(s.st_mode); 39849884Ssheldonh case FILSOCK: 39949884Ssheldonh return S_ISSOCK(s.st_mode); 40049884Ssheldonh case FILSYM: 40149884Ssheldonh return S_ISLNK(s.st_mode); 40249884Ssheldonh case FILSUID: 40349884Ssheldonh return (s.st_mode & S_ISUID) != 0; 40449884Ssheldonh case FILSGID: 40549884Ssheldonh return (s.st_mode & S_ISGID) != 0; 40649884Ssheldonh case FILSTCK: 40749884Ssheldonh return (s.st_mode & S_ISVTX) != 0; 40849884Ssheldonh case FILGZ: 40949884Ssheldonh return s.st_size > (off_t)0; 41049884Ssheldonh case FILUID: 41149884Ssheldonh return s.st_uid == geteuid(); 41249884Ssheldonh case FILGID: 41349884Ssheldonh return s.st_gid == getegid(); 41449884Ssheldonh default: 41549884Ssheldonh return 1; 4162675Scsgr } 41749884Ssheldonh} 4182675Scsgr 41949884Ssheldonhstatic enum token 42090111Simpt_lex(char *s) 42149884Ssheldonh{ 42249884Ssheldonh struct t_op const *op = ops; 42349884Ssheldonh 42449884Ssheldonh if (s == 0) { 42549884Ssheldonh return EOI; 42649884Ssheldonh } 427227984Sjilles while (*op->op_text) { 42849884Ssheldonh if (strcmp(s, op->op_text) == 0) { 429297766Sjilles if (((TOKEN_TYPE(op->op_num) == UNOP || 430297766Sjilles TOKEN_TYPE(op->op_num) == BUNOP) 431192862Sjilles && isunopoperand()) || 432192862Sjilles (op->op_num == LPAREN && islparenoperand()) || 433192862Sjilles (op->op_num == RPAREN && isrparenoperand())) 43449884Ssheldonh break; 43549884Ssheldonh return op->op_num; 4361556Srgrimes } 43749884Ssheldonh op++; 4381556Srgrimes } 43949884Ssheldonh return OPERAND; 4401556Srgrimes} 4411556Srgrimes 44249884Ssheldonhstatic int 443192862Sjillesisunopoperand(void) 4441556Srgrimes{ 44549884Ssheldonh struct t_op const *op = ops; 44649884Ssheldonh char *s; 44749884Ssheldonh char *t; 4481556Srgrimes 449101923Smaxim if (nargc == 1) 45049884Ssheldonh return 1; 451192862Sjilles s = *(t_wp + 1); 452101923Smaxim if (nargc == 2) 453192862Sjilles return parenlevel == 1 && strcmp(s, ")") == 0; 454101923Smaxim t = *(t_wp + 2); 455227984Sjilles while (*op->op_text) { 45649884Ssheldonh if (strcmp(s, op->op_text) == 0) 457297766Sjilles return TOKEN_TYPE(op->op_num) == BINOP && 458192862Sjilles (parenlevel == 0 || t[0] != ')' || t[1] != '\0'); 45949884Ssheldonh op++; 46049884Ssheldonh } 46149884Ssheldonh return 0; 4621556Srgrimes} 4631556Srgrimes 464192862Sjillesstatic int 465192862Sjillesislparenoperand(void) 466192862Sjilles{ 467192862Sjilles struct t_op const *op = ops; 468192862Sjilles char *s; 469192862Sjilles 470192862Sjilles if (nargc == 1) 471192862Sjilles return 1; 472192862Sjilles s = *(t_wp + 1); 473192862Sjilles if (nargc == 2) 474192862Sjilles return parenlevel == 1 && strcmp(s, ")") == 0; 475192862Sjilles if (nargc != 3) 476192862Sjilles return 0; 477227984Sjilles while (*op->op_text) { 478192862Sjilles if (strcmp(s, op->op_text) == 0) 479297766Sjilles return TOKEN_TYPE(op->op_num) == BINOP; 480192862Sjilles op++; 481192862Sjilles } 482192862Sjilles return 0; 483192862Sjilles} 484192862Sjilles 485192862Sjillesstatic int 486192862Sjillesisrparenoperand(void) 487192862Sjilles{ 488192862Sjilles char *s; 489192862Sjilles 490192862Sjilles if (nargc == 1) 491192862Sjilles return 0; 492192862Sjilles s = *(t_wp + 1); 493192862Sjilles if (nargc == 2) 494192862Sjilles return parenlevel == 1 && strcmp(s, ")") == 0; 495192862Sjilles return 0; 496192862Sjilles} 497192862Sjilles 49849884Ssheldonh/* atoi with error detection */ 49949884Ssheldonhstatic int 50090111Simpgetn(const char *s) 5011556Srgrimes{ 50249884Ssheldonh char *p; 50349884Ssheldonh long r; 5041556Srgrimes 50549884Ssheldonh errno = 0; 50649884Ssheldonh r = strtol(s, &p, 10); 50749884Ssheldonh 50888084Sache if (s == p) 50988084Sache error("%s: bad number", s); 51088084Sache 51149884Ssheldonh if (errno != 0) 51287961Sache error((errno == EINVAL) ? "%s: bad number" : 51387961Sache "%s: out of range", s); 51449884Ssheldonh 51549884Ssheldonh while (isspace((unsigned char)*p)) 51686622Sknu p++; 51749884Ssheldonh 51849884Ssheldonh if (*p) 51986622Sknu error("%s: bad number", s); 52049884Ssheldonh 52149884Ssheldonh return (int) r; 5221556Srgrimes} 52349884Ssheldonh 52462925Sse/* atoi with error detection and 64 bit range */ 52593345Sachestatic intmax_t 52690111Simpgetq(const char *s) 52762925Sse{ 52862925Sse char *p; 52993345Sache intmax_t r; 53062925Sse 53162925Sse errno = 0; 53293345Sache r = strtoimax(s, &p, 10); 53362925Sse 53488084Sache if (s == p) 53588084Sache error("%s: bad number", s); 53688084Sache 53762925Sse if (errno != 0) 53887961Sache error((errno == EINVAL) ? "%s: bad number" : 53987961Sache "%s: out of range", s); 54062925Sse 54162925Sse while (isspace((unsigned char)*p)) 54286622Sknu p++; 54362925Sse 54462925Sse if (*p) 54586622Sknu error("%s: bad number", s); 54662925Sse 54762925Sse return r; 54862925Sse} 54962925Sse 55049884Ssheldonhstatic int 55190111Simpintcmp (const char *s1, const char *s2) 55262925Sse{ 55393345Sache intmax_t q1, q2; 55462925Sse 55562925Sse 55662925Sse q1 = getq(s1); 55762925Sse q2 = getq(s2); 55862925Sse 55962925Sse if (q1 > q2) 56062925Sse return 1; 56162925Sse 56262925Sse if (q1 < q2) 56362925Sse return -1; 56462925Sse 56562925Sse return 0; 56662925Sse} 56762925Sse 56862925Ssestatic int 569251208Sjillesnewerf (const char *f1, const char *f2) 57049884Ssheldonh{ 57149884Ssheldonh struct stat b1, b2; 57249884Ssheldonh 573100774Sdwmalone if (stat(f1, &b1) != 0 || stat(f2, &b2) != 0) 574100774Sdwmalone return 0; 575100774Sdwmalone 576251208Sjilles if (b1.st_mtim.tv_sec > b2.st_mtim.tv_sec) 577100774Sdwmalone return 1; 578251208Sjilles if (b1.st_mtim.tv_sec < b2.st_mtim.tv_sec) 579100774Sdwmalone return 0; 580100774Sdwmalone 581251208Sjilles return (b1.st_mtim.tv_nsec > b2.st_mtim.tv_nsec); 58249884Ssheldonh} 58349884Ssheldonh 58449884Ssheldonhstatic int 585251208Sjillesolderf (const char *f1, const char *f2) 586251208Sjilles{ 587251208Sjilles return (newerf(f2, f1)); 588251208Sjilles} 589251208Sjilles 590251208Sjillesstatic int 59190111Simpequalf (const char *f1, const char *f2) 59249884Ssheldonh{ 59349884Ssheldonh struct stat b1, b2; 59449884Ssheldonh 59549884Ssheldonh return (stat (f1, &b1) == 0 && 59649884Ssheldonh stat (f2, &b2) == 0 && 59749884Ssheldonh b1.st_dev == b2.st_dev && 59849884Ssheldonh b1.st_ino == b2.st_ino); 59949884Ssheldonh} 600