/contrib/tcsh/sh.exp.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 1057 lines · 840 code · 126 blank · 91 comment · 212 complexity · b6849cdfc95e90ffd701f2ae88e1214f MD5 · raw file

  1. /* $Header: /p/tcsh/cvsroot/tcsh/sh.exp.c,v 3.58 2011/12/25 15:21:50 christos Exp $ */
  2. /*
  3. * sh.exp.c: Expression evaluations
  4. */
  5. /*-
  6. * Copyright (c) 1980, 1991 The Regents of the University of California.
  7. * All rights reserved.
  8. *
  9. * Redistribution and use in source and binary forms, with or without
  10. * modification, are permitted provided that the following conditions
  11. * are met:
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. * 2. Redistributions in binary form must reproduce the above copyright
  15. * notice, this list of conditions and the following disclaimer in the
  16. * documentation and/or other materials provided with the distribution.
  17. * 3. Neither the name of the University nor the names of its contributors
  18. * may be used to endorse or promote products derived from this software
  19. * without specific prior written permission.
  20. *
  21. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31. * SUCH DAMAGE.
  32. */
  33. #include "sh.h"
  34. RCSID("$tcsh: sh.exp.c,v 3.58 2011/12/25 15:21:50 christos Exp $")
  35. #include "tw.h"
  36. /*
  37. * C shell
  38. */
  39. #define TEXP_IGNORE 1 /* in ignore, it means to ignore value, just parse */
  40. #define TEXP_NOGLOB 2 /* in ignore, it means not to globone */
  41. #define ADDOP 1
  42. #define MULOP 2
  43. #define EQOP 4
  44. #define RELOP 8
  45. #define RESTOP 16
  46. #define ANYOP 31
  47. #define EQEQ 1
  48. #define GTR 2
  49. #define LSS 4
  50. #define NOTEQ 6
  51. #define EQMATCH 7
  52. #define NOTEQMATCH 8
  53. static int sh_access (const Char *, int);
  54. static tcsh_number_t exp1 (Char ***, int);
  55. static tcsh_number_t exp2x (Char ***, int);
  56. static tcsh_number_t exp2a (Char ***, int);
  57. static tcsh_number_t exp2b (Char ***, int);
  58. static tcsh_number_t exp2c (Char ***, int);
  59. static Char *exp3 (Char ***, int);
  60. static Char *exp3a (Char ***, int);
  61. static Char *exp4 (Char ***, int);
  62. static Char *exp5 (Char ***, int);
  63. static Char *exp6 (Char ***, int);
  64. static void evalav (Char **);
  65. static int isa (Char *, int);
  66. static tcsh_number_t egetn (const Char *);
  67. #ifdef EDEBUG
  68. static void etracc (const char *, const Char *, Char ***);
  69. static void etraci (const char *, tcsh_number_t, Char ***);
  70. #else /* !EDEBUG */
  71. #define etracc(A, B, C) ((void)0)
  72. #define etraci(A, B, C) ((void)0)
  73. #endif /* !EDEBUG */
  74. /*
  75. * shell access function according to POSIX and non POSIX
  76. * From Beto Appleton (beto@aixwiz.aix.ibm.com)
  77. */
  78. static int
  79. sh_access(const Char *fname, int mode)
  80. {
  81. #if defined(POSIX) && !defined(USE_ACCESS)
  82. struct stat statb;
  83. #endif /* POSIX */
  84. char *name = short2str(fname);
  85. if (*name == '\0')
  86. return 1;
  87. #if !defined(POSIX) || defined(USE_ACCESS)
  88. return access(name, mode);
  89. #else /* POSIX */
  90. /*
  91. * POSIX 1003.2-d11.2
  92. * -r file True if file exists and is readable.
  93. * -w file True if file exists and is writable.
  94. * True shall indicate only that the write flag is on.
  95. * The file shall not be writable on a read-only file
  96. * system even if this test indicates true.
  97. * -x file True if file exists and is executable.
  98. * True shall indicate only that the execute flag is on.
  99. * If file is a directory, true indicates that the file
  100. * can be searched.
  101. */
  102. if (mode != W_OK && mode != X_OK)
  103. return access(name, mode);
  104. if (stat(name, &statb) == -1)
  105. return 1;
  106. if (access(name, mode) == 0) {
  107. #ifdef S_ISDIR
  108. if (S_ISDIR(statb.st_mode) && mode == X_OK)
  109. return 0;
  110. #endif /* S_ISDIR */
  111. /* root needs permission for someone */
  112. switch (mode) {
  113. case W_OK:
  114. mode = S_IWUSR | S_IWGRP | S_IWOTH;
  115. break;
  116. case X_OK:
  117. mode = S_IXUSR | S_IXGRP | S_IXOTH;
  118. break;
  119. default:
  120. abort();
  121. break;
  122. }
  123. }
  124. else if (euid == statb.st_uid)
  125. mode <<= 6;
  126. else if (egid == statb.st_gid)
  127. mode <<= 3;
  128. # ifdef NGROUPS_MAX
  129. else {
  130. /* you can be in several groups */
  131. long n;
  132. GETGROUPS_T *groups;
  133. /*
  134. * Try these things to find a positive maximum groups value:
  135. * 1) sysconf(_SC_NGROUPS_MAX)
  136. * 2) NGROUPS_MAX
  137. * 3) getgroups(0, unused)
  138. * Then allocate and scan the groups array if one of these worked.
  139. */
  140. # if defined (HAVE_SYSCONF) && defined (_SC_NGROUPS_MAX)
  141. if ((n = sysconf(_SC_NGROUPS_MAX)) == -1)
  142. # endif /* _SC_NGROUPS_MAX */
  143. n = NGROUPS_MAX;
  144. if (n <= 0)
  145. n = getgroups(0, (GETGROUPS_T *) NULL);
  146. if (n > 0) {
  147. groups = xmalloc(n * sizeof(*groups));
  148. n = getgroups((int) n, groups);
  149. while (--n >= 0)
  150. if (groups[n] == statb.st_gid) {
  151. mode <<= 3;
  152. break;
  153. }
  154. }
  155. }
  156. # endif /* NGROUPS_MAX */
  157. if (statb.st_mode & mode)
  158. return 0;
  159. else
  160. return 1;
  161. #endif /* !POSIX */
  162. }
  163. tcsh_number_t
  164. expr(Char ***vp)
  165. {
  166. return (exp0(vp, 0));
  167. }
  168. tcsh_number_t
  169. exp0(Char ***vp, int ignore)
  170. {
  171. tcsh_number_t p1 = exp1(vp, ignore);
  172. etraci("exp0 p1", p1, vp);
  173. while (**vp && eq(**vp, STRor2)) {
  174. int p2;
  175. (*vp)++;
  176. p2 = compat_expr ?
  177. exp0(vp, (ignore & TEXP_IGNORE) || p1) :
  178. exp1(vp, (ignore & TEXP_IGNORE) || p1);
  179. if (compat_expr || !(ignore & TEXP_IGNORE))
  180. p1 = (p1 || p2);
  181. etraci("exp0 p1", p1, vp);
  182. if (compat_expr)
  183. break;
  184. }
  185. return (p1);
  186. }
  187. static tcsh_number_t
  188. exp1(Char ***vp, int ignore)
  189. {
  190. tcsh_number_t p1 = exp2x(vp, ignore);
  191. etraci("exp1 p1", p1, vp);
  192. while (**vp && eq(**vp, STRand2)) {
  193. tcsh_number_t p2;
  194. (*vp)++;
  195. p2 = compat_expr ?
  196. exp1(vp, (ignore & TEXP_IGNORE) || !p1) :
  197. exp2x(vp, (ignore & TEXP_IGNORE) || !p1);
  198. etraci("exp1 p2", p2, vp);
  199. if (compat_expr || !(ignore & TEXP_IGNORE))
  200. p1 = (p1 && p2);
  201. etraci("exp1 p1", p1, vp);
  202. if (compat_expr)
  203. break;
  204. }
  205. return (p1);
  206. }
  207. static tcsh_number_t
  208. exp2x(Char ***vp, int ignore)
  209. {
  210. tcsh_number_t p1 = exp2a(vp, ignore);
  211. etraci("exp2x p1", p1, vp);
  212. while (**vp && eq(**vp, STRor)) {
  213. tcsh_number_t p2;
  214. (*vp)++;
  215. p2 = compat_expr ?
  216. exp2x(vp, ignore) :
  217. exp2a(vp, ignore);
  218. etraci("exp2x p2", p2, vp);
  219. if (compat_expr || !(ignore & TEXP_IGNORE))
  220. p1 = (p1 | p2);
  221. etraci("exp2x p1", p1, vp);
  222. if (compat_expr)
  223. break;
  224. }
  225. return (p1);
  226. }
  227. static tcsh_number_t
  228. exp2a(Char ***vp, int ignore)
  229. {
  230. tcsh_number_t p1 = exp2b(vp, ignore);
  231. etraci("exp2a p1", p1, vp);
  232. while (**vp && eq(**vp, STRcaret)) {
  233. tcsh_number_t p2;
  234. (*vp)++;
  235. p2 = compat_expr ?
  236. exp2a(vp, ignore) :
  237. exp2b(vp, ignore);
  238. etraci("exp2a p2", p2, vp);
  239. if (compat_expr || !(ignore & TEXP_IGNORE))
  240. p1 = (p1 ^ p2);
  241. etraci("exp2a p1", p1, vp);
  242. if (compat_expr)
  243. break;
  244. }
  245. return (p1);
  246. }
  247. static tcsh_number_t
  248. exp2b(Char ***vp, int ignore)
  249. {
  250. tcsh_number_t p1 = exp2c(vp, ignore);
  251. etraci("exp2b p1", p1, vp);
  252. while (**vp && eq(**vp, STRand)) {
  253. tcsh_number_t p2;
  254. (*vp)++;
  255. p2 = compat_expr ?
  256. exp2b(vp, ignore) :
  257. exp2c(vp, ignore);
  258. etraci("exp2b p2", p2, vp);
  259. if (compat_expr || !(ignore & TEXP_IGNORE))
  260. p1 = (p1 & p2);
  261. etraci("exp2b p1", p1, vp);
  262. if (compat_expr)
  263. break;
  264. }
  265. return (p1);
  266. }
  267. static tcsh_number_t
  268. exp2c(Char ***vp, int ignore)
  269. {
  270. Char *p1 = exp3(vp, ignore);
  271. Char *p2;
  272. tcsh_number_t i;
  273. cleanup_push(p1, xfree);
  274. etracc("exp2c p1", p1, vp);
  275. if ((i = isa(**vp, EQOP)) != 0) {
  276. (*vp)++;
  277. if (i == EQMATCH || i == NOTEQMATCH)
  278. ignore |= TEXP_NOGLOB;
  279. p2 = exp3(vp, ignore);
  280. cleanup_push(p2, xfree);
  281. etracc("exp2c p2", p2, vp);
  282. if (!(ignore & TEXP_IGNORE))
  283. switch (i) {
  284. case EQEQ:
  285. i = eq(p1, p2);
  286. break;
  287. case NOTEQ:
  288. i = !eq(p1, p2);
  289. break;
  290. case EQMATCH:
  291. i = Gmatch(p1, p2);
  292. break;
  293. case NOTEQMATCH:
  294. i = !Gmatch(p1, p2);
  295. break;
  296. }
  297. cleanup_until(p1);
  298. return (i);
  299. }
  300. i = egetn(p1);
  301. cleanup_until(p1);
  302. return (i);
  303. }
  304. static Char *
  305. exp3(Char ***vp, int ignore)
  306. {
  307. Char *p1, *p2;
  308. tcsh_number_t i;
  309. p1 = exp3a(vp, ignore);
  310. etracc("exp3 p1", p1, vp);
  311. while ((i = isa(**vp, RELOP)) != 0) {
  312. (*vp)++;
  313. if (**vp && eq(**vp, STRequal))
  314. i |= 1, (*vp)++;
  315. cleanup_push(p1, xfree);
  316. p2 = compat_expr ?
  317. exp3(vp, ignore) :
  318. exp3a(vp, ignore);
  319. cleanup_push(p2, xfree);
  320. etracc("exp3 p2", p2, vp);
  321. if (!(ignore & TEXP_IGNORE))
  322. switch (i) {
  323. case GTR:
  324. i = egetn(p1) > egetn(p2);
  325. break;
  326. case GTR | 1:
  327. i = egetn(p1) >= egetn(p2);
  328. break;
  329. case LSS:
  330. i = egetn(p1) < egetn(p2);
  331. break;
  332. case LSS | 1:
  333. i = egetn(p1) <= egetn(p2);
  334. break;
  335. }
  336. cleanup_until(p1);
  337. p1 = putn(i);
  338. etracc("exp3 p1", p1, vp);
  339. if (compat_expr)
  340. break;
  341. }
  342. return (p1);
  343. }
  344. static Char *
  345. exp3a(Char ***vp, int ignore)
  346. {
  347. Char *p1, *p2;
  348. const Char *op;
  349. tcsh_number_t i;
  350. p1 = exp4(vp, ignore);
  351. etracc("exp3a p1", p1, vp);
  352. op = **vp;
  353. if (op && any("<>", op[0]) && op[0] == op[1]) {
  354. (*vp)++;
  355. cleanup_push(p1, xfree);
  356. p2 = compat_expr ?
  357. exp3a(vp, ignore) :
  358. exp4(vp, ignore);
  359. cleanup_push(p2, xfree);
  360. etracc("exp3a p2", p2, vp);
  361. if (op[0] == '<')
  362. i = egetn(p1) << egetn(p2);
  363. else
  364. i = egetn(p1) >> egetn(p2);
  365. cleanup_until(p1);
  366. p1 = putn(i);
  367. etracc("exp3a p1", p1, vp);
  368. }
  369. return (p1);
  370. }
  371. static Char *
  372. exp4(Char ***vp, int ignore)
  373. {
  374. Char *p1, *p2;
  375. tcsh_number_t i = 0;
  376. p1 = exp5(vp, ignore);
  377. etracc("exp4 p1", p1, vp);
  378. while (isa(**vp, ADDOP)) {
  379. const Char *op = *(*vp)++;
  380. cleanup_push(p1, xfree);
  381. p2 = compat_expr ?
  382. exp4(vp, ignore) :
  383. exp5(vp, ignore);
  384. cleanup_push(p2, xfree);
  385. etracc("exp4 p2", p2, vp);
  386. if (!(ignore & TEXP_IGNORE))
  387. switch (op[0]) {
  388. case '+':
  389. i = egetn(p1) + egetn(p2);
  390. break;
  391. case '-':
  392. i = egetn(p1) - egetn(p2);
  393. break;
  394. }
  395. cleanup_until(p1);
  396. p1 = putn(i);
  397. etracc("exp4 p1", p1, vp);
  398. if (compat_expr)
  399. break;
  400. }
  401. return (p1);
  402. }
  403. static Char *
  404. exp5(Char ***vp, int ignore)
  405. {
  406. Char *p1, *p2;
  407. tcsh_number_t i = 0;
  408. p1 = exp6(vp, ignore);
  409. etracc("exp5 p1", p1, vp);
  410. while (isa(**vp, MULOP)) {
  411. const Char *op = *(*vp)++;
  412. if ((ignore & TEXP_NOGLOB) != 0) {
  413. /*
  414. * We are just trying to get the right side of
  415. * a =~ or !~ operator
  416. */
  417. xfree(p1);
  418. return Strsave(op);
  419. }
  420. cleanup_push(p1, xfree);
  421. p2 = compat_expr ?
  422. exp5(vp, ignore) :
  423. exp6(vp, ignore);
  424. cleanup_push(p2, xfree);
  425. etracc("exp5 p2", p2, vp);
  426. if (!(ignore & TEXP_IGNORE))
  427. switch (op[0]) {
  428. case '*':
  429. i = egetn(p1) * egetn(p2);
  430. break;
  431. case '/':
  432. i = egetn(p2);
  433. if (i == 0)
  434. stderror(ERR_DIV0);
  435. i = egetn(p1) / i;
  436. break;
  437. case '%':
  438. i = egetn(p2);
  439. if (i == 0)
  440. stderror(ERR_MOD0);
  441. i = egetn(p1) % i;
  442. break;
  443. }
  444. cleanup_until(p1);
  445. p1 = putn(i);
  446. etracc("exp5 p1", p1, vp);
  447. if (compat_expr)
  448. break;
  449. }
  450. return (p1);
  451. }
  452. static Char *
  453. exp6(Char ***vp, int ignore)
  454. {
  455. tcsh_number_t ccode;
  456. tcsh_number_t i = 0;
  457. Char *cp;
  458. if (**vp == 0)
  459. stderror(ERR_NAME | ERR_EXPRESSION);
  460. if (eq(**vp, STRbang)) {
  461. (*vp)++;
  462. cp = exp6(vp, ignore);
  463. cleanup_push(cp, xfree);
  464. etracc("exp6 ! cp", cp, vp);
  465. i = egetn(cp);
  466. cleanup_until(cp);
  467. return (putn(!i));
  468. }
  469. if (eq(**vp, STRtilde)) {
  470. (*vp)++;
  471. cp = exp6(vp, ignore);
  472. cleanup_push(cp, xfree);
  473. etracc("exp6 ~ cp", cp, vp);
  474. i = egetn(cp);
  475. cleanup_until(cp);
  476. return (putn(~i));
  477. }
  478. if (eq(**vp, STRLparen)) {
  479. (*vp)++;
  480. ccode = exp0(vp, ignore);
  481. etraci("exp6 () ccode", ccode, vp);
  482. if (**vp == 0 || ***vp != ')')
  483. stderror(ERR_NAME | ERR_EXPRESSION);
  484. (*vp)++;
  485. return (putn(ccode));
  486. }
  487. if (eq(**vp, STRLbrace)) {
  488. Char **v;
  489. struct command faket;
  490. Char *fakecom[2];
  491. faket.t_dtyp = NODE_COMMAND;
  492. faket.t_dflg = F_BACKQ;
  493. faket.t_dcar = faket.t_dcdr = faket.t_dspr = NULL;
  494. faket.t_dcom = fakecom;
  495. fakecom[0] = STRfakecom;
  496. fakecom[1] = NULL;
  497. (*vp)++;
  498. v = *vp;
  499. for (;;) {
  500. if (!**vp)
  501. stderror(ERR_NAME | ERR_MISSING, '}');
  502. if (eq(*(*vp)++, STRRbrace))
  503. break;
  504. }
  505. if (ignore & TEXP_IGNORE)
  506. return (Strsave(STRNULL));
  507. psavejob();
  508. cleanup_push(&faket, psavejob_cleanup); /* faket is only a marker */
  509. if (pfork(&faket, -1) == 0) {
  510. *--(*vp) = 0;
  511. evalav(v);
  512. exitstat();
  513. }
  514. pwait();
  515. cleanup_until(&faket);
  516. etraci("exp6 {} status", egetn(varval(STRstatus)), vp);
  517. return (putn(egetn(varval(STRstatus)) == 0));
  518. }
  519. if (isa(**vp, ANYOP))
  520. return (Strsave(STRNULL));
  521. cp = *(*vp)++;
  522. #ifdef convex
  523. # define FILETESTS "erwxfdzoplstSXLbcugkmKR"
  524. #else
  525. # define FILETESTS "erwxfdzoplstSXLbcugkmK"
  526. #endif /* convex */
  527. #define FILEVALS "ZAMCDIUGNFPL"
  528. if (*cp == '-' && (any(FILETESTS, cp[1]) || any(FILEVALS, cp[1])))
  529. return(filetest(cp, vp, ignore));
  530. etracc("exp6 default", cp, vp);
  531. return (ignore & TEXP_NOGLOB ? Strsave(cp) : globone(cp, G_APPEND));
  532. }
  533. /*
  534. * Extended file tests
  535. * From: John Rowe <rowe@excc.exeter.ac.uk>
  536. */
  537. Char *
  538. filetest(Char *cp, Char ***vp, int ignore)
  539. {
  540. #ifdef convex
  541. struct cvxstat stb, *st = NULL;
  542. # define TCSH_STAT stat64
  543. #else
  544. # define TCSH_STAT stat
  545. struct stat stb, *st = NULL;
  546. #endif /* convex */
  547. #ifdef S_IFLNK
  548. # ifdef convex
  549. struct cvxstat lstb, *lst = NULL;
  550. # define TCSH_LSTAT lstat64
  551. # else
  552. # define TCSH_LSTAT lstat
  553. struct stat lstb, *lst = NULL;
  554. # endif /* convex */
  555. char *filnam;
  556. #endif /* S_IFLNK */
  557. tcsh_number_t i = 0;
  558. unsigned pmask = 0xffff;
  559. int altout = 0;
  560. Char *ft = cp, *dp, *ep, *strdev, *strino, *strF, *str, valtest = '\0',
  561. *errval = STR0;
  562. char *string, string0[22 + MB_LEN_MAX + 1]; // space for 64 bit octal
  563. time_t footime;
  564. struct passwd *pw;
  565. struct group *gr;
  566. while(any(FILETESTS, *++ft))
  567. continue;
  568. if (!*ft && *(ft - 1) == 'L')
  569. --ft;
  570. if (any(FILEVALS, *ft)) {
  571. valtest = *ft++;
  572. /*
  573. * Value tests return '-1' on failure as 0 is
  574. * a legitimate value for many of them.
  575. * 'F' returns ':' for compatibility.
  576. */
  577. errval = valtest == 'F' ? STRcolon : STRminus1;
  578. if (valtest == 'P' && *ft >= '0' && *ft <= '7') {
  579. pmask = (char) *ft - '0';
  580. while ( *++ft >= '0' && *ft <= '7' )
  581. pmask = 8 * pmask + ((char) *ft - '0');
  582. }
  583. if (Strcmp(ft, STRcolon) == 0 && any("AMCUGP", valtest)) {
  584. altout = 1;
  585. ++ft;
  586. }
  587. }
  588. if (*ft || ft == cp + 1)
  589. stderror(ERR_NAME | ERR_FILEINQ);
  590. /*
  591. * Detect missing file names by checking for operator in the file name
  592. * position. However, if an operator name appears there, we must make
  593. * sure that there's no file by that name (e.g., "/") before announcing
  594. * an error. Even this check isn't quite right, since it doesn't take
  595. * globbing into account.
  596. */
  597. if (isa(**vp, ANYOP) && TCSH_STAT(short2str(**vp), &stb))
  598. stderror(ERR_NAME | ERR_FILENAME);
  599. dp = *(*vp)++;
  600. if (ignore & TEXP_IGNORE)
  601. return (Strsave(STRNULL));
  602. ep = globone(dp, G_APPEND);
  603. cleanup_push(ep, xfree);
  604. ft = &cp[1];
  605. do
  606. switch (*ft) {
  607. case 'r':
  608. i = !sh_access(ep, R_OK);
  609. break;
  610. case 'w':
  611. i = !sh_access(ep, W_OK);
  612. break;
  613. case 'x':
  614. i = !sh_access(ep, X_OK);
  615. break;
  616. case 'X': /* tcsh extension, name is an executable in the path
  617. * or a tcsh builtin command
  618. */
  619. i = find_cmd(ep, 0);
  620. break;
  621. case 't': /* SGI extension, true when file is a tty */
  622. i = isatty(atoi(short2str(ep)));
  623. break;
  624. default:
  625. #ifdef S_IFLNK
  626. if (tolower(*ft) == 'l') {
  627. /*
  628. * avoid convex compiler bug.
  629. */
  630. if (!lst) {
  631. lst = &lstb;
  632. if (TCSH_LSTAT(short2str(ep), lst) == -1) {
  633. cleanup_until(ep);
  634. return (Strsave(errval));
  635. }
  636. }
  637. if (*ft == 'L')
  638. st = lst;
  639. }
  640. else
  641. #endif /* S_IFLNK */
  642. /*
  643. * avoid convex compiler bug.
  644. */
  645. if (!st) {
  646. st = &stb;
  647. if (TCSH_STAT(short2str(ep), st) == -1) {
  648. cleanup_until(ep);
  649. return (Strsave(errval));
  650. }
  651. }
  652. switch (*ft) {
  653. case 'f':
  654. #ifdef S_ISREG
  655. i = S_ISREG(st->st_mode);
  656. #else /* !S_ISREG */
  657. i = 0;
  658. #endif /* S_ISREG */
  659. break;
  660. case 'd':
  661. #ifdef S_ISDIR
  662. i = S_ISDIR(st->st_mode);
  663. #else /* !S_ISDIR */
  664. i = 0;
  665. #endif /* S_ISDIR */
  666. break;
  667. case 'p':
  668. #ifdef S_ISFIFO
  669. i = S_ISFIFO(st->st_mode);
  670. #else /* !S_ISFIFO */
  671. i = 0;
  672. #endif /* S_ISFIFO */
  673. break;
  674. case 'm' :
  675. #ifdef S_ISOFL
  676. i = S_ISOFL(st->st_dm_mode);
  677. #else /* !S_ISOFL */
  678. i = 0;
  679. #endif /* S_ISOFL */
  680. break ;
  681. case 'K' :
  682. #ifdef S_ISOFL
  683. i = stb.st_dm_key;
  684. #else /* !S_ISOFL */
  685. i = 0;
  686. #endif /* S_ISOFL */
  687. break ;
  688. case 'l':
  689. #ifdef S_ISLNK
  690. i = S_ISLNK(lst->st_mode);
  691. #else /* !S_ISLNK */
  692. i = 0;
  693. #endif /* S_ISLNK */
  694. break;
  695. case 'S':
  696. # ifdef S_ISSOCK
  697. i = S_ISSOCK(st->st_mode);
  698. # else /* !S_ISSOCK */
  699. i = 0;
  700. # endif /* S_ISSOCK */
  701. break;
  702. case 'b':
  703. #ifdef S_ISBLK
  704. i = S_ISBLK(st->st_mode);
  705. #else /* !S_ISBLK */
  706. i = 0;
  707. #endif /* S_ISBLK */
  708. break;
  709. case 'c':
  710. #ifdef S_ISCHR
  711. i = S_ISCHR(st->st_mode);
  712. #else /* !S_ISCHR */
  713. i = 0;
  714. #endif /* S_ISCHR */
  715. break;
  716. case 'u':
  717. i = (S_ISUID & st->st_mode) != 0;
  718. break;
  719. case 'g':
  720. i = (S_ISGID & st->st_mode) != 0;
  721. break;
  722. case 'k':
  723. i = (S_ISVTX & st->st_mode) != 0;
  724. break;
  725. case 'z':
  726. i = st->st_size == 0;
  727. break;
  728. #ifdef convex
  729. case 'R':
  730. i = (stb.st_dmonflags & IMIGRATED) == IMIGRATED;
  731. break;
  732. #endif /* convex */
  733. case 's':
  734. i = stb.st_size != 0;
  735. break;
  736. case 'e':
  737. i = 1;
  738. break;
  739. case 'o':
  740. i = st->st_uid == uid;
  741. break;
  742. /*
  743. * Value operators are a tcsh extension.
  744. */
  745. case 'D':
  746. i = (tcsh_number_t) st->st_dev;
  747. break;
  748. case 'I':
  749. i = (tcsh_number_t) st->st_ino;
  750. break;
  751. case 'F':
  752. strdev = putn( (int) st->st_dev);
  753. strino = putn( (int) st->st_ino);
  754. strF = xmalloc((2 + Strlen(strdev) + Strlen(strino))
  755. * sizeof(Char));
  756. (void) Strcat(Strcat(Strcpy(strF, strdev), STRcolon), strino);
  757. xfree(strdev);
  758. xfree(strino);
  759. cleanup_until(ep);
  760. return(strF);
  761. case 'L':
  762. if ( *(ft + 1) ) {
  763. i = 1;
  764. break;
  765. }
  766. #ifdef S_ISLNK
  767. filnam = short2str(ep);
  768. string = areadlink(filnam);
  769. strF = string == NULL ? errval : str2short(string);
  770. xfree(string);
  771. cleanup_until(ep);
  772. return(Strsave(strF));
  773. #else /* !S_ISLNK */
  774. i = 0;
  775. break;
  776. #endif /* S_ISLNK */
  777. case 'N':
  778. i = (tcsh_number_t) st->st_nlink;
  779. break;
  780. case 'P':
  781. string = string0 + 1;
  782. (void) xsnprintf(string, sizeof(string0) - 1, "%o",
  783. pmask & (unsigned int)
  784. ((S_IRWXU|S_IRWXG|S_IRWXO|S_ISUID|S_ISGID) & st->st_mode));
  785. if (altout && *string != '0')
  786. *--string = '0';
  787. cleanup_until(ep);
  788. return(Strsave(str2short(string)));
  789. case 'U':
  790. if (altout && (pw = xgetpwuid(st->st_uid))) {
  791. cleanup_until(ep);
  792. return(Strsave(str2short(pw->pw_name)));
  793. }
  794. i = (tcsh_number_t) st->st_uid;
  795. break;
  796. case 'G':
  797. if (altout && (gr = xgetgrgid(st->st_gid))) {
  798. cleanup_until(ep);
  799. return(Strsave(str2short(gr->gr_name)));
  800. }
  801. i = (tcsh_number_t) st->st_gid;
  802. break;
  803. case 'Z':
  804. i = (tcsh_number_t) st->st_size;
  805. break;
  806. case 'A': case 'M': case 'C':
  807. footime = *ft == 'A' ? st->st_atime :
  808. *ft == 'M' ? st->st_mtime : st->st_ctime;
  809. if (altout) {
  810. strF = str2short(ctime(&footime));
  811. if ((str = Strchr(strF, '\n')) != NULL)
  812. *str = (Char) '\0';
  813. cleanup_until(ep);
  814. return(Strsave(strF));
  815. }
  816. i = (tcsh_number_t) footime;
  817. break;
  818. }
  819. }
  820. while (*++ft && i);
  821. etraci("exp6 -? i", i, vp);
  822. cleanup_until(ep);
  823. return (putn(i));
  824. }
  825. static void
  826. evalav(Char **v)
  827. {
  828. struct wordent paraml1;
  829. struct wordent *hp = &paraml1;
  830. struct command *t;
  831. struct wordent *wdp = hp;
  832. setcopy(STRstatus, STR0, VAR_READWRITE);
  833. hp->prev = hp->next = hp;
  834. hp->word = STRNULL;
  835. while (*v) {
  836. struct wordent *new = xcalloc(1, sizeof *wdp);
  837. new->prev = wdp;
  838. new->next = hp;
  839. wdp->next = new;
  840. wdp = new;
  841. wdp->word = Strsave(*v++);
  842. }
  843. hp->prev = wdp;
  844. cleanup_push(&paraml1, lex_cleanup);
  845. alias(&paraml1);
  846. t = syntax(paraml1.next, &paraml1, 0);
  847. cleanup_push(t, syntax_cleanup);
  848. if (seterr)
  849. stderror(ERR_OLD);
  850. execute(t, -1, NULL, NULL, TRUE);
  851. cleanup_until(&paraml1);
  852. }
  853. static int
  854. isa(Char *cp, int what)
  855. {
  856. if (cp == 0)
  857. return ((what & RESTOP) != 0);
  858. if (*cp == '\0')
  859. return 0;
  860. if (cp[1] == 0) {
  861. if (what & ADDOP && (*cp == '+' || *cp == '-'))
  862. return (1);
  863. if (what & MULOP && (*cp == '*' || *cp == '/' || *cp == '%'))
  864. return (1);
  865. if (what & RESTOP && (*cp == '(' || *cp == ')' || *cp == '!' ||
  866. *cp == '~' || *cp == '^' || *cp == '"'))
  867. return (1);
  868. }
  869. else if (cp[2] == 0) {
  870. if (what & RESTOP) {
  871. if (cp[0] == '|' && cp[1] == '&')
  872. return (1);
  873. if (cp[0] == '<' && cp[1] == '<')
  874. return (1);
  875. if (cp[0] == '>' && cp[1] == '>')
  876. return (1);
  877. }
  878. if (what & EQOP) {
  879. if (cp[0] == '=') {
  880. if (cp[1] == '=')
  881. return (EQEQ);
  882. if (cp[1] == '~')
  883. return (EQMATCH);
  884. }
  885. else if (cp[0] == '!') {
  886. if (cp[1] == '=')
  887. return (NOTEQ);
  888. if (cp[1] == '~')
  889. return (NOTEQMATCH);
  890. }
  891. }
  892. }
  893. if (what & RELOP) {
  894. if (*cp == '<')
  895. return (LSS);
  896. if (*cp == '>')
  897. return (GTR);
  898. }
  899. return (0);
  900. }
  901. static tcsh_number_t
  902. egetn(const Char *cp)
  903. {
  904. if (*cp && *cp != '-' && !Isdigit(*cp))
  905. stderror(ERR_NAME | ERR_EXPRESSION);
  906. return (getn(cp));
  907. }
  908. /* Phew! */
  909. #ifdef EDEBUG
  910. static void
  911. etraci(const char *str, tcsh_number_t i, Char ***vp)
  912. {
  913. #ifdef HAVE_LONG_LONG
  914. xprintf("%s=%lld\t", str, i);
  915. #else
  916. xprintf("%s=%ld\t", str, i);
  917. #endif
  918. blkpr(*vp);
  919. xputchar('\n');
  920. }
  921. static void
  922. etracc(const char *str, const Char *cp, Char ***vp)
  923. {
  924. xprintf("%s=%S\t", str, cp);
  925. blkpr(*vp);
  926. xputchar('\n');
  927. }
  928. #endif /* EDEBUG */