home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume25 / pdksh / part01 next >
Text File  |  1991-11-12  |  56KB  |  2,636 lines

  1. Newsgroups: comp.sources.misc
  2. From: sjg@zen.void.oz.au (Simon J. Gerraty)
  3. Subject:  v25i047:  pdksh - Public Domain Korn Shell, v4, Part01/09
  4. Message-ID: <csm-v25i047=pdksh.210931@sparky.IMD.Sterling.COM>
  5. X-Md4-Signature: 49a12c19b06e4666179b8736de09b441
  6. Date: Wed, 13 Nov 1991 03:10:19 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: sjg@zen.void.oz.au (Simon J. Gerraty)
  10. Posting-number: Volume 25, Issue 47
  11. Archive-name: pdksh/part01
  12. Environment: UNIX
  13.  
  14. This is the latest version of the PD ksh (pdksh).  It is not
  15. intended to be the ultimate shell but rather a usable ksh work
  16. alike.  For those of us who have to work on multiple systems it
  17. is nice to have the same user interface on all.  Pdksh is not
  18. 100% compatible with the ksh.  Having said that, I use it daily
  19. beside a real ksh88 and find them virtually indistinguishable.
  20.  
  21. I only run this shell on sun's and only for interactive use.  I
  22. use it on sun4c, sun3 and sun386 systems.  The makefiles are
  23. probably set up for a sun386 :-).
  24.  
  25. I am releasing this version of the shell (with the kind
  26. permission of the previous maintainers and major contributors) to
  27. ensure that it is available from usenet archive sites.  Of
  28. course it remains in the Public Domain.  Equally obviously
  29. neither myself nor any other contributors make any claims of
  30. suitability etc.  Ie. NO WARRANTY!!!
  31.  
  32. HISTORY:
  33.  
  34. This shell was written by Eric Gisin.  It is based on Charles
  35. Forsyth's public domain V7 shell, which he later contributed to
  36. Minix.  John R MacMillan picked up Eric Gisin's version after
  37. Eric moved on to other projects (see ReadMe.jrm).
  38.  
  39. Since then there have been many contributors to this shell.
  40. Most have left their fingerprints within the source and various
  41. ReadMe.xxx and Changes.xxx files reflect their input.
  42.  
  43. This version is basically that known as Eric Gisin's version 3.3
  44. alpha which I obtained indirectly from John R MacMillan who is
  45. the most recent maintainer.  This version has much improved
  46. emacs-mode command line editing (my main contribution) plus
  47. enough extra emacs-mode features to make it difficult to
  48. distinguish from ksh88.  Bug fixes from various contributors are
  49. the only other changes from John MacMillan's version.
  50.  
  51. I have upped the version number for this release to distinguish
  52. it from the original 3.3 version.  This version is much improved
  53. despite the small number of new features.
  54.  
  55. Please see the README for additional information concerning pdksh.
  56.  
  57. Simon J. Gerraty
  58. -----------------
  59. #! /bin/sh
  60. # This is a shell archive.  Remove anything before this line, then feed it
  61. # into a shell via "sh file" or similar.  To overwrite existing files,
  62. # type "sh file -c".
  63. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  64. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  65. # Contents:  README . etc sh sh/emacs.c sh/var.c std std/posix std/stdc
  66. # Wrapped by kent@sparky on Tue Nov 12 20:44:31 1991
  67. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  68. echo If this archive is complete, you will see the following message:
  69. echo '          "shar: End of archive 1 (of 9)."'
  70. if test -f 'README' -a "${1}" != "-c" ; then 
  71.   echo shar: Will not clobber existing file \"'README'\"
  72. else
  73.   echo shar: Extracting \"'README'\" \(3792 characters\)
  74.   sed "s/^X//" >'README' <<'END_OF_FILE'
  75. X        Public Domain Korn Shell
  76. X              Version 4.1
  77. X
  78. XPD KSH:
  79. X
  80. XThis is the latest version of the PD ksh (pdksh).  It is not
  81. Xintended to be the ultimate shell but rather a usable ksh work
  82. Xalike.  For those of us who have to work on multiple systems it
  83. Xis nice to have the same user interface on all.  Pdksh is not
  84. X100% compatible with the ksh.  Having said that, I use it daily
  85. Xbeside a real ksh88 and find them virtually indistinguishable.
  86. X
  87. XI only run this shell on sun's and only for interactive use.  I
  88. Xuse it on sun4c, sun3 and sun386 systems.  The makefiles are
  89. Xprobably set up for a sun386 :-).  
  90. X
  91. XI am releasing this version of the shell (with the kind
  92. Xpermission of the previous maintainers and major contributors) to
  93. Xensure that it is available from usenet archive sites.  Of
  94. Xcourse it remains in the Public Domain.  Equally obviously
  95. Xneither myself nor any other contributors make any claims of
  96. Xsuitability etc.  Ie. NO WARRANTY!!!  
  97. X
  98. XHISTORY:
  99. X
  100. XThis shell was written by Eric Gisin.  It is based on Charles
  101. XForsyth's public domain V7 shell, which he later contributed to
  102. XMinix.  John R MacMillan picked up Eric Gisin's version after
  103. XEric moved on to other projects (see ReadMe.jrm).
  104. X
  105. XSince then there have been many contributors to this shell.
  106. XMost have left their fingerprints within the source and various
  107. XReadMe.xxx and Changes.xxx files reflect their input.
  108. X
  109. XThis version is basically that known as Eric Gisin's version 3.3
  110. Xalpha which I obtained indirectly from John R MacMillan who is
  111. Xthe most recent maintainer.  This version has much improved
  112. Xemacs-mode command line editing (my main contribution) plus
  113. Xenough extra emacs-mode features to make it difficult to
  114. Xdistinguish from ksh88.  Bug fixes from various contributors are
  115. Xthe only other changes from John MacMillan's version.
  116. X
  117. XI have upped the version number for this release to distinguish
  118. Xit from the original 3.3 version.  This version is much improved
  119. Xdespite the small number of new features.
  120. X
  121. XINSTALLATION:
  122. X
  123. XReadMe.jrm is John R MacMillan's README file and contains
  124. Xinformation about the current source arrangement.  Please read it.
  125. X
  126. XEric Gisin's original ReadMe file can be found in ./sh,  it is
  127. Xsomewhat out of date but retained for history's sake :-)  Use
  128. Xthe instructions in ReadMe.jrm.
  129. X
  130. XThe original instructions indicated that a POSIX compliant
  131. Xenvironment and possibly an ANSI compiler are required.  I have
  132. Xused both gcc and native Sun compilers without problems.
  133. XActually I use gcc on the sun386 and cc on the others.
  134. XI do know that a friend's SysVr2 NS3210 system required some
  135. Xserious modifications to get the shell running.  If he ever
  136. Xsends me the diffs I'll fix the source :-)
  137. X
  138. XENVIRONMENT:
  139. X
  140. XMy main interest in this shell is for Sun workstations.  Every
  141. Xother UNIX system I use comes with a real ksh.  Being a strictly
  142. XC-shell environment, some improved profile files are in order on
  143. XSun's.
  144. X
  145. XThe etc directory contains a set of useful environment files.
  146. XThese are the same files I use on several systems (many use a
  147. Xreal ksh):
  148. X./etc/profile
  149. X./etc/sys_config.sh
  150. X./etc/ksh.kshrc    
  151. X
  152. XThe first one is obvious.  The second, sys_config.sh is sourced
  153. Xby /etc/profile and several other scripts.  It is used to
  154. Xdetermine the system type so that scripts like profile can be
  155. Xused on multiple platforms.
  156. XThe third one is also quite useful, add 
  157. X. /etc/ksh.kshrc 
  158. Xto user's ~/.kshrc to simplify alias management.
  159. X
  160. XBUGS:
  161. X
  162. XMany folk have contributed to this shell.  There are surely
  163. Xstill plenty of bugs to be found/fixed.
  164. X
  165. XFeel free to e-mail fixes to pdksh-bug@zen.void.oz.au
  166. XPlease use context diffs (ie diff -c, get gnudiff if your
  167. Xsystem's diff doesn't support -c).
  168. XI will, if need be, release patches following the C-news style.
  169. X
  170. XI hope you find this shell as useful as I do...
  171. X
  172. XSimon J. Gerraty <sjg@zen.void.oz.au>
  173. END_OF_FILE
  174.   if test 3792 -ne `wc -c <'README'`; then
  175.     echo shar: \"'README'\" unpacked with wrong size!
  176.   fi
  177.   # end of 'README'
  178. fi
  179. if test ! -d 'etc' ; then
  180.     echo shar: Creating directory \"'etc'\"
  181.     mkdir 'etc'
  182. fi
  183. if test ! -d 'sh' ; then
  184.     echo shar: Creating directory \"'sh'\"
  185.     mkdir 'sh'
  186. fi
  187. if test -f 'sh/emacs.c' -a "${1}" != "-c" ; then 
  188.   echo shar: Will not clobber existing file \"'sh/emacs.c'\"
  189. else
  190.   echo shar: Extracting \"'sh/emacs.c'\" \(32990 characters\)
  191.   sed "s/^X//" >'sh/emacs.c' <<'END_OF_FILE'
  192. X/*
  193. X *  Emacs-like command line editing and history
  194. X *
  195. X *  created by Ron Natalie at BRL
  196. X *  modified by Doug Kingston, Doug Gwyn, and Lou Salkind
  197. X *  adapted to PD ksh by Eric Gisin
  198. X */
  199. X
  200. X#include "config.h"
  201. X#ifdef EMACS
  202. X
  203. X#ifndef lint
  204. Xstatic char *RCSid = "$Id: emacs.c,v 3.2 89/03/27 15:49:17 egisin Exp $";
  205. Xstatic char *sccs_id = "@(#)emacs.c    1.5 91/11/09 15:35:13 (sjg)";
  206. X#endif
  207. X
  208. X#include <stddef.h>
  209. X#include <stdlib.h>
  210. X#include <string.h>
  211. X#include <stdio.h>
  212. X#include <signal.h>
  213. X#include <sys/types.h>
  214. X#include <sys/stat.h>
  215. X#include <dirent.h>
  216. X#include <unistd.h>
  217. X#include <fcntl.h>
  218. X#include <ctype.h>
  219. X#include <errno.h>
  220. X#include <setjmp.h>
  221. X#include "sh.h"
  222. X#include "lex.h"
  223. X#include "tree.h"        /* DOTILDE */
  224. X#include "table.h"
  225. X#include "expand.h"
  226. X#include "edit.h"
  227. X
  228. X#define PUSH_DELETE 1            /* push all deletes of >1 char */
  229. X
  230. Xstatic    Area    aedit;
  231. X#define    AEDIT    &aedit        /* area for kill ring and macro defns */
  232. X
  233. X#undef CTRL            /* _BSD brain damage */
  234. X#define    CTRL(x)        ((x) == '?' ? 0x7F : (x) & 0x1F)    /* ASCII */
  235. X#define    UNCTRL(x)    ((x) == 0x7F ? '?' : (x) | 0x40)    /* ASCII */
  236. X
  237. X#ifndef S_ISDIR
  238. X#define S_ISDIR(mode)    (((mode) & S_IFMT) == S_IFDIR)
  239. X#endif
  240. X
  241. X#ifndef S_ISREG
  242. X#define S_ISREG(mode)    (((mode) & S_IFMT) == S_IFREG)
  243. X#endif
  244. X
  245. X/* values returned by keyboard functions */
  246. X#define    KSTD    0
  247. X#define    KPREF    1        /* ^[, ^X */
  248. X#define    KEOL    2        /* ^M, ^J */
  249. X#define    KINTR    3        /* ^G, ^C */
  250. X#define    KNULL    4
  251. X    
  252. Xstruct    x_ftab  {
  253. X    int    (*xf_func)();
  254. X    char    *xf_name;
  255. X    char    xf_db_tab;
  256. X    char    xf_db_char;
  257. X    short    xf_flags;
  258. X};
  259. X
  260. X#define    XF_ALLOC    2
  261. X#define    XF_NOBIND    4
  262. X
  263. X#define    iscfs(c)    (c == ' ' || c == '\t')    /* Separator for completion */
  264. X#define    ismfs(c)    (!(isalnum(c)|| c == '$'))  /* Separator for motion */
  265. X#define    BEL        0x07
  266. X#define    CMASK        0x7F    /* 7-bit ASCII character mask */
  267. X
  268. Xstatic    int    x_prefix1 = CTRL('['), x_prefix2 = CTRL('X');
  269. Xstatic    char   **x_histp;    /* history position */
  270. Xstatic    char   **x_nextcmdp;    /* for newline-and-next */
  271. Xstatic    char    *xmp;        /* mark pointer */
  272. Xstatic    int    (*x_last_command)();
  273. X/*static    struct    x_ftab *x_tab[3][128];*/
  274. Xstatic    struct    x_ftab Const *(*x_tab)[128] = NULL; /* key definition */
  275. Xstatic    char    *(*x_atab)[128] = NULL; /* macro definitions */
  276. X#define    KILLSIZE    20
  277. Xstatic    char    *killstack[KILLSIZE];
  278. Xstatic    int    killsp, killtp;
  279. Xstatic    int    x_curprefix;
  280. Xstatic    char    *macroptr;
  281. Xstatic    int    x_maxlen;    /* to determine column width */
  282. X
  283. Xstatic    void    x_goto(), x_bs(), x_delete(), x_ins(), x_mapin();
  284. Xstatic    int    x_fword(), x_bword(), x_size(), x_size_str();
  285. Xstatic    void    x_zotc(), x_zots(), x_push(), x_load_hist();
  286. Xstatic    void    compl_command(), compl_dec(), compl_file();
  287. Xstatic    int    x_insert(), x_ins_string(), x_del_back();
  288. Xstatic    int    x_del_char(), x_del_bword(), x_mv_bword(), x_mv_fword();
  289. Xstatic    int    x_del_fword(), x_mv_back(), x_mv_forw(), x_search_char();
  290. Xstatic    int    x_newline(), x_end_of_text(), x_abort(), x_error();
  291. Xstatic    int    x_beg_hist(), x_end_hist(), x_prev_com(), x_next_com();
  292. Xstatic    int    x_search_hist(), x_del_line(), x_mv_end(), x_mv_begin();
  293. Xstatic    int    x_draw_line(), x_transpose(), x_meta1(), x_meta2();
  294. Xstatic    int    x_kill(), x_yank(), x_meta_yank(), x_literal();
  295. Xstatic    int    x_stuffreset(), x_stuff(), x_complete(), x_enumerate();
  296. Xstatic    int    x_set_mark(), x_kill_region(), x_xchg_point_mark();
  297. Xstatic    int    x_nl_next_com(), x_eot_del();
  298. Xstatic    int    x_copy_arg();
  299. Xstatic    int    x_noop();
  300. X#ifdef SILLY
  301. Xstatic    int    x_game_of_life();
  302. X#endif
  303. Xstatic    int    x_comp_file(), x_comp_comm();
  304. Xstatic    int    x_list_file(), x_list_comm();
  305. Xstatic    int    strmatch();
  306. Xstatic int    x_prev_histword(), x_set_arg(), x_fold_case();
  307. X
  308. X
  309. Xstatic    struct x_ftab Const x_ftab[] = {
  310. X     {x_insert,    "auto-insert",        0,     0,    0 },
  311. X    {x_error,    "error",        0,     0,    0 },
  312. X     {x_ins_string,    "macro-string",        0,     0,    XF_NOBIND|XF_ALLOC},
  313. X    {x_del_back,    "delete-char-backward",    0, CTRL('H'),    0 },
  314. X    {x_eot_del,    "eot-or-delete",    0, CTRL('D'),    0 },
  315. X    {x_del_bword,    "delete-word-backward",    1, CTRL('H'),    0 },
  316. X    {x_mv_bword,    "backward-word",     1,    'b',    0 },
  317. X    {x_del_line,    "kill-line",        0,     0,    0 },
  318. X    {x_abort,    "abort",        0,    0,    0 },
  319. X    {x_noop,    "no-op",        0,    0,    0 },
  320. X/* Do not move the above! */
  321. X    {x_mv_fword,    "forward-word",        1,    'f',    0 },
  322. X    {x_del_fword,    "delete-word-forward",     1,    'd',    0 },
  323. X    {x_mv_back,    "backward-char",    0, CTRL('B'),    0 },
  324. X    {x_mv_forw,    "forward-char",        0, CTRL('F'),    0 },
  325. X    {x_search_char,    "search-character",    0, CTRL(']'),    0 },
  326. X    {x_newline,    "newline",        0, CTRL('M'),    0 },
  327. X    {x_newline,    "newline",        0, CTRL('J'),    0 },
  328. X    {x_end_of_text,    "eot",            0, CTRL('_'),    0 },
  329. X    {x_abort,    "abort",        0, CTRL('G'),    0 },
  330. X    {x_prev_com,    "up-history",        0, CTRL('P'),    0},
  331. X    {x_next_com,    "down-history",        0, CTRL('N'),    0},
  332. X    {x_search_hist,    "search-history",    0, CTRL('R'),    0},
  333. X    {x_beg_hist,    "beginning-of-history",    1,    '<',    0},
  334. X    {x_end_hist,    "end-of-history",    1,    '>',    0},
  335. X    {x_mv_end,    "end-of-line",        0, CTRL('E'),    0 },
  336. X    {x_mv_begin,    "beginning-of-line",    0, CTRL('A'),    0 },
  337. X    {x_draw_line,    "redraw",        0, CTRL('L'),    0 },
  338. X    {x_meta1,    "prefix-1",        0, CTRL('['),    0 },
  339. X    {x_meta2,    "prefix-2",        0, CTRL('X'),    0 },
  340. X    {x_kill,    "kill-to-eol",        0, CTRL('K'),    0 },
  341. X    {x_yank,    "yank",            0, CTRL('Y'),    0 },
  342. X    {x_meta_yank,    "yank-pop",         1,    'y',    0 },
  343. X    {x_literal,    "quote",        0, CTRL('^'),    0 },
  344. X    {x_stuffreset,     "stuff-reset",        0,     0,    0 },
  345. X#if defined(BRL) && defined(TIOCSTI)
  346. X    {x_stuff,     "stuff",        0, CTRL('T'),    0 },
  347. X    {x_transpose,    "transpose-chars",    0,     0,    0 },
  348. X#else
  349. X    {x_stuff,     "stuff",        0,     0,    0 },
  350. X    {x_transpose,    "transpose-chars",    0, CTRL('T'),    0 },
  351. X#endif
  352. X    {x_complete,    "complete",        1, CTRL('['),    0 },
  353. X    {x_enumerate,    "list",            1,    '?',    0 },
  354. X    {x_comp_file,    "complete-file",    1, CTRL('X'),    0 },
  355. X    {x_comp_comm,    "complete-command",    2, CTRL('['),    0 },
  356. X    {x_list_file,    "list-file",        0,     0,    0 },
  357. X    {x_list_comm,    "list-command",        2,    '?',    0 },
  358. X    {x_nl_next_com,    "newline-and-next",    0, CTRL('O'),    0 },
  359. X    {x_set_mark,    "set-mark-command",    1,    ' ',    0 },
  360. X    {x_kill_region,    "kill-region",        0, CTRL('W'),    0 },
  361. X    {x_xchg_point_mark, "exchange-point-and-mark", 2, CTRL('X'), 0 },
  362. X#if 0
  363. X    {x_copy_arg,    "copy-last-arg",    1,    '_',    0},
  364. X#endif
  365. X#ifdef SILLY
  366. X    {x_game_of_life, "play-game-of-life",    0,    0,    0 },
  367. X#endif 
  368. X#ifdef DEBUG
  369. X        {x_debug_info,    "debug-info",        1, CTRL('H'),    0 },
  370. X#endif
  371. X    {x_prev_histword, "prev-hist-word",     1,    '.',    0 },
  372. X    {x_prev_histword, "prev-hist-word",     1,    '_',    0 },
  373. X        {x_set_arg,    "",            1,    '0',    0 },
  374. X        {x_set_arg,    "",            1,    '1',    0 },
  375. X        {x_set_arg,    "",            1,    '2',    0 },
  376. X        {x_set_arg,    "",            1,    '3',    0 },
  377. X        {x_set_arg,    "",            1,    '4',    0 },
  378. X        {x_set_arg,    "",            1,    '5',    0 },
  379. X        {x_set_arg,    "",            1,    '6',    0 },
  380. X        {x_set_arg,    "",            1,    '7',    0 },
  381. X        {x_set_arg,    "",            1,    '8',    0 },
  382. X        {x_set_arg,    "",            1,    '9',    0 },
  383. X        {x_fold_case,    "upcase-word",        1,    'U',    0 },
  384. X        {x_fold_case,    "downcase-word",    1,    'L',    0 },
  385. X        {x_fold_case,    "capitalize-word",    1,    'C',    0 },
  386. X        {x_fold_case,    "upcase-word",        1,    'u',    0 },
  387. X        {x_fold_case,    "downcase-word",    1,    'l',    0 },
  388. X        {x_fold_case,    "capitalize-word",    1,    'c',    0 },
  389. X    { 0 }
  390. X};
  391. X
  392. X#define    xft_insert &x_ftab[0]
  393. X#define    xft_error &x_ftab[1]
  394. X#define    xft_ins_string &x_ftab[2]
  395. X#define    xft_erase &x_ftab[3]
  396. X#define    xft_kill &x_ftab[7]
  397. X#define    xft_werase &x_ftab[5]
  398. X#define xft_intr &x_ftab[8]
  399. X#define    xft_quit &x_ftab[9]
  400. X
  401. Xint
  402. Xx_emacs(buf, len)
  403. X    char *buf;
  404. X    size_t len;
  405. X{
  406. X    char    c;
  407. X    int    i;
  408. X    int   (*func)();
  409. X    extern    x_insert();
  410. X
  411. X    xbp = xbuf = buf; xend = buf + len;
  412. X    xlp = xcp = xep = buf;
  413. X    *xcp = 0;
  414. X    xlp_valid = TRUE;
  415. X    xmp = NULL;
  416. X    x_curprefix = 0;
  417. X    macroptr = null;
  418. X    x_histp = histptr + 1;
  419. X
  420. X    if (x_nextcmdp != NULL) {
  421. X        x_load_hist(x_nextcmdp);
  422. X        x_nextcmdp = NULL;
  423. X    }
  424. X
  425. X    /* <sjg@sun0> this may not be correct */
  426. X    if ((i = atoi(strval(global("COLUMNS")))) > 0)
  427. X      x_cols = i;
  428. X    else
  429. X      x_cols = 80;
  430. X    x_col = promptlen(prompt);
  431. X    x_adj_ok = 1;
  432. X    x_displen = x_cols - 2 - x_col;
  433. X    x_adj_done = 0;
  434. X
  435. X    while (1)  {
  436. X        x_flush();
  437. X        if (*macroptr)  {
  438. X            c = *macroptr++;
  439. X            if (*macroptr == 0)
  440. X                macroptr = null;
  441. X        }
  442. X        else {
  443. X            if ((c = x_getc()) < 0)
  444. X                return i;
  445. X        }
  446. X
  447. X        if (x_curprefix == -1)
  448. X            func = x_insert;
  449. X        else
  450. X            func = x_tab[x_curprefix][c&CMASK]->xf_func;
  451. X        if (func == NULL)
  452. X            func = x_error;
  453. X        i = c | (x_curprefix << 8);
  454. X        x_curprefix = 0;
  455. X        switch (i = (*func)(i))  {
  456. X          case KSTD:
  457. X            x_last_command = func;
  458. X          case KPREF:
  459. X          case KNULL:
  460. X            break;
  461. X          case KEOL:
  462. X            i = xep - xbuf;
  463. X            x_last_command = 0;
  464. X            return i;
  465. X          case KINTR:    /* special case for interrupt */
  466. X            errno = EINTR;
  467. X            return -1;
  468. X        }
  469. X    }
  470. X}
  471. X
  472. Xstatic int
  473. Xx_insert(c)  {
  474. X    char    str[2];
  475. X
  476. X    /*
  477. X     *  Should allow tab and control chars.
  478. X     */
  479. X    if (c == 0)  {
  480. X        x_putc(BEL);
  481. X        return KSTD;
  482. X    }
  483. X    str[0] = c;
  484. X    str[1] = 0;
  485. X    x_ins(str);
  486. X    return KSTD;
  487. X}
  488. X
  489. Xstatic int
  490. Xx_ins_string(c)
  491. X{
  492. X    if (*macroptr)   {
  493. X        x_putc(BEL);
  494. X        return KSTD;
  495. X    }
  496. X    macroptr = x_atab[c>>8][c & CMASK];
  497. X    return KSTD;
  498. X}
  499. X
  500. Xstatic void
  501. Xx_ins(cp)
  502. X    char    *cp;
  503. X{
  504. X    int    count, i;
  505. X    register int    adj = x_adj_done;
  506. X
  507. X    count = strlen(cp);
  508. X    if (xep+count >= xend) {
  509. X        x_putc(BEL);
  510. X        return;
  511. X    }
  512. X
  513. X    if (xcp != xep)
  514. X        memmove(xcp+count, xcp, xep - xcp + 1);
  515. X    else
  516. X        xcp[count] = 0;
  517. X    memmove(xcp, cp, count);
  518. X    /*
  519. X     * x_zots() may result in a call to x_adjust()
  520. X     * we want xcp to reflect the new position.
  521. X     */
  522. X    cp = xcp;
  523. X    xcp += count;
  524. X    xep += count;
  525. X    xlp_valid = FALSE;
  526. X    x_lastcp();
  527. X    x_adj_ok = (xcp >= xlp);
  528. X    x_zots(cp);
  529. X    if (adj == x_adj_done)    /* has x_adjust() been called? */
  530. X    {
  531. X      /* no */
  532. X      for (cp = xlp; cp > xcp; )
  533. X        x_bs(*--cp);
  534. X    }
  535. X
  536. X    x_adj_ok = 1;
  537. X    return;
  538. X}
  539. X
  540. Xstatic int
  541. Xx_del_back(c)  {
  542. X    if (xcp == xbuf)  {
  543. X        x_putc(BEL);
  544. X        return KSTD;
  545. X    }
  546. X    x_goto(xcp - 1);
  547. X    x_delete(1);
  548. X    return KSTD;
  549. X}
  550. X
  551. Xstatic int
  552. Xx_del_char(c)  {
  553. X    if (xcp == xep)  {
  554. X        x_putc(BEL);
  555. X        return KSTD;
  556. X    }
  557. X    x_delete(1);
  558. X    return KSTD;
  559. X}
  560. X
  561. Xstatic void
  562. Xx_delete(nc)
  563. X  int nc;
  564. X{
  565. X    int    i,j;
  566. X    char    *cp;
  567. X    
  568. X    if (nc == 0)
  569. X        return;
  570. X    if (xmp != NULL) {
  571. X        if (xcp + nc > xmp)
  572. X            xmp = xcp;
  573. X        else if (xmp > xcp)
  574. X            xmp -= nc;
  575. X    }
  576. X#ifdef PUSH_DELETE
  577. X    /*
  578. X     * This lets us yank a word we have deleted.
  579. X     */
  580. X    if (nc > 1)
  581. X      x_push(nc);
  582. X#endif
  583. X    xep -= nc;
  584. X    cp = xcp;
  585. X    j = 0;
  586. X    i = nc;
  587. X    while (i--)  {
  588. X        j += x_size(*cp++);
  589. X    }
  590. X    memmove(xcp, xcp+nc, xep - xcp + 1);    /* Copies the null */
  591. X    x_adj_ok = 0;            /* don't redraw */
  592. X    x_zots(xcp);
  593. X    /*
  594. X     * if we are already filling the line,
  595. X     * there is no need to ' ','\b'.
  596. X     * But if we must, make sure we do the minimum.
  597. X     */
  598. X    if ((i = x_cols - 2 - x_col) > 0)
  599. X    {
  600. X      j = (j < i) ? j : i;
  601. X      i = j;
  602. X      while (i--)
  603. X        x_putc(' ');
  604. X      i = j;
  605. X      while (i--)
  606. X        x_putc('\b');
  607. X    }
  608. X    /*x_goto(xcp);*/
  609. X    x_adj_ok = 1;
  610. X    xlp_valid = FALSE;
  611. X    for (cp = x_lastcp(); cp > xcp; )
  612. X      x_bs(*--cp);
  613. X
  614. X    return;    
  615. X}
  616. X
  617. Xstatic int
  618. Xx_del_bword(c)  {
  619. X    x_delete(x_bword());
  620. X    return KSTD;
  621. X}
  622. X
  623. Xstatic int
  624. Xx_mv_bword(c)  {
  625. X    (void)x_bword();
  626. X    return KSTD;
  627. X}
  628. X
  629. Xstatic int
  630. Xx_mv_fword(c)  {
  631. X    x_goto(xcp + x_fword());
  632. X    return KSTD;
  633. X}
  634. X
  635. Xstatic int
  636. Xx_del_fword(c)  {
  637. X    x_delete(x_fword());
  638. X    return KSTD;
  639. X}
  640. X
  641. Xstatic int
  642. Xx_bword()  {
  643. X    int    nc = 0;
  644. X    register char *cp = xcp;
  645. X
  646. X    if (cp == xbuf)  {
  647. X        x_putc(BEL);
  648. X        return 0;
  649. X    }
  650. X    if (x_last_command != x_set_arg)
  651. X      x_arg = 1;
  652. X    while (x_arg--)
  653. X    {
  654. X      while (cp != xbuf && ismfs(cp[-1]))
  655. X      {
  656. X        cp--;
  657. X        nc++;
  658. X      }
  659. X      while (cp != xbuf && !ismfs(cp[-1]))
  660. X      {
  661. X        cp--;
  662. X        nc++;
  663. X      }
  664. X    }
  665. X    x_goto(cp);
  666. X    return nc;
  667. X}
  668. X
  669. Xstatic int
  670. Xx_fword()  {
  671. X    int    nc = 0;
  672. X    register char    *cp = xcp;
  673. X
  674. X    if (cp == xep)  {
  675. X        x_putc(BEL);
  676. X        return 0;
  677. X    }
  678. X    if (x_last_command != x_set_arg)
  679. X      x_arg = 1;
  680. X    while (x_arg--)
  681. X    {
  682. X      while (cp != xep && !ismfs(*cp))
  683. X      {
  684. X        cp++;
  685. X        nc++;
  686. X      }
  687. X      while (cp != xep && ismfs(*cp))
  688. X      {
  689. X        cp++;
  690. X        nc++;
  691. X      }
  692. X    }
  693. X    return nc;
  694. X}
  695. X
  696. Xstatic void
  697. Xx_goto(cp)
  698. X    register char *cp;
  699. X{
  700. X  if (cp < xbp || cp >= (xbp + x_displen))
  701. X  {
  702. X    /* we are heading off screen */
  703. X    xcp = cp;
  704. X    x_adjust();
  705. X  }
  706. X  else
  707. X  {
  708. X    if (cp < xcp)        /* move back */
  709. X    {
  710. X      while (cp < xcp)
  711. X    x_bs(*--xcp);
  712. X    }
  713. X    else
  714. X    {
  715. X      if (cp > xcp)         /* move forward */
  716. X      {
  717. X    while (cp > xcp)
  718. X      x_zotc(*xcp++);
  719. X      }
  720. X    }
  721. X  }
  722. X}
  723. X
  724. Xstatic void
  725. Xx_bs(c)  {
  726. X    register i;
  727. X    i = x_size(c);
  728. X    while (i--)
  729. X        x_putc('\b');
  730. X}
  731. X
  732. Xstatic int
  733. Xx_size_str(cp)
  734. X    register char *cp;
  735. X{
  736. X    register size = 0;
  737. X    while (*cp)
  738. X        size += x_size(*cp++);
  739. X    return size;
  740. X}
  741. X
  742. Xstatic int
  743. Xx_size(c)  {
  744. X    if (c=='\t')
  745. X        return 4;    /* Kludge, tabs are always four spaces. */
  746. X    if (c < ' ' || c == 0x7F) /* ASCII control char */
  747. X        return 2;
  748. X    return 1;
  749. X}
  750. X
  751. Xstatic void
  752. Xx_zots(str)
  753. X    register char *str;
  754. X{
  755. X  register int    adj = x_adj_done;
  756. X
  757. X  x_lastcp();
  758. X  while (*str && str < xlp && adj == x_adj_done)
  759. X    x_zotc(*str++);
  760. X}
  761. X
  762. Xstatic void
  763. Xx_zotc(c)
  764. X    int c;
  765. X{
  766. X    if (c == '\t')  {
  767. X        /*  Kludge, tabs are always four spaces.  */
  768. X        x_puts("    ");
  769. X    } else if (c < ' ' || c == 0x7F)  { /* ASCII */
  770. X        x_putc('^');
  771. X        x_putc(UNCTRL(c));
  772. X    } else
  773. X        x_putc(c);
  774. X}
  775. X
  776. Xstatic int
  777. Xx_mv_back(c)  {
  778. X    if (xcp == xbuf)  {
  779. X        x_putc(BEL);
  780. X        return KSTD;
  781. X    }
  782. X    x_goto(xcp-1);
  783. X    return KSTD;
  784. X}
  785. X
  786. Xstatic int
  787. Xx_mv_forw(c)  {
  788. X    if (xcp == xep)  {
  789. X        x_putc(BEL);
  790. X        return KSTD;
  791. X    }
  792. X    x_goto(xcp+1);
  793. X    return KSTD;
  794. X}
  795. X
  796. Xstatic int
  797. Xx_search_char(c)
  798. X    int c;
  799. X{
  800. X    char *cp;
  801. X
  802. X    *xep = '\0';
  803. X    if ((c = x_getc()) < 0 ||
  804. X        /* we search forward, I don't know what Korn does */
  805. X        (cp = (xcp == xep) ? NULL : strchr(xcp+1, c)) == NULL &&
  806. X        (cp = strchr(xbuf, c)) == NULL) {
  807. X        x_putc(BEL);
  808. X        return KSTD;
  809. X    }
  810. X    x_goto(cp);
  811. X    return KSTD;
  812. X}
  813. X
  814. Xstatic int
  815. Xx_newline(c)  {
  816. X    x_putc('\n');
  817. X    x_flush();
  818. X    *xep++ = '\n';
  819. X    return KEOL;
  820. X}
  821. X
  822. Xstatic int
  823. Xx_end_of_text(c)  {
  824. X#if 0
  825. X    x_store_hist();
  826. X#endif
  827. X    return KEOL;
  828. X}
  829. X
  830. Xstatic int x_beg_hist(c) {x_load_hist(history); return KSTD;}
  831. X
  832. Xstatic int x_end_hist(c) {x_load_hist(histptr); return KSTD;}
  833. X
  834. Xstatic int x_prev_com(c) {x_load_hist(x_histp-1); return KSTD;}
  835. X
  836. Xstatic int x_next_com(c) {x_load_hist(x_histp+1); return KSTD;}
  837. X
  838. Xstatic void
  839. Xx_load_hist(hp)
  840. X    register char **hp;
  841. X{
  842. X    int    oldsize;
  843. X
  844. X    if (hp < history || hp > histptr) {
  845. X        x_putc(BEL);
  846. X        return;
  847. X    }
  848. X    x_histp = hp;
  849. X    oldsize = x_size_str(xbuf);
  850. X    (void)strcpy(xbuf, *hp);
  851. X    xbp = xbuf;
  852. X    xep = xcp = xbuf + strlen(*hp);
  853. X    xlp_valid = FALSE;
  854. X    if (xep > x_lastcp())
  855. X      x_goto(xep);
  856. X    else
  857. X      x_redraw(oldsize);
  858. X}
  859. X
  860. Xstatic int
  861. Xx_nl_next_com(c)
  862. Xint    c;
  863. X{
  864. X    x_nextcmdp = x_histp + 1;
  865. X    return (x_newline(c));
  866. X}
  867. X
  868. Xstatic int
  869. Xx_eot_del(c)
  870. Xint    c;
  871. X{
  872. X    if (xep == xbuf)
  873. X        return (x_end_of_text(c));
  874. X    else
  875. X        return (x_del_char(c));
  876. X}
  877. X
  878. Xstatic int x_search(), x_match();
  879. X
  880. X/* reverse incremental history search */
  881. Xstatic int
  882. Xx_search_hist(c)
  883. X    int c;
  884. X{
  885. X    int offset = -1;    /* offset of match in xbuf, else -1 */
  886. X    char pat [256+1];    /* pattern buffer */
  887. X    register char *p = pat;
  888. X    int (*func)();
  889. X
  890. X    *p = 0;
  891. X    while (1) {
  892. X        if (offset < 0) {
  893. X            x_puts("\nI-search: ");
  894. X            x_zots(pat);
  895. X        }
  896. X        x_flush();
  897. X        if ((c = x_getc()) < 0)
  898. X            return KSTD;
  899. X        func = x_tab[0][c&CMASK]->xf_func;
  900. X        if (c == CTRL('['))
  901. X            break;
  902. X        else if (func == x_search_hist)
  903. X            offset = x_search(pat, offset);
  904. X        else if (func == x_del_back)
  905. X            continue;    /* todo */
  906. X        else if (func == x_insert) {
  907. X            /* add char to pattern */
  908. X            *p++ = c, *p = 0;
  909. X            if (offset >= 0) {
  910. X                /* already have partial match */
  911. X                offset = x_match(xbuf, pat);
  912. X                if (offset >= 0) {
  913. X                    x_goto(xbuf + offset + (p - pat) - (*pat == '^'));
  914. X                    continue;
  915. X                }
  916. X            }
  917. X            offset = x_search(pat, offset);
  918. X        } else { /* other command */
  919. X            static char push[2];
  920. X            push[0] = c;
  921. X            macroptr = push; /* push command */
  922. X            break;
  923. X        }
  924. X    }
  925. X    if (offset < 0)
  926. X        x_redraw(-1);
  927. X    return KSTD;
  928. X}
  929. X
  930. X/* search backward from current line */
  931. Xstatic int
  932. Xx_search(pat, offset)
  933. X    char *pat;
  934. X    int offset;
  935. X{
  936. X    register char **hp;
  937. X    int i;
  938. X
  939. X    for (hp = x_histp; --hp >= history; ) {
  940. X        i = x_match(*hp, pat);
  941. X        if (i >= 0) {
  942. X            if (offset < 0)
  943. X                x_putc('\n');
  944. X            x_load_hist(hp);
  945. X            x_goto(xbuf + i + strlen(pat) - (*pat == '^'));
  946. X            return i;
  947. X        }
  948. X    }
  949. X    x_putc(BEL);
  950. X    x_histp = histptr;
  951. X    return -1;
  952. X}
  953. X
  954. X/* return position of first match of pattern in string, else -1 */
  955. Xstatic int
  956. Xx_match(str, pat)
  957. X    char *str, *pat;
  958. X{
  959. X    if (*pat == '^') {
  960. X        return (strncmp(str, pat+1, strlen(pat+1)) == 0) ? 0 : -1;
  961. X    } else {
  962. X        char *q = strstr(str, pat);
  963. X        return (q == NULL) ? -1 : q - str;
  964. X    }
  965. X}
  966. X
  967. Xstatic int
  968. Xx_del_line(c)  {
  969. X    int    i, j;
  970. X
  971. X    *xep = 0;
  972. X    i = xep- xbuf;
  973. X    j = x_size_str(xbuf);
  974. X    xcp = xbuf;
  975. X    x_push(i);
  976. X    xlp = xbp = xep = xbuf;
  977. X    xlp_valid = TRUE;
  978. X    *xcp = 0;
  979. X    xmp = NULL;
  980. X    x_redraw(j);
  981. X    return KSTD;
  982. X}
  983. X
  984. Xstatic int
  985. Xx_mv_end(c)  {
  986. X    x_goto(xep);
  987. X    return KSTD;
  988. X}
  989. X
  990. Xstatic int
  991. Xx_mv_begin(c)  {
  992. X    x_goto(xbuf);
  993. X    return KSTD;
  994. X}
  995. X
  996. Xstatic int
  997. Xx_draw_line(c)
  998. X{
  999. X    x_redraw(-1);
  1000. X    return KSTD;
  1001. X
  1002. X}
  1003. X
  1004. Xvoid
  1005. Xx_redraw(limit)
  1006. X  int limit;
  1007. X{
  1008. X    int    i, j;
  1009. X    char    *cp;
  1010. X    
  1011. X    x_adj_ok = 0;
  1012. X    if (limit == -1)
  1013. X        x_putc('\n');
  1014. X    else 
  1015. X        x_putc('\r');
  1016. X    x_flush();
  1017. X    if (xbp == xbuf)
  1018. X    {
  1019. X      pprompt(prompt);
  1020. X      x_col = promptlen(prompt);
  1021. X    }
  1022. X    x_displen = x_cols - 2 - x_col;
  1023. X    xlp_valid = FALSE;
  1024. X    cp = x_lastcp();
  1025. X    x_zots(xbp);
  1026. X    if (xbp != xbuf || xep > xlp)
  1027. X      limit = x_cols;
  1028. X    if (limit >= 0)
  1029. X    {
  1030. X      if (xep > xlp)
  1031. X        i = 0;            /* we fill the line */
  1032. X      else
  1033. X        i = limit - (xlp - xbp);
  1034. X
  1035. X      for (j = 0; j < i && x_col < (x_cols - 2); j++)
  1036. X        x_putc(' ');
  1037. X      i = ' ';
  1038. X      if (xep > xlp)        /* more off screen */
  1039. X      {
  1040. X        if (xbp > xbuf)
  1041. X          i = '*';
  1042. X        else
  1043. X          i = '>';
  1044. X      }
  1045. X      else
  1046. X        if (xbp > xbuf)
  1047. X          i = '<';
  1048. X      x_putc(i);
  1049. X      j++;
  1050. X      while (j--)
  1051. X        x_putc('\b');
  1052. X    }
  1053. X    for (cp = xlp; cp > xcp; )
  1054. X      x_bs(*--cp);
  1055. X    x_adj_ok = 1;
  1056. X    _D_(x_flush();)
  1057. X    return;
  1058. X}
  1059. X
  1060. Xstatic int
  1061. Xx_transpose(c)  {
  1062. X    char    tmp;
  1063. X    if (xcp == xbuf) {
  1064. X        x_putc(BEL);
  1065. X        return KSTD;
  1066. X    } else if (xcp == xep) {
  1067. X        if (xcp - xbuf == 1) {
  1068. X            x_putc(BEL);
  1069. X            return KSTD;
  1070. X        }
  1071. X        x_bs(xcp[-1]);
  1072. X        x_bs(xcp[-2]);
  1073. X        x_zotc(xcp[-1]);
  1074. X        x_zotc(xcp[-2]);
  1075. X        tmp = xcp[-1];
  1076. X        xcp[-1] = xcp[-2];
  1077. X        xcp[-2] = tmp;
  1078. X    } else {
  1079. X        x_bs(xcp[-1]);
  1080. X        x_zotc(xcp[0]);
  1081. X        x_zotc(xcp[-1]);
  1082. X        tmp = xcp[-1];
  1083. X        xcp[-1] = xcp[0];
  1084. X        xcp[0] = tmp;
  1085. X        x_bs(xcp[0]);
  1086. X    }
  1087. X    return KSTD;
  1088. X}
  1089. X
  1090. Xstatic int
  1091. Xx_literal(c)  {
  1092. X    x_curprefix = -1;
  1093. X    return KSTD;
  1094. X}
  1095. X
  1096. Xstatic int
  1097. Xx_meta1(c)  {
  1098. X    x_curprefix = 1;
  1099. X    return KPREF;
  1100. X}
  1101. X
  1102. Xstatic int
  1103. Xx_meta2(c)  {
  1104. X    x_curprefix = 2;
  1105. X    return KPREF;
  1106. X}
  1107. X
  1108. Xstatic int
  1109. Xx_kill(c)  {
  1110. X    int    i;
  1111. X
  1112. X    i = xep - xcp;
  1113. X    xlp = xcp;
  1114. X    xlp_valid = TRUE;
  1115. X    x_push(i);
  1116. X    x_delete(i);
  1117. X    return KSTD;
  1118. X}
  1119. X
  1120. Xstatic void
  1121. Xx_push(nchars)  {
  1122. X    char    *cp;
  1123. X    cp = alloc((size_t)(nchars+1), AEDIT);
  1124. X    memmove(cp, xcp, nchars);
  1125. X    cp[nchars] = 0;
  1126. X    if (killstack[killsp])
  1127. X        afree((Void *)killstack[killsp], AEDIT);
  1128. X    killstack[killsp] = cp;
  1129. X    killsp = (killsp + 1) % KILLSIZE;
  1130. X}
  1131. X
  1132. Xstatic int
  1133. Xx_yank(c)  {
  1134. X    if (killsp == 0)
  1135. X        killtp = KILLSIZE;
  1136. X    else
  1137. X        killtp = killsp;
  1138. X    killtp --;
  1139. X    if (killstack[killtp] == 0)  {
  1140. X        x_puts("\nnothing to yank");
  1141. X        x_redraw(-1);
  1142. X        return KSTD;
  1143. X    }
  1144. X    xmp = xcp;
  1145. X    x_ins(killstack[killtp]);
  1146. X    return KSTD;
  1147. X}
  1148. X
  1149. Xstatic int
  1150. Xx_meta_yank(c)  {
  1151. X    int    len;
  1152. X    if (x_last_command != x_yank && x_last_command != x_meta_yank)  {
  1153. X        x_puts("\nyank something first");
  1154. X        x_redraw(-1);
  1155. X        return KSTD;
  1156. X    }
  1157. X    len = strlen(killstack[killtp]);
  1158. X    x_goto(xcp - len);
  1159. X    x_delete(len);
  1160. X    do  {
  1161. X        if (killtp == 0)
  1162. X            killtp = KILLSIZE - 1;
  1163. X        else
  1164. X            killtp--;
  1165. X    }  while (killstack[killtp] == 0);
  1166. X    x_ins(killstack[killtp]);
  1167. X    return KSTD;
  1168. X}
  1169. X
  1170. Xstatic int
  1171. Xx_abort(c) {
  1172. X    /* x_zotc(c); */
  1173. X    xlp = xep = xcp = xbp = xbuf;
  1174. X    xlp_valid = TRUE;
  1175. X    *xcp = 0;
  1176. X    return KINTR;
  1177. X}
  1178. X
  1179. Xstatic int
  1180. Xx_error(c) {
  1181. X    x_putc(BEL);
  1182. X    return KSTD;
  1183. X}
  1184. X
  1185. Xstatic int
  1186. Xx_stuffreset(c)
  1187. X{
  1188. X#ifdef TIOCSTI
  1189. X    (void)x_stuff(c);
  1190. X    return KINTR;
  1191. X#else
  1192. X    x_zotc(c);
  1193. X    xlp = xcp = xep = xbp = xbuf;
  1194. X    xlp_valid = TRUE;
  1195. X    *xcp = 0;
  1196. X    x_redraw(-1);
  1197. X    return KSTD;
  1198. X#endif
  1199. X}
  1200. X
  1201. Xstatic int
  1202. Xx_stuff(c)
  1203. X{
  1204. X#if 0 || defined TIOCSTI
  1205. X    char    ch = c;
  1206. X    bool_t    savmode = x_mode(FALSE);
  1207. X
  1208. X    (void)ioctl(ttyfd, TIOCSTI, &ch);
  1209. X    (void)x_mode(savmode);
  1210. X    x_redraw(-1);
  1211. X#endif
  1212. X    return KSTD;
  1213. X}
  1214. X
  1215. Xstatic void
  1216. Xx_mapin(cp)
  1217. X    char    *cp;
  1218. X{
  1219. X    char    *op;
  1220. X
  1221. X    op = cp;
  1222. X    while (*cp)  {
  1223. X        /* XXX -- should handle \^ escape? */
  1224. X        if (*cp == '^')  {
  1225. X            cp++;
  1226. X            if (*cp >= '?')    /* includes '?'; ASCII */
  1227. X                *op++ = CTRL(*cp);
  1228. X            else  {
  1229. X                *op++ = '^';
  1230. X                cp--;
  1231. X            }
  1232. X        } else
  1233. X            *op++ = *cp;
  1234. X        cp++;
  1235. X    }
  1236. X    *op = 0;
  1237. X}
  1238. X
  1239. Xstatic char *
  1240. Xx_mapout(c)
  1241. X    int c;
  1242. X{
  1243. X    static char buf[8];
  1244. X    register char *p = buf;
  1245. X
  1246. X    if (c < ' ' || c == 0x7F)  { /* ASCII */
  1247. X        *p++ = '^';
  1248. X        *p++ = (c == 0x7F) ? '?' : (c | 0x40);
  1249. X    } else
  1250. X        *p++ = c;
  1251. X    *p = 0;
  1252. X    return buf;
  1253. X}
  1254. X
  1255. Xstatic void
  1256. Xx_print(prefix, key)
  1257. X    int prefix, key;
  1258. X{
  1259. X    if (prefix == 1)
  1260. X        shellf("%s", x_mapout(x_prefix1));
  1261. X    if (prefix == 2)
  1262. X        shellf("%s", x_mapout(x_prefix2));
  1263. X    shellf("%s = ", x_mapout(key));
  1264. X    if (x_tab[prefix][key]->xf_func != x_ins_string)
  1265. X        shellf("%s\n", x_tab[prefix][key]->xf_name);
  1266. X    else
  1267. X        shellf("'%s'\n", x_atab[prefix][key]);
  1268. X}
  1269. X
  1270. Xvoid
  1271. Xx_bind(a1, a2, macro)
  1272. X    char *a1, *a2;
  1273. X    int macro;        /* bind -m */
  1274. X{
  1275. X    struct x_ftab Const *fp;
  1276. X    int prefix, key;
  1277. X    char *sp = NULL;
  1278. X
  1279. X    if (x_tab == NULL)
  1280. X        errorf("cannot bind, not a tty\n");
  1281. X
  1282. X    if (a1 == NULL) {
  1283. X        for (prefix = 0; prefix < 3; prefix++)
  1284. X            for (key = 0; key < 0x80; key++) {
  1285. X            fp = x_tab[prefix][key];
  1286. X            if (fp == NULL ||
  1287. X                fp->xf_func == x_insert || fp->xf_func == x_error)
  1288. X                continue;
  1289. X            x_print(prefix, key);
  1290. X            }
  1291. X        return;
  1292. X    }
  1293. X
  1294. X    x_mapin(a1);
  1295. X    prefix = key = 0;
  1296. X    for (;; a1++) {
  1297. X        key = *a1;
  1298. X        if (x_tab[prefix][key]->xf_func == x_meta1)
  1299. X            prefix = 1;
  1300. X        else
  1301. X        if (x_tab[prefix][key]->xf_func == x_meta2)
  1302. X            prefix = 2;
  1303. X        else
  1304. X            break;
  1305. X    }
  1306. X
  1307. X    if (a2 == NULL) {
  1308. X        x_print(prefix, key);
  1309. X        return;
  1310. X    }
  1311. X
  1312. X    if (*a2 == 0)
  1313. X        fp = xft_insert;
  1314. X    else if (!macro) {
  1315. X        for (fp = x_ftab; fp->xf_func; fp++)
  1316. X            if (strcmp(fp->xf_name, a2) == 0)
  1317. X                break;
  1318. X        if (fp->xf_func == NULL || (fp->xf_flags & XF_NOBIND))
  1319. X            errorf("%s: no such function\n", a2);
  1320. X        if (fp->xf_func == x_meta1)
  1321. X            x_prefix1 = key;
  1322. X        if (fp->xf_func == x_meta2)
  1323. X            x_prefix2 = key;
  1324. X    } else {
  1325. X        fp = xft_ins_string;
  1326. X        x_mapin(a2);
  1327. X        sp = strsave(a2, AEDIT);
  1328. X    }
  1329. X
  1330. X    if ((x_tab[prefix][key]->xf_flags & XF_ALLOC) && x_atab[prefix][key])
  1331. X        afree((Void *)x_atab[prefix][key], AEDIT);
  1332. X    x_tab[prefix][key] = fp;
  1333. X    x_atab[prefix][key] = sp;
  1334. X}
  1335. X
  1336. Xvoid
  1337. Xx_init_emacs()
  1338. X{
  1339. X    register int i, j;
  1340. X    struct x_ftab Const *fp;
  1341. X
  1342. X    ainit(AEDIT);
  1343. X
  1344. X    x_tab = (struct x_ftab ***) alloc(sizeofN(*x_tab, 3), AEDIT);
  1345. X    for (j = 0; j < 128; j++)
  1346. X        x_tab[0][j] = xft_insert;
  1347. X    for (i = 1; i < 3; i++)
  1348. X        for (j = 0; j < 128; j++)
  1349. X            x_tab[i][j] = xft_error;
  1350. X    for (fp = x_ftab; fp->xf_func; fp++)
  1351. X        if (fp->xf_db_char || fp->xf_db_tab)
  1352. X            x_tab[fp->xf_db_tab][fp->xf_db_char] = fp;
  1353. X
  1354. X    x_atab = (char ***) alloc(sizeofN(*x_atab, 3), AEDIT);
  1355. X    for (i = 1; i < 3; i++)
  1356. X        for (j = 0; j < 128; j++)
  1357. X            x_atab[i][j] = NULL;
  1358. X}
  1359. X
  1360. Xvoid
  1361. Xx_emacs_keys(erase, kill, werase, intr, quit)
  1362. X    int erase, kill, werase, intr, quit;
  1363. X{
  1364. X    x_tab[0][erase] = xft_erase;
  1365. X    x_tab[0][kill] = xft_kill;
  1366. X    x_tab[0][werase] = xft_werase;
  1367. X    x_tab[0][intr] = xft_intr;
  1368. X    x_tab[0][quit] = xft_quit;
  1369. X}
  1370. X
  1371. Xstatic int
  1372. Xx_set_mark(c) {
  1373. X    xmp = xcp;
  1374. X    return KSTD;
  1375. X}
  1376. X
  1377. Xstatic int
  1378. Xx_kill_region(c) {
  1379. X    int    rsize;
  1380. X    char    *xr;
  1381. X
  1382. X    if (xmp == NULL) {
  1383. X        x_putc(BEL);
  1384. X        return KSTD;
  1385. X    }
  1386. X    if (xmp > xcp) {
  1387. X        rsize = xmp - xcp;
  1388. X        xr = xcp;
  1389. X    } else {
  1390. X        rsize = xcp - xmp;
  1391. X        xr = xmp;
  1392. X    }
  1393. X    x_goto(xr);
  1394. X    x_push(rsize);
  1395. X    x_delete(rsize);
  1396. X    xmp = xr;
  1397. X    return KSTD;
  1398. X}
  1399. X
  1400. Xstatic int
  1401. Xx_xchg_point_mark(c) {
  1402. X    char    *tmp;
  1403. X
  1404. X    if (xmp == NULL) {
  1405. X        x_putc(BEL);
  1406. X        return KSTD;
  1407. X    }
  1408. X    tmp = xmp;
  1409. X    xmp = xcp;
  1410. X    x_goto( tmp );
  1411. X    return KSTD;
  1412. X}
  1413. X
  1414. X#if 0
  1415. Xstatic int
  1416. Xx_copy_arg(c)    {
  1417. X    char *last;
  1418. X    if ((last = strval(local("_"))) && *last)
  1419. X        x_ins(last);
  1420. X    return KSTD;
  1421. X}
  1422. X#endif
  1423. X
  1424. Xstatic int
  1425. Xx_noop(c) {
  1426. X    return KNULL;
  1427. X}
  1428. X
  1429. X#ifdef SILLY
  1430. Xstatic int
  1431. Xx_game_of_life(c)  {
  1432. X    char    newbuf [256+1];
  1433. X    register char *ip, *op;
  1434. X    int    i, len;
  1435. X
  1436. X    i = xep - xbuf;
  1437. X    *xep = 0;
  1438. X    len = x_size_str(xbuf);
  1439. X    xcp = xbp = xbuf;
  1440. X    memmove(newbuf+1, xbuf, i);
  1441. X    newbuf[0] = 'A';
  1442. X    newbuf[i] = 'A';
  1443. X    for (ip = newbuf+1, op = xbuf; --i >= 0; ip++, op++)  {
  1444. X        /*  Empty space  */
  1445. X        if (*ip < '@' || *ip == '_' || *ip == 0x7F)  {
  1446. X            /*  Two adults, make whoopee */
  1447. X            if (ip[-1] < '_' && ip[1] < '_')  {
  1448. X                /*  Make kid look like parents.  */
  1449. X                *op = '`' + ((ip[-1] + ip[1])/2)%32;
  1450. X                if (*op == 0x7F) /* Birth defect */
  1451. X                    *op = '`';
  1452. X            }
  1453. X            else
  1454. X                *op = ' ';    /* nothing happens */
  1455. X            continue;
  1456. X        }
  1457. X        /*  Child */
  1458. X        if (*ip > '`')  {
  1459. X            /*  All alone, dies  */
  1460. X            if (ip[-1] == ' ' && ip[1] == ' ')
  1461. X                *op = ' ';
  1462. X            else    /*  Gets older */
  1463. X                *op = *ip-'`'+'@';
  1464. X            continue;
  1465. X        }
  1466. X        /*  Adult  */
  1467. X        /*  Overcrowded, dies */
  1468. X        if (ip[-1] >= '@' && ip[1] >= '@')  {
  1469. X            *op = ' ';
  1470. X            continue;
  1471. X        }
  1472. X        *op = *ip;
  1473. X    }
  1474. X    *op = 0;
  1475. X    x_redraw(len);
  1476. X    return KSTD;
  1477. X}
  1478. X#endif
  1479. X
  1480. X/*
  1481. X *    File/command name completion routines
  1482. X */
  1483. X
  1484. X/* type: 0 for list, 1 for completion */
  1485. X
  1486. Xstatic    XPtrV words;
  1487. X
  1488. Xstatic void
  1489. Xadd_stash(dirnam, name)
  1490. X    char *dirnam;    /* directory name, if file */
  1491. X    char *name;
  1492. X{
  1493. X    char *cp;
  1494. X    register int type = 0;    /* '*' if executable, '/' if directory, else 0 */
  1495. X    register int len = strlen(name);
  1496. X
  1497. X    /* determine file type */
  1498. X    if (dirnam)  {
  1499. X        struct stat statb;
  1500. X        char *buf = alloc((size_t)(strlen(dirnam)+len+2), ATEMP);
  1501. X
  1502. X        if (strcmp(dirnam, ".") == 0)
  1503. X            *buf = '\0';
  1504. X        else if (strcmp(dirnam, "/") == 0)
  1505. X            (void)strcpy(buf, "/");
  1506. X        else
  1507. X            (void)strcat(strcpy(buf, dirnam), "/");
  1508. X        (void)strcat(buf, name);
  1509. X        if (stat(buf, &statb)==0)
  1510. X            if (S_ISDIR(statb.st_mode))
  1511. X                type = '/';
  1512. X            else if (S_ISREG(statb.st_mode) && access(buf, 01)==0)
  1513. X                type = '*';
  1514. X        if (type)
  1515. X            ++len;
  1516. X        afree((Void *)buf, ATEMP);
  1517. X    }
  1518. X
  1519. X    if (len > x_maxlen)
  1520. X        x_maxlen = len;
  1521. X
  1522. X    /* stash name for later sorting */
  1523. X    cp = alloc((size_t)(len+1), ATEMP);
  1524. X    (void)strcpy(cp = alloc((size_t)(len+1), ATEMP), name);
  1525. X    if (dirnam && type)  {    /* append file type indicator */
  1526. X        cp[len-1] = type;
  1527. X        cp[len] = '\0';
  1528. X    }
  1529. X    XPput(words, cp);
  1530. X}
  1531. X
  1532. Xstatic void
  1533. Xlist_stash()
  1534. X{
  1535. X    register char **array, **record;
  1536. X    int items = 0, tabstop, loc, nrows, jump, offset;
  1537. X
  1538. X    items = XPsize(words);
  1539. X    array = (char**) XPptrv(words);
  1540. X    if (items == 0)
  1541. X        return;
  1542. X    qsortp(XPptrv(words), (size_t)XPsize(words), xstrcmp);
  1543. X
  1544. X    /* print names */
  1545. X    x_maxlen = (x_maxlen/8 + 1) * 8;    /* column width */
  1546. X    nrows = (items-1) / (x_cols/x_maxlen) + 1;
  1547. X    for (offset = 0; offset < nrows; ++offset)  {
  1548. X        tabstop = loc = 0;
  1549. X        x_putc('\n');
  1550. X        for (jump = 0; offset+jump < items; jump += nrows)  {
  1551. X            if (jump)
  1552. X                while (loc < tabstop)  {
  1553. X                    x_putc('\t');
  1554. X                    loc = (loc/8 + 1) * 8;
  1555. X                }
  1556. X            record = array + (offset + jump);
  1557. X            x_puts(*record);
  1558. X            loc += strlen(*record);
  1559. X            tabstop += x_maxlen;    /* next tab stop */
  1560. X            afree((Void *)*record, ATEMP);
  1561. X        }
  1562. X    }
  1563. X
  1564. X    afree((Void*)array, ATEMP);
  1565. X    x_redraw(-1);
  1566. X}
  1567. X
  1568. Xstatic int
  1569. Xx_comp_comm(c)  {
  1570. X    compl_command(1);
  1571. X    return KSTD;
  1572. X}
  1573. Xstatic int
  1574. Xx_list_comm(c)  {
  1575. X    compl_command(0);
  1576. X    return KSTD;
  1577. X}
  1578. Xstatic int
  1579. Xx_complete(c)  {
  1580. X    compl_dec(1);
  1581. X    return KSTD;
  1582. X}
  1583. Xstatic int
  1584. Xx_enumerate(c)  {
  1585. X    compl_dec(0);
  1586. X    return KSTD;
  1587. X}
  1588. Xstatic int
  1589. Xx_comp_file(c)   {
  1590. X    compl_file(1);
  1591. X    return KSTD;
  1592. X}
  1593. Xstatic int
  1594. Xx_list_file(c)  {
  1595. X    compl_file(0);
  1596. X    return KSTD;
  1597. X}
  1598. X
  1599. Xstatic void
  1600. Xcompl_dec(type)
  1601. X{
  1602. X    char    *cp;
  1603. X    cp = xcp;
  1604. X
  1605. X    while (cp != xbuf && !iscfs(*cp))
  1606. X        cp--;
  1607. X    if (cp == xbuf && strchr(cp, '/') == NULL)
  1608. X        compl_command(type);
  1609. X    else
  1610. X        compl_file(type);
  1611. X}
  1612. X
  1613. Xstatic void
  1614. Xcompl_file(type)
  1615. X{
  1616. X    char    *str;
  1617. X    register char *cp, *xp;
  1618. X    char    *lastp;
  1619. X    char    *dirnam;
  1620. X    char    buf [256+1];
  1621. X    char    bug [256+1];
  1622. X    DIR    *dirp;
  1623. X    struct dirent *dp;
  1624. X    long    loc = -1;
  1625. X    int    len;
  1626. X    int    multi = 0;
  1627. X
  1628. X    str = xcp;
  1629. X    cp = buf;
  1630. X    xp = str;
  1631. X    while (xp != xbuf)  {
  1632. X        --xp;
  1633. X        if (iscfs(*xp))  {
  1634. X            xp++;
  1635. X            break;
  1636. X        }
  1637. X    }
  1638. X    if (digit(*xp) && (xp[1] == '<' || xp[1] == '>'))
  1639. X        xp++;
  1640. X    while (*xp == '<' || *xp == '>')
  1641. X        xp++;
  1642. X    if (type)
  1643. X        while (*xcp && !iscfs(*xcp))
  1644. X            x_zotc(*xcp++);
  1645. X    else {
  1646. X        x_maxlen = 0;
  1647. X        XPinit(words, 16);
  1648. X    }
  1649. X    while (*xp && !iscfs(*xp))
  1650. X        *cp++ = *xp++;
  1651. X
  1652. X    *cp = 0;
  1653. X    strcpy(buf, cp = substitute(buf, DOTILDE));
  1654. X    afree((Void*)cp, ATEMP);
  1655. X    lastp = strrchr(buf, '/');
  1656. X    if (lastp)
  1657. X        *lastp = 0;
  1658. X
  1659. X    dirnam = (lastp == NULL) ? "." : (lastp == buf) ? "/" : buf;
  1660. X    dirp = opendir(dirnam);
  1661. X    if (dirp == NULL) {
  1662. X        x_putc(BEL);
  1663. X        return;
  1664. X    }
  1665. X
  1666. X    if (lastp == NULL)
  1667. X        lastp = buf;
  1668. X    else
  1669. X        lastp++;
  1670. X    len = strlen(lastp);
  1671. X
  1672. X    while ((dp = readdir(dirp)) != NULL)  {
  1673. X        cp = dp->d_name;
  1674. X        if (cp[0] == '.' &&
  1675. X            (cp[1] == '\0' || cp[1] == '.' && cp[2] == '\0'))
  1676. X            continue; /* always ignore . and .. */
  1677. X        if (strncmp(lastp, cp, len) == 0)
  1678. X            if (type)  {
  1679. X                if (loc == -1)  {
  1680. X                    (void)strcpy(bug, cp);
  1681. X                    loc = strlen(cp);
  1682. X                } else {
  1683. X                    multi = 1;
  1684. X                    loc = strmatch(bug, cp);
  1685. X                    bug[loc] = 0;
  1686. X                }
  1687. X            } else
  1688. X                add_stash(dirnam, cp);
  1689. X    }
  1690. X    (void)closedir(dirp);
  1691. X
  1692. X    if (type) {
  1693. X        if (loc <= 0)  {
  1694. X            x_putc(BEL);
  1695. X            return;
  1696. X        }
  1697. X        cp = bug + len;
  1698. X        x_ins(cp);
  1699. X        if (!multi)  {
  1700. X            struct stat statb;
  1701. X            if (lastp == buf)
  1702. X                buf[0] = 0;
  1703. X            else if (lastp == buf + 1)  {
  1704. X                buf[1] = 0;
  1705. X                buf[0] = '/';
  1706. X            }  else
  1707. X                (void)strcat(buf, "/");
  1708. X            (void)strcat(buf, bug);
  1709. X            if (stat(buf, &statb) == 0 && S_ISDIR(statb.st_mode))
  1710. X                x_ins("/");
  1711. X            else
  1712. X                x_ins(" ");
  1713. X        }
  1714. X    } else
  1715. X        list_stash();
  1716. X}
  1717. X
  1718. Xstatic void
  1719. Xcompl_command(type)
  1720. X{
  1721. X    register struct tbl *tp;
  1722. X    char    *str;
  1723. X    char    buf [256+1];
  1724. X    char    bug [256+1];
  1725. X    char    *xp;
  1726. X    char    *cp;
  1727. X    int  len;
  1728. X    int  multi;
  1729. X    int  loc;
  1730. X
  1731. X    str = xcp;
  1732. X    cp = buf;
  1733. X    xp = str;
  1734. X    while (xp != xbuf)  {
  1735. X        --xp;
  1736. X        if (iscfs(*xp))  {
  1737. X            xp++;
  1738. X            break;
  1739. X        }
  1740. X    }
  1741. X    if (type)
  1742. X        while (*xcp && !iscfs(*xcp))
  1743. X            x_zotc(*xcp++);
  1744. X    else {
  1745. X        x_maxlen = 0;
  1746. X        XPinit(words, 16);
  1747. X    }
  1748. X    while (*xp && !iscfs(*xp))
  1749. X        *cp++ = *xp++;
  1750. X    *cp = 0;
  1751. X
  1752. X    len = strlen(buf);
  1753. X    loc = -1;
  1754. X    multi = 0;
  1755. X
  1756. X    for (twalk(&commands); (tp = tnext()) != NULL; ) {
  1757. X        int    klen;
  1758. X
  1759. X        if (!(tp->flag&ISSET))
  1760. X            continue;
  1761. X        klen = strlen(tp->name);
  1762. X        if (klen < len)
  1763. X            continue;
  1764. X        if (strncmp(buf, tp->name, len) ==0)
  1765. X            if (type)  {
  1766. X                if (loc == -1)  {
  1767. X                    (void)strcpy(bug, tp->name);
  1768. X                    loc = klen;
  1769. X                } else {
  1770. X                    multi = 1;
  1771. X                    loc = strmatch(bug, tp->name);
  1772. X                    bug[loc] = 0;
  1773. X                }
  1774. X            } else
  1775. X                add_stash((char *)0, tp->name);
  1776. X    }
  1777. X
  1778. X    if (type)  {
  1779. X        if (loc <= 0)  {
  1780. X            x_putc(BEL);
  1781. X            return;
  1782. X        }
  1783. X        cp = bug + len;
  1784. X        x_ins(cp);
  1785. X        if (!multi)
  1786. X            x_ins(" ");
  1787. X    } else
  1788. X        list_stash();
  1789. X}
  1790. X
  1791. Xstatic int
  1792. Xstrmatch(s1, s2)
  1793. X    register char *s1, *s2;
  1794. X{
  1795. X    register char *p;
  1796. X
  1797. X    for (p = s1; *p == *s2++ && *p != 0; p++)
  1798. X        ;
  1799. X    return p - s1;
  1800. X}
  1801. X
  1802. X
  1803. X
  1804. X/* NAME:
  1805. X *      x_set_arg - set an arg value for next function
  1806. X *
  1807. X * DESCRIPTION:
  1808. X *      This is a simple implementation of M-[0-9].
  1809. X *
  1810. X * RETURN VALUE:
  1811. X *      KSTD
  1812. X */
  1813. X
  1814. Xstatic int
  1815. Xx_set_arg(c)
  1816. X  int c;
  1817. X{
  1818. X  if ((x_arg = (c &= CMASK) - '0') < 0 || x_arg > 9)
  1819. X  {
  1820. X    x_arg = 1;
  1821. X    x_putc(BEL);
  1822. X  }
  1823. X  return KSTD;
  1824. X}
  1825. X
  1826. X
  1827. X/* NAME:
  1828. X *      x_prev_histword - recover word from prev command
  1829. X *
  1830. X * DESCRIPTION:
  1831. X *      This function recovers the last word from the previous 
  1832. X *      command and inserts it into the current edit line.  If a 
  1833. X *      numeric arg is supplied then the n'th word from the 
  1834. X *      start of the previous command is used.  
  1835. X *      
  1836. X *      Bound to M-.
  1837. X *
  1838. X * RETURN VALUE:
  1839. X *      KSTD
  1840. X */
  1841. X
  1842. Xstatic int
  1843. Xx_prev_histword()
  1844. X{
  1845. X  register char *rcp;
  1846. X  char *cp;
  1847. X  char **hp;
  1848. X
  1849. X  hp = x_histp-1;
  1850. X  if (hp < history || hp > histptr)
  1851. X  {
  1852. X    x_putc(BEL);
  1853. X    return;
  1854. X  }
  1855. X  cp = *hp;
  1856. X  if (x_last_command != x_set_arg)
  1857. X  {
  1858. X    rcp = &cp[strlen(cp) - 1];
  1859. X    /*
  1860. X     * ignore white-space after the last word
  1861. X     */
  1862. X    while (rcp > cp && iscfs(*rcp))
  1863. X      rcp--;
  1864. X    while (rcp > cp && !iscfs(*rcp))
  1865. X      rcp--;
  1866. X    if (iscfs(*rcp))
  1867. X      rcp++;
  1868. X    x_ins(rcp);
  1869. X  }
  1870. X  else
  1871. X  {
  1872. X    int c;
  1873. X    
  1874. X    rcp = cp;
  1875. X    /*
  1876. X     * ignore white-space at start of line
  1877. X     */
  1878. X    while (*rcp && iscfs(*rcp))
  1879. X      rcp++;
  1880. X    while (x_arg-- > 1)
  1881. X    {
  1882. X      while (*rcp && !iscfs(*rcp))
  1883. X    rcp++;
  1884. X      while (*rcp && iscfs(*rcp))
  1885. X    rcp++;
  1886. X    }
  1887. X    cp = rcp;
  1888. X    while (*rcp && !iscfs(*rcp))
  1889. X      rcp++;
  1890. X    c = *rcp;
  1891. X    *rcp = '\0';
  1892. X    x_ins(cp);
  1893. X    *rcp = c;
  1894. X  }
  1895. X  return KSTD;
  1896. X}
  1897. X
  1898. X/* NAME:
  1899. X *      x_fold_case - convert word to UPPER/lower case
  1900. X *
  1901. X * DESCRIPTION:
  1902. X *      This function is used to implement M-u,M-l and M-c
  1903. X *      to upper case, lower case or Capitalize words.
  1904. X *
  1905. X * RETURN VALUE:
  1906. X *      None
  1907. X */
  1908. X
  1909. Xstatic int
  1910. Xx_fold_case(c)
  1911. X  int c;
  1912. X{
  1913. X  register char    *cp = xcp;
  1914. X  
  1915. X  if (cp == xep)
  1916. X  {
  1917. X    x_putc(BEL);
  1918. X    return 0;
  1919. X  }
  1920. X  c &= 0137;                /* strip prefixes and case */
  1921. X  if (x_last_command != x_set_arg)
  1922. X    x_arg = 1;
  1923. X  while (x_arg--)
  1924. X  {
  1925. X    /*
  1926. X     * fisrt skip over any white-space
  1927. X     */
  1928. X    while (cp != xep && ismfs(*cp))
  1929. X    {
  1930. X      cp++;
  1931. X    }
  1932. X    /*
  1933. X     * do the first char on its own since it may be
  1934. X     * a different action than for the rest.
  1935. X     */
  1936. X    if (cp != xep)
  1937. X    {
  1938. X      if (c == 'L')            /* M-l */
  1939. X      {
  1940. X    if (isupper(*cp))
  1941. X      *cp = tolower(*cp);
  1942. X      }
  1943. X      else                /* M-u or M-c */
  1944. X      {
  1945. X    if (islower(*cp))
  1946. X      *cp = toupper(*cp);
  1947. X      }
  1948. X      cp++;
  1949. X    }
  1950. X    /*
  1951. X     * now for the rest of the word
  1952. X     */
  1953. X    while (cp != xep && !ismfs(*cp))
  1954. X    {
  1955. X      if (c == 'U')            /* M-u */
  1956. X      {
  1957. X    if (islower(*cp))
  1958. X      *cp = toupper(*cp);
  1959. X      }
  1960. X      else                /* M-l or M-c */
  1961. X      {
  1962. X    if (isupper(*cp))
  1963. X      *cp = tolower(*cp);
  1964. X      }
  1965. X      cp++;
  1966. X    }
  1967. X  }
  1968. X  x_goto(cp);
  1969. X  return 0;
  1970. X}
  1971. X
  1972. X/* NAME:
  1973. X *      x_lastcp - last visible char
  1974. X *
  1975. X * SYNOPSIS:
  1976. X *      x_lastcp()
  1977. X *
  1978. X * DESCRIPTION:
  1979. X *      This function returns a pointer to that  char in the 
  1980. X *      edit buffer that will be the last displayed on the 
  1981. X *      screen.  The sequence:
  1982. X *      
  1983. X *      for (cp = x_lastcp(); cp > xcp; cp)
  1984. X *        x_bs(*--cp);
  1985. X *      
  1986. X *      Will position the cursor correctly on the screen.
  1987. X *
  1988. X * RETURN VALUE:
  1989. X *      cp or NULL
  1990. X */
  1991. X
  1992. Xchar *
  1993. Xx_lastcp()
  1994. X{
  1995. X  register char *rcp;
  1996. X  register int i;
  1997. X
  1998. X  if (!xlp_valid)
  1999. X  {
  2000. X    for (i = 0, rcp = xbp; rcp < xep && i < x_displen; rcp++)
  2001. X      i += x_size(*rcp);
  2002. X    xlp = rcp;
  2003. X  }
  2004. X  xlp_valid = TRUE;
  2005. X  return (xlp);
  2006. X}
  2007. X
  2008. X#endif /* EDIT */
  2009. X
  2010. END_OF_FILE
  2011.   if test 32990 -ne `wc -c <'sh/emacs.c'`; then
  2012.     echo shar: \"'sh/emacs.c'\" unpacked with wrong size!
  2013.   fi
  2014.   # end of 'sh/emacs.c'
  2015. fi
  2016. if test -f 'sh/var.c' -a "${1}" != "-c" ; then 
  2017.   echo shar: Will not clobber existing file \"'sh/var.c'\"
  2018. else
  2019.   echo shar: Extracting \"'sh/var.c'\" \(11520 characters\)
  2020.   sed "s/^X//" >'sh/var.c' <<'END_OF_FILE'
  2021. X#ifndef lint
  2022. Xstatic char *RCSid = "$Id: var.c,v 3.2 89/03/27 15:52:21 egisin Exp $";
  2023. Xstatic char *sccs_id = "@(#)var.c    1.3 91/11/09 15:35:17 (sjg)";
  2024. X#endif
  2025. X
  2026. X#include <stddef.h>
  2027. X#include <string.h>
  2028. X#include <errno.h>
  2029. X#include <setjmp.h>
  2030. X#include <time.h>
  2031. X#include "sh.h"
  2032. X#include "table.h"
  2033. X#include "expand.h"
  2034. X
  2035. X/*
  2036. X * Variables
  2037. X *
  2038. X * WARNING: unreadable code, needs a rewrite
  2039. X *
  2040. X * if (flag&INTEGER), val.i contains integer value, and type contains base.
  2041. X * otherwise, (val.s + type) contains string value.
  2042. X * if (flag&EXPORT), val.s contains "name=value" for E-Z exporting.
  2043. X */
  2044. Xchar    null []    = "";
  2045. Xstatic    struct tbl vtemp;
  2046. Xstatic    void getspec(), setspec();
  2047. Xstatic    void export ARGS((struct tbl *, char *val));
  2048. Xstatic    int special ARGS ((char *name));
  2049. X
  2050. X/*
  2051. X * create a new block for function calls and simple commands
  2052. X * assume caller has allocated and set up e.loc
  2053. X */
  2054. Xvoid
  2055. Xnewblock()
  2056. X{
  2057. X    register struct block *l = e.loc;
  2058. X    static char *empty[] = {""};
  2059. X
  2060. X    ainit(&l->area);
  2061. X    l->argc = 0;
  2062. X    l->argv = empty;
  2063. X    l->exit = l->error = NULL;
  2064. X    tinit(&l->vars, &l->area);
  2065. X    tinit(&l->funs, &l->area);
  2066. X}
  2067. X
  2068. X/*
  2069. X * pop a block handling special variables
  2070. X */
  2071. Xvoid
  2072. Xpopblock()
  2073. X{
  2074. X    register struct block *l = e.loc;
  2075. X    register struct tbl *vp, **vpp = l->vars.tbls;
  2076. X    register int i;
  2077. X
  2078. X    e.loc = l->next;    /* pop block */
  2079. X    for (i = l->vars.size; --i >= 0; )
  2080. X        if ((vp = *vpp++) != NULL && (vp->flag&SPECIAL))
  2081. X            setspec(global(vp->name));
  2082. X    afreeall(&l->area);
  2083. X}
  2084. X
  2085. X/*
  2086. X * Search for variable, if not found create globally.
  2087. X */
  2088. Xstruct tbl *
  2089. Xglobal(n)
  2090. X    register char *n;
  2091. X{
  2092. X    register struct block *l = e.loc;
  2093. X    register struct tbl *vp;
  2094. X    register int c;
  2095. X    unsigned h = hash(n);
  2096. X
  2097. X    c = n[0];
  2098. X    if (digit(c)) {
  2099. X        vp = &vtemp;
  2100. X        lastarea = ATEMP;
  2101. X        vp->flag = (DEFINED|RDONLY);
  2102. X        vp->type = 0;
  2103. X        *vp->name = c;    /* should strncpy */
  2104. X        for (c = 0; digit(*n) && c < 1000; n++)
  2105. X            c = c*10 + *n-'0';
  2106. X        if (c <= l->argc)
  2107. X            setstr(vp, l->argv[c]);
  2108. X        return vp;
  2109. X    } else
  2110. X    if (!letter(c)) {
  2111. X        vp = &vtemp;
  2112. X        lastarea = ATEMP;
  2113. X        vp->flag = (DEFINED|RDONLY);
  2114. X        vp->type = 0;
  2115. X        *vp->name = c;
  2116. X        if (n[1] != '\0')
  2117. X            return vp;
  2118. X        vp->flag |= ISSET|INTEGER;
  2119. X        switch (c) {
  2120. X          case '$':
  2121. X            vp->val.i = kshpid;
  2122. X            break;
  2123. X          case '!':
  2124. X            vp->val.i = async;
  2125. X            break;
  2126. X          case '?':
  2127. X            vp->val.i = exstat;
  2128. X            break;
  2129. X          case '#':
  2130. X            vp->val.i = l->argc;
  2131. X            break;
  2132. X          case '-':
  2133. X            vp->flag &= ~ INTEGER;
  2134. X            vp->val.s = getoptions();
  2135. X            break;
  2136. X          default:
  2137. X            vp->flag &= ~(ISSET|INTEGER);
  2138. X        }
  2139. X        return vp;
  2140. X    }
  2141. X    for (l = e.loc; l != NULL; l = l->next) {
  2142. X        vp = tsearch(&l->vars, n, h);
  2143. X        lastarea = &l->area;
  2144. X        if (vp != NULL)
  2145. X            return vp;
  2146. X        if (l->next == NULL)
  2147. X            break;
  2148. X    }
  2149. X    vp = tenter(&l->vars, n, h);
  2150. X    vp->flag |= DEFINED;
  2151. X    if (special(n))
  2152. X        vp->flag |= SPECIAL;
  2153. X    return vp;
  2154. X}
  2155. X
  2156. X/*
  2157. X * Search for local variable, if not found create locally.
  2158. X */
  2159. Xstruct tbl *
  2160. Xlocal(n)
  2161. X    register char *n;
  2162. X{
  2163. X    register struct block *l = e.loc;
  2164. X    register struct tbl *vp;
  2165. X    unsigned h = hash(n);
  2166. X
  2167. X    if (!letter(*n)) {
  2168. X        vp = &vtemp;
  2169. X        lastarea = ATEMP;
  2170. X        vp->flag = (DEFINED|RDONLY);
  2171. X        vp->type = 0;
  2172. X        return vp;
  2173. X    }
  2174. X    vp = tenter(&l->vars, n, h);
  2175. X    lastarea = &l->area;
  2176. X    vp->flag |= DEFINED;
  2177. X    if (special(n))
  2178. X        vp->flag |= SPECIAL;
  2179. X    return vp;
  2180. X}
  2181. X
  2182. X/* get variable string value */
  2183. Xchar *
  2184. Xstrval(vp)
  2185. X    register struct tbl *vp;
  2186. X{
  2187. X    register char *s;
  2188. X    static char strbuf[40];
  2189. X
  2190. X    if ((vp->flag&SPECIAL))
  2191. X        getspec(vp);
  2192. X    if (!(vp->flag&ISSET))
  2193. X        return null;    /* special to dollar() */
  2194. X    if (!(vp->flag&INTEGER))    /* string source */
  2195. X        s = vp->val.s + vp->type;
  2196. X    else {                /* integer source */
  2197. X        register unsigned long n;
  2198. X        register int base;
  2199. X
  2200. X        s = strbuf + sizeof(strbuf);
  2201. X        n = (vp->val.i < 0) ? -vp->val.i : vp->val.i;
  2202. X        base = (vp->type == 0) ? 10 : vp->type;
  2203. X
  2204. X        *--s = '\0';
  2205. X        do {
  2206. X            *--s = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[n%base];
  2207. X            n /= base;
  2208. X        } while (n != 0);
  2209. X        /* todo: should we output base# ? */
  2210. X        if (vp->val.i < 0)
  2211. X            *--s = '-';
  2212. X    }
  2213. X    return s;
  2214. X}
  2215. X
  2216. X/* get variable integer value */
  2217. Xlong
  2218. Xintval(vp)
  2219. X    register struct tbl *vp;
  2220. X{
  2221. X    register struct tbl *vq;
  2222. X
  2223. X    if ((vp->flag&SPECIAL))
  2224. X        getspec(vp);
  2225. X    if ((vp->flag&INTEGER))
  2226. X        return vp->val.i;
  2227. X    vq = &vtemp;
  2228. X    vq->flag = (INTEGER);
  2229. X    vq->type = 0;
  2230. X    if (strint(vq, vp) == NULL)
  2231. X        errorf("%s: bad number\n", vp->val.s);
  2232. X    return vq->val.i;
  2233. X}
  2234. X
  2235. X/* set variable to string value */
  2236. Xvoid
  2237. Xsetstr(vq, s)
  2238. X    register struct tbl *vq;
  2239. X    char *s;
  2240. X{
  2241. X    if (!(vq->flag&INTEGER)) { /* string dest */
  2242. X        if ((vq->flag&ALLOC))
  2243. X            afree((Void*)vq->val.s, lastarea);
  2244. X        vq->flag &= ~ (ISSET|ALLOC);
  2245. X        vq->type = 0;
  2246. X        if ((vq->flag&EXPORT))
  2247. X            export(vq, s);
  2248. X        else
  2249. X            vq->val.s = strsave(s, lastarea);
  2250. X        vq->flag |= ALLOC;
  2251. X    } else {        /* integer dest */
  2252. X        register struct tbl *vp = &vtemp;    
  2253. X        vp->flag = (DEFINED|ISSET);
  2254. X        vp->type = 0;
  2255. X        vp->val.s = s;
  2256. X        if (strint(vq, vp) == NULL)
  2257. X            errorf("%s: bad number\n", s);
  2258. X    }
  2259. X    vq->flag |= ISSET;
  2260. X    if ((vq->flag&SPECIAL))
  2261. X        setspec(vq);
  2262. X}
  2263. X    
  2264. X/* convert variable to integer variable */
  2265. Xstruct tbl *
  2266. Xstrint(vq, vp)
  2267. X    register struct tbl *vq, *vp;
  2268. X{
  2269. X    register char *s = vp->val.s + vp->type;
  2270. X    register int c;
  2271. X    int base, neg = 0;
  2272. X    
  2273. X    vq->flag |= INTEGER;
  2274. X    if (!(vp->flag&ISSET) || (s == NULL && !(vp->flag&INTEGER))) {
  2275. X        vq->flag &= ~ ISSET;
  2276. X        return NULL;
  2277. X    }
  2278. X    if ((vp->flag&INTEGER)) {
  2279. X        vq->val.i = vp->val.i;
  2280. X        return vq;
  2281. X    }
  2282. X    vq->val.i = 0;
  2283. X    base = 10;
  2284. X    for (c = *s++; c ; c = *s++)
  2285. X        if (c == '-') {
  2286. X            neg++;
  2287. X        } else if (c == '#') {
  2288. X            base = vq->type = vq->val.i;
  2289. X            vq->val.i = 0;
  2290. X        } else if (letnum(c)) {
  2291. X            if ('0' <= c && c <= '9')
  2292. X                c -= '0';
  2293. X            else if ('a' <= c && c <= 'z') /* fuck EBCDIC */
  2294. X                c -= 'a'-10;
  2295. X            else if ('A' <= c && c <= 'Z')
  2296. X                c -= 'A'-10;
  2297. X            if (c < 0 || c >= base) {
  2298. X                vq->flag &= ~ ISSET;
  2299. X                return NULL;
  2300. X            }
  2301. X            vq->val.i = (vq->val.i*base) + c;
  2302. X        } else
  2303. X            break;
  2304. X    if (neg)
  2305. X        vq->val.i = -vq->val.i;
  2306. X    if (vq->type < 2 || vq->type > 36)
  2307. X        vq->type = 0;    /* default base (10) */
  2308. X    return vq;
  2309. X}
  2310. X
  2311. X/* set variable to integer */
  2312. Xvoid
  2313. Xsetint(vq, n)
  2314. X    register struct tbl *vq;
  2315. X    long n;
  2316. X{
  2317. X    if (!(vq->flag&INTEGER)) {
  2318. X        register struct tbl *vp = &vtemp;
  2319. X        vp->flag = (ISSET|INTEGER);
  2320. X        vp->type = 0;
  2321. X        vp->val.i = n;
  2322. X        setstr(vq, strval(vp));    /* ? */
  2323. X    } else
  2324. X        vq->val.i = n;
  2325. X    vq->flag |= ISSET;
  2326. X    if ((vq->flag&SPECIAL))
  2327. X        setspec(vq);
  2328. X}
  2329. X
  2330. X/* set variable from enviroment */
  2331. Ximport(thing)
  2332. X    char *thing;
  2333. X{
  2334. X    register struct tbl *vp;
  2335. X    register char *val;
  2336. X
  2337. X    val = strchr(thing, '=');
  2338. X    if (val == NULL)
  2339. X        return 0;
  2340. X    *val = '\0';
  2341. X    vp = local(thing);
  2342. X    *val++ = '=';
  2343. X    vp->flag |= DEFINED|ISSET|EXPORT;
  2344. X    vp->val.s = thing;
  2345. X    vp->type = val - thing;
  2346. X    if ((vp->flag&SPECIAL))
  2347. X        setspec(vp);
  2348. X    return 1;
  2349. X}
  2350. X
  2351. X/*
  2352. X * make vp->val.s be "name=value" for quick exporting.
  2353. X */
  2354. Xstatic void
  2355. Xexport(vp, val)
  2356. X    register struct tbl *vp;
  2357. X    char *val;
  2358. X{
  2359. X    register char *cp, *xp;
  2360. X    char *op = (vp->flag&ALLOC) ? vp->val.s : NULL;
  2361. X
  2362. X    xp = (char*)alloc(strlen(vp->name) + strlen(val) + 2, lastarea);
  2363. X    vp->flag |= ALLOC;
  2364. X    vp->val.s = xp;
  2365. X    for (cp = vp->name; (*xp = *cp++) != '\0'; xp++)
  2366. X        ;
  2367. X    *xp++ = '=';
  2368. X    vp->type = xp - vp->val.s; /* offset to value */
  2369. X    for (cp = val; (*xp++ = *cp++) != '\0'; )
  2370. X        ;
  2371. X    if (op != NULL)
  2372. X        afree((Void*)op, lastarea);
  2373. X}
  2374. X
  2375. X/*
  2376. X * lookup variable (according to (set&LOCAL)),
  2377. X * set its attributes (INTEGER, RDONLY, EXPORT, TRACE),
  2378. X * and optionally set its value if an assignment.
  2379. X */
  2380. Xstruct tbl *
  2381. Xtypeset(var, set, clr)
  2382. X    register char *var;
  2383. X    int clr, set;
  2384. X{
  2385. X    register struct tbl *vp;
  2386. X    register char *val;
  2387. X
  2388. X    /* check for valid variable name, search for value */
  2389. X    val = var;
  2390. X    if (!letter(*val))
  2391. X        return NULL;
  2392. X    for (val++; *val != '\0'; val++)
  2393. X        if (*val == '=')
  2394. X            break;
  2395. X        else if (letnum(*val))
  2396. X            ;
  2397. X        else
  2398. X            return NULL;
  2399. X    if (*val == '=')
  2400. X        *val = '\0';
  2401. X    else
  2402. X        val = NULL;
  2403. X    vp = (set&LOCAL) ? local(var) : global(var);
  2404. X    set &= ~ LOCAL;
  2405. X    if (val != NULL)
  2406. X        *val++ = '=';
  2407. X
  2408. X    if (!(vp->flag&ISSET))
  2409. X        vp->flag = vp->flag & ~clr | set;
  2410. X    else
  2411. X        if (!(vp->flag&INTEGER) && (set&INTEGER)) {
  2412. X        /* string to integer */
  2413. X        vtemp.flag = (ISSET);
  2414. X        vtemp.type = 0;
  2415. X        vtemp.val.s = vp->val.s + vp->type;
  2416. X        if ((vp->flag&ALLOC))
  2417. X            afree((Void*)vp->val.s, lastarea); /* dangerous, used later */
  2418. X        vp->flag &= ~ ALLOC;
  2419. X        vp->flag |= INTEGER;
  2420. X        vp->type = 0;
  2421. X        if (val == NULL && strint(vp, &vtemp) == NULL) {
  2422. X            vp->flag &= ~ ISSET;
  2423. X            errorf("%s: bad number\n", vtemp.val.s);
  2424. X        }
  2425. X        } else
  2426. X        if ((clr&INTEGER) && (vp->flag&INTEGER)) {
  2427. X        /* integer to string */
  2428. X        vtemp.val.s = strval(vp);
  2429. X        vp->flag &= ~ INTEGER;
  2430. X        setstr(vp, vtemp.val.s);
  2431. X        }
  2432. X
  2433. X    vp->flag = vp->flag & ~clr | set;
  2434. X
  2435. X    if (val != NULL) {
  2436. X        if ((vp->flag&RDONLY))
  2437. X            errorf("cannot set readonly %s\n", var);
  2438. X        if ((vp->flag&INTEGER))
  2439. X            /* setstr should be able to handle this */
  2440. X            (void)evaluate(var);
  2441. X        else
  2442. X            setstr(vp, val);
  2443. X    }
  2444. X
  2445. X    if ((vp->flag&EXPORT) && !(vp->flag&INTEGER) && vp->type == 0)
  2446. X        export(vp, (vp->flag&ISSET) ? vp->val.s : null);
  2447. X
  2448. X    return vp;
  2449. X}
  2450. X
  2451. Xvoid
  2452. Xunset(vp)
  2453. X    register struct tbl *vp;
  2454. X{
  2455. X    if ((vp->flag&ALLOC))
  2456. X        afree((Void*)vp->val.s, lastarea);
  2457. X    vp->flag &= SPECIAL;    /* Should ``unspecial'' some vars */
  2458. X}
  2459. X
  2460. Xint
  2461. Xisassign(s)
  2462. X    register char *s;
  2463. X{
  2464. X    if (!letter(*s))
  2465. X        return (0);
  2466. X    for (s++; *s != '='; s++)
  2467. X        if (*s == 0 || !letnum(*s))
  2468. X            return (0);
  2469. X    return (1);
  2470. X}
  2471. X
  2472. X/*
  2473. X * Make the exported environment from the exported names in the dictionary.
  2474. X */
  2475. Xchar **
  2476. Xmakenv()
  2477. X{
  2478. X    struct block *l = e.loc;
  2479. X    XPtrV env;
  2480. X    register struct tbl *vp, **vpp;
  2481. X    register int i;
  2482. X
  2483. X    XPinit(env, 64);
  2484. X    for (l = e.loc; l != NULL; l = l->next)
  2485. X        for (vpp = l->vars.tbls, i = l->vars.size; --i >= 0; )
  2486. X            if ((vp = *vpp++) != NULL
  2487. X                && (vp->flag&(ISSET|EXPORT)) == (ISSET|EXPORT)) {
  2488. X                register struct block *l2;
  2489. X                register struct tbl *vp2;
  2490. X                unsigned h = hash(vp->name);
  2491. X
  2492. X                lastarea = &l->area;
  2493. X
  2494. X                /* unexport any redefined instances */
  2495. X                for (l2 = l->next; l2 != NULL; l2 = l2->next) {
  2496. X                    vp2 = tsearch(&l2->vars, vp->name, h);
  2497. X                    if (vp2 != NULL)
  2498. X                        vp2->flag &= ~ EXPORT;
  2499. X                }
  2500. X                if ((vp->flag&INTEGER)) {
  2501. X                    /* integer to string */
  2502. X                    char *val;
  2503. X                    val = strval(vp);
  2504. X                    vp->flag &= ~ INTEGER;
  2505. X                    setstr(vp, val);
  2506. X                }
  2507. X                XPput(env, vp->val.s);
  2508. X            }
  2509. X    XPput(env, NULL);
  2510. X    return (char **) XPclose(env);
  2511. X}
  2512. X
  2513. X/*
  2514. X * handle special variables with side effects - PATH, SECONDS.
  2515. X */
  2516. X
  2517. Xstatic int
  2518. Xspecial(name)
  2519. X    register char * name;
  2520. X{
  2521. X    if (strcmp("PATH", name) == 0)
  2522. X        return V_PATH;
  2523. X    if (strcmp("IFS", name) == 0)
  2524. X        return V_IFS;
  2525. X    if (strcmp("SECONDS", name) == 0)
  2526. X        return V_SECONDS;
  2527. X    if (strcmp("OPTIND", name) == 0)
  2528. X        return V_OPTIND;
  2529. X    if (strcmp("MAIL", name) == 0)
  2530. X        return V_MAIL;
  2531. X    if (strcmp("MAILPATH", name) == 0)
  2532. X        return V_MAILPATH;
  2533. X    if (strcmp("RANDOM", name) == 0)
  2534. X        return V_RANDOM;
  2535. X    return V_NONE;
  2536. X}
  2537. X
  2538. Xextern    time_t time();
  2539. Xstatic    time_t    seconds;        /* time SECONDS last set */
  2540. Xextern    int    rand();
  2541. Xextern    void    srand();
  2542. X
  2543. Xstatic void
  2544. Xgetspec(vp)
  2545. X    register struct tbl *vp;
  2546. X{
  2547. X    switch (special(vp->name)) {
  2548. X    case V_SECONDS:
  2549. X        vp->flag &= ~ SPECIAL;
  2550. X        setint(vp, time((time_t *)0) - seconds);
  2551. X        vp->flag |= SPECIAL;
  2552. X        break;
  2553. X    case V_RANDOM:
  2554. X        vp->flag &= ~ SPECIAL;
  2555. X        setint(vp, (rand() & 0x7fff));
  2556. X        vp->flag |= SPECIAL;
  2557. X        break;
  2558. X    }
  2559. X}
  2560. X
  2561. Xstatic void
  2562. Xsetspec(vp)
  2563. X    register struct tbl *vp;
  2564. X{
  2565. X    extern void    mbset(), mpset();
  2566. X
  2567. X    switch (special(vp->name)) {
  2568. X      case V_PATH:
  2569. X        path = strval(vp);
  2570. X        flushcom(1);    /* clear tracked aliases */
  2571. X        break;
  2572. X      case V_IFS:
  2573. X        setctypes(strval(vp), C_IFS);
  2574. X        break;
  2575. X      case V_SECONDS:
  2576. X        seconds = time((time_t *)0);
  2577. X        break;
  2578. X      case V_OPTIND:
  2579. X        if (intval(vp) == 1)
  2580. X            resetopts();
  2581. X        break;
  2582. X      case V_MAIL:
  2583. X        mbset(strval(vp));
  2584. X        break;
  2585. X      case V_MAILPATH:
  2586. X        mpset(strval(vp));
  2587. X        break;
  2588. X      case V_RANDOM:
  2589. X        vp->flag &= ~ SPECIAL;
  2590. X        srand((unsigned int)intval(vp));
  2591. X        vp->flag |= SPECIAL;
  2592. X        break;
  2593. X    }
  2594. X}
  2595. X
  2596. END_OF_FILE
  2597.   if test 11520 -ne `wc -c <'sh/var.c'`; then
  2598.     echo shar: \"'sh/var.c'\" unpacked with wrong size!
  2599.   fi
  2600.   # end of 'sh/var.c'
  2601. fi
  2602. if test ! -d 'std' ; then
  2603.     echo shar: Creating directory \"'std'\"
  2604.     mkdir 'std'
  2605. fi
  2606. if test ! -d 'std/posix' ; then
  2607.     echo shar: Creating directory \"'std/posix'\"
  2608.     mkdir 'std/posix'
  2609. fi
  2610. if test ! -d 'std/stdc' ; then
  2611.     echo shar: Creating directory \"'std/stdc'\"
  2612.     mkdir 'std/stdc'
  2613. fi
  2614. echo shar: End of archive 1 \(of 9\).
  2615. cp /dev/null ark1isdone
  2616. MISSING=""
  2617. for I in 1 2 3 4 5 6 7 8 9 ; do
  2618.     if test ! -f ark${I}isdone ; then
  2619.     MISSING="${MISSING} ${I}"
  2620.     fi
  2621. done
  2622. if test "${MISSING}" = "" ; then
  2623.     echo You have unpacked all 9 archives.
  2624.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2625. else
  2626.     echo You still must unpack the following archives:
  2627.     echo "        " ${MISSING}
  2628. fi
  2629. exit 0
  2630. exit 0 # Just in case...
  2631. -- 
  2632. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  2633. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  2634. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  2635. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  2636.