home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume23 / rc / part03 < prev    next >
Text File  |  1991-10-18  |  56KB  |  2,392 lines

  1. Newsgroups: comp.sources.misc
  2. From: byron@archone.tamu.edu (Byron Rakitzis)
  3. Subject:  v23i063:  rc - A Plan 9 shell reimplementation, v1.2, Part03/06
  4. Message-ID: <1991Oct18.034340.2235@sparky.imd.sterling.com>
  5. X-Md4-Signature: 1ebbb60177aa5936f82228f7d564ba5f
  6. Date: Fri, 18 Oct 1991 03:43:40 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: byron@archone.tamu.edu (Byron Rakitzis)
  10. Posting-number: Volume 23, Issue 63
  11. Archive-name: rc/part03
  12. Environment: UNIX
  13. Supersedes: rc: Volume 20, Issue 10-13
  14.  
  15. #!/bin/sh
  16. # do not concatenate these parts, unpack them in order with /bin/sh
  17. # file hfix.awk continued
  18. #
  19. if test ! -r _shar_seq_.tmp; then
  20.     echo 'Please unpack part 1 first!'
  21.     exit 1
  22. fi
  23. (read Scheck
  24.  if test "$Scheck" != 3; then
  25.     echo Please unpack part "$Scheck" next!
  26.     exit 1
  27.  else
  28.     exit 0
  29.  fi
  30. ) < _shar_seq_.tmp || exit 1
  31. if test ! -f _shar_wnt_.tmp; then
  32.     echo 'x - still skipping hfix.awk'
  33. else
  34. echo 'x - continuing file hfix.awk'
  35. sed 's/^X//' << 'SHAR_EOF' >> 'hfix.awk' &&
  36. X                print "extern void b_exec(), funcall(), b_dot(), b_builtin();";
  37. X                next;
  38. X                }
  39. /^extern void qsort\(void \*, SIZE_T, SIZE_T, int \(\*\)\(const void \*, const void \*\)\);$/ {
  40. X                print "extern void qsort();";
  41. X                next;
  42. X                }
  43. /^extern Node \*treecpy\(Node \*s, void \*\(\*\)\(SIZE_T\)\);$/ {
  44. X                print "extern Node *treecpy();";
  45. X                next;
  46. X                }
  47. /^extern .*\);/ || /^typedef .*\);/        {
  48. X                n = split($0, tmp1, "(");
  49. X                if (n != 2) {
  50. X                    print | "sh -c 'cat >&2'";
  51. X                    print "ERROR with left parens: ", n | "sh -c 'cat >&2'";
  52. X                    next;
  53. X                }
  54. X                printf "%s();\n", tmp1[1];
  55. X                next;
  56. X                }
  57. X                { print; }
  58. SHAR_EOF
  59. echo 'File hfix.awk is complete' &&
  60. chmod 0644 hfix.awk ||
  61. echo 'restore of hfix.awk failed'
  62. Wc_c="`wc -c < 'hfix.awk'`"
  63. test 714 -eq "$Wc_c" ||
  64.     echo 'hfix.awk: original size 714, current size' "$Wc_c"
  65. rm -f _shar_wnt_.tmp
  66. fi
  67. # ============= history.1 ==============
  68. if test -f 'history.1' -a X"$1" != X"-c"; then
  69.     echo 'x - skipping history.1 (File already exists)'
  70.     rm -f _shar_wnt_.tmp
  71. else
  72. > _shar_wnt_.tmp
  73. echo 'x - extracting history.1 (Text)'
  74. sed 's/^X//' << 'SHAR_EOF' > 'history.1' &&
  75. .\" rc.1
  76. .\"-------
  77. .\" Dd    distance to space vertically before a "display"
  78. .\" These are what n/troff use for interparagraph distance
  79. .\"-------
  80. .if t .nr Dd .4v
  81. .if n .nr Dd 1v
  82. .\"-------
  83. .\" Ds    begin a display
  84. .\"-------
  85. .de Ds
  86. .RS \\$1
  87. .sp \\n(Ddu
  88. .nf
  89. ..
  90. .\"-------
  91. .\" De    end a display (no trailing vertical spacing)
  92. .\"-------
  93. .de De
  94. .fi
  95. .RE
  96. ..
  97. .\"-------
  98. .\" I stole the Xf macro from the -man macros on my machine (originally
  99. .\" "}S", I renamed it so that it won't conflict).
  100. .\"-------
  101. .\" Set Cf to the name of the constant width font.
  102. .\" It will be "C" or "(CW", typically.
  103. .\" NOTEZ BIEN the lines defining Cf must have no trailing white space:
  104. .\"-------
  105. .if t .ds Cf C
  106. .if n .ds Cf R
  107. .\"-------
  108. .\" Rc - Alternate Roman and Courier
  109. .\"-------
  110. .de Rc
  111. .Xf 1 \\*(Cf \& "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6"
  112. ..
  113. .\"-------
  114. .\" Ic - Alternate Italic and Courier
  115. .\"-------
  116. .de Ic
  117. .Xf 2 \\*(Cf \& "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6"
  118. ..
  119. .\"-------
  120. .\" Bc - Alternate Bold and Courier
  121. .\"-------
  122. .de Bc
  123. .Xf 3 \\*(Cf \& "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6"
  124. ..
  125. .\"-------
  126. .\" Cr - Alternate Courier and Roman
  127. .\"-------
  128. .de Cr
  129. .Xf \\*(Cf 1 \& "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6"
  130. ..
  131. .\"-------
  132. .\" Ci - Alternate Courier and Italic
  133. .\"-------
  134. .de Ci
  135. .Xf \\*(Cf 2 \& "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6"
  136. ..
  137. .\"-------
  138. .\" Cb - Alternate Courier and Bold
  139. .\"-------
  140. .de Cb
  141. .Xf \\*(Cf 3 \& "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6"
  142. ..
  143. .\"-------
  144. .\" Xf - Alternate fonts
  145. .\"
  146. .\" \$1 - first font
  147. .\" \$2 - second font
  148. .\" \$3 - desired word with embedded font changes, built up by recursion
  149. .\" \$4 - text for first font
  150. .\" \$5 - \$9 - remaining args
  151. .\"
  152. .\" Every time we are called:
  153. .\"
  154. .\" If        there is something in \$4
  155. .\" then    Call ourself with the fonts switched,
  156. .\"        with a new word made of the current word (\$3) and \$4
  157. .\"        rendered in the first font,
  158. .\"        and with the remaining args following \$4.
  159. .\" else    We are done recursing.  \$3 holds the desired output
  160. .\"        word.  We emit \$3, change to Roman font, and restore
  161. .\"        the point size to the default.
  162. .\" fi
  163. .\"
  164. .\" Use Xi to add a little bit of space after italic text.
  165. .\"-------
  166. .de Xf
  167. .ds Xi
  168. .if "\\$1"2" .if !"\\$5"" .ds Xi \^
  169. .if "\\$1"I" .if !"\\$5"" .ds Xi \^
  170. .ie !"\\$4"" \{\
  171. .    Xf \\$2 \\$1 "\\$3\\f\\$1\\$4\\*(Xi" "\\$5" "\\$6" "\\$7" "\\$8" "\\$9"
  172. .\}
  173. .el \{\\$3
  174. .    ft R    \" Restore the default font, since we don't know
  175. .        \" what the last font change was.
  176. .    ps 10    \" Restore the default point size, since it might
  177. .        \" have been changed by an argument to this macro.
  178. .\}
  179. ..
  180. .TH HISTORY 1 "30 July 1991"
  181. .SH NAME
  182. \-, \-\-, \-p, \-\-p \- shell history programs
  183. .SH SYNOPSIS
  184. .B \-
  185. [
  186. .I pattern
  187. ]
  188. .I substitutions
  189. ]
  190. .SH DESCRIPTION
  191. This set of programs provides a crude history mechanism for the shell
  192. .IR rc (1).
  193. It is based on the v8 UNIX programs =, ==, etc.
  194. .PP
  195. The program
  196. .I \-
  197. runs the shell on the command it is requested to find.
  198. The program
  199. .I \-\-
  200. edits that command first.
  201. .I \-p
  202. and
  203. .I \-\-p
  204. are similar, except that they print the final command on their standard
  205. output instead of running the shell.
  206. .PP
  207. The commands work by looking for a file named by the environment variable
  208. .Cr $history ,
  209. and by searching for previous commands in this file.
  210. Old commands can be edited, or simply re-executed according to the rules
  211. below:
  212. .PP
  213. A command is searched for by examining the lines in
  214. .Cr $history
  215. in reverse order. Lines which contain a previous invokation of the history
  216. program itself are ignored. If one or more
  217. .I pattern
  218. is supplied on the command line, then the patterns are used as a means of
  219. limiting the search.
  220. Patterns match any substring of a previous command, and if more than one
  221. pattern is present then all patterns must be matched before a command
  222. is selected.
  223. .PP
  224. Substitutions may also be specified on the command line. These have
  225. the syntax:
  226. .Ds
  227. .Cr old:new
  228. .De
  229. .PP
  230. (Note that the
  231. .I old
  232. pattern is used as a search-limiting pattern also.)
  233. Substitutions happen on the first match.
  234. .PP
  235. Finally, a command may be edited in a crude line-mode fashion:
  236. The line to be edited is printed out, and below it the user
  237. supplies modifications to the command:
  238. .TP
  239. .B any character
  240. Replaces the character above.
  241. .TP
  242. .B space or tab
  243. Skips over the above character(s).
  244. .TP
  245. .B #
  246. Deletes one character.
  247. .TP
  248. .B %
  249. Replaces one character with a space.
  250. .TP
  251. .B ^
  252. Inserts the rest of the typed line just before the character.
  253. .TP
  254. .B $
  255. Deletes the rest of the line from that character on, and replaces
  256. it with the rest of the typed line.
  257. .TP
  258. .B \-
  259. Backs up to a previous command satisfying the same matching
  260. constraints.
  261. .SH EXAMPLES
  262. The history programs work best when their output is reinterpreted by
  263. the shell using an
  264. .Cr eval
  265. command.
  266. This can be achieved by writing a shell function to perform the
  267. reinterpretation:
  268. .Ds
  269. .Cr "fn - -- {
  270. .Cr "    comm = \`{$0^p $*}
  271. .Cr "    if (! ~ $#comm 0) {
  272. .Cr "        echo $comm
  273. .Cr "        eval $comm
  274. .Cr "    }
  275. .Cr "}
  276. SHAR_EOF
  277. chmod 0644 history.1 ||
  278. echo 'restore of history.1 failed'
  279. Wc_c="`wc -c < 'history.1'`"
  280. test 4951 -eq "$Wc_c" ||
  281.     echo 'history.1: original size 4951, current size' "$Wc_c"
  282. rm -f _shar_wnt_.tmp
  283. fi
  284. # ============= history.c ==============
  285. if test -f 'history.c' -a X"$1" != X"-c"; then
  286.     echo 'x - skipping history.c (File already exists)'
  287.     rm -f _shar_wnt_.tmp
  288. else
  289. > _shar_wnt_.tmp
  290. echo 'x - extracting history.c (Text)'
  291. sed 's/^X//' << 'SHAR_EOF' > 'history.c' &&
  292. /*
  293. X    history.c -- primitive history mechanism
  294. X
  295. X    Paul Haahr & Byron Rakitzis, July 1991.
  296. X
  297. X    This program mimics the att v8 = and == history programs.
  298. X    The edit() algorithm was adapted from a similar program
  299. X    that Boyd Roberts wrote, but otherwise all the code has
  300. X    been written from scratch.
  301. X
  302. X    edit() was subsequently redone by Hugh Redelmeier in order
  303. X    to correctly deal with tab characters in the source line.
  304. X
  305. X    BUGS:
  306. X    There is an implicit assumption that commands are no
  307. X    more than 1k characters long. 
  308. */
  309. X
  310. #include <stdio.h>
  311. #include "stddef.h"
  312. #include "string.h"
  313. #include "stdlib.h"
  314. #include "unistd.h"
  315. X
  316. static char *id = "@(#) history.c  8/91";
  317. X
  318. enum chunk { CHUNKSIZE = 65536 };
  319. X
  320. #undef FALSE
  321. #undef TRUE
  322. X
  323. typedef enum { FALSE, TRUE } boolean;
  324. X
  325. static struct {
  326. X    char *old, *new;
  327. } *replace;
  328. X
  329. static char **search, *progname, *history;
  330. static char me;    /* typically ':' or '-' */
  331. static boolean editit = FALSE, printit = FALSE;
  332. static int nreplace = 0, nsearch = 0;
  333. static FILE *fp;
  334. X
  335. static void *ealloc(SIZE_T n) {
  336. X    void *p = malloc(n);
  337. X    if (p == NULL) {
  338. X        perror("malloc");
  339. X        exit(1);
  340. X    }
  341. X    return p;
  342. }
  343. X
  344. static void *erealloc(void *p, SIZE_T n) {
  345. X    p = realloc(p, n);
  346. X    if (p == NULL) {
  347. X        perror("realloc");
  348. X        exit(1);
  349. X    }
  350. X    return p;
  351. }
  352. X
  353. static char *newstr() {
  354. X    return ealloc((SIZE_T)1024);
  355. }
  356. X
  357. static char *basename(char *s) {
  358. X    char *t = strrchr(s, '/');
  359. X    return (t == NULL) ? s : t + 1;
  360. }
  361. X
  362. /* stupid O(n^2) substring matching routine */
  363. X
  364. static char *isin(char *target, char *pattern) {
  365. X    SIZE_T plen = strlen(pattern);
  366. X    SIZE_T tlen = strlen(target);
  367. X    for (; tlen >= plen; target++, --tlen)
  368. X        if (strncmp(target, pattern, plen) == 0)
  369. X            return target;
  370. X    return NULL;
  371. }
  372. X
  373. /* replace the first match in the string with "new" */
  374. static char *sub(char *s, char *old, char *new) {
  375. X    char *t, *u;
  376. X
  377. X    t = isin(s, old);
  378. X    u = newstr();
  379. X
  380. X    *t = '\0';
  381. X    while (*old != '\0')
  382. X        old++, t++;
  383. X    strcpy(u, s);
  384. X    strcat(u, new);
  385. X    strcat(u, t);
  386. X    return u;
  387. }
  388. X
  389. static char *edit(char *s) {
  390. X    char *final, *f, *end;
  391. X    int col;
  392. X    boolean ins;
  393. X    
  394. start:
  395. X    fprintf(stderr, "%s\n", s);    
  396. X    f = final = newstr();
  397. X    end = s + strlen(s);
  398. X    col = 0;
  399. X    ins = FALSE;
  400. X    
  401. X    for (;; col++) {
  402. X        int    c = getchar();
  403. X
  404. X        if (c == me && col == 0) {
  405. X            int    peekc = getchar();
  406. X            if (peekc == '\n')
  407. X                return NULL;
  408. X            ungetc(peekc, stdin);
  409. X        }
  410. X        if (c == '\n') {
  411. X            if (col == 0)
  412. X                return s;
  413. X            
  414. X            while (s < end) /* copy remainder of string */
  415. X                *f++ = *s++;
  416. X            *f = '\0';
  417. X            s = final;
  418. X            goto start;
  419. X        } else if (ins || s>=end) {
  420. X            /* col need not be accurate -- tabs need not be interpreted */
  421. X            *f++ = c;
  422. X        } else {
  423. X            switch (c) {
  424. X            case '%':
  425. X                c = ' ';
  426. X                /* FALLTHROUGH */
  427. X            default:
  428. X                *f++ = c;
  429. X                break;    
  430. X            case EOF:
  431. X                exit(1);
  432. X                /* NOTREACHED */
  433. X            case ' ':
  434. X                if (*s == '\t') {
  435. X                    int    oldcol = col;
  436. X
  437. X                    for (;; col++) {
  438. X                        int    peekc;
  439. X
  440. X                        if ((col&07) == 07) {
  441. X                            *f++ = '\t';    /* we spaced past a tab */
  442. X                            break;
  443. X                        }
  444. X                        peekc = getchar();
  445. X                        if (peekc != ' ') {
  446. X                            ungetc(peekc, stdin);
  447. X                            if (peekc != '\n') {
  448. X                                /* we spaced partially into a tab */
  449. X                                do {
  450. X                                    *f++ = ' ';
  451. X                                    oldcol++;
  452. X                                } while (oldcol <= col);
  453. X                            }
  454. X                            break;
  455. X                        }
  456. X                    }
  457. X                } else {
  458. X                    *f++ = *s;
  459. X                }
  460. X                break;
  461. X            case '#':
  462. X                break;
  463. X            case '$':
  464. X                end = s;    /* truncate s */
  465. X                continue;    /* skip incrementing s */
  466. X            case '^':
  467. X                ins = TRUE;
  468. X                continue;    /* skip incrementing s */
  469. X            case '\t':
  470. X                for (;; col++) {
  471. X                    if ((*f++ = s<end? *s++ : '\t') == '\t') {
  472. X                        col = col | 07;    /* advance to before next tabstop */
  473. X                    }
  474. X                    if ((col&07) == 07)    /* stop before tabstop */
  475. X                        break;
  476. X                }
  477. X                continue;    /* skip incrementing s */
  478. X            }
  479. X            if (s<end && (*s!='\t' || (col&07)==07))
  480. X                s++;
  481. X        }
  482. X    }
  483. }
  484. X
  485. static char *readhistoryfile(char **last) {
  486. X    char *buf;
  487. X    SIZE_T count, size;
  488. X    long nread;
  489. X
  490. X    if ((history = getenv("history")) == NULL) {
  491. X        fprintf(stderr, "$history not set\n");
  492. X        exit(1);
  493. X    }
  494. X    fp = fopen(history, "r+");
  495. X    if (fp == NULL) {
  496. X        perror(history);
  497. X        exit(1);
  498. X    }
  499. X
  500. X    size = 0;
  501. X    count = 0;
  502. X    buf = ealloc(size = CHUNKSIZE);
  503. X    while ((nread = fread(buf + count, sizeof (char), size - count, fp)) > 0) {
  504. X        count += nread;
  505. X        if (size - count == 0)
  506. X            buf = erealloc(buf, size *= 4);
  507. X    }
  508. X    if (nread == -1) {
  509. X        perror(history);
  510. X        exit(1);
  511. X    }
  512. X    *last = buf + count;
  513. X    return buf;
  514. }
  515. X
  516. static char *getcommand() {
  517. X    char *s, *t;
  518. X    static char *hist = NULL, *last;
  519. X
  520. X    if (hist == NULL) {
  521. X        hist = readhistoryfile(&last);
  522. X        *--last = '\0';        /* trim final newline */
  523. X    }
  524. X
  525. again:    s = last;
  526. X    if (s < hist)
  527. X        return NULL;
  528. X    while (*--s != '\n')
  529. X        if (s <= hist) {
  530. X            last = hist - 1;
  531. X            return hist;
  532. X        }
  533. X    *s = '\0';
  534. X    last = s++;
  535. X
  536. X    /*
  537. X     * if the command contains the "me" character at the start of the line
  538. X     * or after any of [`{|()] then try again
  539. X     */
  540. X
  541. X    for (t = s; *t != '\0'; t++)
  542. X        if (*t == me) {
  543. X            char *u = t - 1;
  544. X            while (u >= s && (*u == ' ' || *u == '\t'))
  545. X                --u;
  546. X            if (u < s || *u == '`' || *u == '{' || *u == '|' || *u == '(' || *u == ')')
  547. X                goto again;
  548. X        }
  549. X    return s;
  550. }
  551. X
  552. int main(int argc, char **argv) {
  553. X    int i;
  554. X    char *s;
  555. X
  556. X    s = progname = basename(argv[0]);
  557. X    me = *s++;
  558. X    if (*s == me) {
  559. X        s++;
  560. X        editit = TRUE;
  561. X    }
  562. X    if (*s == 'p') {
  563. X        s++;
  564. X        printit = TRUE;
  565. X    }
  566. X    if (*s != '\0') {
  567. X        fprintf(stderr, "\"%s\": bad name for history program\n", progname);
  568. X        exit(1);
  569. X    }
  570. X
  571. X    if (argc > 1) {
  572. X        replace = ealloc((argc - 1) * sizeof *replace);
  573. X        search = ealloc((argc - 1) * sizeof *search);
  574. X    }
  575. X    for (i = 1; i < argc; i++)
  576. X        if ((s = strchr(argv[i], ':')) == NULL)
  577. X            search[nsearch++] = argv[i];
  578. X        else {
  579. X            *(char *)s = '\0';    /* do we confuse ps too much? */
  580. X            replace[nreplace].old = argv[i];
  581. X            replace[nreplace].new = s + 1;
  582. X            nreplace++;
  583. X        }
  584. X
  585. next:    s = getcommand();
  586. X    if (s == NULL) {
  587. X        fprintf(stderr, "command not matched\n");
  588. X        return 1;
  589. X    }
  590. X    for (i = 0; i < nsearch; i++)
  591. X        if (!isin(s, search[i]))
  592. X            goto next;
  593. X    for (i = 0; i < nreplace; i++)
  594. X        if (!isin(s, replace[i].old))
  595. X            goto next;
  596. X        else
  597. X            s = sub(s, replace[i].old, replace[i].new);
  598. X    if (editit) {
  599. X        s = edit(s);
  600. X        if (s == NULL)
  601. X            goto next;
  602. X    }
  603. X    fseek(fp, 0, 2); /* 2 == end of file. i.e., append command to $history */
  604. X    fprintf(fp, "%s\n", s);
  605. X    fclose(fp);
  606. X    if (printit)
  607. X        printf("%s\n", s);
  608. X    else {
  609. X        char *shell = getenv("SHELL");
  610. X
  611. X        if (!editit)
  612. X            fprintf(stderr, "%s\n", s);
  613. X        if (shell == NULL)
  614. X            shell = "/bin/sh";
  615. X        execl(shell, basename(shell), "-c", s, NULL);
  616. X        perror(shell);
  617. X        exit(1);
  618. X    }
  619. X    return 0;
  620. }
  621. SHAR_EOF
  622. chmod 0644 history.c ||
  623. echo 'restore of history.c failed'
  624. Wc_c="`wc -c < 'history.c'`"
  625. test 6420 -eq "$Wc_c" ||
  626.     echo 'history.c: original size 6420, current size' "$Wc_c"
  627. rm -f _shar_wnt_.tmp
  628. fi
  629. # ============= input.c ==============
  630. if test -f 'input.c' -a X"$1" != X"-c"; then
  631.     echo 'x - skipping input.c (File already exists)'
  632.     rm -f _shar_wnt_.tmp
  633. else
  634. > _shar_wnt_.tmp
  635. echo 'x - extracting input.c (Text)'
  636. sed 's/^X//' << 'SHAR_EOF' > 'input.c' &&
  637. /* input.c: i/o routines for files and pseudo-files (strings) */
  638. X
  639. #include <errno.h>
  640. #include "jbwrap.h"
  641. #include <stdarg.h>
  642. #include "rc.h"
  643. #include "input.h"
  644. #include "utils.h"
  645. #include "walk.h"
  646. #include "hash.h"
  647. #include "lex.h"
  648. #include "open.h"
  649. #include "nalloc.h"
  650. #include "except.h"
  651. #include "glom.h"
  652. #include "builtins.h"
  653. #include "parse.h"
  654. #include "tree.h"
  655. #include "footobar.h"
  656. X
  657. /*
  658. X   warning, changes have been made to (fd|string)(gchar|ugchar) so that
  659. X   you cannot unget EOF more than once. lex.c never does this, so I'm
  660. X   safe, but if you unget EOF more than once, expect to be able to read
  661. X   it back only once. The reason is that EOF is an int, whereas the buffers
  662. X   are character buffers.
  663. */
  664. X
  665. typedef struct Input {
  666. X    enum inputtype t;
  667. X    char *ibuf;
  668. X    int fd;
  669. X    int index;
  670. X    int read;
  671. X    int lineno;
  672. X    boolean saved;
  673. } Input;
  674. X
  675. #define BUFSIZE ((SIZE_T) 256)
  676. X
  677. #ifdef READLINE
  678. extern char *readline(char *);
  679. extern void add_history(char *);
  680. static char *rlinebuf;
  681. #endif
  682. X
  683. char *prompt, *prompt2;
  684. boolean rcrc;
  685. char *histstr;
  686. int histfd;
  687. X
  688. static int dead(void);
  689. static int fdgchar(void);
  690. static int stringgchar(void);
  691. static void history(void);
  692. static void ugdead(int);
  693. X
  694. static char *inbuf;
  695. static SIZE_T istacksize, chars_out, chars_in;
  696. static boolean eofread = FALSE, save_lineno = TRUE;
  697. static Input *istack, *itop;
  698. X
  699. static int (*realgchar)(void);
  700. static void (*realugchar)(int);
  701. X
  702. int last;
  703. X
  704. int gchar() {
  705. X    if (eofread) {
  706. X        eofread = FALSE;
  707. X        return last = EOF;
  708. X    }
  709. X    return realgchar();
  710. }
  711. X
  712. void ugchar(int c) {
  713. X    realugchar(c);
  714. }
  715. X
  716. static int dead() {
  717. X    return last = EOF;
  718. }
  719. X
  720. static void ugdead(int c) {
  721. X    return;
  722. }
  723. X
  724. static void ugalive(int c) {
  725. X    if (c == EOF)
  726. X        eofread = TRUE;
  727. X    else
  728. X        inbuf[--chars_out] = c;
  729. }
  730. X
  731. /* get the next character from a string. */
  732. X
  733. static int stringgchar() {
  734. X    return last = (inbuf[chars_out] == '\0' ? EOF : inbuf[chars_out++]);
  735. }
  736. X
  737. /*
  738. X   read a character from a file-descriptor. If GNU readline is defined, add a newline and doctor
  739. X   the buffer to look like a regular fdgchar buffer.
  740. */
  741. X
  742. static int fdgchar() {
  743. X    if (chars_out >= chars_in + 2) { /* has the buffer been exhausted? if so, replenish it */
  744. X        while (1) {
  745. #ifdef READLINE
  746. X            if (interactive && istack->fd == 0) {
  747. X                rlinebuf = readline(prompt);
  748. X                if (rlinebuf == NULL) {
  749. X                    chars_in = 0;
  750. X                } else {
  751. X                    if (*rlinebuf != '\0')
  752. X                        add_history(rlinebuf);
  753. X                    chars_in = strlen(rlinebuf) + 1;
  754. X                    efree(inbuf);
  755. X                    inbuf = ealloc(chars_in + 3);
  756. X                    strcpy(inbuf+2, rlinebuf);
  757. X                    strcat(inbuf+2, "\n");
  758. X                    efree(rlinebuf);
  759. X                }
  760. X            } else
  761. #endif
  762. X                {
  763. X                int /* (ssize_t) */ r = read(istack->fd, inbuf + 2, BUFSIZE);
  764. X
  765. X                if (r < 0) {
  766. X                    if (errno == EINTR)
  767. X                        continue; /* Suppose it was interrupted by a signal */
  768. X                    uerror("read");
  769. X                    rc_exit(1);
  770. X                }
  771. X
  772. X                chars_in = (SIZE_T) r;
  773. X            }
  774. X            break;
  775. X        }
  776. X
  777. X        if (chars_in == 0)
  778. X            return last = EOF;
  779. X
  780. X        chars_out = 2;
  781. X        if (dashvee)
  782. X            writeall(2, inbuf + 2, chars_in);
  783. X        history();
  784. X    }
  785. X    return last = inbuf[chars_out++];
  786. }
  787. X
  788. /* set up the input stack, and put a "dead" input at the bottom, so that yyparse will always read eof */
  789. X
  790. void initinput() {
  791. X    istack = itop = ealloc(istacksize = 256 * sizeof (Input));
  792. X    istack->t = FD;
  793. X    istack->fd = -1;
  794. X    realugchar = ugalive;
  795. }
  796. X
  797. /* push an input source onto the stack. set up a new input buffer, and set the right getchar() */
  798. X
  799. void pushinput(int /*enum inputtype*/ t,...) {
  800. X    SIZE_T count, idiff;
  801. X    char **a;
  802. X    va_list ap;
  803. X
  804. X    va_start(ap, t);
  805. X
  806. X    istack->index = chars_out;
  807. X    istack->read = chars_in;
  808. X    istack->ibuf = inbuf;
  809. X    istack->lineno = lineno;
  810. X    istack->saved = save_lineno;
  811. X    istack++;
  812. X
  813. X    idiff = istack - itop;
  814. X
  815. X    if (idiff >= istacksize / sizeof (Input)) {
  816. X        itop = erealloc(itop, istacksize *= 2);
  817. X        istack = itop + idiff;
  818. X    }
  819. X
  820. X    istack->t = t;
  821. X    if (t == FD) {
  822. X        save_lineno = TRUE;
  823. X        istack->fd = va_arg(ap, int);
  824. X        realgchar = fdgchar;
  825. X        inbuf = ealloc(BUFSIZE + 2);
  826. X    } else {
  827. X        count = strarraylen(a = va_arg(ap, char **));
  828. X        save_lineno = va_arg(ap, boolean);
  829. X        sprint((inbuf = ealloc(count + 3)) + 2, "%a", a);
  830. X        realgchar = stringgchar;
  831. X    }
  832. X
  833. X    va_end(ap);
  834. X
  835. X    realugchar = ugalive;
  836. X    chars_out = 2;
  837. X    chars_in = 0;
  838. X    if (save_lineno)
  839. X        lineno = 1;
  840. X    else
  841. X        --lineno;
  842. }
  843. X
  844. /* remove an input source from the stack. restore the right kind of getchar (string,fd) etc. */
  845. X
  846. void popinput() {
  847. X    if (istack->t == FD)
  848. X        close(istack->fd);
  849. X    efree(inbuf);
  850. X
  851. X    --istack;
  852. X
  853. X    realgchar = (istack->t == STRING ? stringgchar : fdgchar);
  854. X
  855. X    if (istack->fd == -1) { /* top of input stack */
  856. X        realgchar = dead;
  857. X        realugchar = ugdead;
  858. X    }
  859. X
  860. X    inbuf = istack->ibuf;
  861. X    chars_out = istack->index;
  862. X    chars_in = istack->read;
  863. X    if (save_lineno)
  864. X        lineno = istack->lineno;
  865. X    else
  866. X        lineno++;
  867. X    save_lineno = istack->saved;
  868. }
  869. X
  870. /* flush input characters upto newline. Used by scanerror() */
  871. X
  872. void flushu() {
  873. X    int c;
  874. X
  875. X    if (last == '\n' || last == EOF)
  876. X        return;
  877. X
  878. X    while ((c = gchar()) != '\n' && c != EOF)
  879. X        ; /* skip to newline */
  880. X
  881. X    if (c == EOF)
  882. X        ugchar(c);
  883. }
  884. X
  885. /* the wrapper loop in rc: prompt for commands until EOF, calling yyparse and walk() */
  886. X
  887. Node *doit(boolean execit) {
  888. X    boolean eof;
  889. X    jbwrap j;
  890. X    Estack e1, e2;
  891. X
  892. X    if (dashen)
  893. X        execit = FALSE;
  894. X
  895. X    setjmp(j.j);
  896. X    except(ERROR, &j, &e1);
  897. X
  898. X    for (eof = FALSE; !eof;) {
  899. X        except(ARENA, NULL, &e2);
  900. X
  901. X        if (dashell) {
  902. X            char *fname[3];
  903. X
  904. X            fname[1] = concat(varlookup("home"),word("/.rcrc",NULL))->w;
  905. X            fname[2] = NULL;
  906. X            rcrc = TRUE;
  907. X            dashell = FALSE;
  908. X            b_dot(fname);
  909. X        }
  910. X
  911. X        if (interactive) {
  912. X            List *s;
  913. X
  914. X            if (fnlookup("prompt") != NULL) {
  915. X                static char *arglist[] = { "prompt", NULL };
  916. X                funcall(arglist);
  917. X            }
  918. X
  919. X            if ((s = varlookup("prompt")) != NULL) {
  920. #ifdef READLINE
  921. X                prompt = s->w;
  922. #else
  923. X                fprint(2,"%s",s->w);
  924. #endif
  925. X                prompt2 = (s->n == NULL ? "" : s->n->w);
  926. X            }
  927. X        }
  928. X
  929. X        inityy();
  930. X
  931. X        if (yyparse() == 1 && execit)
  932. X            rc_raise(ERROR);
  933. X
  934. X        eof = (last == EOF); /* "last" can be clobbered during a walk() */
  935. X
  936. X        if (parsetree != NULL) {
  937. X            if (execit)
  938. X                walk(parsetree, TRUE);
  939. X            else if (dashex && dashen)
  940. X                fprint(2, "%s\n", ptree(parsetree));
  941. X        }
  942. X
  943. X        unexcept(); /* ARENA */
  944. X    }
  945. X
  946. X    popinput();
  947. X    unexcept(); /* ERROR */
  948. X    return parsetree;
  949. }
  950. X
  951. /* parse a function imported from the environment */
  952. X
  953. Node *parseline(char *extdef) {
  954. X    char *in[2];
  955. X    int i = interactive;
  956. X    Node *ret;
  957. X
  958. X    in[0] = extdef;
  959. X    in[1] = NULL;
  960. X    interactive = FALSE;
  961. X    pushinput(STRING, in, TRUE);
  962. X    ret = doit(FALSE);
  963. X    interactive = i;
  964. X    return ret;
  965. }
  966. X
  967. /* write last command out to a file. Check to see if $history has changed, also */
  968. X
  969. static void history() {
  970. X    List *histlist;
  971. X    SIZE_T a;
  972. X
  973. X    if (!interactive)
  974. X        return;
  975. X
  976. X    if ((histlist = varlookup("history")) == NULL) {
  977. X        if (histstr != NULL) {
  978. X            efree(histstr);
  979. X            close(histfd);
  980. X            histstr = NULL;
  981. X        }
  982. X        return;
  983. X    }
  984. X
  985. X    if (histstr == NULL || !streq(histstr, histlist->w)) { /* open new file */
  986. X        if (histstr != NULL) {
  987. X            efree(histstr);
  988. X            close(histfd);
  989. X        }
  990. X        histstr = ecpy(histlist->w);
  991. X        histfd = rc_open(histstr, APPEND);
  992. X        if (histfd < 0) {
  993. X            uerror(histstr);
  994. X            efree(histstr);
  995. X            histstr = NULL;
  996. X            varrm("history", FALSE);
  997. X        }
  998. X    }
  999. X
  1000. X    /*
  1001. X       small unix hack: since read() reads only up to a newline from a terminal, then
  1002. X       presumably this write() will write at most only one input line at a time.
  1003. X    */
  1004. X
  1005. X    for (a = 2; a < chars_in + 2; a++) { /* skip empty lines and comments in history. */
  1006. X        if (inbuf[a] == '#' || inbuf[a] == '\n')
  1007. X            return;
  1008. X        if (inbuf[a] != ' ' && inbuf[a] != '\t')
  1009. X            break;
  1010. X    }
  1011. X    writeall(histfd, inbuf + 2, chars_in);
  1012. }
  1013. SHAR_EOF
  1014. chmod 0644 input.c ||
  1015. echo 'restore of input.c failed'
  1016. Wc_c="`wc -c < 'input.c'`"
  1017. test 7405 -eq "$Wc_c" ||
  1018.     echo 'input.c: original size 7405, current size' "$Wc_c"
  1019. rm -f _shar_wnt_.tmp
  1020. fi
  1021. # ============= input.h ==============
  1022. if test -f 'input.h' -a X"$1" != X"-c"; then
  1023.     echo 'x - skipping input.h (File already exists)'
  1024.     rm -f _shar_wnt_.tmp
  1025. else
  1026. > _shar_wnt_.tmp
  1027. echo 'x - extracting input.h (Text)'
  1028. sed 's/^X//' << 'SHAR_EOF' > 'input.h' &&
  1029. enum inputtype { FD, STRING };
  1030. X
  1031. #define EOF (-1)
  1032. X
  1033. extern void initinput(void);
  1034. extern Node *parseline(char *);
  1035. extern int gchar(void);
  1036. extern void ugchar(int);
  1037. extern Node *doit(boolean);
  1038. extern void flushu(void);
  1039. extern void pushinput(int /*enum inputtype*/,...);
  1040. extern void popinput(void);
  1041. extern int last;
  1042. X
  1043. extern boolean rcrc;
  1044. extern char *histstr;
  1045. extern int histfd;
  1046. SHAR_EOF
  1047. chmod 0644 input.h ||
  1048. echo 'restore of input.h failed'
  1049. Wc_c="`wc -c < 'input.h'`"
  1050. test 373 -eq "$Wc_c" ||
  1051.     echo 'input.h: original size 373, current size' "$Wc_c"
  1052. rm -f _shar_wnt_.tmp
  1053. fi
  1054. # ============= jbwrap.h ==============
  1055. if test -f 'jbwrap.h' -a X"$1" != X"-c"; then
  1056.     echo 'x - skipping jbwrap.h (File already exists)'
  1057.     rm -f _shar_wnt_.tmp
  1058. else
  1059. > _shar_wnt_.tmp
  1060. echo 'x - extracting jbwrap.h (Text)'
  1061. sed 's/^X//' << 'SHAR_EOF' > 'jbwrap.h' &&
  1062. /* certain braindamaged compilers don't define jmp_buf as an array, so... */
  1063. X
  1064. #include <setjmp.h>
  1065. X
  1066. typedef struct jbwrap {
  1067. X    jmp_buf j;
  1068. } jbwrap;
  1069. X
  1070. extern int setjmp(jmp_buf);
  1071. extern void longjmp(jmp_buf, int);
  1072. SHAR_EOF
  1073. chmod 0644 jbwrap.h ||
  1074. echo 'restore of jbwrap.h failed'
  1075. Wc_c="`wc -c < 'jbwrap.h'`"
  1076. test 209 -eq "$Wc_c" ||
  1077.     echo 'jbwrap.h: original size 209, current size' "$Wc_c"
  1078. rm -f _shar_wnt_.tmp
  1079. fi
  1080. # ============= lex.c ==============
  1081. if test -f 'lex.c' -a X"$1" != X"-c"; then
  1082.     echo 'x - skipping lex.c (File already exists)'
  1083.     rm -f _shar_wnt_.tmp
  1084. else
  1085. > _shar_wnt_.tmp
  1086. echo 'x - extracting lex.c (Text)'
  1087. sed 's/^X//' << 'SHAR_EOF' > 'lex.c' &&
  1088. /* lex.c: rc's lexical analyzer */
  1089. X
  1090. #include "rc.h"
  1091. #include "lex.h"
  1092. #include "y.tab.h"
  1093. #include "nalloc.h"
  1094. #include "input.h"
  1095. #include "utils.h"
  1096. #include "hash.h"
  1097. #include "heredoc.h"
  1098. X
  1099. /*
  1100. X    Special characters (i.e., "non-word") in rc:
  1101. X        \t \n # ; & | ^ $ = ~ ` ' { } @ ! ( ) < > \
  1102. X
  1103. X    The lexical analyzer is fairly straightforward. The only really unclean part
  1104. X    concerns backslash continuation and "double backslashes". A backslash followed by
  1105. X    a newline is treated as a space, otherwise backslash is not a special characeter
  1106. X    (i.e., it can be part of a word).  This introduces a host of unwanted special
  1107. X    cases. In our case, \ cannot be a word character, since we wish to read in all
  1108. X    word characters in a tight loop.
  1109. X
  1110. X    Note: to save the trouble of declaring these arrays with TRUEs and FALSEs, I am assuming
  1111. X    that FALSE = 0, TRUE = 1. (and so is it declared in rc.h)
  1112. */
  1113. X
  1114. #define BUFSIZE ((SIZE_T) 1000)    /*    malloc hates power of 2 buffers? */
  1115. #define BUFMAX (8 * BUFSIZE)    /*     How big the buffer can get before we re-allocate the
  1116. X                    space at BUFSIZE again. Premature optimization? Maybe.
  1117. X                */
  1118. X
  1119. enum wordstates { NW, RW, KW }; /* "nonword", "realword", "keyword" */
  1120. X
  1121. static void getpair(int);
  1122. X
  1123. int lineno;
  1124. X
  1125. const char nw[] = {
  1126. X    1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1127. X    1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,
  1128. X    1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0,
  1129. X    1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,
  1130. X    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1131. X    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1132. X    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1133. X    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
  1134. };
  1135. X
  1136. const char dnw[] = {
  1137. X    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  1138. X    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
  1139. X    1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,
  1140. X    1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
  1141. X    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  1142. X    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  1143. X    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  1144. X    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
  1145. };
  1146. X
  1147. static SIZE_T bufsize = BUFSIZE;
  1148. static char *realbuf = NULL;
  1149. static boolean newline = FALSE;
  1150. static boolean errset = FALSE;
  1151. static boolean prerror = FALSE;
  1152. static enum wordstates word = NW;
  1153. static int fd_left, fd_right;
  1154. X
  1155. #define checkfreecaret {if (word != NW) { word = NW; ugchar(c); return '^'; }}
  1156. X
  1157. enum filedescriptors { UNSET = -9, CLOSED = -1 };
  1158. X
  1159. int yylex() {
  1160. X    static boolean dollar = FALSE;
  1161. X    boolean saw_meta = FALSE;
  1162. X    int c;
  1163. X    SIZE_T i;            /* The purpose of all these local assignments is to    */
  1164. X    const char *meta;        /* allow optimizing compilers like gcc to load these    */
  1165. X    char *buf = realbuf;        /* values into registers. On a sparc this is a        */
  1166. X    YYSTYPE *y = &yylval;        /* win, in code size *and* execution time        */
  1167. X
  1168. X    if (errset) {
  1169. X        errset = FALSE;
  1170. X        return '\n';
  1171. X    }
  1172. X
  1173. X    /* rc variable-names may contain only alnum, '*' and '_', so use dnw if we are scanning one. */
  1174. X    meta = (dollar ? dnw : nw);
  1175. X    dollar = FALSE;
  1176. X
  1177. X    if (newline) {
  1178. X        --lineno; /* slight space optimization; print_prompt2() always increments lineno */
  1179. X        print_prompt2();
  1180. X        newline = FALSE;
  1181. X    }
  1182. X
  1183. top:    while ((c = gchar()) == ' ' || c == '\t')
  1184. X        word = NW;
  1185. X
  1186. X    if (c == EOF)
  1187. X        return END;
  1188. X
  1189. X    if (!meta[(unsigned char) c]) {    /* it's a word or keyword. */
  1190. X        checkfreecaret;
  1191. X        word = RW;
  1192. X        i = 0;
  1193. X    read:    do {
  1194. X            buf[i++] = c;
  1195. X            if (c == '?' || c == '[' || c == '*')
  1196. X                saw_meta = TRUE;
  1197. X            if (i >= bufsize)
  1198. X                buf = realbuf = erealloc(buf, bufsize *= 2);
  1199. X        } while ((c = gchar()) != EOF && !meta[(unsigned char) c]);
  1200. X        if (c == '\\') {
  1201. X    anotherbs:    if ((c = gchar()) == '\n') {
  1202. X                print_prompt2();
  1203. X                c = ' '; /* Pretend a space was read */
  1204. X            } else {
  1205. X    bs:            buf[i++] = '\\';
  1206. X                if (i >= bufsize)
  1207. X                    buf = realbuf = erealloc(buf, bufsize *= 2);
  1208. X                if (!meta[(unsigned char) c])
  1209. X                    goto read;
  1210. X                if (c == '\\')
  1211. X                    goto anotherbs;
  1212. X            }
  1213. X        }
  1214. X        ugchar(c);
  1215. X        buf[i] = '\0';
  1216. X        word = KW;
  1217. X        if (i == 2) {
  1218. X            if (*buf == 'i' && buf[1] == 'f') return IF;
  1219. X            if (*buf == 'f' && buf[1] == 'n') return FN;
  1220. X            if (*buf == 'i' && buf[1] == 'n') return IN;
  1221. X        }
  1222. X        if (streq(buf, "for")) return FOR;
  1223. X        if (streq(buf, "else")) return ELSE;
  1224. X        if (streq(buf, "switch")) return SWITCH;
  1225. X        if (streq(buf, "while")) return WHILE;
  1226. X        if (streq(buf, "case")) return CASE;
  1227. X        word = RW;
  1228. X        y->word.w = ncpy(buf);
  1229. X        if (saw_meta) {
  1230. X            char *r, *s;
  1231. X
  1232. X            y->word.m = nalloc(strlen(buf) + 1);
  1233. X            for (r = buf, s = y->word.m; *r != '\0'; r++, s++)
  1234. X                *s = (*r == '?' || *r == '[' || *r == '*');
  1235. X        } else {
  1236. X            y->word.m = NULL;
  1237. X        }
  1238. X        return WORD;
  1239. X    }
  1240. X
  1241. X    if (c == '`' || c == '!' || c == '@' || c == '~' || c == '$' || c == '\'') {
  1242. X        checkfreecaret;
  1243. X        if (c == '!' || c == '@' || c == '~')
  1244. X            word = KW;
  1245. X    }
  1246. X
  1247. X    switch (c) {
  1248. X    case '\0':
  1249. X        pr_error("warning: null character ignored");
  1250. X        goto top;
  1251. X    case '!':
  1252. X        return BANG;
  1253. X    case '@':
  1254. X        return SUBSHELL;
  1255. X    case '~':
  1256. X        return TWIDDLE;
  1257. X    case '`':
  1258. X        c = gchar();
  1259. X        if (c == '`')
  1260. X            return BACKBACK;
  1261. X        ugchar(c);
  1262. X        return '`';
  1263. X    case '$':
  1264. X        dollar = TRUE;
  1265. X        c = gchar();
  1266. X        if (c == '#')
  1267. X            return COUNT;
  1268. X        if (c == '^')
  1269. X            return FLAT;
  1270. X        ugchar(c);
  1271. X        return '$';
  1272. X    case '\'':
  1273. X        word = RW;
  1274. X        i = 0;
  1275. X        do {
  1276. X            buf[i++] = c;
  1277. X            if (c == '\n')
  1278. X                print_prompt2();
  1279. X            if (c == EOF) {
  1280. X                word = NW;
  1281. X                scanerror("eof in quoted string");
  1282. X                return HUH;
  1283. X            }
  1284. X            if (i >= bufsize)
  1285. X                buf = realbuf = erealloc(buf, bufsize *= 2);
  1286. X        } while ((c = gchar()) != '\'' || (c = gchar()) == '\''); /* quote "'" thus: 'how''s it going?' */
  1287. X        ugchar(c);
  1288. X        buf[i] = '\0';
  1289. X        y->word.w = ncpy(buf);
  1290. X        y->word.m = NULL;
  1291. X        return WORD;
  1292. X    case '\\':
  1293. X        if ((c = gchar()) == '\n') {
  1294. X            print_prompt2();
  1295. X            goto top; /* Pretend it was just another space. */
  1296. X        }
  1297. X        ugchar(c);
  1298. X        c = '\\';
  1299. X        checkfreecaret;
  1300. X        c = gchar();
  1301. X        i = 0;
  1302. X        goto bs;
  1303. X    case '(':
  1304. X        if (word == RW) /* SUB's happen only after real words, not keyowrds, so if () and while () work */
  1305. X            c = SUB;
  1306. X        word = NW;
  1307. X        return c;
  1308. X    case '#':
  1309. X        while ((c = gchar()) != '\n') /* skip comment until newline */
  1310. X            if (c == EOF)
  1311. X                return END;
  1312. X        /* FALLTHROUGH */
  1313. X    case '\n':
  1314. X        lineno++;
  1315. X        newline = TRUE;
  1316. X        /* FALLTHROUGH */
  1317. X    case ';':
  1318. X    case '^':
  1319. X    case ')':
  1320. X    case '=':
  1321. X    case '{': case '}':
  1322. X        word = NW;
  1323. X        return c;
  1324. X    case '&':
  1325. X        word = NW;
  1326. X        c = gchar();
  1327. X        if (c == '&')
  1328. X            return ANDAND;
  1329. X        ugchar(c);
  1330. X        return '&';
  1331. X    case '|':
  1332. X        word = NW;
  1333. X        c = gchar();
  1334. X        if (c == '|')
  1335. X            return OROR;
  1336. X        getpair(c);
  1337. X        if (errset)
  1338. X            return HUH;
  1339. X        if ((y->pipe.left = fd_left) == UNSET)
  1340. X            y->pipe.left = 1;                /* default to fd 1 */
  1341. X        if ((y->pipe.right = fd_right) == UNSET)
  1342. X            y->pipe.right = 0;                /* default to fd 0 */
  1343. X        if (y->pipe.right == CLOSED) {
  1344. X            scanerror("expected digit after '='");        /* can't close a pipe */
  1345. X            return HUH;
  1346. X        }
  1347. X        return PIPE;
  1348. X    case '>':
  1349. X        c = gchar();
  1350. X        if (c == '>') {
  1351. X            c = gchar();
  1352. X            y->redir.type = APPEND;
  1353. X        } else
  1354. X            y->redir.type = CREATE;
  1355. X        y->redir.fd = 1;
  1356. X        goto common;
  1357. X    case '<':
  1358. X        c = gchar();
  1359. X        if (c == '<') {
  1360. X            c = gchar();
  1361. X            if (c == '<') {
  1362. X                c = gchar();
  1363. X                y->redir.type = HERESTRING;
  1364. X            } else {
  1365. X                y->redir.type = HEREDOC;
  1366. X            }
  1367. X        } else
  1368. X            y->redir.type = FROM;
  1369. X        y->redir.fd = 0;
  1370. X    common:
  1371. X        word = NW;
  1372. X        getpair(c);
  1373. X        if (errset)
  1374. X            return HUH;
  1375. X        if (fd_right == UNSET) { /* redirection, not dup */
  1376. X            if (fd_left != UNSET)
  1377. X                y->redir.fd = fd_left;
  1378. X            return REDIR;
  1379. X        } else { /* dup; recast yylval */
  1380. X            y->dup.type = y->redir.type;
  1381. X            y->dup.left = fd_left;
  1382. X            y->dup.right = fd_right;
  1383. X            return DUP;
  1384. X        }
  1385. X    default:
  1386. X        word = NW;
  1387. X        return c; /* don't know what it is, let yacc barf on it */
  1388. X    }
  1389. }
  1390. X
  1391. void yyerror(const char *s) {
  1392. X    char *tok;
  1393. X    char tokbuf[128];
  1394. X
  1395. X    if (prerror) { /* don't print "syntax error" if there's a more informative scanerror */
  1396. X        prerror = FALSE;
  1397. X        return;
  1398. X    }
  1399. X
  1400. X    if (!interactive) {
  1401. X        if (word != NW)
  1402. X            tok = realbuf;
  1403. X        else if (last == EOF)
  1404. X            tok = "end of input";
  1405. X        else if (last == '\n')
  1406. X            tok = "end of line";
  1407. X        else
  1408. X            sprint(tok = tokbuf, (last < 32 || last > 126) ? "(decimal %d)" : "'%c'",last);
  1409. X        fprint(2,"line %d: %s near %s\n", lineno - (last == '\n'), s, tok);
  1410. X    } else
  1411. X        fprint(2,"%s\n",s);
  1412. }
  1413. X
  1414. void scanerror(char *s) {
  1415. X    flushu(); /* flush upto newline */
  1416. X    yyerror(s);
  1417. X    errset = prerror = TRUE;
  1418. }
  1419. X
  1420. void inityy() {
  1421. X    newline = FALSE;
  1422. X    word = NW;
  1423. X    hq = NULL;
  1424. X
  1425. X    /* return memory to the system if the buffer got too large */
  1426. X
  1427. X    if (bufsize > BUFMAX && realbuf != NULL) {
  1428. X        efree(realbuf);
  1429. X        bufsize = BUFSIZE;
  1430. X        realbuf = ealloc(bufsize);
  1431. X    } else if (realbuf == NULL)
  1432. X        realbuf = ealloc(bufsize);
  1433. }
  1434. X
  1435. void print_prompt2() {
  1436. X    lineno++;
  1437. #ifdef READLINE
  1438. X    prompt = prompt2;
  1439. #else
  1440. X    if (interactive)
  1441. X        fprint(2,"%s",prompt2);
  1442. #endif
  1443. }
  1444. X
  1445. /*
  1446. X   Scan in a pair of integers for redirections like >[2=1]. CLOSED represents a closed file
  1447. X   descriptor (i.e., >[2=]) and UNSET represents an undesignated file descriptor (e.g.,
  1448. X   >[2] is represented as (2,UNSET).
  1449. X
  1450. X   This function makes use of unsigned compares to make range tests in one compare operation.
  1451. */
  1452. X
  1453. static void getpair(int c) {
  1454. X    int n;
  1455. X
  1456. X    fd_left = fd_right = UNSET;
  1457. X
  1458. X    if (c != '[') {
  1459. X        ugchar(c);
  1460. X        return;
  1461. X    }
  1462. X
  1463. X    if ((unsigned int) (n = gchar() - '0') > 9) {
  1464. X        scanerror("expected digit after '['");
  1465. X        return;
  1466. X    }
  1467. X
  1468. X    while ((unsigned int) (c = gchar() - '0') <= 9)
  1469. X        n = n * 10 + c;
  1470. X
  1471. X    fd_left = n;
  1472. X    c += '0';
  1473. X
  1474. X    switch (c) {
  1475. X    default:
  1476. X        scanerror("expected '=' or ']' after digit");
  1477. X        return;
  1478. X    case ']':
  1479. X        return;
  1480. X    case '=':
  1481. X        if ((unsigned int) (n = gchar() - '0') > 9) {
  1482. X            if (n != ']' - '0') {
  1483. X                scanerror("expected digit or ']' after '='");
  1484. X                return;
  1485. X            }
  1486. X            fd_right = CLOSED;
  1487. X        } else {
  1488. X            while ((unsigned int) (c = gchar() - '0') <= 9)
  1489. X                n = n * 10 + c;
  1490. X            if (c != ']' - '0') {
  1491. X                scanerror("expected ']' after digit");
  1492. X                return;
  1493. X            }
  1494. X            fd_right = n;
  1495. X        }
  1496. X    }
  1497. }
  1498. SHAR_EOF
  1499. chmod 0644 lex.c ||
  1500. echo 'restore of lex.c failed'
  1501. Wc_c="`wc -c < 'lex.c'`"
  1502. test 10411 -eq "$Wc_c" ||
  1503.     echo 'lex.c: original size 10411, current size' "$Wc_c"
  1504. rm -f _shar_wnt_.tmp
  1505. fi
  1506. # ============= lex.h ==============
  1507. if test -f 'lex.h' -a X"$1" != X"-c"; then
  1508.     echo 'x - skipping lex.h (File already exists)'
  1509.     rm -f _shar_wnt_.tmp
  1510. else
  1511. > _shar_wnt_.tmp
  1512. echo 'x - extracting lex.h (Text)'
  1513. sed 's/^X//' << 'SHAR_EOF' > 'lex.h' &&
  1514. enum redirtype {
  1515. X    FROM, CREATE, APPEND, HEREDOC, HERESTRING
  1516. };
  1517. X
  1518. typedef struct Pipe {
  1519. X    int left,right;
  1520. } Pipe;
  1521. X
  1522. typedef struct Dup {
  1523. X    enum redirtype type;
  1524. X    int left,right;
  1525. } Dup;
  1526. X
  1527. typedef struct Redir {
  1528. X    enum redirtype type;
  1529. X    int fd;
  1530. } Redir;
  1531. X
  1532. typedef struct Word {
  1533. X    char *w;
  1534. X    char *m;
  1535. } Word;
  1536. X
  1537. extern int yylex(void);
  1538. extern void inityy(void);
  1539. extern void yyerror(const char *);
  1540. extern void scanerror(char *);
  1541. extern void print_prompt2(void);
  1542. X
  1543. extern const char nw[], dnw[];
  1544. SHAR_EOF
  1545. chmod 0644 lex.h ||
  1546. echo 'restore of lex.h failed'
  1547. Wc_c="`wc -c < 'lex.h'`"
  1548. test 476 -eq "$Wc_c" ||
  1549.     echo 'lex.h: original size 476, current size' "$Wc_c"
  1550. rm -f _shar_wnt_.tmp
  1551. fi
  1552. # ============= list.c ==============
  1553. if test -f 'list.c' -a X"$1" != X"-c"; then
  1554.     echo 'x - skipping list.c (File already exists)'
  1555.     rm -f _shar_wnt_.tmp
  1556. else
  1557. > _shar_wnt_.tmp
  1558. echo 'x - extracting list.c (Text)'
  1559. sed 's/^X//' << 'SHAR_EOF' > 'list.c' &&
  1560. /* list.c: routines for manipulating the List type */
  1561. X
  1562. #include "rc.h"
  1563. #include "utils.h"
  1564. #include "list.h"
  1565. X
  1566. /*
  1567. X   These list routines assign meta values of null to the resulting lists;
  1568. X   it is impossible to glob with the value of a variable unless this value
  1569. X   is rescanned with eval---therefore it is safe to throw away the meta-ness
  1570. X   of the list.
  1571. */
  1572. X
  1573. /* free a list from malloc space */
  1574. X
  1575. void listfree(List *p) {
  1576. X    if (p == NULL)
  1577. X        return;
  1578. X    listfree(p->n);
  1579. X    efree(p->w);
  1580. X    efree(p);
  1581. }
  1582. X
  1583. /* copy of list in malloc space (for storing a variable) */
  1584. X
  1585. List *listcpy(List *s) {
  1586. X    List *r;
  1587. X
  1588. X    if (s == NULL)
  1589. X        return NULL;
  1590. X
  1591. X    r = enew(List);
  1592. X    r->w = ecpy(s->w);
  1593. X    r->m = NULL;
  1594. X    r->n = listcpy(s->n);
  1595. X
  1596. X    return r;
  1597. }
  1598. X
  1599. /* length of list */
  1600. X
  1601. SIZE_T listlen(List *s) {
  1602. X    SIZE_T size;
  1603. X
  1604. X    for (size = 0; s != NULL; s = s->n)
  1605. X        size += strlen(s->w) + 1;
  1606. X
  1607. X    return size;
  1608. }
  1609. X
  1610. /* number of elements in list */
  1611. X
  1612. int listnel(List *s) {
  1613. X    int nel;
  1614. X
  1615. X    for (nel = 0; s != NULL; s = s->n)
  1616. X        nel++;
  1617. X
  1618. X    return nel;
  1619. }
  1620. SHAR_EOF
  1621. chmod 0644 list.c ||
  1622. echo 'restore of list.c failed'
  1623. Wc_c="`wc -c < 'list.c'`"
  1624. test 984 -eq "$Wc_c" ||
  1625.     echo 'list.c: original size 984, current size' "$Wc_c"
  1626. rm -f _shar_wnt_.tmp
  1627. fi
  1628. # ============= list.h ==============
  1629. if test -f 'list.h' -a X"$1" != X"-c"; then
  1630.     echo 'x - skipping list.h (File already exists)'
  1631.     rm -f _shar_wnt_.tmp
  1632. else
  1633. > _shar_wnt_.tmp
  1634. echo 'x - extracting list.h (Text)'
  1635. sed 's/^X//' << 'SHAR_EOF' > 'list.h' &&
  1636. extern void listfree(List *);
  1637. extern List *listcpy(List *);
  1638. extern SIZE_T listlen(List *);
  1639. extern int listnel(List *);
  1640. SHAR_EOF
  1641. chmod 0644 list.h ||
  1642. echo 'restore of list.h failed'
  1643. Wc_c="`wc -c < 'list.h'`"
  1644. test 119 -eq "$Wc_c" ||
  1645.     echo 'list.h: original size 119, current size' "$Wc_c"
  1646. rm -f _shar_wnt_.tmp
  1647. fi
  1648. # ============= main.c ==============
  1649. if test -f 'main.c' -a X"$1" != X"-c"; then
  1650.     echo 'x - skipping main.c (File already exists)'
  1651.     rm -f _shar_wnt_.tmp
  1652. else
  1653. > _shar_wnt_.tmp
  1654. echo 'x - extracting main.c (Text)'
  1655. sed 's/^X//' << 'SHAR_EOF' > 'main.c' &&
  1656. /* main.c: handles initialization of rc and command line options */
  1657. X
  1658. #include <stdarg.h>
  1659. #include "rc.h"
  1660. #include "utils.h"
  1661. #include "input.h"
  1662. #include "nalloc.h"
  1663. #include "hash.h"
  1664. #include "lex.h"
  1665. #include "open.h"
  1666. #include "tree.h"
  1667. #include "glom.h"
  1668. #include "builtins.h"
  1669. #include "parse.h"
  1670. #include "status.h"
  1671. #include "getopt.h"
  1672. X
  1673. boolean dashdee, dashee, dashvee, dashex, dashell, dasheye, dashen, interactive;
  1674. int rc_pid;
  1675. X
  1676. #define REALLYNULL ((void *) 0) /* used to terminate a vararg list with NULL */
  1677. X
  1678. static void assigndefault(char *,...);
  1679. X
  1680. void main(int argc, char *argv[], char *envp[]) {
  1681. X    char *dashsee[2], pid[8], *dollarzero, *null[1];
  1682. X    int c;
  1683. X
  1684. X    dashee = dashell = dashvee = dashex = dashdee = dashen = FALSE;
  1685. X    dashsee[0] = dashsee[1] = NULL;
  1686. X    dollarzero = argv[0];
  1687. X    rc_pid = getpid();
  1688. X
  1689. X    dashell = (*argv[0] == '-'); /* Unix tradition */
  1690. X
  1691. X    while ((c = getopt(argc, argv, "nleivdxc:")) != -1)
  1692. X        switch (c) {
  1693. X        case 'l':
  1694. X            dashell = TRUE;
  1695. X            break;
  1696. X        case 'e':
  1697. X            dashee = TRUE;
  1698. X            break;
  1699. X        case 'i':
  1700. X            dasheye = interactive = TRUE;
  1701. X            break;
  1702. X        case 'v':
  1703. X            dashvee = TRUE;
  1704. X            break;
  1705. X        case 'x':
  1706. X            dashex = TRUE;
  1707. X            break;
  1708. X        case 'd':
  1709. X            dashdee = TRUE;
  1710. X            break;
  1711. X        case 'c':
  1712. X            dashsee[0] = optarg;
  1713. X            goto quitopts;
  1714. X        case 'n':
  1715. X            dashen = TRUE;
  1716. X            break;
  1717. X        case '?':
  1718. X            exit(1);
  1719. X        }
  1720. X
  1721. quitopts:
  1722. X    argv += optind;
  1723. X
  1724. X    /* use isatty() iff -i is not set, and iff the input is not from a script or -c flag */
  1725. X    if (!dasheye && dashsee[0] == NULL && *argv == NULL)
  1726. X        interactive = isatty(0);
  1727. X
  1728. X    if (dashsee[0] != NULL) { /* rc -c must always ignore signals, e.g., for "rc -c sh" */
  1729. X        int i = interactive;
  1730. X    
  1731. X        interactive = TRUE;
  1732. X        inithandler();
  1733. X        interactive = i;
  1734. X    } else
  1735. X        inithandler();
  1736. X    inithash();
  1737. X    initparse();
  1738. X    assigndefault("prompt", "; ", "", REALLYNULL);
  1739. X    assigndefault("path", ".", "/bin", "/usr/bin", "/usr/ucb", REALLYNULL);
  1740. X    assigndefault("ifs", " ", "\t", "\n", REALLYNULL);
  1741. X    assigndefault("pid", sprint(pid, "%d", rc_pid), REALLYNULL);
  1742. X    initenv(envp);
  1743. X    initinput();
  1744. X    null[0] = NULL;
  1745. X    starassign(dollarzero, null, FALSE); /* assign $0 to $* */
  1746. X
  1747. X    if (dashsee[0] != NULL) {    /* input from the -c flag? */
  1748. X        if (*argv != NULL)
  1749. X            starassign(dollarzero, argv, FALSE);
  1750. X        pushinput(STRING, dashsee, TRUE);
  1751. X    } else if (*argv != NULL) {    /* else from a file? */
  1752. X        b_dot(--argv);
  1753. X        rc_exit(getstatus());
  1754. X    } else {            /* else stdin */
  1755. X        pushinput(FD, 0);
  1756. X    }
  1757. X
  1758. X    dasheye = FALSE;
  1759. X    doit(TRUE);
  1760. X    rc_exit(getstatus());
  1761. }
  1762. X
  1763. static void assigndefault(char *name,...) {
  1764. X    va_list ap;
  1765. X    List *l;
  1766. X    char *v;
  1767. X
  1768. X    va_start(ap, name);
  1769. X
  1770. X    for (l = NULL; (v = va_arg(ap, char *)) != NULL;)
  1771. X        l = append(l, word(v, NULL));
  1772. X
  1773. X    varassign(name, l, FALSE);
  1774. X
  1775. X    if (streq(name,"path"))
  1776. X        alias(name, l, FALSE);
  1777. X
  1778. X    va_end(ap);
  1779. }
  1780. SHAR_EOF
  1781. chmod 0644 main.c ||
  1782. echo 'restore of main.c failed'
  1783. Wc_c="`wc -c < 'main.c'`"
  1784. test 2703 -eq "$Wc_c" ||
  1785.     echo 'main.c: original size 2703, current size' "$Wc_c"
  1786. rm -f _shar_wnt_.tmp
  1787. fi
  1788. # ============= match.c ==============
  1789. if test -f 'match.c' -a X"$1" != X"-c"; then
  1790.     echo 'x - skipping match.c (File already exists)'
  1791.     rm -f _shar_wnt_.tmp
  1792. else
  1793. > _shar_wnt_.tmp
  1794. echo 'x - extracting match.c (Text)'
  1795. sed 's/^X//' << 'SHAR_EOF' > 'match.c' &&
  1796. /* match.c: pattern matching routines */
  1797. X
  1798. #include "rc.h"
  1799. #include "utils.h"
  1800. #include "match.h"
  1801. X
  1802. static int rangematch(char *, char);
  1803. X
  1804. /*
  1805. X   match() matches a single pattern against a single string.
  1806. */
  1807. X
  1808. boolean match(char *p, char *m, char *s) {
  1809. X    int i = 0;
  1810. X    int j;
  1811. X
  1812. X    if (m == NULL)
  1813. X        return streq(p, s);
  1814. X
  1815. X    while(1) {
  1816. X        if (p[i] == '\0')
  1817. X            return *s == '\0';
  1818. X        else if (m[i]) {
  1819. X            switch (p[i++]) {
  1820. X            case '?':
  1821. X                if (*s++ == '\0')
  1822. X                    return FALSE;
  1823. X                break;
  1824. X            case '*':
  1825. X                /* collapse multiple stars */
  1826. X                while (p[i] == '*' && m[i] == 1)
  1827. X                    i++;
  1828. X
  1829. X                /* star at end of pattern? */
  1830. X                if (p[i] == '\0')
  1831. X                    return TRUE;
  1832. X
  1833. X                while (*s != '\0')
  1834. X                    if (match(p + i, m + i, s++))
  1835. X                        return TRUE;
  1836. X                return FALSE;
  1837. X            case '[':
  1838. X                if (*s == '\0' || ((j = rangematch(p + i, *s++)) < 0))
  1839. X                    return FALSE;
  1840. X                i += j;
  1841. X                break;
  1842. X            default:
  1843. X                fprint(2,"%c is not a metacharacter\n", p[i-1]);
  1844. X                return FALSE;
  1845. X            }
  1846. X        } else if (p[i++] != *s++) {
  1847. X                return FALSE;
  1848. X        }
  1849. X    }
  1850. }
  1851. X
  1852. /*
  1853. X   From the ed(1) man pages (on ranges):
  1854. X
  1855. X    The `-' is treated as an ordinary character if it occurs first
  1856. X    (or first after an initial ^) or last in the string.
  1857. X
  1858. X    The right square bracket does not terminate the enclosed string
  1859. X    if it is the first character (after an initial `^', if any), in
  1860. X    the bracketed string.
  1861. X
  1862. X   rangematch() matches a single character against a class, and returns
  1863. X   an integer offset to the end of the range on success, or -1 on
  1864. X   failure.
  1865. */
  1866. X
  1867. static int rangematch(char *p, char c) {
  1868. X    char *orig = p;
  1869. X    boolean neg = (*p == '~');
  1870. X    boolean matched = FALSE;
  1871. X
  1872. X    if (neg)
  1873. X        p++;
  1874. X
  1875. X    if (*p == ']') {
  1876. X        p++;
  1877. X        matched = (c == ']');
  1878. X    }
  1879. X
  1880. X    for (; *p != ']'; p++) {
  1881. X        if (*p == '\0')
  1882. X            return -1;    /* bad syntax */
  1883. X        if (p[1] == '-' && p[2] != ']') { /* check for [..-..] but ignore [..-] */
  1884. X            if (c >= *p)
  1885. X                matched |= (c <= p[2]);
  1886. X            p += 2;
  1887. X        } else {
  1888. X            matched |= (*p == c);
  1889. X        }
  1890. X    }
  1891. X
  1892. X    if (matched ^ neg)
  1893. X        return p - orig + 1; /* skip the right-bracket */
  1894. X    else
  1895. X        return -1;
  1896. }
  1897. X
  1898. SHAR_EOF
  1899. chmod 0644 match.c ||
  1900. echo 'restore of match.c failed'
  1901. Wc_c="`wc -c < 'match.c'`"
  1902. test 1992 -eq "$Wc_c" ||
  1903.     echo 'match.c: original size 1992, current size' "$Wc_c"
  1904. rm -f _shar_wnt_.tmp
  1905. fi
  1906. # ============= match.h ==============
  1907. if test -f 'match.h' -a X"$1" != X"-c"; then
  1908.     echo 'x - skipping match.h (File already exists)'
  1909.     rm -f _shar_wnt_.tmp
  1910. else
  1911. > _shar_wnt_.tmp
  1912. echo 'x - extracting match.h (Text)'
  1913. sed 's/^X//' << 'SHAR_EOF' > 'match.h' &&
  1914. extern boolean match(char *, char *, char *);
  1915. SHAR_EOF
  1916. chmod 0644 match.h ||
  1917. echo 'restore of match.h failed'
  1918. Wc_c="`wc -c < 'match.h'`"
  1919. test 46 -eq "$Wc_c" ||
  1920.     echo 'match.h: original size 46, current size' "$Wc_c"
  1921. rm -f _shar_wnt_.tmp
  1922. fi
  1923. # ============= mksignal ==============
  1924. if test -f 'mksignal' -a X"$1" != X"-c"; then
  1925.     echo 'x - skipping mksignal (File already exists)'
  1926.     rm -f _shar_wnt_.tmp
  1927. else
  1928. > _shar_wnt_.tmp
  1929. echo 'x - extracting mksignal (Text)'
  1930. sed 's/^X//' << 'SHAR_EOF' > 'mksignal' &&
  1931. #!/bin/sh
  1932. # generate rc's internal signal table from signal.h
  1933. X
  1934. exec > sigmsgs.c
  1935. X
  1936. echo '#include "sigmsgs.h"'
  1937. echo
  1938. echo 'char *signals[][2] = {'
  1939. X
  1940. sed '    s/\/\*[     ]*//
  1941. X    s/[     ]*\*\///
  1942. X    s/([@*+!]) //
  1943. X    s/[     ]*([a-zA-Z,->& ]*)[     ]*//
  1944. X    s/[     ]*signal$//' $1 |
  1945. awk '
  1946. X    BEGIN {
  1947. X        # assign to nomesg["SIGNAME"] to suppress a long message
  1948. X        nomesg["SIGINT"] = 1
  1949. X        nomesg["SIGPIPE"] = 1
  1950. X        # assign to mesg["SIGNAME"] to override a message
  1951. X        mesg["SIGHUP"] = "hangup"
  1952. X        mesg["SIGKILL"] = "killed"
  1953. X        mesg["SIGQUIT"] = "quit"
  1954. X        mesg["SIGTERM"] = "terminated"
  1955. X        mesg["SIGURG"] = "urgent condition on i/o channel"
  1956. X        mesg["SIGSTOP"] = "stop signal not from tty"
  1957. X        mesg["SIGTSTP"] = "stopped"
  1958. X        mesg["SIGCONT"] = "continue"
  1959. X        mesg["SIGCHLD"] = "child stop or exit"
  1960. X        mesg["SIGTTIN"] = "background tty read"
  1961. X        mesg["SIGTTOU"] = "background tty write"
  1962. X        # assign to ignore["SIGNAME"] to explicitly ignore a named signal
  1963. X        ignore["SIGMAX"] = 1
  1964. X    }
  1965. X    $1 == "#define" && $2 == "NSIG" && $3 ~ /^[0-9]+$/ { nsig = $3 }
  1966. X    $1 == "#define" && $2 ~ /^SIG/ && $3 ~ /^[0-9]+$/ && sig[$3] == "" && ignore[$2] == 0 {
  1967. X        sig[$3] = $2
  1968. X        if ($3 > max)
  1969. X            max = $3
  1970. X        if (mesg[$2] == "" && nomesg[$2] == 0) {
  1971. X            str = $4
  1972. X            for (i = 5; i <= NF; i++)
  1973. X                str = str " " $i
  1974. X            mesg[$2] = str
  1975. X        }
  1976. X    }
  1977. X    END {
  1978. X        if (nsig == 0)
  1979. X            nsig = max + 1
  1980. X        printf "    !!,        !!,\n"
  1981. X        for (i = 1; i < nsig; i++) {
  1982. X            if (sig[i] == "")
  1983. X                printf "    !!,        !!,\n"
  1984. X            else
  1985. X                printf "    !%s!,    !%s!,\n", sig[i], mesg[sig[i]]
  1986. X        }
  1987. X    }
  1988. ' |
  1989. tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ!' 'abcdefghijklmnopqrstuvwxyz"'
  1990. X
  1991. echo '};'
  1992. X
  1993. exec > sigmsgs.h
  1994. X
  1995. echo 'extern char *signals[][2];'
  1996. X
  1997. grep '^    ' sigmsgs.c |        # the thing in quotes is ^<tab>
  1998. awk '
  1999. X        { sum = sum + 1; }
  2000. X    END    { print "#define NUMOFSIGNALS", sum }
  2001. '
  2002. SHAR_EOF
  2003. chmod 0644 mksignal ||
  2004. echo 'restore of mksignal failed'
  2005. Wc_c="`wc -c < 'mksignal'`"
  2006. test 1716 -eq "$Wc_c" ||
  2007.     echo 'mksignal: original size 1716, current size' "$Wc_c"
  2008. rm -f _shar_wnt_.tmp
  2009. fi
  2010. # ============= nalloc.c ==============
  2011. if test -f 'nalloc.c' -a X"$1" != X"-c"; then
  2012.     echo 'x - skipping nalloc.c (File already exists)'
  2013.     rm -f _shar_wnt_.tmp
  2014. else
  2015. > _shar_wnt_.tmp
  2016. echo 'x - extracting nalloc.c (Text)'
  2017. sed 's/^X//' << 'SHAR_EOF' > 'nalloc.c' &&
  2018. /* nalloc.c: a simple single-arena allocator for command-line-lifetime allocation */
  2019. X
  2020. #include "rc.h"
  2021. #include "utils.h"
  2022. #include "nalloc.h"
  2023. X
  2024. static struct Block {
  2025. X    SIZE_T used;
  2026. X    SIZE_T size;
  2027. X    char *mem;
  2028. X    Block *n;
  2029. } *fl, *ul;
  2030. X
  2031. /* alignto() works only with power of 2 blocks and assumes 2's complement arithmetic */
  2032. #define alignto(m, n)   ((m + n - 1) & ~(n - 1))
  2033. #define BLOCKSIZE ((SIZE_T) 4096)
  2034. X
  2035. /* gets a block from malloc space and places it at the head of the used-list */
  2036. X
  2037. static void getblock(SIZE_T n) {
  2038. X    Block *r, *p;
  2039. X
  2040. X    for (r = fl, p = NULL; r != NULL; p = r, r = r->n)
  2041. X        if (n <= r->size)
  2042. X            break;
  2043. X
  2044. X    if (r != NULL) {
  2045. X        if (p != NULL)
  2046. X            p->n = r->n;
  2047. X        else
  2048. X            fl = r->n;
  2049. X    } else {
  2050. X        r = enew(Block);
  2051. X        r->mem = ealloc(alignto(n, BLOCKSIZE));
  2052. X        r->size = alignto(n, BLOCKSIZE);
  2053. X    }
  2054. X
  2055. X    r->used = 0;
  2056. X    r->n = ul;
  2057. X    ul = r;
  2058. }
  2059. X
  2060. /*
  2061. X   A fast single-arena allocator. Looks at the current block, and if there is not enough room,
  2062. X   it goes to getblock() for more. "ul" stands for "used list", and the head of the list is the
  2063. X   current block.
  2064. */
  2065. X
  2066. void *nalloc(SIZE_T n) {
  2067. X    char *ret;
  2068. X
  2069. X        n = alignto(n, sizeof (ALIGN_T));
  2070. X
  2071. X    if (ul == NULL || n + ul->used >= ul->size)
  2072. X        getblock(n);
  2073. X
  2074. X    ret = ul->mem + ul->used;
  2075. X    ul->used += n;
  2076. X    return ret;
  2077. }
  2078. X
  2079. /*
  2080. X   Frees memory from nalloc space by putting it on the freelist. Returns free blocks to the
  2081. X   system, retaining at least MAXMEM bytes worth of blocks for nalloc.
  2082. */
  2083. X
  2084. #define MAXMEM 500000
  2085. X
  2086. void nfree() {
  2087. X    Block *r;
  2088. X    SIZE_T count;
  2089. X
  2090. X    if (ul == NULL)
  2091. X        return;
  2092. X
  2093. X    for (r = ul; r->n != NULL; r = r->n)
  2094. X        ;
  2095. X
  2096. X    r->n = fl;
  2097. X    fl = ul;
  2098. X    ul = NULL;
  2099. X
  2100. X    for (r = fl, count = r->size; r->n != NULL; r = r->n, count += r->size) {
  2101. X        if (count >= MAXMEM) {
  2102. X            Block *tmp = r;
  2103. X
  2104. X            r = r->n;
  2105. X            tmp->n = NULL;        /* terminate the freelist */
  2106. X
  2107. X            while (r != NULL) {    /* free memory off the tail of the freelist */
  2108. X                tmp = r->n;
  2109. X                efree(r->mem);
  2110. X                efree(r);
  2111. X                r = tmp;
  2112. X            }
  2113. X        return;
  2114. X        }
  2115. X    }
  2116. }
  2117. X
  2118. /*
  2119. X   "allocates" a new arena by zeroing out the old one. Up to the calling routine to keep
  2120. X   the old value of the block around.
  2121. */
  2122. X
  2123. Block *newblock() {
  2124. X    Block *ret = ul;
  2125. X
  2126. X    ul = NULL;
  2127. X    return ret;
  2128. }
  2129. X
  2130. /* "restores" an arena to its saved value. */
  2131. X
  2132. void restoreblock(Block *b) {
  2133. X    nfree();
  2134. X    ul = b;
  2135. }
  2136. SHAR_EOF
  2137. chmod 0644 nalloc.c ||
  2138. echo 'restore of nalloc.c failed'
  2139. Wc_c="`wc -c < 'nalloc.c'`"
  2140. test 2229 -eq "$Wc_c" ||
  2141.     echo 'nalloc.c: original size 2229, current size' "$Wc_c"
  2142. rm -f _shar_wnt_.tmp
  2143. fi
  2144. # ============= nalloc.h ==============
  2145. if test -f 'nalloc.h' -a X"$1" != X"-c"; then
  2146.     echo 'x - skipping nalloc.h (File already exists)'
  2147.     rm -f _shar_wnt_.tmp
  2148. else
  2149. > _shar_wnt_.tmp
  2150. echo 'x - extracting nalloc.h (Text)'
  2151. sed 's/^X//' << 'SHAR_EOF' > 'nalloc.h' &&
  2152. extern Block *newblock(void);
  2153. extern void *nalloc(SIZE_T);
  2154. extern void nfree(void);
  2155. extern void restoreblock(Block *);
  2156. X
  2157. #undef offsetof
  2158. #define offsetof(t, m) ((SIZE_T) &((t *)0)->m)
  2159. X
  2160. /* memory allocation abbreviation */
  2161. #define nnew(x) ((x *) nalloc(sizeof(x)))
  2162. #define ncpy(x) (strcpy((char *) nalloc(strlen(x) + 1), x))
  2163. SHAR_EOF
  2164. chmod 0644 nalloc.h ||
  2165. echo 'restore of nalloc.h failed'
  2166. Wc_c="`wc -c < 'nalloc.h'`"
  2167. test 323 -eq "$Wc_c" ||
  2168.     echo 'nalloc.h: original size 323, current size' "$Wc_c"
  2169. rm -f _shar_wnt_.tmp
  2170. fi
  2171. # ============= node.h ==============
  2172. if test -f 'node.h' -a X"$1" != X"-c"; then
  2173.     echo 'x - skipping node.h (File already exists)'
  2174.     rm -f _shar_wnt_.tmp
  2175. else
  2176. > _shar_wnt_.tmp
  2177. echo 'x - extracting node.h (Text)'
  2178. sed 's/^X//' << 'SHAR_EOF' > 'node.h' &&
  2179. enum nodetype {
  2180. X    rANDAND, ASSIGN, BACKQ, rBANG, BODY, CBODY, NOWAIT, BRACE, CONCAT,
  2181. X    rCOUNT, rELSE, rFLAT, rDUP, EPILOG, NEWFN, FORIN, rIF, QWORD,
  2182. X    rOROR, rPIPE, PRE, rREDIR, RMFN, ARGS, rSUBSHELL, rCASE,
  2183. X    rSWITCH, MATCH, VAR, VARSUB, rWHILE, rWORD, LAPPEND, NMPIPE
  2184. };
  2185. X
  2186. typedef struct Node Node;
  2187. X
  2188. struct Node {
  2189. X    enum nodetype type;
  2190. X    union { char *s; int i; Node *p; } u[4];
  2191. };
  2192. SHAR_EOF
  2193. chmod 0644 node.h ||
  2194. echo 'restore of node.h failed'
  2195. Wc_c="`wc -c < 'node.h'`"
  2196. test 377 -eq "$Wc_c" ||
  2197.     echo 'node.h: original size 377, current size' "$Wc_c"
  2198. rm -f _shar_wnt_.tmp
  2199. fi
  2200. # ============= open.c ==============
  2201. if test -f 'open.c' -a X"$1" != X"-c"; then
  2202.     echo 'x - skipping open.c (File already exists)'
  2203.     rm -f _shar_wnt_.tmp
  2204. else
  2205. > _shar_wnt_.tmp
  2206. echo 'x - extracting open.c (Text)'
  2207. sed 's/^X//' << 'SHAR_EOF' > 'open.c' &&
  2208. /* open.c: to insulate <fcntl.h> from the rest of rc. */
  2209. X
  2210. #include <fcntl.h>
  2211. #include "lex.h"
  2212. #include "open.h"
  2213. X
  2214. /* prototype for open() follows. comment out if necessary */
  2215. X
  2216. /*extern int open(const char *, int,...);*/
  2217. extern void rc_error(const char *);
  2218. X
  2219. /*
  2220. X   Opens a file with the necessary flags. Assumes the following
  2221. X   declaration for enum redirtype:
  2222. X
  2223. X    enum redirtype {
  2224. X        FROM, CREATE, APPEND, HEREDOC, HERESTRING
  2225. X    };
  2226. */
  2227. X
  2228. static const int mode_masks[] = {
  2229. X    /* read */    O_RDONLY,
  2230. X    /* create */    O_TRUNC | O_CREAT | O_WRONLY,
  2231. X    /* append */    O_APPEND | O_CREAT | O_WRONLY
  2232. };
  2233. X
  2234. int rc_open(const char *name, enum redirtype m) {
  2235. X    if ((unsigned int) m >= (sizeof(mode_masks)/sizeof(int)))
  2236. X        rc_error("bad mode passed to rc_open");
  2237. X
  2238. X    return open(name, mode_masks[m], 0644);
  2239. }
  2240. SHAR_EOF
  2241. chmod 0644 open.c ||
  2242. echo 'restore of open.c failed'
  2243. Wc_c="`wc -c < 'open.c'`"
  2244. test 772 -eq "$Wc_c" ||
  2245.     echo 'open.c: original size 772, current size' "$Wc_c"
  2246. rm -f _shar_wnt_.tmp
  2247. fi
  2248. # ============= open.h ==============
  2249. if test -f 'open.h' -a X"$1" != X"-c"; then
  2250.     echo 'x - skipping open.h (File already exists)'
  2251.     rm -f _shar_wnt_.tmp
  2252. else
  2253. > _shar_wnt_.tmp
  2254. echo 'x - extracting open.h (Text)'
  2255. sed 's/^X//' << 'SHAR_EOF' > 'open.h' &&
  2256. extern int rc_open(const char *, enum redirtype);
  2257. SHAR_EOF
  2258. chmod 0644 open.h ||
  2259. echo 'restore of open.h failed'
  2260. Wc_c="`wc -c < 'open.h'`"
  2261. test 50 -eq "$Wc_c" ||
  2262.     echo 'open.h: original size 50, current size' "$Wc_c"
  2263. rm -f _shar_wnt_.tmp
  2264. fi
  2265. # ============= parse.h ==============
  2266. if test -f 'parse.h' -a X"$1" != X"-c"; then
  2267.     echo 'x - skipping parse.h (File already exists)'
  2268.     rm -f _shar_wnt_.tmp
  2269. else
  2270. > _shar_wnt_.tmp
  2271. echo 'x - extracting parse.h (Text)'
  2272. sed 's/^X//' << 'SHAR_EOF' > 'parse.h' &&
  2273. extern Node *parsetree;
  2274. extern int yyparse(void);
  2275. extern void initparse(void);
  2276. SHAR_EOF
  2277. chmod 0644 parse.h ||
  2278. echo 'restore of parse.h failed'
  2279. Wc_c="`wc -c < 'parse.h'`"
  2280. test 79 -eq "$Wc_c" ||
  2281.     echo 'parse.h: original size 79, current size' "$Wc_c"
  2282. rm -f _shar_wnt_.tmp
  2283. fi
  2284. # ============= parse.y ==============
  2285. if test -f 'parse.y' -a X"$1" != X"-c"; then
  2286.     echo 'x - skipping parse.y (File already exists)'
  2287.     rm -f _shar_wnt_.tmp
  2288. else
  2289. > _shar_wnt_.tmp
  2290. echo 'x - extracting parse.y (Text)'
  2291. sed 's/^X//' << 'SHAR_EOF' > 'parse.y' &&
  2292. /* parse.y */
  2293. X
  2294. /*
  2295. X * Adapted from rc grammar, v10 manuals, volume 2.
  2296. X */
  2297. X
  2298. %{
  2299. #include "stddef.h"
  2300. #include "node.h"
  2301. #include "lex.h"
  2302. #include "tree.h"
  2303. #include "heredoc.h"
  2304. #include "parse.h"
  2305. #include "utils.h"
  2306. #undef NULL
  2307. #define NULL 0
  2308. #undef lint
  2309. #define lint        /* hush up gcc -Wall, leave out the dumb sccsid's. */
  2310. static Node *star, *nolist;
  2311. Node *parsetree;    /* not using yylval because bison declares it as an auto */
  2312. %}
  2313. X
  2314. %term ANDAND BACKBACK BANG CASE COUNT DUP ELSE END FLAT FN FOR IF IN
  2315. %term OROR PIPE REDIR SUB SUBSHELL SWITCH TWIDDLE WHILE WORD HUH
  2316. X
  2317. %left WHILE ')' ELSE
  2318. %left ANDAND OROR '\n'
  2319. %left BANG SUBSHELL
  2320. %left PIPE
  2321. %right '$' 
  2322. %left SUB
  2323. /*
  2324. */
  2325. X
  2326. %union {
  2327. X    struct Node *node;
  2328. X    struct Redir redir;
  2329. X    struct Pipe pipe;
  2330. X    struct Dup dup;
  2331. X    struct Word word;
  2332. X    char *keyword;
  2333. }
  2334. X
  2335. %type <redir> REDIR
  2336. %type <pipe> PIPE
  2337. %type <dup> DUP
  2338. %type <word> WORD
  2339. %type <keyword> keyword
  2340. %type <node> assign body brace case cbody cmd cmdsa cmdsan comword epilog
  2341. X         first line paren redir sword simple iftail word words
  2342. X
  2343. %start rc
  2344. X
  2345. %%
  2346. X
  2347. rc    : line end        { parsetree = $1; YYACCEPT; }
  2348. X    | error end        { yyerrok; parsetree = NULL; YYABORT; }
  2349. X
  2350. /* an rc line may end in end-of-file as well as newline, e.g., rc -c 'ls' */
  2351. end    : END    /* EOF */    { if (!heredoc(1)) YYABORT; } /* flag error if there is a heredoc in the queue */
  2352. X    | '\n'            { if (!heredoc(0)) YYABORT; } /* get heredoc on \n */
  2353. X
  2354. /* a cmdsa is a command followed by ampersand or newline (used in "line" and "body") */
  2355. cmdsa    : cmd ';'
  2356. X    | cmd '&'        { $$ = ($1 != NULL ? newnode(NOWAIT,$1) : $1); }
  2357. X
  2358. /* a line is a single command, or a command terminated by ; or & followed by a line (recursive) */
  2359. line    : cmd
  2360. X    | cmdsa line        { $$ = ($1 != NULL ? newnode(BODY,$1,$2) : $2); }
  2361. X
  2362. /* a body is like a line, only commands may also be terminated by newline */
  2363. body    : cmd
  2364. X    | cmdsan body        { $$ = ($1 == NULL ? $2 : $2 == NULL ? $1 : newnode(BODY,$1,$2)); }
  2365. X
  2366. cmdsan    : cmdsa
  2367. X    | cmd '\n'        { $$ = $1; if (!heredoc(0)) YYABORT; } /* get h.d. on \n */
  2368. X
  2369. brace    : '{' body '}'        { $$ = $2; }
  2370. X
  2371. paren    : '(' body ')'        { $$ = $2; }
  2372. X
  2373. assign    : first '=' word    { $$ = newnode(ASSIGN,$1,$3); }
  2374. X
  2375. epilog    :            { $$ = NULL; }
  2376. X    | redir epilog        { $$ = newnode(EPILOG,$1,$2); }
  2377. X
  2378. /* a redirection is a dup (e.g., >[1=2]) or a file redirection. (e.g., > /dev/null) */
  2379. SHAR_EOF
  2380. true || echo 'restore of parse.y failed'
  2381. fi
  2382. echo 'End of  part 3'
  2383. echo 'File parse.y is continued in part 4'
  2384. echo 4 > _shar_seq_.tmp
  2385. exit 0
  2386. exit 0 # Just in case...
  2387. -- 
  2388. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  2389. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  2390. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  2391. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  2392.