home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 2 / 2268 < prev    next >
Encoding:
Internet Message Format  |  1990-12-28  |  46.6 KB

  1. From: netnews@netcom.UUCP (USENET Administration)
  2. Newsgroups: alt.sources
  3. Subject: Public Domain Korn Shell - Part.03 of 7
  4. Message-ID: <18608@netcom.UUCP>
  5. Date: 12 Dec 90 11:36:21 GMT
  6.  
  7. #!/bin/sh
  8. # This is part 03 of ksh-pd
  9. # ============= src/lex.c ==============
  10. if test ! -d 'src'; then
  11.     echo 'x - creating directory src'
  12.     mkdir 'src'
  13. fi
  14. if test -f 'src/lex.c' -a X"$1" != X"-c"; then
  15.     echo 'x - skipping src/lex.c (File already exists)'
  16. else
  17. echo 'x - extracting src/lex.c (Text)'
  18. sed 's/^X//' << 'SHAR_EOF' > 'src/lex.c' &&
  19. X/*
  20. X * lexical analysis and source input
  21. X */
  22. X
  23. Xstatic char *RCSid = "$Header: /tmp/egisin/src/RCS/lex.c,v 3.4 88/12/17 21:19:21 egisin Exp $";
  24. X
  25. X#include <stddef.h>
  26. X#include <stdio.h>
  27. X#include <string.h>
  28. X#include <errno.h>
  29. X#include <setjmp.h>
  30. X#include <unistd.h>
  31. X#include "sh.h"
  32. X#include "lex.h"
  33. X#include "tree.h"
  34. X#include "table.h"
  35. X#include "expand.h"
  36. X
  37. X    int    ttyfd = -1;        /* tty fd for edit and jobs */
  38. X    char   *history[HISTORY];    /* saved commands */
  39. X    char  **histptr = history - 1;    /* last history item */
  40. X    int    histpush;        /* number of pushed fc commands */
  41. X
  42. Xstatic    int    alias;
  43. Xstatic    int    getsc_ ARGS((void));
  44. X
  45. X/* optimized getsc_() */
  46. X#define    getsc()    ((*source->str != 0) ? *source->str++ : getsc_())
  47. X#define    ungetsc() (source->str--)
  48. X
  49. X/*
  50. X * Lexical analyzer
  51. X *
  52. X * tokens are not regular expressions, they are LL(1).
  53. X * for example, "${var:-${PWD}}", and "$(size $(whence ksh))".
  54. X * hence the state stack.
  55. X */
  56. X
  57. Xint
  58. Xyylex(cf)
  59. X    int cf;
  60. X{
  61. X    register int c, state;
  62. X    char states [64], *statep = states;
  63. X    XString ws;        /* expandable output word */
  64. X    register char *wp;    /* output word pointer */
  65. X    register char *sp, *dp;
  66. X    int istate;
  67. X    int c2;
  68. X
  69. X  Again:
  70. X    Xinit(ws, wp, 256);
  71. X    if (alias) {            /* trailing ' ' in alias definition */
  72. X        alias = 0;
  73. X        cf |= ALIAS;
  74. X    }
  75. X
  76. X    if (cf&ONEWORD)
  77. X        istate = SWORD;
  78. X    else {            /* normal lexing */
  79. X        istate = SBASE;
  80. X        while ((c = getsc()) == ' ' || c == '\t')
  81. X            ;
  82. X        if (c == '#')
  83. X            while ((c = getsc()) != 0 && c != '\n')
  84. X                ;
  85. X        ungetsc();
  86. X    }
  87. X
  88. X    /* collect non-special or quoted characters to form word */
  89. X    for (*statep = state = istate;
  90. X         !((c = getsc()) == 0 || state == SBASE && ctype(c, C_LEX1)); ) {
  91. X        Xcheck(ws, wp);
  92. X        switch (state) {
  93. X          case SBASE:
  94. X          Sbase:
  95. X            switch (c) {
  96. X              case '\\':
  97. X                c = getsc();
  98. X                if (c != '\n')
  99. X                    *wp++ = QCHAR, *wp++ = c;
  100. X                else
  101. X                    if (wp == Xstring(ws, wp))
  102. X                        goto Again;
  103. X                break;
  104. X              case '\'':
  105. X                *++statep = state = SSQUOTE;
  106. X                *wp++ = OQUOTE;
  107. X                break;
  108. X              case '"':
  109. X                *++statep = state = SDQUOTE;
  110. X                *wp++ = OQUOTE;
  111. X                break;
  112. X              default:
  113. X                goto Subst;
  114. X            }
  115. X            break;
  116. X
  117. X          Subst:
  118. X            switch (c) {
  119. X              case '\\':
  120. X                c = getsc();
  121. X                switch (c) {
  122. X                  case '\n':
  123. X                    break;
  124. X                  case '"': case '\\':
  125. X                  case '$': case '`':
  126. X                    *wp++ = QCHAR, *wp++ = c;
  127. X                    break;
  128. X                  default:
  129. X                    *wp++ = CHAR, *wp++ = '\\';
  130. X                    *wp++ = CHAR, *wp++ = c;
  131. X                    break;
  132. X                }
  133. X                break;
  134. X              case '$':
  135. X                c = getsc();
  136. X                if (c == '(') {
  137. X                    *++statep = state = SPAREN;
  138. X                    *wp++ = COMSUB;
  139. X                } else
  140. X                if (c == '{') {
  141. X                    *++statep = state = SBRACE;
  142. X                    *wp++ = OSUBST;
  143. X                    c = getsc();
  144. X                    do {
  145. X                        Xcheck(ws, wp);
  146. X                        *wp++ = c;
  147. X                        c = getsc();
  148. X                    } while (ctype(c, C_ALPHA|C_DIGIT));
  149. X                    *wp++ = 0;
  150. X                    /* todo: more compile-time checking */
  151. X                    if (c == '}')
  152. X                        ungetsc();
  153. X                    else if (c == '#' || c == '%') {
  154. X                        /* Korn pattern trimming */
  155. X                        if (getsc() == c)
  156. X                            c |= 0x80;
  157. X                        else
  158. X                            ungetsc();
  159. X                        *wp++ = c;
  160. X                    } else if (c == ':')
  161. X                        *wp++ = 0x80|getsc();
  162. X                    else
  163. X                        *wp++ = c;
  164. X                } else if (ctype(c, C_ALPHA)) {
  165. X                    *wp++ = OSUBST;
  166. X                    do {
  167. X                        *wp++ = c;
  168. X                        c = getsc();
  169. X                    } while (ctype(c, C_ALPHA|C_DIGIT));
  170. X                    *wp++ = 0;
  171. X                    *wp++ = CSUBST;
  172. X                    ungetsc();
  173. X                } else if (ctype(c, C_DIGIT|C_VAR1)) {
  174. X                    *wp++ = OSUBST;
  175. X                    *wp++ = c;
  176. X                    *wp++ = 0;
  177. X                    *wp++ = CSUBST;
  178. X                } else {
  179. X                    *wp++ = CHAR, *wp++ = '$';
  180. X                    ungetsc();
  181. X                }
  182. X                break;
  183. X              case '`':
  184. X                *++statep = state = SBQUOTE;
  185. X                *wp++ = COMSUB;
  186. X                break;
  187. X              default:
  188. X                *wp++ = CHAR, *wp++ = c;
  189. X            }
  190. X            break;
  191. X
  192. X          case SSQUOTE:
  193. X            if (c == '\'') {
  194. X                state = *--statep;
  195. X                *wp++ = CQUOTE;
  196. X            } else
  197. X                *wp++ = QCHAR, *wp++ = c;
  198. X            break;
  199. X
  200. X          case SDQUOTE:
  201. X            if (c == '"') {
  202. X                state = *--statep;
  203. X                *wp++ = CQUOTE;
  204. X            } else
  205. X                goto Subst;
  206. X            break;
  207. X
  208. X          case SPAREN:
  209. X            if (c == '(')
  210. X                *++statep = state;
  211. X            else if (c == ')')
  212. X                state = *--statep;
  213. X            if (state == SPAREN)
  214. X                *wp++ = c;
  215. X            else
  216. X                *wp++ = 0; /* end of COMSUB */
  217. X            break;
  218. X
  219. X          case SBRACE:
  220. X            if (c == '}') {
  221. X                state = *--statep;
  222. X                *wp++ = CSUBST;
  223. X            } else
  224. X                goto Sbase;
  225. X            break;
  226. X
  227. X          case SBQUOTE:
  228. X            if (c == '`') {
  229. X                *wp++ = 0;
  230. X                state = *--statep;
  231. X            } else    /* todo: handle silly `\`` escapes */
  232. X                /* todo: both \" and \` in "`...`" */
  233. X                *wp++ = c;
  234. X            break;
  235. X
  236. X          case SWORD:    /* ONEWORD */
  237. X            goto Subst;
  238. X        }
  239. X    }
  240. X    if (state != istate)
  241. X        yyerror("no closing quote");
  242. X
  243. X    if (c == '<' || c == '>') {
  244. X        char *cp = Xstring(ws, wp);
  245. X        if (wp > cp && cp[0] == CHAR && digit(cp[1])) {
  246. X            wp = cp; /* throw away word */
  247. X            c2/*unit*/ = cp[1] - '0';
  248. X        } else
  249. X            c2/*unit*/ = c == '>'; /* 0 for <, 1 for > */
  250. X    }
  251. X
  252. X    if (wp == Xstring(ws, wp) && state == SBASE) {
  253. X        Xfree(ws, sp);    /* free word */
  254. X        /* no word, process LEX1 character */
  255. X        switch (c) {
  256. X          default:
  257. X            return c;
  258. X
  259. X          case '|':
  260. X          case '&':
  261. X          case ';':
  262. X            if (getsc() == c)
  263. X                c = (c == ';') ? BREAK :
  264. X                    (c == '|') ? LOGOR :
  265. X                    (c == '&') ? LOGAND :
  266. X                    YYERRCODE;
  267. X            else
  268. X                ungetsc();
  269. X            return c;
  270. X
  271. X          case '>':
  272. X          case '<': {
  273. X            register struct ioword *iop;
  274. X
  275. X            iop = (struct ioword *) alloc(sizeof(*iop), ATEMP);
  276. X            iop->unit = c2/*unit*/;
  277. X
  278. X            c2 = getsc();
  279. X            if (c2 == '>' || c2 == '<') {
  280. X                iop->flag = c != c2 ? IORDWR : c == '>' ? IOCAT : IOHERE;
  281. X                c2 = getsc();
  282. X            } else
  283. X                iop->flag = c == '>' ? IOWRITE : IOREAD;
  284. X
  285. X            if (iop->flag == IOHERE)
  286. X                if (c2 == '-')
  287. X                    iop->flag |= IOSKIP;
  288. X                else
  289. X                    ungetsc();
  290. X            else
  291. X                if (c2 == '&')
  292. X                    iop->flag = IODUP;
  293. X                else if (c2 == '!' && iop->flag == IOWRITE)
  294. X                    iop->flag |= IOCLOB;
  295. X                else
  296. X                    ungetsc();
  297. X            yylval.iop = iop;
  298. X            return REDIR;
  299. X            }
  300. X          case '\n':
  301. X            gethere();
  302. X            if (cf & CONTIN)
  303. X                goto Again;
  304. X            return c;
  305. X
  306. X          case '(':
  307. X            c2 = getsc();
  308. X            if (c2 == ')')
  309. X                c = MPAREN;
  310. X            else if (c2 == '(')
  311. X                yyerror("(( not supported");
  312. X            else
  313. X                ungetsc();
  314. X          case ')':
  315. X            return c;
  316. X        }
  317. X    }
  318. X
  319. X    *wp++ = EOS;        /* terminate word */
  320. X    yylval.cp = Xclose(ws, wp);
  321. X    if (state == SWORD)    /* ONEWORD? */
  322. X        return LWORD;
  323. X    ungetsc();        /* unget terminator */
  324. X
  325. X    /* copy word to unprefixed string ident */
  326. X    for (sp = yylval.cp, dp = ident; dp < ident+IDENT && (c = *sp++) == CHAR; )
  327. X        *dp++ = *sp++;
  328. X    *dp = 0;
  329. X#if 0
  330. X    if (*ident == '~' || (dp = strchr(ident, '=')) != NULL && dp[1] == '~')
  331. X        "Tilde expansion";
  332. X#endif
  333. X    if (c != EOS)
  334. X        *ident = 0;    /* word is not unquoted */
  335. X
  336. X    if (*ident != 0 && (cf&(KEYWORD|ALIAS))) {
  337. X        register struct tbl *p;
  338. X
  339. X        p = tsearch(&lexicals, ident, hash(ident));
  340. X        if (p != NULL && (p->flag&ISSET))
  341. X            if (p->type == CKEYWD && (cf&KEYWORD)) {
  342. X                afree(yylval.cp, ATEMP);
  343. X                return p->val.i;
  344. X            } else
  345. X            if (p->type == CALIAS && (cf&ALIAS)) {
  346. X                register Source *s;
  347. X
  348. X                /* check for recursive aliasing */
  349. X                for (s = source; s->type == SALIAS; s = s->next)
  350. X                    if (s->u.tblp == p)
  351. X                        return LWORD;
  352. X                afree(yylval.cp, ATEMP);
  353. X
  354. X                /* push alias expansion */
  355. X                s = pushs(SALIAS);
  356. X                s->str = p->val.s;
  357. X                s->u.tblp = p;
  358. X                s->next = source;
  359. X                source = s;
  360. X                goto Again;
  361. X            }
  362. X    }
  363. X
  364. X    return LWORD;
  365. X}
  366. X
  367. Xstatic void readhere();
  368. X
  369. Xgethere()
  370. X{
  371. X    register struct ioword **p;
  372. X
  373. X    for (p = heres; p < herep; p++)
  374. X        readhere(*p);
  375. X    herep = heres;
  376. X}
  377. X
  378. X/*
  379. X * read "<<word" text into temp file
  380. X * todo: set up E_ERR to fclose(f) on unwind
  381. X */
  382. X
  383. Xstatic void
  384. Xreadhere(iop)
  385. X    register struct ioword *iop;
  386. X{
  387. X    register FILE *f;
  388. X    struct temp *h;
  389. X    register int c;
  390. X    char *eof;
  391. X    register char *cp;
  392. X    char line [LINE+1];
  393. X
  394. X    eof = evalstr(iop->name, 0);
  395. X
  396. X    h = maketemp(ATEMP);
  397. X    h->next = e.temps; e.temps = h;
  398. X    iop->name = h->name;
  399. X    f = fopen(h->name, "w");
  400. X    if (f == NULL)
  401. X        errorf("Cannot create temporary file\n");
  402. X    setvbuf(f, (char *)NULL, _IOFBF, BUFSIZ);
  403. X
  404. X    for (;;) {
  405. X        cp = line;
  406. X        while ((c = getsc()) != '\n') {
  407. X            if (c == 0)
  408. X                errorf("here document `%s' unclosed\n", eof);
  409. X            if (cp >= line+LINE)
  410. X                break;
  411. X            *cp++ = c;
  412. X        }
  413. X        ungetsc();
  414. X        *cp = 0;
  415. X        for (cp = line; iop->flag&IOSKIP && *cp == '\t'; cp++)
  416. X            ;
  417. X        if (strcmp(eof, cp) == 0 || c == 0)
  418. X            break;
  419. X        while ((c = *cp++) != '\0')
  420. X            putc(c, f);
  421. X        while ((c = getsc()) != '\n') {
  422. X            if (c == 0)
  423. X                errorf("here document `%s' unclosed\n", eof);
  424. X            putc(c, f);
  425. X        }
  426. X        putc(c, f);
  427. X    }
  428. X    fclose(f);
  429. X}
  430. X
  431. Xvoid
  432. Xyyerror(msg)
  433. X    Const char *msg;
  434. X{
  435. X    yynerrs++;
  436. X    while (source->type == SALIAS) /* pop aliases */
  437. X        source = source->next;
  438. X    if (source->file != NULL)
  439. X        shellf("%s[%d]: ", source->file, source->line);
  440. X    source->str = null;    /* zap pending input */
  441. X    errorf("%s\n", msg);
  442. X}
  443. X
  444. X/*
  445. X * input for yylex with alias expansion
  446. X */
  447. X
  448. XSource *
  449. Xpushs(type)
  450. X    int type;
  451. X{
  452. X    register Source *s;
  453. X
  454. X    s = (Source *) alloc(sizeof(Source), ATEMP);
  455. X    s->type = type;
  456. X    s->str = null;        /* "" */
  457. X    s->line = 0;
  458. X    s->file = NULL;
  459. X    s->echo = 0;
  460. X    s->next = NULL;
  461. X    return s;
  462. X}
  463. X
  464. Xstatic int
  465. Xgetsc_()
  466. X{
  467. X    register Source *s = source;
  468. X    register int c;
  469. X
  470. X    while ((c = *s->str++) == 0) {
  471. X        s->str = NULL;        /* return 0 for EOF by default */
  472. X        switch (s->type) {
  473. X          case SEOF:
  474. X            s->str = null;
  475. X            return 0;
  476. X
  477. X          case STTY:
  478. X            if (histpush < 0) {    /* commands pushed by dofc */
  479. X                s->type = SHIST;
  480. X                s->str = null;
  481. X                continue;
  482. X            }
  483. X            s->line++;
  484. X            s->str = line;
  485. X            line[0] = '\0';
  486. X            pprompt(prompt);
  487. X            flushshf(1);    flushshf(2);
  488. X#if EDIT
  489. X            if (flag[FEMACS])
  490. X                c = x_read(ttyfd, line, LINE);
  491. X            else
  492. X#endif
  493. X                c = read(ttyfd, line, LINE);
  494. X            if (c < 0)     /* read error */
  495. X                c = 0;
  496. X            if (c == 0) /* EOF */
  497. X                s->str = NULL;
  498. X            prompt = strval(global("PS2"));
  499. X            line[c] = '\0';
  500. X            if (line[0] != '\n')
  501. X                histsave(line);
  502. X            else
  503. X                s->line--;
  504. X            break;
  505. X
  506. X          case SHIST:
  507. X            if (histpush == 0) {
  508. X                s->type = STTY;
  509. X                s->str = null;
  510. X                continue;
  511. X            }
  512. X            s->line++;
  513. X            s->str = histptr[++histpush];
  514. X            pprompt("!< ");    /* todo: PS9 */
  515. X            shellf("%s\n", s->str);
  516. X            strcpy(line, s->str);
  517. X            s->str = strchr(line, 0);
  518. X            *s->str++ = '\n';
  519. X            *s->str = 0;
  520. X            s->str = line;
  521. X            break;
  522. X
  523. X          case SFILE:
  524. X            s->line++;
  525. X            s->str = fgets(line, LINE, s->u.file);
  526. X            if (s->str == NULL)
  527. X                if (s->u.file != stdin)
  528. X                    fclose(s->u.file);
  529. X            break;
  530. X
  531. X          case SWSTR:
  532. X            break;
  533. X
  534. X          case SSTRING:
  535. X            s->str = "\n";
  536. X            s->type = SEOF;
  537. X            break;
  538. X
  539. X          case SWORDS:
  540. X            s->str = *s->u.strv++;
  541. X            s->type = SWORDSEP;
  542. X            break;
  543. X
  544. X          case SWORDSEP:
  545. X            if (*s->u.strv == NULL) {
  546. X                s->str = "\n";
  547. X                s->type = SEOF;
  548. X            } else {
  549. X                s->str = " ";
  550. X                s->type = SWORDS;
  551. X            }
  552. X            break;
  553. X
  554. X          case SALIAS:
  555. X            s->str = s->u.tblp->val.s;
  556. X            if (s->str[0] != 0 && strchr(s->str, 0)[-1] == ' ')
  557. X                alias = 1;    /* trailing ' ' */
  558. X            source = s = s->next;    /* pop source stack */
  559. X            continue;
  560. X        }
  561. X        if (s->str == NULL) {
  562. X            s->type = SEOF;
  563. X            s->str = null; /* "" */
  564. X            return 0;
  565. X        }
  566. X        if (s->echo)
  567. X            fputs(s->str, shlout);
  568. X    }
  569. X    return c;
  570. X}
  571. X
  572. Xpprompt(cp)
  573. X    register char *cp;
  574. X{
  575. X    while (*cp != 0)
  576. X        if (*cp != '!')
  577. X            putc(*cp++, shlout);
  578. X        else
  579. X            if (*++cp == '!')
  580. X                putc(*cp++, shlout);
  581. X            else
  582. X                shellf("%d", source->line);
  583. X    fflush(shlout);
  584. X}
  585. X
  586. SHAR_EOF
  587. true || echo 'restore of src/lex.c failed'
  588. fi
  589. # ============= src/edit.c ==============
  590. if test -f 'src/edit.c' -a X"$1" != X"-c"; then
  591.     echo 'x - skipping src/edit.c (File already exists)'
  592. else
  593. echo 'x - extracting src/edit.c (Text)'
  594. sed 's/^X//' << 'SHAR_EOF' > 'src/edit.c' &&
  595. X/*
  596. X *  EDIT.C -- Emacs-like command line editing and history
  597. X *
  598. X *  created by Ron Natalie at BRL
  599. X *  modified by Doug Kingston, Doug Gwyn, and Lou Salkind
  600. X *  adapted to PD ksh by Eric Gisin
  601. X */
  602. X
  603. X#if EDIT
  604. X
  605. Xstatic char *RCSid = "$Header: /tmp/egisin/src/RCS/edit.c,v 3.2 88/12/14 20:11:44 egisin Exp $";
  606. X
  607. X#include <stddef.h>
  608. X#include <stdlib.h>
  609. X#include <string.h>
  610. X#include <stdio.h>
  611. X#include <unistd.h>
  612. X#include <signal.h>
  613. X#include <sys/types.h>
  614. X#include <sys/stat.h>
  615. X#include <dirent.h>
  616. X#include <fcntl.h>
  617. X#include <ctype.h>
  618. X#include <errno.h>
  619. X#include <setjmp.h>
  620. X#include "sh.h"
  621. X#include "lex.h"
  622. X#include "tree.h"        /* DOTILDE */
  623. X#include "tty.h"
  624. X#include "table.h"
  625. X#include "expand.h"
  626. X
  627. XArea    aedit;
  628. X#define    AEDIT    &aedit        /* area for kill ring and macro defns */
  629. X
  630. X#undef CTRL            /* _BSD brain damage */
  631. X#define    CTRL(x)        ((x) == '?' ? 0x7F : (x) & 0x1F)    /* ASCII */
  632. X#define    UNCTRL(x)    ((x) == 0x7F ? '?' : (x) | 0x40)    /* ASCII */
  633. X
  634. X#if ! defined S_ISDIR
  635. X#define S_ISDIR(mode)    (((mode) & S_IFMT) == S_IFDIR)
  636. X#endif
  637. X
  638. X#if ! defined S_ISREG
  639. X#define S_ISREG(mode)    (((mode) & S_IFMT) == S_IFREG)
  640. X#endif
  641. X
  642. X#if defined _CRAY2
  643. Xextern unsigned    sleep();
  644. X#endif
  645. X
  646. X/* values returned by keyboard functions */
  647. X#define    KSTD    0
  648. X#define    KPREF    1        /* ^[, ^X */
  649. X#define    KEOL    2        /* ^M, ^J */
  650. X#define    KINTR    3        /* ^G, ^C */
  651. X    
  652. Xstruct    x_ftab  {
  653. X    int    (*xf_func)();
  654. X    char    *xf_name;
  655. X    char    xf_db_tab;
  656. X    char    xf_db_char;
  657. X    short    xf_flags;
  658. X};
  659. X
  660. X#define    XF_NINPUT    1
  661. X#define    XF_ALLOC    2
  662. X#define    XF_NOBIND    4
  663. X
  664. X#define    isfs(c)        (c == ' ' || c == '\t')
  665. X#define    BEL        0x07
  666. X#define    CMASK        0x7F    /* 7-bit ASCII character mask */
  667. X
  668. Xtypedef int bool_t;
  669. X#define    FALSE    0
  670. X#define    TRUE    1
  671. X
  672. Xstatic bool_t    x_mode = FALSE;
  673. Xstatic int    x_prefix1 = CTRL('['), x_prefix2 = CTRL('X');
  674. Xstatic char   **x_histp;    /* history position */
  675. Xstatic    char   *xbuf;        /* beg input buffer */
  676. Xstatic    char   *xend;        /* end input buffer */
  677. Xstatic char    *xcp;
  678. Xstatic char    *xep;
  679. Xstatic int    (*x_last_command)();
  680. X/*static struct    x_ftab *x_tab[3][128];*/
  681. Xstatic struct    x_ftab Const *(*x_tab)[128] = NULL; /* key definition */
  682. Xstatic char    *(*x_atab)[128] = NULL; /* macro definitions */
  683. X#define    KILLSIZE    20
  684. Xstatic char    *killstack[KILLSIZE];
  685. Xstatic int    killsp, killtp;
  686. Xstatic int    x_curprefix;
  687. Xstatic char    *macroptr;
  688. Xstatic int    first_time = 1;
  689. Xstatic int    x_maxlen;    /* to determine column width */
  690. Xstatic int    x_cols = 80;    /* todo: $COLUMNS */
  691. X
  692. Xstatic void    x_flush(), x_putc(), x_puts();
  693. Xstatic void    x_goto(), x_bs(), x_delete(), x_ins(), x_mapin();
  694. Xstatic int    x_fword(), x_bword(), x_size(), x_size_str();
  695. Xstatic void    x_zotc(), x_zots(), x_push(), x_redraw(), x_load_hist();
  696. Xstatic void    compl_command(), compl_dec(), compl_file();
  697. Xstatic int    x_insert(), x_ins_string(), x_del_back();
  698. Xstatic int    x_del_char(), x_del_bword(), x_mv_bword(), x_mv_fword();
  699. Xstatic int    x_del_fword(), x_mv_back(), x_mv_forw(), x_search_char();
  700. Xstatic int    x_newline(), x_end_of_text(), x_abort(), x_error();
  701. Xstatic int    x_beg_hist(), x_end_hist(), x_prev_com(), x_next_com();
  702. Xstatic int    x_search_hist(), x_del_line(), x_mv_end(), x_mv_begin();
  703. Xstatic int    x_draw_line(), x_transpose(), x_meta1(), x_meta2();
  704. Xstatic int    x_kill(), x_yank(), x_meta_yank(), x_literal();
  705. Xstatic int    x_stuffreset(), x_stuff(), x_complete(), x_enumerate();
  706. X#if SILLY
  707. Xstatic int    x_game_of_life();
  708. X#endif
  709. Xstatic int    x_comp_file(), x_comp_comm();
  710. Xstatic int    x_list_file(), x_list_comm();
  711. Xstatic int    strmatch();
  712. X
  713. Xstatic struct x_ftab Const x_ftab[] = {
  714. X     {x_insert,    "auto-insert",        0,     0,    0 },
  715. X    {x_error,    "error",        0,     0,    0 },
  716. X     {x_ins_string,    "macro-string",        0,     0,    XF_NOBIND|XF_ALLOC},
  717. X/* Do not move the above! */
  718. X    {x_del_back,    "delete-char-backward",    0, CTRL('H'),    0 },
  719. X    {x_del_char,    "delete-char-forward",    0, CTRL('D'),    0 },
  720. X    {x_del_bword,    "delete-word-backward",    0, CTRL('W'),    0 },
  721. X    {x_mv_bword,    "backward-word",     1,    'b',    0 },
  722. X    {x_mv_fword,    "forward-word",        1,    'f',    0 },
  723. X    {x_del_fword,    "delete-word-forward",     1,    'd',    0 },
  724. X    {x_mv_back,    "backward-char",    0, CTRL('B'),    0 },
  725. X    {x_mv_forw,    "forward-char",        0, CTRL('F'),    0 },
  726. X    {x_search_char,    "search-character",    0, CTRL(']'),    0 },
  727. X    {x_newline,    "newline",        0, CTRL('M'),    0 },
  728. X    {x_newline,    "newline",        0, CTRL('J'),    0 },
  729. X    {x_end_of_text,    "eot",            0, CTRL('_'),    0 },
  730. X    {x_abort,    "abort",        0, CTRL('G'),    0 },
  731. X    {x_prev_com,    "up-history",        0, CTRL('P'),    XF_NINPUT},
  732. X    {x_next_com,    "down-history",        0, CTRL('N'),    XF_NINPUT},
  733. X    {x_search_hist,    "search-history",    0, CTRL('R'),    XF_NINPUT},
  734. X    {x_beg_hist,    "beginning-of-history",    1,    '<',    XF_NINPUT},
  735. X    {x_end_hist,    "end-of-history",    1,    '>',    XF_NINPUT},
  736. X    {x_del_line,    "kill-line",        0, CTRL('U'),    0 },
  737. X    {x_mv_end,    "end-of-line",        0, CTRL('E'),    0 },
  738. X    {x_mv_begin,    "beginning-of-line",    0, CTRL('A'),    0 },
  739. X    {x_draw_line,    "redraw",        0, CTRL('L'),    0 },
  740. X    {x_meta1,    "prefix-1",        0, CTRL('['),    0 },
  741. X    {x_meta2,    "prefix-2",        0, CTRL('X'),    0 },
  742. X    {x_kill,    "kill-to-eol",        0, CTRL('K'),    0 },
  743. X    {x_yank,    "yank",            0, CTRL('Y'),    0 },
  744. X    {x_meta_yank,    "yank-pop",         1,    'y',    0 },
  745. X    {x_literal,    "quote",        0, CTRL('^'),    0 },
  746. X    {x_stuffreset,     "stuff-reset",        0,     0,    0 },
  747. X#if BRL && defined(TIOCSTI)
  748. X    {x_stuff,     "stuff",        0, CTRL('T'),    0 },
  749. X    {x_transpose,    "transpose-chars",    0,     0,    0 },
  750. X#else
  751. X    {x_stuff,     "stuff",        0,     0,    0 },
  752. X    {x_transpose,    "transpose-chars",    0, CTRL('T'),    0 },
  753. X#endif
  754. X    {x_complete,    "complete",        1, CTRL('['),    0 },
  755. X    {x_enumerate,    "list",            1,    '?',    0 },
  756. X    {x_comp_file,    "complete-file",    2, CTRL('X'),    0 },
  757. X    {x_comp_comm,    "complete-command",    2, CTRL('['),    0 },
  758. X    {x_list_file,    "list-file",        0,     0,    0 },
  759. X    {x_list_comm,    "list-command",        2,    '?',    0 },
  760. X#if SILLY
  761. X    {x_game_of_life, "play-game-of-life",    0,    0,    0 },
  762. X#endif 
  763. X    { 0 }
  764. X};
  765. X
  766. X#define    xft_insert &x_ftab[0]
  767. X#define    xft_error &x_ftab[1]
  768. X#define    xft_ins_string &x_ftab[2]
  769. X
  770. Xint
  771. Xx_read(fd, buf, len)
  772. X    int fd;            /* not used */
  773. X    char *buf;
  774. X    size_t len;
  775. X{
  776. X    char    c;
  777. X    int    i;
  778. X    int   (*func)();
  779. X    extern    x_insert();
  780. X
  781. X    (void)set_xmode(TRUE);
  782. X    xbuf = buf; xend = buf + len;
  783. X    xcp = xep = buf;
  784. X    *xcp = 0;
  785. X    x_curprefix = 0;
  786. X    macroptr = null;
  787. X    x_histp = histptr + 1;
  788. X
  789. X    while (1)  {
  790. X        x_flush();
  791. X        if (*macroptr)  {
  792. X            c = *macroptr++;
  793. X            if (*macroptr == 0)
  794. X                macroptr = null;
  795. X        }
  796. X        else {
  797. X            i = read(ttyfd, &c, 1);
  798. X            if (i != 1)
  799. X                goto Exit;
  800. X        }
  801. X
  802. X        if (x_curprefix == -1)
  803. X            func = x_insert;
  804. X        else
  805. X            func = x_tab[x_curprefix][c&CMASK]->xf_func;
  806. X        if (func == NULL)
  807. X            func = x_error;
  808. X        i = c | (x_curprefix << 8);
  809. X        x_curprefix = 0;
  810. X        switch (i = (*func)(i))  {
  811. X          case KSTD:
  812. X            x_last_command = func;
  813. X          case KPREF:
  814. X            break;
  815. X          case KEOL:
  816. X            i = xep - xbuf;
  817. X            x_last_command = 0;
  818. X            /* XXX -- doesn't get them all */
  819. X            if (strncmp(xbuf, "stty", 4) == 0)
  820. X                first_time = 1;
  821. X            goto Exit;
  822. X          case KINTR:    /* special case for interrupt */
  823. X            i = -1;
  824. X            errno = EINTR;
  825. X            goto Exit;
  826. X        }
  827. X    }
  828. X  Exit:
  829. X    (void)set_xmode(FALSE);
  830. X    if (i < 0 && errno == EINTR)
  831. X        trapsig(SIGINT);
  832. X    return i;
  833. X}
  834. X
  835. Xstatic int
  836. Xx_insert(c)  {
  837. X    char    str[2];
  838. X
  839. X    /*
  840. X     *  Should allow tab and control chars.
  841. X     */
  842. X    if (c == 0)  {
  843. X        x_putc(BEL);
  844. X        return KSTD;
  845. X    }
  846. X    str[0] = c;
  847. X    str[1] = 0;
  848. X    x_ins(str);
  849. X    return KSTD;
  850. X}
  851. X
  852. Xstatic int
  853. Xx_ins_string(c)
  854. X{
  855. X    if (*macroptr)   {
  856. X        x_putc(BEL);
  857. X        return KSTD;
  858. X    }
  859. X    macroptr = x_atab[c>>8][c & CMASK];
  860. X    return KSTD;
  861. X}
  862. X
  863. Xstatic void
  864. Xx_ins(cp)
  865. X    char    *cp;
  866. X{
  867. X    int    count, i;
  868. X
  869. X    count = strlen(cp);
  870. X    if (xep+count >= xend) {
  871. X        x_putc(BEL);
  872. X        return;
  873. X    }
  874. X
  875. X    if (xcp != xep)
  876. X        memmove(xcp+count, xcp, xep - xcp + 1);
  877. X    else
  878. X        xcp[count] = 0;
  879. X    memmove(xcp, cp, count);
  880. X    x_zots(xcp);
  881. X    xcp += count;
  882. X    xep += count;
  883. X    i = xep - xcp;
  884. X    cp = xep;
  885. X    while (i--)
  886. X        x_bs(*--cp);
  887. X    return;
  888. X}
  889. X
  890. Xstatic int
  891. Xx_del_back(c)  {
  892. X    if (xcp == xbuf)  {
  893. X        x_putc(BEL);
  894. X        return KSTD;
  895. X    }
  896. X    x_goto(xcp - 1);
  897. X    x_delete(1);
  898. X    return KSTD;
  899. X}
  900. X
  901. Xstatic int
  902. Xx_del_char(c)  {
  903. X    if (xcp == xep)  {
  904. X        x_putc(BEL);
  905. X        return KSTD;
  906. X    }
  907. X    x_delete(1);
  908. X    return KSTD;
  909. X}
  910. X
  911. Xstatic void
  912. Xx_delete(nc)  {
  913. X    int    i,j;
  914. X    char    *cp;
  915. X
  916. X    if (nc == 0)
  917. X        return;
  918. X    xep -= nc;
  919. X    cp = xcp;
  920. X    j = 0;
  921. X    i = nc;
  922. X    while (i--)  {
  923. X        j += x_size(*cp++);
  924. X    }
  925. X    memmove(xcp, xcp+nc, xep - xcp + 1);    /* Copies the null */
  926. X    x_zots(xcp);
  927. X    i = j;
  928. X    while (i--)
  929. X        x_putc(' ');
  930. X    i = j;
  931. X    while (i--)
  932. X        x_putc('\b');
  933. X    /*x_goto(xcp);*/
  934. X    i = xep - xcp;
  935. X    cp = xep;
  936. X    while (i--)
  937. X        x_bs(*--cp);
  938. X    return;    
  939. X}
  940. X
  941. Xstatic int
  942. Xx_del_bword(c)  {
  943. X    x_delete(x_bword());
  944. X    return KSTD;
  945. X}
  946. X
  947. Xstatic int
  948. Xx_mv_bword(c)  {
  949. X    (void)x_bword();
  950. X    return KSTD;
  951. X}
  952. X
  953. Xstatic int
  954. Xx_mv_fword(c)  {
  955. X    x_goto(xcp + x_fword());
  956. X    return KSTD;
  957. X}
  958. X
  959. Xstatic int
  960. Xx_del_fword(c)  {
  961. X    x_delete(x_fword());
  962. X    return KSTD;
  963. X}
  964. X
  965. Xstatic int
  966. Xx_bword()  {
  967. X    int    nc = 0;
  968. X    register char *cp = xcp;
  969. X
  970. X    if (cp == xbuf)  {
  971. X        x_putc(BEL);
  972. X        return 0;
  973. X    }
  974. X    while (cp != xbuf && isfs(cp[-1]))  {
  975. X        cp--;
  976. X        nc++;
  977. X    }
  978. X    while (cp != xbuf && !isfs(cp[-1]))  {
  979. X        cp--;
  980. X        nc++;
  981. X    }
  982. X    x_goto(cp);
  983. X    return nc;
  984. X}
  985. X
  986. Xstatic int
  987. Xx_fword()  {
  988. X    int    nc = 0;
  989. X    char    *cp = xcp;
  990. X
  991. X    if (cp == xep)  {
  992. X        x_putc(BEL);
  993. X        return 0;
  994. X    }
  995. X    while (cp != xep && !isfs(*cp))  {
  996. X        cp++;
  997. X        nc++;
  998. X    }
  999. X    while (cp != xep && isfs(*cp))  {
  1000. X        cp++;
  1001. X        nc++;
  1002. X    }
  1003. X    return nc;
  1004. X}
  1005. X
  1006. Xstatic void
  1007. Xx_goto(cp)
  1008. X    register char *cp;
  1009. X{
  1010. X    if (cp < xcp) {        /* move back */
  1011. X        while (cp < xcp)
  1012. X            x_bs(*--xcp);
  1013. X    } else
  1014. X    if (cp > xcp) {        /* move forward */
  1015. X        while (cp > xcp)
  1016. X            x_zotc(*xcp++);
  1017. X    }
  1018. X}
  1019. X
  1020. Xstatic void
  1021. Xx_bs(c)  {
  1022. X    register i;
  1023. X    i = x_size(c);
  1024. X    while (i--)
  1025. X        x_putc('\b');
  1026. X}
  1027. X
  1028. Xstatic int
  1029. Xx_size_str(cp)
  1030. X    register char *cp;
  1031. X{
  1032. X    register size = 0;
  1033. X    while (*cp)
  1034. X        size += x_size(*cp++);
  1035. X    return size;
  1036. X}
  1037. X
  1038. Xstatic int
  1039. Xx_size(c)  {
  1040. X    if (c=='\t')
  1041. X        return 4;    /* Kludge, tabs are always four spaces. */
  1042. X    if (c < ' ' || c == 0x7F) /* ASCII control char */
  1043. X        return 2;
  1044. X    return 1;
  1045. X}
  1046. X
  1047. Xstatic void
  1048. Xx_zots(str)
  1049. X    register char *str;
  1050. X{
  1051. X    while (*str)
  1052. X        x_zotc(*str++);
  1053. X}
  1054. X
  1055. Xstatic void
  1056. Xx_zotc(c)
  1057. X    int c;
  1058. X{
  1059. X    if (c == '\t')  {
  1060. X        /*  Kludge, tabs are always four spaces.  */
  1061. X        x_puts("    ");
  1062. X    } else if (c < ' ' || c == 0x7F)  { /* ASCII */
  1063. X        x_putc('^');
  1064. X        x_putc(UNCTRL(c));
  1065. X    } else
  1066. X        x_putc(c);
  1067. X}
  1068. X
  1069. X/* tty output */
  1070. X
  1071. Xstatic void
  1072. Xx_flush()
  1073. X{
  1074. X    fflush(stdout);
  1075. X}
  1076. X
  1077. Xstatic void
  1078. Xx_putc(c)
  1079. X    int c;
  1080. X{
  1081. X    putc(c, stdout);
  1082. X}
  1083. X
  1084. Xstatic void
  1085. Xx_puts(s)
  1086. X    register char *s;
  1087. X{
  1088. X    while (*s != 0)
  1089. X        putc(*s++, stdout);
  1090. X}
  1091. X
  1092. Xstatic int
  1093. Xx_mv_back(c)  {
  1094. X    if (xcp == xbuf)  {
  1095. X        x_putc(BEL);
  1096. X        return KSTD;
  1097. X    }
  1098. X    x_goto(xcp-1);
  1099. X    return KSTD;
  1100. X}
  1101. X
  1102. Xstatic int
  1103. Xx_mv_forw(c)  {
  1104. X    if (xcp == xep)  {
  1105. X        x_putc(BEL);
  1106. X        return KSTD;
  1107. X    }
  1108. X    x_goto(xcp+1);
  1109. X    return KSTD;
  1110. X}
  1111. X
  1112. Xstatic int
  1113. Xx_search_char(c) {
  1114. X    char ci, *cp;
  1115. X
  1116. X    *xep = '\0';
  1117. X    if (read(ttyfd, &ci, 1) != 1 ||
  1118. X        /* we search forward, I don't know what Korn does */
  1119. X        (cp = (xcp == xep) ? NULL : strchr(xcp+1, ci)) == NULL &&
  1120. X        (cp = strchr(xbuf, ci)) == NULL) {
  1121. X        x_putc(BEL);
  1122. X        return KSTD;
  1123. X    }
  1124. X    x_goto(cp);
  1125. X    return KSTD;
  1126. X}
  1127. X
  1128. Xstatic int
  1129. Xx_newline(c)  {
  1130. X    x_putc('\n');
  1131. X    x_flush();
  1132. X    *xep++ = '\n';
  1133. X    return KEOL;
  1134. X}
  1135. X
  1136. Xstatic int
  1137. Xx_end_of_text(c)  {
  1138. X#if 0
  1139. X    x_store_hist();
  1140. X#endif
  1141. X    return KEOL;
  1142. X}
  1143. X
  1144. Xstatic int x_beg_hist(c) {x_load_hist(history); return KSTD;}
  1145. X
  1146. Xstatic int x_end_hist(c) {x_load_hist(histptr); return KSTD;}
  1147. X
  1148. Xstatic int x_prev_com(c) {x_load_hist(x_histp-1); return KSTD;}
  1149. X
  1150. Xstatic int x_next_com(c) {x_load_hist(x_histp+1); return KSTD;}
  1151. X
  1152. Xstatic void
  1153. Xx_load_hist(hp)
  1154. X    register char **hp;
  1155. X{
  1156. X    int    oldsize;
  1157. X
  1158. X    if (hp < history || hp > histptr) {
  1159. X        x_putc(BEL);
  1160. X        return;
  1161. X    }
  1162. X    x_histp = hp;
  1163. X    oldsize = x_size_str(xbuf);
  1164. X    (void)strcpy(xbuf, *hp);
  1165. X    xep = xcp = xbuf + strlen(*hp);
  1166. X    x_redraw(oldsize);
  1167. X}
  1168. X
  1169. Xstatic int x_search(), x_match();
  1170. X
  1171. X/* reverse incremental history search */
  1172. Xstatic int
  1173. Xx_search_hist(ci)
  1174. X{
  1175. X    int offset = -1;    /* offset of match in xbuf, else -1 */
  1176. X    static char c[2];    /* input buffer */
  1177. X    char pat [256+1];    /* pattern buffer */
  1178. X    register char *p = pat;
  1179. X    int (*func)();
  1180. X
  1181. X    *p = 0;
  1182. X    while (1) {
  1183. X        if (offset < 0) {
  1184. X            x_puts("\nI-search: ");
  1185. X            x_zots(pat);
  1186. X        }
  1187. X        x_flush();
  1188. X        if (read(ttyfd, c, 1) < 1)
  1189. X            return KSTD;
  1190. X        func = x_tab[0][*c&CMASK]->xf_func;
  1191. X        if (*c == CTRL('['))
  1192. X            break;
  1193. X        else if (func == x_search_hist)
  1194. X            offset = x_search(pat, offset);
  1195. X        else if (func == x_del_back)
  1196. X            continue;    /* todo */
  1197. X        else if (func == x_insert) {
  1198. X            /* add char to pattern */
  1199. X            *p++ = *c, *p = 0;
  1200. X            if (offset >= 0) {
  1201. X                /* already have partial match */
  1202. X                offset = x_match(xbuf, pat);
  1203. X                if (offset >= 0) {
  1204. X                    x_goto(xbuf + offset + (p - pat) - (*pat == '^'));
  1205. X                    continue;
  1206. X                }
  1207. X            }
  1208. X            offset = x_search(pat, offset);
  1209. X        } else { /* other command */
  1210. X            macroptr = c; /* push command */
  1211. X            break;
  1212. X        }
  1213. X    }
  1214. X    if (offset < 0)
  1215. X        x_redraw(-1);
  1216. X    return KSTD;
  1217. X}
  1218. X
  1219. X/* search backward from current line */
  1220. Xstatic int
  1221. Xx_search(pat, offset)
  1222. X    char *pat;
  1223. X    int offset;
  1224. X{
  1225. X    register char **hp;
  1226. X    int i;
  1227. X
  1228. X    for (hp = x_histp; --hp >= history; ) {
  1229. X        i = x_match(*hp, pat);
  1230. X        if (i >= 0) {
  1231. X            if (offset < 0)
  1232. X                x_putc('\n');
  1233. X            x_load_hist(hp);
  1234. X            x_goto(xbuf + i + strlen(pat) - (*pat == '^'));
  1235. X            return i;
  1236. X        }
  1237. X    }
  1238. X    x_putc(BEL);
  1239. X    x_histp = histptr;
  1240. X    return -1;
  1241. X}
  1242. X
  1243. X/* return position of first match of pattern in string, else -1 */
  1244. Xstatic int
  1245. Xx_match(str, pat)
  1246. X    char *str, *pat;
  1247. X{
  1248. X    if (*pat == '^') {
  1249. X        return (strncmp(str, pat+1, strlen(pat+1)) == 0) ? 0 : -1;
  1250. X    } else {
  1251. X        char *q = strstr(str, pat);
  1252. X        return (q == NULL) ? -1 : q - str;
  1253. X    }
  1254. X}
  1255. X
  1256. Xstatic int
  1257. Xx_del_line(c)  {
  1258. X    int    i, j;
  1259. X
  1260. X    *xep = 0;
  1261. X    i = xep- xbuf;
  1262. X    j = x_size_str(xbuf);
  1263. X    xcp = xbuf;
  1264. X    x_push(i);
  1265. X    xep = xbuf;
  1266. X    *xcp = 0;
  1267. X    x_redraw(j);
  1268. X    return KSTD;
  1269. X}
  1270. X
  1271. Xstatic int
  1272. Xx_mv_end(c)  {
  1273. X    x_goto(xep);
  1274. X    return KSTD;
  1275. X}
  1276. X
  1277. Xstatic int
  1278. Xx_mv_begin(c)  {
  1279. X    x_goto(xbuf);
  1280. X    return KSTD;
  1281. X}
  1282. X
  1283. Xstatic int
  1284. Xx_draw_line(c)
  1285. X{
  1286. X    x_redraw(-1);
  1287. X    return KSTD;
  1288. X
  1289. X}
  1290. X
  1291. Xstatic void
  1292. Xx_redraw(limit)  {
  1293. X    int    i, j;
  1294. X    char    *cp;
  1295. X
  1296. X    if (limit == -1)
  1297. X        x_putc('\n');
  1298. X    else 
  1299. X        x_putc('\r');
  1300. X    x_flush();
  1301. X    pprompt(prompt);
  1302. X    x_zots(xbuf);
  1303. X    if (limit != -1)  {
  1304. X        i = limit - x_size_str(xbuf);
  1305. X        j = 0;
  1306. X        while (j < i)  {
  1307. X            x_putc(' ');
  1308. X            j++;
  1309. X        }
  1310. X        while (j--)
  1311. X            x_putc('\b');
  1312. X    }
  1313. X    i = xep - xcp;
  1314. X    cp = xep;
  1315. X    while (i--)
  1316. X        x_bs(*--cp);
  1317. X    return;
  1318. X}
  1319. X
  1320. Xstatic int
  1321. Xx_transpose(c)  {
  1322. X    char    tmp;
  1323. X    if (xcp == xbuf || xcp == xep)  {
  1324. X        x_putc(BEL);
  1325. X        return KSTD;
  1326. X    }
  1327. X    x_bs(xcp[-1]);
  1328. X    x_zotc(xcp[0]);
  1329. X    x_zotc(xcp[-1]);
  1330. X    tmp = xcp[-1];
  1331. X    xcp[-1] = xcp[0];
  1332. X    xcp[0] = tmp;
  1333. X    x_bs(xcp[0]);
  1334. X    return KSTD;
  1335. X}
  1336. X
  1337. Xstatic int
  1338. Xx_literal(c)  {
  1339. X    x_curprefix = -1;
  1340. X    return KSTD;
  1341. X}
  1342. X
  1343. Xstatic int
  1344. Xx_meta1(c)  {
  1345. X    x_curprefix = 1;
  1346. X    return KPREF;
  1347. X}
  1348. X
  1349. Xstatic int
  1350. Xx_meta2(c)  {
  1351. X    x_curprefix = 2;
  1352. X    return KPREF;
  1353. X}
  1354. X
  1355. Xstatic int
  1356. Xx_kill(c)  {
  1357. X    int    i;
  1358. X
  1359. X    i = xep - xcp;
  1360. X    x_push(i);
  1361. X    x_delete(i);
  1362. X    return KSTD;
  1363. X}
  1364. X
  1365. Xstatic void
  1366. Xx_push(nchars)  {
  1367. X    char    *cp;
  1368. X    cp = alloc((size_t)(nchars+1), AEDIT);
  1369. X    memmove(cp, xcp, nchars);
  1370. X    cp[nchars] = 0;
  1371. X    if (killstack[killsp])
  1372. X        afree((Void *)killstack[killsp], AEDIT);
  1373. X    killstack[killsp] = cp;
  1374. X    killsp = (killsp + 1) % KILLSIZE;
  1375. X}
  1376. X
  1377. Xstatic int
  1378. Xx_yank(c)  {
  1379. X    if (killsp == 0)
  1380. X        killtp = KILLSIZE;
  1381. X    else
  1382. X        killtp = killsp;
  1383. X    killtp --;
  1384. X    if (killstack[killtp] == 0)  {
  1385. X        x_puts("\nnothing to yank");
  1386. X        x_redraw(-1);
  1387. X        return KSTD;
  1388. X    }
  1389. X    x_ins(killstack[killtp]);
  1390. X    return KSTD;
  1391. X}
  1392. X
  1393. Xstatic int
  1394. Xx_meta_yank(c)  {
  1395. X    int    len;
  1396. X    if (x_last_command != x_yank && x_last_command != x_meta_yank)  {
  1397. X        x_puts("\nyank something first");
  1398. X        x_redraw(-1);
  1399. X        return KSTD;
  1400. X    }
  1401. X    len = strlen(killstack[killtp]);
  1402. X    x_goto(xcp - len);
  1403. X    x_delete(len);
  1404. X    do  {
  1405. X        if (killtp == 0)
  1406. X            killtp = KILLSIZE - 1;
  1407. X        else
  1408. X            killtp--;
  1409. X    }  while (killstack[killtp] == 0);
  1410. X    x_ins(killstack[killtp]);
  1411. X    return KSTD;
  1412. X}
  1413. X
  1414. Xstatic int
  1415. Xx_abort(c) {
  1416. X    /* x_zotc(c); */
  1417. X    return KINTR;
  1418. X}
  1419. X
  1420. Xstatic int
  1421. Xx_error(c) {
  1422. X    x_putc(BEL);
  1423. X    return KSTD;
  1424. X}
  1425. X
  1426. X#if _BSD
  1427. X#if defined TIOCGATC
  1428. Xstatic struct ttychars lchars, lcharsorig;
  1429. X#else
  1430. Xstatic struct tchars tchars, tcharsorig;
  1431. Xstatic struct ltchars ltchars, ltcharsorig;
  1432. X#endif
  1433. X#endif
  1434. X
  1435. X#if _BSD
  1436. Xbool_t
  1437. Xset_xmode(onoff)
  1438. Xbool_t    onoff;
  1439. X{
  1440. X    bool_t    prev;
  1441. Xtypedef    struct sgttyb    Sgttyb;
  1442. X    static     Sgttyb cb;
  1443. X    static  Sgttyb orig;
  1444. X
  1445. X    if (x_mode == onoff) return x_mode;
  1446. X    prev = x_mode;
  1447. X    x_mode = onoff;
  1448. X    if (onoff)  {
  1449. X        if (first_time)  {
  1450. X            (void)ioctl(0, TIOCGETP, &cb);
  1451. X            orig = cb;
  1452. X            cb.sg_flags &= ~ECHO;
  1453. X            cb.sg_flags |= CBREAK;
  1454. X#if defined TIOCGATC
  1455. X            (void)ioctl(0, TIOCGATC, &lcharsorig);
  1456. X            lchars = lcharsorig;
  1457. X            lchars.tc_suspc = -1;
  1458. X            lchars.tc_dsuspc = -1;
  1459. X            lchars.tc_lnextc = -1;
  1460. X            lchars.tc_statc = -1;
  1461. X            lchars.tc_intrc = -1;
  1462. X            lchars.tc_quitc = -1;
  1463. X            lchars.tc_rprntc = -1;
  1464. X#else
  1465. X            (void)ioctl(0, TIOCGETC, &tcharsorig);
  1466. X            (void)ioctl(0, TIOCGLTC, <charsorig);
  1467. X            tchars = tcharsorig;
  1468. X            ltchars = ltcharsorig;
  1469. X            ltchars.t_suspc = -1;
  1470. X            ltchars.t_dsuspc = -1;
  1471. X            ltchars.t_lnextc = -1;
  1472. X            tchars.t_intrc = -1;
  1473. X            tchars.t_quitc = -1;
  1474. X            ltchars.t_rprntc = -1;
  1475. X#endif
  1476. X            first_time = 0;
  1477. X        }
  1478. X        (void)ioctl(0, TIOCSETN, &cb);
  1479. X#if defined TIOCGATC
  1480. X        (void)ioctl(0, TIOCSATC, &lchars);
  1481. X#else
  1482. X        (void)ioctl(0, TIOCSETC, &tchars);
  1483. X        (void)ioctl(0, TIOCSLTC, <chars);
  1484. X#endif
  1485. X    }
  1486. X    else {
  1487. X        (void)ioctl(0, TIOCSETN, &orig);
  1488. X#if defined TIOCGATC
  1489. X        (void)ioctl(0, TIOCSATC, &lcharsorig);
  1490. X#else
  1491. X        (void)ioctl(0, TIOCSETC, &tcharsorig);
  1492. X        (void)ioctl(0, TIOCSLTC, <charsorig);
  1493. X#endif
  1494. X    }
  1495. X    return prev;
  1496. X}
  1497. X
  1498. X#else    /* !_BSD */
  1499. X
  1500. Xbool_t
  1501. Xset_xmode(onoff)
  1502. Xbool_t    onoff;
  1503. X{
  1504. X    bool_t    prev;
  1505. X    static    struct termio cb, orig;
  1506. X
  1507. X    if (x_mode == onoff) return x_mode;
  1508. X    prev = x_mode;
  1509. X    x_mode = onoff;
  1510. X
  1511. X    if (onoff)  {
  1512. X        if (first_time)  {
  1513. X            (void)ioctl(0, TCGETA, &cb);
  1514. X            orig = cb;
  1515. X#if defined _CRAY2                /* brain-damaged terminal handler */
  1516. X            cb.c_lflag &= ~(ICANON|ECHO);
  1517. X            /* rely on print routine to map '\n' to CR,LF */
  1518. X#else
  1519. X            cb.c_iflag &= ~(INLCR|ICRNL);
  1520. X#if _BSD_SYSV    /* need to force CBREAK instead of RAW (need CRMOD on output) */
  1521. X            cb.c_lflag &= ~(ICANON|ECHO);
  1522. X#else
  1523. X            cb.c_lflag &= ~(ISIG|ICANON|ECHO);
  1524. X#endif
  1525. X            cb.c_cc[VTIME] = 0;
  1526. X            cb.c_cc[VMIN] = 1;
  1527. X#endif    /* _CRAY2 */
  1528. X            first_time = 0;
  1529. X        }
  1530. X#if ! defined TCSETAW                /* e.g. Cray-2 */
  1531. X        /* first wait for output to drain */
  1532. X#if defined TCSBRK
  1533. X        (void)ioctl(0, TCSBRK, 1);
  1534. X#else    /* the following kludge is minimally intrusive, but sometimes fails */
  1535. X        (void)sleep((unsigned)1);    /* fake it */
  1536. X#endif
  1537. X#endif
  1538. X#if _BSD_SYSV || !defined(TCSETAW)
  1539. X/* _BSD_SYSV needs to force TIOCSETN instead of TIOCSETP (preserve type-ahead) */
  1540. X        (void)ioctl(0, TCSETA, &cb);
  1541. X#else
  1542. X        (void)ioctl(0, TCSETAW, &cb);
  1543. X#endif
  1544. X    }
  1545. X    else {
  1546. X#if ! defined TCSETAW                /* e.g. Cray-2 */
  1547. X        /* first wait for output to drain */
  1548. X#if defined TCSBRK
  1549. X        (void)ioctl(0, TCSBRK, 1);
  1550. X#else
  1551. X/* doesn't seem to be necessary when leaving xmode */
  1552. X/*        (void)sleep((unsigned)1);    /* fake it */
  1553. X#endif
  1554. X#endif
  1555. X#if _BSD_SYSV || !defined(TCSETAW)
  1556. X/* _BSD_SYSV needs to force TIOCSETN instead of TIOCSETP (preserve type-ahead) */
  1557. X        (void)ioctl(0, TCSETA, &orig);
  1558. X#else
  1559. X        (void)ioctl(0, TCSETAW, &orig);
  1560. X#endif
  1561. X    }
  1562. X    return prev;
  1563. X}
  1564. X#endif    /* _BSD */
  1565. X
  1566. Xstatic int
  1567. Xx_stuffreset(c)
  1568. X{
  1569. X#if defined TIOCSTI
  1570. X    (void)x_stuff(c);
  1571. X    return KINTR;
  1572. X#else
  1573. X    x_zotc(c);
  1574. X    xcp = xep = xbuf;
  1575. X    *xcp = 0;
  1576. X    x_redraw(-1);
  1577. X    return KSTD;
  1578. X#endif
  1579. X}
  1580. X
  1581. Xstatic int
  1582. Xx_stuff(c)
  1583. X{
  1584. X#if defined TIOCSTI
  1585. X    char    ch = c;
  1586. X    bool_t    savmode = set_xmode(FALSE);
  1587. X
  1588. X    (void)ioctl(0, TIOCSTI, &ch);
  1589. X    (void)set_xmode(savmode);
  1590. X    x_redraw(-1);
  1591. X#endif
  1592. X    return KSTD;
  1593. X}
  1594. X
  1595. Xstatic void
  1596. Xx_mapin(cp)
  1597. X    char    *cp;
  1598. X{
  1599. X    char    *op;
  1600. X
  1601. X    op = cp;
  1602. X    while (*cp)  {
  1603. X        /* XXX -- should handle \^ escape? */
  1604. X        if (*cp == '^')  {
  1605. X            cp++;
  1606. X            if (*cp >= '?')    /* includes '?'; ASCII */
  1607. X                *op++ = CTRL(*cp);
  1608. X            else  {
  1609. X                *op++ = '^';
  1610. X                cp--;
  1611. X            }
  1612. X        } else
  1613. X            *op++ = *cp;
  1614. X        cp++;
  1615. X    }
  1616. X    *op = 0;
  1617. X}
  1618. X
  1619. Xstatic char *
  1620. Xx_mapout(c)
  1621. X    int c;
  1622. X{
  1623. X    static char buf[8];
  1624. X    register char *p = buf;
  1625. X
  1626. X    if (c < ' ' || c == 0x7F)  { /* ASCII */
  1627. X        *p++ = '^';
  1628. X        *p++ = (c == 0x7F) ? '?' : (c | 0x40);
  1629. X    } else
  1630. X        *p++ = c;
  1631. X    *p = 0;
  1632. X    return buf;
  1633. X}
  1634. X
  1635. Xstatic void
  1636. Xx_print(prefix, key)
  1637. X    int prefix, key;
  1638. X{
  1639. X    if (prefix == 1)
  1640. X        shellf("%s", x_mapout(x_prefix1));
  1641. X    if (prefix == 2)
  1642. X        shellf("%s", x_mapout(x_prefix2));
  1643. X    shellf("%s = ", x_mapout(key));
  1644. X    if (x_tab[prefix][key]->xf_func != x_ins_string)
  1645. X        shellf("%s\n", x_tab[prefix][key]->xf_name);
  1646. X    else
  1647. X        shellf("'%s'\n", x_atab[prefix][key]);
  1648. X}
  1649. X
  1650. Xvoid
  1651. Xx_bind(a1, a2, macro)
  1652. X    char *a1, *a2;
  1653. X    int macro;        /* bind -m */
  1654. X{
  1655. X    struct x_ftab Const *fp;
  1656. X    int prefix, key;
  1657. X    char *sp = NULL;
  1658. X
  1659. X    if (x_tab == NULL)
  1660. X        errorf("cannot bind, not a tty\n");
  1661. X
  1662. X    if (a1 == NULL) {
  1663. X        for (prefix = 0; prefix < 3; prefix++)
  1664. X            for (key = 0; key < 0x80; key++) {
  1665. X            fp = x_tab[prefix][key];
  1666. X            if (fp == NULL ||
  1667. X                fp->xf_func == x_insert || fp->xf_func == x_error)
  1668. X                continue;
  1669. X            x_print(prefix, key);
  1670. X            }
  1671. X        return;
  1672. X    }
  1673. X
  1674. X    x_mapin(a1);
  1675. X    prefix = key = 0;
  1676. X    for (;; a1++) {
  1677. X        key = *a1;
  1678. X        if (x_tab[prefix][key]->xf_func == x_meta1)
  1679. X            prefix = 1;
  1680. X        else
  1681. X        if (x_tab[prefix][key]->xf_func == x_meta2)
  1682. X            prefix = 2;
  1683. X        else
  1684. X            break;
  1685. X    }
  1686. X
  1687. X    if (a2 == NULL) {
  1688. X        x_print(prefix, key);
  1689. X        return;
  1690. X    }
  1691. X
  1692. X    if (*a2 == 0)
  1693. X        fp = xft_insert;
  1694. X    else if (!macro) {
  1695. X        for (fp = x_ftab; fp->xf_func; fp++)
  1696. X            if (strcmp(fp->xf_name, a2) == 0)
  1697. X                break;
  1698. X        if (fp->xf_func == NULL || (fp->xf_flags & XF_NOBIND))
  1699. X            errorf("%s: no such function\n", a2);
  1700. X        if (fp->xf_func == x_meta1)
  1701. X            x_prefix1 = key;
  1702. X        if (fp->xf_func == x_meta2)
  1703. X            x_prefix2 = key;
  1704. X    } else {
  1705. X        fp = xft_ins_string;
  1706. X        x_mapin(a2);
  1707. X        sp = strsave(a2, AEDIT);
  1708. X    }
  1709. X
  1710. X    if ((x_tab[prefix][key]->xf_flags & XF_ALLOC) && x_atab[prefix][key])
  1711. X        afree((Void *)x_atab[prefix][key], AEDIT);
  1712. X    x_tab[prefix][key] = fp;
  1713. X    x_atab[prefix][key] = sp;
  1714. X}
  1715. X
  1716. Xvoid
  1717. Xx_init()
  1718. X{
  1719. X    register int i, j;
  1720. X    struct x_ftab Const *fp;
  1721. X
  1722. X    ainit(AEDIT);
  1723. X
  1724. X    x_tab = alloc(sizeofN(*x_tab, 3), AEDIT);
  1725. X    for (j = 0; j < 128; j++)
  1726. X        x_tab[0][j] = xft_insert;
  1727. X    for (i = 1; i < 3; i++)
  1728. X        for (j = 0; j < 128; j++)
  1729. X            x_tab[i][j] = xft_error;
  1730. X    for (fp = x_ftab; fp->xf_func; fp++)
  1731. X        if (fp->xf_db_char || fp->xf_db_tab)
  1732. X            x_tab[fp->xf_db_tab][fp->xf_db_char] = fp;
  1733. X
  1734. X    x_atab = alloc(sizeofN(*x_atab, 3), AEDIT);
  1735. X    for (i = 1; i < 3; i++)
  1736. X        for (j = 0; j < 128; j++)
  1737. X            x_atab[i][j] = NULL;
  1738. X}
  1739. X
  1740. X#if SILLY
  1741. Xstatic int
  1742. Xx_game_of_life(c)  {
  1743. X    char    newbuf [256+1];
  1744. X    register char *ip, *op;
  1745. X    int    i, len;
  1746. X
  1747. X    i = xep - xbuf;
  1748. X    *xep = 0;
  1749. X    len = x_size_str(xbuf);
  1750. X    xcp = xbuf;
  1751. X    memmove(newbuf+1, xbuf, i);
  1752. X    newbuf[0] = 'A';
  1753. X    newbuf[i] = 'A';
  1754. X    for (ip = newbuf+1, op = xbuf; --i >= 0; ip++, op++)  {
  1755. X        /*  Empty space  */
  1756. X        if (*ip < '@' || *ip == '_' || *ip == 0x7F)  {
  1757. X            /*  Two adults, make whoopee */
  1758. X            if (ip[-1] < '_' && ip[1] < '_')  {
  1759. X                /*  Make kid look like parents.  */
  1760. X                *op = '`' + ((ip[-1] + ip[1])/2)%32;
  1761. X                if (*op == 0x7F) /* Birth defect */
  1762. X                    *op = '`';
  1763. X            }
  1764. X            else
  1765. X                *op = ' ';    /* nothing happens */
  1766. X            continue;
  1767. X        }
  1768. X        /*  Child */
  1769. X        if (*ip > '`')  {
  1770. X            /*  All alone, dies  */
  1771. X            if (ip[-1] == ' ' && ip[1] == ' ')
  1772. X                *op = ' ';
  1773. X            else    /*  Gets older */
  1774. X                *op = *ip-'`'+'@';
  1775. X            continue;
  1776. X        }
  1777. X        /*  Adult  */
  1778. X        /*  Overcrowded, dies */
  1779. X        if (ip[-1] >= '@' && ip[1] >= '@')  {
  1780. X            *op = ' ';
  1781. X            continue;
  1782. X        }
  1783. X        *op = *ip;
  1784. X    }
  1785. X    *op = 0;
  1786. X    x_redraw(len);
  1787. X    return KSTD;
  1788. X}
  1789. X#endif
  1790. X
  1791. X/*
  1792. X *    File/command name completion routines
  1793. X */
  1794. X
  1795. X/* type: 0 for list, 1 for completion */
  1796. X
  1797. Xstatic    XPtrV words;
  1798. X
  1799. Xstatic void
  1800. Xadd_stash(dirnam, name)
  1801. X    char *dirnam;    /* directory name, if file */
  1802. X    char *name;
  1803. X{
  1804. X    char *cp;
  1805. X    register int type = 0;    /* '*' if executable, '/' if directory, else 0 */
  1806. X    register int len = strlen(name);
  1807. X
  1808. X    /* determine file type */
  1809. X    if (dirnam)  {
  1810. X        struct stat statb;
  1811. X        char *buf = alloc((size_t)(strlen(dirnam)+len+2), ATEMP);
  1812. X
  1813. X        if (strcmp(dirnam, ".") == 0)
  1814. X            *buf = '\0';
  1815. X        else if (strcmp(dirnam, "/") == 0)
  1816. X            (void)strcpy(buf, "/");
  1817. X        else
  1818. X            (void)strcat(strcpy(buf, dirnam), "/");
  1819. X        (void)strcat(buf, name);
  1820. X        if (stat(buf, &statb)==0)
  1821. X            if (S_ISDIR(statb.st_mode))
  1822. X                type = '/';
  1823. X            else if (S_ISREG(statb.st_mode) && access(buf, 01)==0)
  1824. X                type = '*';
  1825. X        if (type)
  1826. X            ++len;
  1827. X        afree((Void *)buf, ATEMP);
  1828. X    }
  1829. X
  1830. X    if (len > x_maxlen)
  1831. X        x_maxlen = len;
  1832. X
  1833. X    /* stash name for later sorting */
  1834. X    cp = alloc((size_t)(len+1), ATEMP);
  1835. X    (void)strcpy(cp = alloc((size_t)(len+1), ATEMP), name);
  1836. X    if (dirnam && type)  {    /* append file type indicator */
  1837. X        cp[len-1] = type;
  1838. X        cp[len] = '\0';
  1839. X    }
  1840. X    XPput(words, cp);
  1841. X}
  1842. X
  1843. Xstatic void
  1844. Xlist_stash()
  1845. X{
  1846. X    register char **array, **record;
  1847. X    int items = 0, tabstop, loc, nrows, jump, offset;
  1848. X
  1849. X    items = XPsize(words);
  1850. X    array = (char**) XPptrv(words);
  1851. X    if (items == 0)
  1852. X        return;
  1853. X    qsortp(XPptrv(words), (size_t)XPsize(words), xstrcmp);
  1854. X
  1855. X    /* print names */
  1856. X    x_maxlen = (x_maxlen/8 + 1) * 8;    /* column width */
  1857. X    nrows = (items-1) / (x_cols/x_maxlen) + 1;
  1858. X    for (offset = 0; offset < nrows; ++offset)  {
  1859. X        tabstop = loc = 0;
  1860. X        x_putc('\n');
  1861. X        for (jump = 0; offset+jump < items; jump += nrows)  {
  1862. X            if (jump)
  1863. X                while (loc < tabstop)  {
  1864. X                    x_putc('\t');
  1865. X                    loc = (loc/8 + 1) * 8;
  1866. X                }
  1867. X            record = array + (offset + jump);
  1868. X            x_puts(*record);
  1869. X            afree((Void *)*record, ATEMP);
  1870. X            loc += strlen(*record);
  1871. X            tabstop += x_maxlen;    /* next tab stop */
  1872. X        }
  1873. X    }
  1874. X
  1875. X    afree((Void*)array, ATEMP);
  1876. X    x_redraw(-1);
  1877. X}
  1878. X
  1879. Xstatic int
  1880. Xx_comp_comm(c)  {
  1881. X    compl_command(1);
  1882. X    return KSTD;
  1883. X}
  1884. Xstatic int
  1885. Xx_list_comm(c)  {
  1886. X    compl_command(0);
  1887. X    return KSTD;
  1888. X}
  1889. Xstatic int
  1890. Xx_complete(c)  {
  1891. X    compl_dec(1);
  1892. X    return KSTD;
  1893. X}
  1894. Xstatic int
  1895. Xx_enumerate(c)  {
  1896. X    compl_dec(0);
  1897. X    return KSTD;
  1898. X}
  1899. Xstatic int
  1900. Xx_comp_file(c)   {
  1901. X    compl_file(1);
  1902. X    return KSTD;
  1903. X}
  1904. Xstatic int
  1905. Xx_list_file(c)  {
  1906. X    compl_file(0);
  1907. X    return KSTD;
  1908. X}
  1909. X
  1910. Xstatic void
  1911. Xcompl_dec(type)
  1912. X{
  1913. X    char    *cp;
  1914. X    cp = xcp;
  1915. X
  1916. X    while (cp != xbuf && !isfs(*cp))
  1917. X        cp--;
  1918. X    if (cp == xbuf && strchr(cp, '/') == NULL)
  1919. X        compl_command(type);
  1920. X    else
  1921. X        compl_file(type);
  1922. X}
  1923. X
  1924. Xstatic void
  1925. Xcompl_file(type)
  1926. X{
  1927. X    char    *str;
  1928. X    register char *cp, *xp;
  1929. X    char    *lastp;
  1930. X    char    *dirnam;
  1931. X    char    buf [256+1];
  1932. X    char    bug [256+1];
  1933. X    DIR    *dirp;
  1934. X    struct dirent *dp;
  1935. X    long    loc = -1;
  1936. X    int    len;
  1937. X    int    multi = 0;
  1938. X
  1939. X    str = xcp;
  1940. X    cp = buf;
  1941. X    xp = str;
  1942. X    while (xp != xbuf)  {
  1943. X        --xp;
  1944. X        if (isfs(*xp))  {
  1945. X            xp++;
  1946. X            break;
  1947. X        }
  1948. X    }
  1949. X    if (digit(*xp) && (xp[1] == '<' || xp[1] == '>'))
  1950. X        xp++;
  1951. X    while (*xp == '<' || *xp == '>')
  1952. X        xp++;
  1953. X    if (type)
  1954. X        while (*xcp && !isfs(*xcp))
  1955. X            x_zotc(*xcp++);
  1956. X    else {
  1957. X        x_maxlen = 0;
  1958. X        XPinit(words, 16);
  1959. X    }
  1960. X    while (*xp && !isfs(*xp))
  1961. X        *cp++ = *xp++;
  1962. X
  1963. X    *cp = 0;
  1964. X    strcpy(buf, cp = substitute(buf, DOTILDE));
  1965. X    afree((Void*)cp, ATEMP);
  1966. X    lastp = strrchr(buf, '/');
  1967. X    if (lastp)
  1968. X        *lastp = 0;
  1969. X
  1970. X    dirnam = (lastp == NULL) ? "." : (lastp == buf) ? "/" : buf;
  1971. X    dirp = opendir(dirnam);
  1972. X    if (dirp == NULL) {
  1973. X        x_putc(BEL);
  1974. X        return;
  1975. X    }
  1976. X
  1977. X    if (lastp == NULL)
  1978. X        lastp = buf;
  1979. X    else
  1980. X        lastp++;
  1981. X    len = strlen(lastp);
  1982. X
  1983. X    while ((dp = readdir(dirp)) != NULL)  {
  1984. X        cp = dp->d_name;
  1985. X        if (cp[0] == '.' &&
  1986. X            (cp[1] == '\0' || cp[1] == '.' && cp[2] == '\0'))
  1987. X            continue; /* always ignore . and .. */
  1988. X        if (strncmp(lastp, cp, len) == 0)
  1989. X            if (type)  {
  1990. X                if (loc == -1)  {
  1991. X                    (void)strcpy(bug, cp);
  1992. X                    loc = strlen(cp);
  1993. X                } else {
  1994. X                    multi = 1;
  1995. X                    loc = strmatch(bug, cp);
  1996. X                    bug[loc] = 0;
  1997. X                }
  1998. X            } else
  1999. X                add_stash(dirnam, cp);
  2000. X    }
  2001. X    (void)closedir(dirp);
  2002. X
  2003. X    if (type) {
  2004. X        if (loc <= 0)  {
  2005. X            x_putc(BEL);
  2006. X            return;
  2007. X        }
  2008. X        cp = bug + len;
  2009. X        x_ins(cp);
  2010. X        if (!multi)  {
  2011. X            struct stat statb;
  2012. X            if (lastp == buf)
  2013. X                buf[0] = 0;
  2014. X            else if (lastp == buf + 1)  {
  2015. X                buf[1] = 0;
  2016. X                buf[0] = '/';
  2017. X            }  else
  2018. X                (void)strcat(buf, "/");
  2019. X            (void)strcat(buf, bug);
  2020. X            if (stat(buf, &statb) == 0 && S_ISDIR(statb.st_mode))
  2021. X                x_ins("/");
  2022. X            else
  2023. X                x_ins(" ");
  2024. X        }
  2025. X    } else
  2026. X        list_stash();
  2027. X}
  2028. X
  2029. Xstatic void
  2030. Xcompl_command(type)
  2031. X{
  2032. X    register struct tbl *tp;
  2033. X    char    *str;
  2034. X    char    buf [256+1];
  2035. X    char    bug [256+1];
  2036. X    char    *xp;
  2037. X    char    *cp;
  2038. X    int  len;
  2039. X    int  multi;
  2040. X    int  loc;
  2041. X
  2042. X    str = xcp;
  2043. X    cp = buf;
  2044. X    xp = str;
  2045. X    while (xp != xbuf)  {
  2046. X        --xp;
  2047. X        if (isfs(*xp))  {
  2048. X            xp++;
  2049. X            break;
  2050. X        }
  2051. X    }
  2052. X    if (type)
  2053. X        while (*xcp && !isfs(*xcp))
  2054. X            x_zotc(*xcp++);
  2055. X    else {
  2056. X        x_maxlen = 0;
  2057. X        XPinit(words, 16);
  2058. X    }
  2059. X    while (*xp && !isfs(*xp))
  2060. X        *cp++ = *xp++;
  2061. X    *cp = 0;
  2062. X
  2063. X    len = strlen(buf);
  2064. X    loc = -1;
  2065. X    multi = 0;
  2066. X
  2067. X    for (twalk(&commands); (tp = tnext()) != NULL; ) {
  2068. X        int    klen;
  2069. X
  2070. X        if (!(tp->flag&ISSET))
  2071. X            continue;
  2072. X        klen = strlen(tp->name);
  2073. X        if (klen < len)
  2074. X            return;
  2075. X        if (strncmp(buf, tp->name, len) ==0)
  2076. X            if (type)  {
  2077. X                if (loc == -1)  {
  2078. X                    (void)strcpy(bug, tp->name);
  2079. X                    loc = klen;
  2080. X                } else {
  2081. X                    multi = 1;
  2082. X                    loc = strmatch(bug, tp->name);
  2083. X                    bug[loc] = 0;
  2084. X                }
  2085. X            } else
  2086. X                add_stash((char *)0, tp->name);
  2087. X    }
  2088. X
  2089. X    if (type)  {
  2090. X        if (loc <= 0)  {
  2091. X            x_putc(BEL);
  2092. X            return;
  2093. X        }
  2094. X        cp = bug + len;
  2095. X        x_ins(cp);
  2096. X        if (!multi)
  2097. X            x_ins(" ");
  2098. X    } else
  2099. X        list_stash();
  2100. X}
  2101. X
  2102. Xstatic int
  2103. Xstrmatch(s1, s2)
  2104. X    register char *s1, *s2;
  2105. X{
  2106. X    register char *p;
  2107. X
  2108. X    for (p = s1; *p == *s2++ && *p != 0; p++)
  2109. X        ;
  2110. X    return p - s1;
  2111. X}
  2112. X
  2113. X#endif /* EDIT */
  2114. X
  2115. SHAR_EOF
  2116. true || echo 'restore of src/edit.c failed'
  2117. fi
  2118. # ============= src/history.c ==============
  2119. if test -f 'src/history.c' -a X"$1" != X"-c"; then
  2120.     echo 'x - skipping src/history.c (File already exists)'
  2121. else
  2122. echo 'x - extracting src/history.c (Text)'
  2123. sed 's/^X//' << 'SHAR_EOF' > 'src/history.c' &&
  2124. X/*
  2125. X * command history
  2126. X *
  2127. X * only implements in-memory history.
  2128. X */
  2129. X
  2130. Xstatic char *RCSid = "$Header: /tmp/egisin/src/RCS/history.c,v 3.2 88/11/21 10:34:30 egisin Exp $";
  2131. X
  2132. X#include <stddef.h>
  2133. X#include <stdio.h>
  2134. X#include <string.h>
  2135. X#include <errno.h>
  2136. X#include <setjmp.h>
  2137. X#include "sh.h"
  2138. X#include "lex.h"
  2139. X
  2140. Xchar  **histget();
  2141. Xchar   *histrpl();
  2142. X
  2143. Xc_fc(wp)
  2144. X    register char **wp;
  2145. X{
  2146. X    register char *id;
  2147. X    FILE *f;
  2148. X    struct temp *tf;
  2149. X    register char **hp;
  2150. X    char **hbeg, **hend;
  2151. X    int lflag = 0, nflag = 0, sflag = 0;
  2152. X
  2153. X    for (wp++; (id = *wp) != NULL && *id == '-' && !sflag; wp++)
  2154. X        switch (id[1]) {
  2155. X          case 'l':
  2156. X            lflag++;
  2157. X            break;
  2158. X          case 'n':
  2159. X            nflag++;
  2160. X            break;
  2161. X          case 's':
  2162. X            sflag++;
  2163. X            break;
  2164. X        }
  2165. X
  2166. X    /* fc -s [pat=rep] [cmd], equivalent to Korn's fc -e - [pat=rep] */
  2167. X    if (sflag) {
  2168. X        char *pat = NULL, *rep = NULL;
  2169. X
  2170. X        hp = histptr - 1;
  2171. X        while ((id = *wp++) != NULL)
  2172. X            /* todo: multiple substitutions */
  2173. X            if ((rep = strchr(id, '=')) != NULL) {
  2174. X                pat = id;
  2175. X                *rep++ = '\0';
  2176. X            } else
  2177. X                hp = histget(id);
  2178. X
  2179. X        if (hp == NULL || hp < history)
  2180. X            errorf("cannot find history\n");
  2181. X        if (pat == NULL)
  2182. X            strcpy(line, *hp);
  2183. X        else
  2184. X            histrpl(*hp, pat, rep);
  2185. X        histsave(line);
  2186. X        histpush--;
  2187. X        line[0] = '\0';
  2188. X        return 0;
  2189. X    }
  2190. X
  2191. X    if (*wp != NULL) {
  2192. X        hbeg = histget(*wp++); /* first */
  2193. X        if (*wp != NULL)
  2194. X            hend = histget(*wp++); /* last */
  2195. X        else
  2196. X            hend = hbeg;
  2197. X    } else {
  2198. X        if (lflag)
  2199. X            hbeg = histptr - 12, hend = histptr;
  2200. X        else
  2201. X            hbeg = hend = histptr - 1;
  2202. X        if (hbeg < history)
  2203. X            hbeg = history;
  2204. X    }
  2205. X    if (hbeg == NULL || hend == NULL)
  2206. X        errorf("can't find history\n");
  2207. X
  2208. X    if (lflag)
  2209. X        f = stdout;
  2210. X    else {
  2211. X        nflag++;
  2212. X        tf = maketemp(ATEMP);
  2213. X        tf->next = e.temps; e.temps = tf;
  2214. X        f = fopen(tf->name, "w");
  2215. X        if (f == NULL)
  2216. X            errorf("cannot create temp file %s", tf->name);
  2217. X        setvbuf(f, (char *)NULL, _IOFBF, BUFSIZ);
  2218. X    }
  2219. X
  2220. X    for (hp = hbeg; hp <= hend; hp++) {
  2221. X        if (!nflag)
  2222. X            fprintf(f, "%3d: ", source->line - (int)(histptr-hp));
  2223. X        fprintf(f, "%s\n", *hp);
  2224. X    }
  2225. X
  2226. X    if (lflag)
  2227. X        return 0;
  2228. X    else
  2229. X        fclose(f);
  2230. X
  2231. X    setstr(local("_"), tf->name);
  2232. X    command("${FCEDIT:-/bin/ed} $_"); /* edit temp file */
  2233. X
  2234. X    f = fopen(tf->name, "r");
  2235. X    if (f == NULL)
  2236. X        errorf("cannot open temp file %s\n", tf->name);
  2237. X    setvbuf(f, (char *)NULL, _IOFBF, BUFSIZ);
  2238. X    /* we push the editted lines onto the history list */
  2239. X    while (fgets(line, sizeof(line), f) != NULL) {
  2240. X        histsave(line);
  2241. X        histpush--;
  2242. X    }
  2243. X    line[0] = '\0';
  2244. X    fclose(f);
  2245. X
  2246. X    return 0;
  2247. X}
  2248. X
  2249. X/*
  2250. X * save command in history
  2251. X */
  2252. Xvoid
  2253. Xhistsave(cmd)
  2254. X    char *cmd;
  2255. X{
  2256. X    register char **hp = histptr;
  2257. X    char *cp;
  2258. X
  2259. X    if (++hp >= history + HISTORY) { /* remove oldest command */
  2260. X        afree((Void*)*history, APERM);
  2261. X        for (hp = history; hp < history + HISTORY - 1; hp++)
  2262. X            hp[0] = hp[1];
  2263. X    }
  2264. X    *hp = strsave(cmd, APERM);
  2265. X    if ((cp = strchr(*hp, '\n')) != NULL)
  2266. X        *cp = '\0';
  2267. X    histptr = hp;
  2268. X}
  2269. X
  2270. X/*
  2271. X * get pointer to history given pattern
  2272. X * pattern is a number or string
  2273. X */
  2274. Xchar **
  2275. Xhistget(str)
  2276. X    char *str;
  2277. X{
  2278. X    register char **hp = NULL;
  2279. X
  2280. X    if (*str == '-')
  2281. X        hp = histptr + getn(str);
  2282. X    else
  2283. X    if (digit(*str))
  2284. X        hp = histptr + (getn(str) - source->line);
  2285. X    else 
  2286. X    if (*str == '?') {    /* unanchored match */
  2287. X        for (hp = histptr-1; hp >= history; hp--)
  2288. X            if (strstr(*hp, str+1) != NULL)
  2289. X                break;
  2290. X    } else {        /* anchored match */
  2291. X        for (hp = histptr; hp >= history; hp--)
  2292. X            if (strncmp(*hp, str, strlen(str)) == 0)
  2293. X                break;
  2294. X    }
  2295. X
  2296. X    return (history <= hp && hp <= histptr) ? hp : NULL;
  2297. X}
  2298. X
  2299. Xchar *
  2300. Xhistrpl(s, pat, rep)
  2301. X    char *s;
  2302. X    char *pat, *rep;
  2303. X{
  2304. X    char *s1;
  2305. X
  2306. X    if (strlen(s) - strlen(pat) + strlen(rep) >= LINE)
  2307. X        errorf("substitution too long\n");
  2308. X    s1 = strstr(s, pat);
  2309. X    if (s1 == NULL)
  2310. X        errorf("substitution failed\n");
  2311. X    *s1 = '\0';
  2312. X    strcpy(line, s);    /* first part */
  2313. X    strcat(line, rep);    /* replacement */
  2314. X    strcat(line, s1 + strlen(pat)); /* last part */
  2315. X    return line;
  2316. X}
  2317. X
  2318. X#if 0
  2319. X
  2320. X/* History file management routines (by DPK@BRL) */
  2321. X
  2322. Xvoid
  2323. Xhist_init()
  2324. X{
  2325. X    register struct namnod *n;
  2326. X    int fd;
  2327. X
  2328. X    if (hist_fd >= 0 || (flags&oneflg))
  2329. X        return;
  2330. X    if ((n = findnam(histname)) == (struct namnod *)0
  2331. X     || n->namval == (char *)0)
  2332. X        return;
  2333. X    if ((fd = open(n->namval, O_RDWR)) >= 0) {
  2334. X        hist_load(fd);
  2335. X        (void)fcntl(fd, F_SETFL, O_APPEND);
  2336. X    }
  2337. X    hist_fd = fd;
  2338. X}
  2339. X
  2340. Xvoid
  2341. Xhist_finish()
  2342. X{
  2343. X    if (hist_fd >= 0)
  2344. X        (void)close(hist_fd);
  2345. X    hist_fd = -1;
  2346. X}
  2347. X
  2348. Xvoid
  2349. Xhist_record(buf, len)
  2350. Xchar    *buf;
  2351. Xint    len;
  2352. X{
  2353. X    if (hist_fd >= 0)
  2354. X        (void)write(hist_fd, buf, (unsigned)len);
  2355. X}
  2356. X
  2357. Xvoid
  2358. Xhist_load(fd)
  2359. Xint    fd;
  2360. X{
  2361. X    extern long    lseek();
  2362. X    struct stat sb;
  2363. X    char *x;
  2364. X    register char *cmdp, *end;
  2365. X    register int    len;
  2366. X    register int    i;
  2367. X
  2368. X    if (fstat(fd, &sb) < 0 || sb.st_size <= 0)
  2369. X        return;
  2370. X    if (x = alloc((unsigned)(sb.st_size+1))) {
  2371. X        (void)lseek(fd, 0L, 0);
  2372. X        if ((len = read(fd, x, (unsigned)sb.st_size)) <= 0) {
  2373. X            free((struct blk *)x);
  2374. X            return;
  2375. X        }
  2376. X        x[len] = 0;
  2377. X        end = x;
  2378. X        for (;;) {
  2379. X            while(*end == NL)
  2380. X                end++;        /* Skip NL */
  2381. X            if (*end == 0)
  2382. X                break;
  2383. X            cmdp = end;
  2384. X            while(*end && *end != NL)
  2385. X                end++;    /* Goto NL */
  2386. X            if (*end == 0)
  2387. X                break;
  2388. X            if ((len = (end - cmdp)) < 2)
  2389. X                continue;
  2390. X            if (len >= BUFSIZ)
  2391. X                len = BUFSIZ - 1;        /* Protection */
  2392. X            i = curhist % NHISTORY;
  2393. X            if(histbuf[i])
  2394. X                free((struct blk *)histbuf[i]);
  2395. X            histbuf[i] = alloc((unsigned)(len+1));
  2396. X            (void)strncpy(histbuf[i], cmdp, len);
  2397. X            histbuf[i][len] = 0;
  2398. X            curhist++;
  2399. X            histpc=curhist;
  2400. X        }
  2401. X        free((struct blk *)x);
  2402. X    }
  2403. X    return;
  2404. X}
  2405. X
  2406. X#endif
  2407. X
  2408. SHAR_EOF
  2409. true || echo 'restore of src/history.c failed'
  2410. fi
  2411. true || echo 'restore of src/tree.c failed'
  2412. echo End of part 3, continue with part 4
  2413. exit 0
  2414.