PageRenderTime 57ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/usr/src/cmd/sh/macro.c

https://github.com/richlowe/illumos-gate
C | 629 lines | 526 code | 29 blank | 74 comment | 200 complexity | eb90c5e48907d6883e4a22f490faaccc MD5 | raw file
  1. /*
  2. * CDDL HEADER START
  3. *
  4. * The contents of this file are subject to the terms of the
  5. * Common Development and Distribution License (the "License").
  6. * You may not use this file except in compliance with the License.
  7. *
  8. * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  9. * or http://www.opensolaris.org/os/licensing.
  10. * See the License for the specific language governing permissions
  11. * and limitations under the License.
  12. *
  13. * When distributing Covered Code, include this CDDL HEADER in each
  14. * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15. * If applicable, add the following below this CDDL HEADER, with the
  16. * fields enclosed by brackets "[]" replaced with your own identifying
  17. * information: Portions Copyright [yyyy] [name of copyright owner]
  18. *
  19. * CDDL HEADER END
  20. */
  21. /*
  22. * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
  23. * Use is subject to license terms.
  24. */
  25. /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
  26. /* All Rights Reserved */
  27. #pragma ident "%Z%%M% %I% %E% SMI"
  28. /*
  29. * UNIX shell
  30. */
  31. #include "defs.h"
  32. #include "sym.h"
  33. #include <wait.h>
  34. static unsigned char quote; /* used locally */
  35. static unsigned char quoted; /* used locally */
  36. static int getch();
  37. static void comsubst(int);
  38. static void flush(int);
  39. static void
  40. copyto(unsigned char endch, int trimflag)
  41. /* trimflag - flag to check if argument will be trimmed */
  42. {
  43. unsigned int c;
  44. unsigned int d;
  45. unsigned char *pc;
  46. while ((c = getch(endch, trimflag)) != endch && c)
  47. if (quote) {
  48. if(c == '\\') { /* don't interpret next character */
  49. if (staktop >= brkend)
  50. growstak(staktop);
  51. pushstak(c);
  52. d = readwc();
  53. if(!escchar(d)) { /* both \ and following
  54. character are quoted if next
  55. character is not $, `, ", or \*/
  56. if (staktop >= brkend)
  57. growstak(staktop);
  58. pushstak('\\');
  59. if (staktop >= brkend)
  60. growstak(staktop);
  61. pushstak('\\');
  62. pc = readw(d);
  63. /* push entire multibyte char */
  64. while(*pc) {
  65. if (staktop >= brkend)
  66. growstak(staktop);
  67. pushstak(*pc++);
  68. }
  69. } else {
  70. pc = readw(d);
  71. /* d might be NULL */
  72. /* Evenif d is NULL, we have to save it */
  73. if (*pc) {
  74. while (*pc) {
  75. if (staktop >= brkend)
  76. growstak(staktop);
  77. pushstak(*pc++);
  78. }
  79. } else {
  80. if (staktop >= brkend)
  81. growstak(staktop);
  82. pushstak(*pc);
  83. }
  84. }
  85. } else { /* push escapes onto stack to quote characters */
  86. pc = readw(c);
  87. if (staktop >= brkend)
  88. growstak(staktop);
  89. pushstak('\\');
  90. while(*pc) {
  91. if (staktop >= brkend)
  92. growstak(staktop);
  93. pushstak(*pc++);
  94. }
  95. }
  96. } else if(c == '\\') {
  97. c = readwc(); /* get character to be escaped */
  98. if (staktop >= brkend)
  99. growstak(staktop);
  100. pushstak('\\');
  101. pc = readw(c);
  102. /* c might be NULL */
  103. /* Evenif c is NULL, we have to save it */
  104. if (*pc) {
  105. while (*pc) {
  106. if (staktop >= brkend)
  107. growstak(staktop);
  108. pushstak(*pc++);
  109. }
  110. } else {
  111. if (staktop >= brkend)
  112. growstak(staktop);
  113. pushstak(*pc);
  114. }
  115. } else {
  116. pc = readw(c);
  117. while (*pc) {
  118. if (staktop >= brkend)
  119. growstak(staktop);
  120. pushstak(*pc++);
  121. }
  122. }
  123. if (staktop >= brkend)
  124. growstak(staktop);
  125. zerostak();
  126. if (c != endch)
  127. error(badsub);
  128. }
  129. static void
  130. skipto(unsigned char endch)
  131. {
  132. /*
  133. * skip chars up to }
  134. */
  135. unsigned int c;
  136. while ((c = readwc()) && c != endch)
  137. {
  138. switch (c)
  139. {
  140. case SQUOTE:
  141. skipto(SQUOTE);
  142. break;
  143. case DQUOTE:
  144. skipto(DQUOTE);
  145. break;
  146. case DOLLAR:
  147. if (readwc() == BRACE)
  148. skipto('}');
  149. }
  150. }
  151. if (c != endch)
  152. error(badsub);
  153. }
  154. static
  155. int getch(endch, trimflag)
  156. unsigned char endch;
  157. int trimflag; /* flag to check if an argument is going to be trimmed, here document
  158. output is never trimmed
  159. */
  160. {
  161. unsigned int d;
  162. int atflag; /* flag to check if $@ has already been seen within double
  163. quotes */
  164. retry:
  165. d = readwc();
  166. if (!subchar(d))
  167. return(d);
  168. if (d == DOLLAR)
  169. {
  170. unsigned int c;
  171. if ((c = readwc(), dolchar(c)))
  172. {
  173. struct namnod *n = (struct namnod *)NIL;
  174. int dolg = 0;
  175. BOOL bra;
  176. BOOL nulflg;
  177. unsigned char *argp, *v;
  178. unsigned char idb[2];
  179. unsigned char *id = idb;
  180. if (bra = (c == BRACE))
  181. c = readwc();
  182. if (letter(c))
  183. {
  184. argp = (unsigned char *)relstak();
  185. while (alphanum(c))
  186. {
  187. if (staktop >= brkend)
  188. growstak(staktop);
  189. pushstak(c);
  190. c = readwc();
  191. }
  192. if (staktop >= brkend)
  193. growstak(staktop);
  194. zerostak();
  195. n = lookup(absstak(argp));
  196. setstak(argp);
  197. if (n->namflg & N_FUNCTN)
  198. error(badsub);
  199. v = n->namval;
  200. id = (unsigned char *)n->namid;
  201. peekc = c | MARK;
  202. }
  203. else if (digchar(c))
  204. {
  205. *id = c;
  206. idb[1] = 0;
  207. if (astchar(c))
  208. {
  209. if(c == '@' && !atflag && quote) {
  210. quoted--;
  211. atflag = 1;
  212. }
  213. dolg = 1;
  214. c = '1';
  215. }
  216. c -= '0';
  217. v = ((c == 0) ? cmdadr : ((int)c <= dolc) ? dolv[c] : (unsigned char *)(dolg = 0));
  218. }
  219. else if (c == '$')
  220. v = pidadr;
  221. else if (c == '!')
  222. v = pcsadr;
  223. else if (c == '#')
  224. {
  225. itos(dolc);
  226. v = numbuf;
  227. }
  228. else if (c == '?')
  229. {
  230. itos(retval);
  231. v = numbuf;
  232. }
  233. else if (c == '-')
  234. v = flagadr;
  235. else if (bra)
  236. error(badsub);
  237. else
  238. goto retry;
  239. c = readwc();
  240. if (c == ':' && bra) /* null and unset fix */
  241. {
  242. nulflg = 1;
  243. c = readwc();
  244. }
  245. else
  246. nulflg = 0;
  247. if (!defchar(c) && bra)
  248. error(badsub);
  249. argp = 0;
  250. if (bra)
  251. {
  252. if (c != '}')
  253. {
  254. argp = (unsigned char *)relstak();
  255. if ((v == 0 || (nulflg && *v == 0)) ^ (setchar(c)))
  256. copyto('}', trimflag);
  257. else
  258. skipto('}');
  259. argp = absstak(argp);
  260. }
  261. }
  262. else
  263. {
  264. peekc = c | MARK;
  265. c = 0;
  266. }
  267. if (v && (!nulflg || *v))
  268. {
  269. if (c != '+')
  270. {
  271. for (;;)
  272. {
  273. if (*v == 0 && quote) {
  274. if (staktop >= brkend)
  275. growstak(staktop);
  276. pushstak('\\');
  277. if (staktop >= brkend)
  278. growstak(staktop);
  279. pushstak('\0');
  280. } else {
  281. while (c = *v) {
  282. wchar_t wc;
  283. int length;
  284. if ((length = mbtowc(&wc, (char *)v, MB_LEN_MAX)) <= 0)
  285. length = 1;
  286. if(quote || (c == '\\' && trimflag)) {
  287. if (staktop >= brkend)
  288. growstak(staktop);
  289. pushstak('\\');
  290. }
  291. while(length-- > 0) {
  292. if (staktop >= brkend)
  293. growstak(staktop);
  294. pushstak(*v++);
  295. }
  296. }
  297. }
  298. if (dolg == 0 || (++dolg > dolc))
  299. break;
  300. else /* $* and $@ expansion */
  301. {
  302. v = dolv[dolg];
  303. if(*id == '*' && quote) {
  304. /* push quoted space so that " $* " will not be broken into separate arguments */
  305. if (staktop >= brkend)
  306. growstak(staktop);
  307. pushstak('\\');
  308. }
  309. if (staktop >= brkend)
  310. growstak(staktop);
  311. pushstak(' ');
  312. }
  313. }
  314. }
  315. }
  316. else if (argp)
  317. {
  318. if (c == '?') {
  319. if(trimflag)
  320. trim(argp);
  321. failed(id, *argp ? (const char *)argp :
  322. badparam);
  323. }
  324. else if (c == '=')
  325. {
  326. if (n)
  327. {
  328. int strlngth = staktop - stakbot;
  329. unsigned char *savptr = fixstak();
  330. unsigned char *newargp;
  331. /*
  332. * copy word onto stack, trim it, and then
  333. * do assignment
  334. */
  335. usestak();
  336. while(c = *argp) {
  337. wchar_t wc;
  338. int len;
  339. if ((len = mbtowc(&wc, (char *)argp, MB_LEN_MAX)) <= 0)
  340. len = 1;
  341. if(c == '\\' && trimflag) {
  342. argp++;
  343. if (*argp == 0) {
  344. argp++;
  345. continue;
  346. }
  347. if ((len = mbtowc(&wc, (char *)argp, MB_LEN_MAX)) <= 0)
  348. len = 1;
  349. }
  350. while(len-- > 0) {
  351. if (staktop >= brkend)
  352. growstak(staktop);
  353. pushstak(*argp++);
  354. }
  355. }
  356. newargp = fixstak();
  357. assign(n, newargp);
  358. tdystak(savptr);
  359. (void) memcpystak(stakbot, savptr, strlngth);
  360. staktop = stakbot + strlngth;
  361. }
  362. else
  363. error(badsub);
  364. }
  365. }
  366. else if (flags & setflg)
  367. failed(id, unset);
  368. goto retry;
  369. }
  370. else
  371. peekc = c | MARK;
  372. }
  373. else if (d == endch)
  374. return(d);
  375. else if (d == SQUOTE)
  376. {
  377. comsubst(trimflag);
  378. goto retry;
  379. }
  380. else if (d == DQUOTE && trimflag)
  381. {
  382. if(!quote) {
  383. atflag = 0;
  384. quoted++;
  385. }
  386. quote ^= QUOTE;
  387. goto retry;
  388. }
  389. return(d);
  390. }
  391. unsigned char *
  392. macro(as)
  393. unsigned char *as;
  394. {
  395. /*
  396. * Strip "" and do $ substitution
  397. * Leaves result on top of stack
  398. */
  399. BOOL savqu = quoted;
  400. unsigned char savq = quote;
  401. struct filehdr fb;
  402. push(&fb);
  403. estabf(as);
  404. usestak();
  405. quote = 0;
  406. quoted = 0;
  407. copyto(0, 1);
  408. pop();
  409. if (quoted && (stakbot == staktop)) {
  410. if (staktop >= brkend)
  411. growstak(staktop);
  412. pushstak('\\');
  413. if (staktop >= brkend)
  414. growstak(staktop);
  415. pushstak('\0');
  416. /*
  417. * above is the fix for *'.c' bug
  418. */
  419. }
  420. quote = savq;
  421. quoted = savqu;
  422. return(fixstak());
  423. }
  424. /* Save file descriptor for command substitution */
  425. int savpipe = -1;
  426. static void
  427. comsubst(int trimflag)
  428. /* trimflag - used to determine if argument will later be trimmed */
  429. {
  430. /*
  431. * command substn
  432. */
  433. struct fileblk cb;
  434. unsigned int d;
  435. int strlngth = staktop - stakbot;
  436. unsigned char *oldstaktop;
  437. unsigned char *savptr = fixstak();
  438. unsigned char *pc;
  439. usestak();
  440. while ((d = readwc()) != SQUOTE && d) {
  441. if(d == '\\') {
  442. d = readwc();
  443. if(!escchar(d) || (d == '"' && !quote)) {
  444. /* trim quotes for `, \, or " if command substitution is within
  445. double quotes */
  446. if (staktop >= brkend)
  447. growstak(staktop);
  448. pushstak('\\');
  449. }
  450. }
  451. pc = readw(d);
  452. /* d might be NULL */
  453. if (*pc) {
  454. while (*pc) {
  455. if (staktop >= brkend)
  456. growstak(staktop);
  457. pushstak(*pc++);
  458. }
  459. } else {
  460. if (staktop >= brkend)
  461. growstak(staktop);
  462. pushstak(*pc);
  463. }
  464. }
  465. {
  466. unsigned char *argc;
  467. argc = fixstak();
  468. push(&cb);
  469. estabf(argc); /* read from string */
  470. }
  471. {
  472. struct trenod *t;
  473. int pv[2];
  474. /*
  475. * this is done like this so that the pipe
  476. * is open only when needed
  477. */
  478. t = makefork(FPOU, cmd(EOFSYM, MTFLG | NLFLG ));
  479. chkpipe(pv);
  480. savpipe = pv[OTPIPE];
  481. initf(pv[INPIPE]); /* read from pipe */
  482. execute(t, XEC_NOSTOP, (int)(flags & errflg), 0, pv);
  483. close(pv[OTPIPE]);
  484. savpipe = -1;
  485. }
  486. tdystak(savptr);
  487. (void) memcpystak(stakbot, savptr, strlngth);
  488. oldstaktop = staktop = stakbot + strlngth;
  489. while (d = readwc()) {
  490. if(quote || (d == '\\' && trimflag)) {
  491. unsigned char *rest;
  492. /* quote output from command subst. if within double
  493. quotes or backslash part of output */
  494. rest = readw(d);
  495. if (staktop >= brkend)
  496. growstak(staktop);
  497. pushstak('\\');
  498. while(d = *rest++) {
  499. /* Pick up all of multibyte character */
  500. if (staktop >= brkend)
  501. growstak(staktop);
  502. pushstak(d);
  503. }
  504. }
  505. else {
  506. pc = readw(d);
  507. while (*pc) {
  508. if (staktop >= brkend)
  509. growstak(staktop);
  510. pushstak(*pc++);
  511. }
  512. }
  513. }
  514. {
  515. extern pid_t parent;
  516. int stat;
  517. int rc;
  518. int ret = 0;
  519. while ((ret = waitpid(parent,&stat,0)) != parent) {
  520. /* break out if waitpid(2) has failed */
  521. if (ret == -1)
  522. break;
  523. }
  524. if (WIFEXITED(stat))
  525. rc = WEXITSTATUS(stat);
  526. else
  527. rc = (WTERMSIG(stat) | SIGFLG);
  528. if (rc && (flags & errflg))
  529. exitsh(rc);
  530. exitval = rc;
  531. flags |= eflag;
  532. exitset();
  533. }
  534. while (oldstaktop != staktop)
  535. { /* strip off trailing newlines from command substitution only */
  536. if ((*--staktop) != NL)
  537. {
  538. ++staktop;
  539. break;
  540. } else if(quote)
  541. staktop--; /* skip past backslashes if quoting */
  542. }
  543. pop();
  544. }
  545. #define CPYSIZ 512
  546. void
  547. subst(int in, int ot)
  548. {
  549. unsigned int c;
  550. struct fileblk fb;
  551. int count = CPYSIZ;
  552. unsigned char *pc;
  553. push(&fb);
  554. initf(in);
  555. /*
  556. * DQUOTE used to stop it from quoting
  557. */
  558. while (c = (getch(DQUOTE, 0))) /* read characters from here document
  559. and interpret them */
  560. {
  561. if(c == '\\') {
  562. c = readwc(); /* check if character in here document is
  563. escaped */
  564. if(!escchar(c) || c == '"') {
  565. if (staktop >= brkend)
  566. growstak(staktop);
  567. pushstak('\\');
  568. }
  569. }
  570. pc = readw(c);
  571. /* c might be NULL */
  572. if (*pc) {
  573. while (*pc) {
  574. if (staktop >= brkend)
  575. growstak(staktop);
  576. pushstak(*pc++);
  577. }
  578. } else {
  579. if (staktop >= brkend)
  580. growstak(staktop);
  581. pushstak(*pc);
  582. }
  583. if (--count == 0)
  584. {
  585. flush(ot);
  586. count = CPYSIZ;
  587. }
  588. }
  589. flush(ot);
  590. pop();
  591. }
  592. static void
  593. flush(int ot)
  594. {
  595. write(ot, stakbot, staktop - stakbot);
  596. if (flags & execpr)
  597. write(output, stakbot, staktop - stakbot);
  598. staktop = stakbot;
  599. }