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

  1. From: kirkenda@eecs.cs.pdx.edu (Steve Kirkendall)
  2. Newsgroups: alt.sources
  3. Subject: Elvis 1.4, part 5 of 8
  4. Message-ID: <829@pdxgate.UUCP>
  5. Date: 3 Dec 90 21:32:42 GMT
  6.  
  7. # --------------------------- cut here ----------------------------
  8. # This is a shar archive.  To unpack it, save it to a file, and delete
  9. # anything above the "cut here" line.  Then run sh on the file.
  10. #
  11. # -rw-r--r--  1 kirkenda     8819 Dec  2 17:57 curses.h
  12. # -rw-r--r--  1 kirkenda    13222 Dec  2 17:57 cut.c
  13. # -rw-r--r--  1 kirkenda    15130 Dec  2 17:57 ex.c
  14. # -rw-r--r--  1 kirkenda    16368 Dec  2 17:57 input.c
  15. # -rw-r--r--  1 kirkenda     7778 Dec  2 17:57 main.c
  16. # -rw-r--r--  1 kirkenda     2166 Dec  2 17:57 misc.c
  17. #
  18.  
  19. if test -f curses.h -a "$1" != -f
  20. then
  21. echo Will not overwrite curses.h
  22. else
  23. echo Extracting curses.h
  24. sed 's/^X//' >curses.h <<\eof
  25. X/* curses.h */
  26. X
  27. X/* Author:
  28. X *    Steve Kirkendall
  29. X *    14407 SW Teal Blvd. #C
  30. X *    Beaverton, OR 97005
  31. X *    kirkenda@cs.pdx.edu
  32. X */
  33. X
  34. X
  35. X/* This is the header file for a small, fast, fake curses package */
  36. X
  37. X/* termcap stuff */
  38. Xextern char    *tgoto();
  39. Xextern char    *tgetstr();
  40. Xextern void    tputs();
  41. X
  42. X#if MSDOS
  43. X/* BIOS interface used instead of termcap for MS-DOS */
  44. Xextern int    vmode;
  45. Xextern void    v_up();
  46. Xextern void    v_cb();
  47. Xextern void    v_cs();
  48. Xextern void    v_ce();
  49. Xextern void    v_cl();
  50. Xextern void    v_cd();
  51. Xextern void    v_al();
  52. Xextern void    v_dl();
  53. Xextern void    v_sr();
  54. Xextern void    v_move();
  55. X#endif
  56. X
  57. X/* faddch() is a function.  a pointer to it is passed to tputs() */
  58. Xextern int    faddch();
  59. X
  60. X/* data types */
  61. X#define WINDOW    char
  62. X
  63. X/* CONSTANTS & SYMBOLS */
  64. X#define TRUE        1
  65. X#define FALSE        0
  66. X#define A_NORMAL    0
  67. X#define A_STANDOUT    1
  68. X#define A_BOLD        2
  69. X#define A_UNDERLINE    3
  70. X#define A_ALTCHARSET    4
  71. X#if MSDOS
  72. X#define KBSIZ        (10*1024)
  73. X#else
  74. X#define KBSIZ        (6*1024)
  75. X#endif
  76. X
  77. X/* extern variables, defined in curses.c */
  78. Xextern short    ospeed;        /* tty speed, eg B2400 */
  79. X#if OSK
  80. Xextern char PC_;    /* Pad char */
  81. Xextern char    *BC;    /* Backspace char string */
  82. X#else
  83. Xextern char    PC;        /* Pad char */
  84. X#endif
  85. Xextern WINDOW    *stdscr;    /* pointer into kbuf[] */
  86. Xextern WINDOW    kbuf[KBSIZ];    /* a very large output buffer */
  87. Xextern int    LINES;        /* :li#: number of rows */
  88. Xextern int    COLS;        /* :co#: number of columns */
  89. Xextern int    AM;        /* :am:  boolean: auto margins? */
  90. Xextern int    PT;        /* :pt:  boolean: physical tabs? */
  91. Xextern char    *VB;        /* :vb=: visible bell */
  92. Xextern char    *UP;        /* :up=: move cursor up */
  93. Xextern char    *SO;        /* :so=: standout start */
  94. Xextern char    *SE;        /* :se=: standout end */
  95. Xextern char    *US;        /* :us=: underline start */
  96. Xextern char    *UE;        /* :ue=: underline end */
  97. Xextern char    *MD;        /* :md=: bold start */
  98. Xextern char    *ME;        /* :me=: bold end */
  99. Xextern char    *AS;        /* :as=: alternate (italic) start */
  100. Xextern char    *AE;        /* :ae=: alternate (italic) end */
  101. Xextern char    *CM;        /* :cm=: cursor movement */
  102. Xextern char    *CE;        /* :ce=: clear to end of line */
  103. Xextern char    *CD;        /* :cd=: clear to end of screen */
  104. Xextern char    *AL;        /* :al=: add a line */
  105. Xextern char    *DL;        /* :dl=: delete a line */
  106. X#if OSK
  107. Xextern char    *SR_;        /* :sr=: scroll reverse */
  108. X#else
  109. Xextern char    *SR;        /* :sr=: scroll reverse */
  110. X#endif
  111. Xextern char    *KS;        /* :ks=: init string for cursor */
  112. Xextern char    *KE;        /* :ke=: restore string for cursor */
  113. Xextern char    *KU;        /* :ku=: sequence sent by up key */
  114. Xextern char    *KD;        /* :kd=: sequence sent by down key */
  115. Xextern char    *KL;        /* :kl=: sequence sent by left key */
  116. Xextern char    *KR;        /* :kr=: sequence sent by right key */
  117. Xextern char    *PU;        /* :PU=: key sequence sent by PgUp key */
  118. Xextern char    *PD;        /* :PD=: key sequence sent by PgDn key */
  119. Xextern char    *HM;        /* :HM=: key sequence sent by Home key */
  120. Xextern char    *EN;        /* :EN=: key sequence sent by End key */
  121. Xextern char    *IM;        /* :im=: insert mode start */
  122. Xextern char    *IC;        /* :ic=: insert following char */
  123. Xextern char    *EI;        /* :ei=: insert mode end */
  124. Xextern char    *DC;        /* :dc=: delete a character */
  125. Xextern char    *TI;        /* :ti=: terminal init */    /* GB */
  126. Xextern char    *TE;        /* :te=: terminal exit */    /* GB */
  127. X#ifndef NO_CURSORSHAPE
  128. Xextern char    *CQ;        /* :cQ=: normal cursor */
  129. Xextern char    *CX;        /* :cX=: cursor used for EX command/entry */
  130. Xextern char    *CV;        /* :cV=: cursor used for VI command mode */
  131. Xextern char    *CI;        /* :cI=: cursor used for VI input mode */
  132. Xextern char    *CR;        /* :cR=: cursor used for VI replace mode */
  133. X#endif
  134. Xextern char    *aend;        /* end an attribute -- either UE or ME */
  135. Xextern char    ERASEKEY;    /* taken from the ioctl structure */
  136. X
  137. X/* Msdos-versions may use bios; others always termcap.
  138. X * Will emit some 'code has no effect' warnings in unix.
  139. X */
  140. X#if MSDOS
  141. Xextern char o_pcbios[1];        /* BAH! */
  142. X#define    CHECKBIOS(x,y)    (*o_pcbios ? (x) : (y))
  143. X#define VOIDBIOS(x,y)    {if (*o_pcbios) {x;} else {y;}}
  144. X#else
  145. X#define    CHECKBIOS(x,y)    (y)
  146. X#define VOIDBIOS(x,y)    {y;}
  147. X#endif
  148. X
  149. X#define    do_VB()        VOIDBIOS(;, tputs(VB, 1, faddch))
  150. X#define    do_UP()        VOIDBIOS(v_up(), tputs(UP, 1, faddch))
  151. X#define    do_SO()        VOIDBIOS((vmode=A_STANDOUT), tputs(SO, 1, faddch))
  152. X#define    do_SE()        VOIDBIOS((vmode=A_NORMAL), tputs(SE, 1, faddch))
  153. X#define    do_US()        VOIDBIOS((vmode=A_UNDERLINE), tputs(US, 1, faddch))
  154. X#define    do_UE()        VOIDBIOS((vmode=A_NORMAL), tputs(UE, 1, faddch))
  155. X#define    do_MD()        VOIDBIOS((vmode=A_BOLD), tputs(MD, 1, faddch))
  156. X#define    do_ME()        VOIDBIOS((vmode=A_NORMAL), tputs(ME, 1, faddch))
  157. X#define    do_AS()        VOIDBIOS((vmode=A_ALTCHARSET), tputs(AS, 1, faddch))
  158. X#define    do_AE()        VOIDBIOS((vmode=A_NORMAL), tputs(AE, 1, faddch))
  159. X#undef    do_CM        /* move */
  160. X#define    do_CE()        VOIDBIOS(v_ce(), tputs(CE, 1, faddch))
  161. X#define    do_CD()        VOIDBIOS(v_cd(), tputs(CD, 1, faddch))
  162. X#define    do_AL()        VOIDBIOS(v_al(), tputs(AL, LINES, faddch))
  163. X#define    do_DL()        VOIDBIOS(v_dl(), tputs(DL, LINES, faddch))
  164. X#if OSK
  165. X#define    do_SR()        VOIDBIOS(v_sr(), tputs(SR_, 1, faddch))
  166. X#else
  167. X#define    do_SR()        VOIDBIOS(v_sr(), tputs(SR, 1, faddch))
  168. X#endif
  169. X#define do_KS()        VOIDBIOS(1, tputs(KS, 1, faddch))
  170. X#define do_KE()        VOIDBIOS(1, tputs(KE, 1, faddch))
  171. X#define    do_IM()        VOIDBIOS(;, tputs(IM, 1, faddch))
  172. X#define    do_IC()        VOIDBIOS(;, tputs(IC, 1, faddch))
  173. X#define    do_EI()        VOIDBIOS(;, tputs(EI, 1, faddch))
  174. X#define    do_DC()        VOIDBIOS(;, tputs(DC, COLS, faddch))
  175. X#define    do_TI()        VOIDBIOS(;, (void)ttywrite(TI, (unsigned)strlen(TI)))
  176. X#define    do_TE()        VOIDBIOS(;, (void)ttywrite(TE, (unsigned)strlen(TE)))
  177. X#ifndef NO_CURSORSHAPE
  178. X# define do_CQ()    VOIDBIOS(v_cs(), tputs(CQ, 1, faddch))
  179. X# define do_CX()    VOIDBIOS(v_cs(), tputs(CX, 1, faddch))
  180. X# define do_CV()    VOIDBIOS(v_cs(), tputs(CV, 1, faddch))
  181. X# define do_CI()    VOIDBIOS(v_cb(), tputs(CI, 1, faddch))
  182. X# define do_CR()    VOIDBIOS(v_cb(), tputs(CR, 1, faddch))
  183. X#endif
  184. X#define    do_aend()    VOIDBIOS((vmode=A_NORMAL), tputs(aend, 1, faddch))
  185. X
  186. X#define    has_AM        CHECKBIOS(1, AM)
  187. X#define    has_PT        CHECKBIOS(0, PT)
  188. X#define    has_VB        CHECKBIOS((char *)0, VB)
  189. X#define    has_UP        CHECKBIOS((char *)1, UP)
  190. X#define    has_SO        CHECKBIOS((char)1, (*SO))
  191. X#define    has_SE        CHECKBIOS((char)1, (*SE))
  192. X#define    has_US        CHECKBIOS((char)1, (*US))
  193. X#define    has_UE        CHECKBIOS((char)1, (*UE))
  194. X#define    has_MD        CHECKBIOS((char)1, (*MD))
  195. X#define    has_ME        CHECKBIOS((char)1, (*ME))
  196. X#define    has_AS        CHECKBIOS((char)1, (*AS))
  197. X#define    has_AE        CHECKBIOS((char)1, (*AE))
  198. X#undef    has_CM        /* cursor move: don't need */
  199. X#define    has_CB        CHECKBIOS(1, 0)
  200. X#define    has_CS        CHECKBIOS(1, 0)
  201. X#define    has_CE        CHECKBIOS((char *)1, CE)
  202. X#define    has_CD        CHECKBIOS((char *)1, CD)
  203. X#define    has_AL        CHECKBIOS((char *)1, AL)
  204. X#define    has_DL        CHECKBIOS((char *)1, DL)
  205. X#if OSK
  206. X#define    has_SR        CHECKBIOS((char *)1, SR_)
  207. X#else
  208. X#define    has_SR        CHECKBIOS((char *)1, SR)
  209. X#endif
  210. X#define has_KS        CHECKBIOS((char)1, (*KS))
  211. X#define has_KE        CHECKBIOS((char)1, (*KE))
  212. X#define    has_KU        CHECKBIOS("#H", KU)
  213. X#define    has_KD        CHECKBIOS("#P", KD)
  214. X#define    has_KL        CHECKBIOS("#K", KL)
  215. X#define    has_KR        CHECKBIOS("#M", KR)
  216. X#define has_HM        CHECKBIOS("#G", HM)
  217. X#define has_EN        CHECKBIOS("#O", EN)
  218. X#define has_PU        CHECKBIOS("#I", PU)
  219. X#define has_PD        CHECKBIOS("#Q", PD)
  220. X#define    has_IM        CHECKBIOS((char)0, (*IM))
  221. X#define    has_IC        CHECKBIOS((char)0, (*IC))
  222. X#define    has_EI        CHECKBIOS((char)0, (*EI))
  223. X#define    has_DC        CHECKBIOS((char *)0, DC)
  224. X#define    has_TI        CHECKBIOS((char)0, (*TI))
  225. X#define    has_TE        CHECKBIOS((char)0, (*TE))
  226. X#ifndef NO_CURSORSHAPE
  227. X#define has_CQ        CHECKBIOS((char *)1, CQ)
  228. X#endif
  229. X
  230. X/* (pseudo)-Curses-functions */
  231. X
  232. X#ifdef lint
  233. X# define _addCR        VOIDBIOS(;, (stdscr[-1] == '\n' ? qaddch('\r') : (stdscr[-1] = '\n')))
  234. X#else
  235. X# if OSK
  236. X#  define _addCR        VOIDBIOS(;, (stdscr[-1] == '\n' ? qaddch('\l') : (stdscr[-1] = stdscr[-1])))
  237. X# else
  238. X# define _addCR        VOIDBIOS(;, (stdscr[-1] == '\n' ? qaddch('\r') : 0))
  239. X#endif
  240. X#endif
  241. X#define qaddch(ch)    CHECKBIOS(v_put(ch), (*stdscr++ = (ch)))
  242. X#if OSK
  243. X#define addch(ch)    if (qaddch(ch) == '\n') qaddch('\l'); else
  244. X#else
  245. X#define addch(ch)    if (qaddch(ch) == '\n') qaddch('\r'); else
  246. X#endif
  247. X
  248. Xextern void initscr();
  249. Xextern void endwin();
  250. Xextern void suspend_curses();
  251. Xextern void resume_curses();
  252. Xextern void attrset();
  253. Xextern void insch();
  254. Xextern void qaddstr();
  255. X#define addstr(str)    {qaddstr(str); _addCR;}
  256. X#define move(y,x)    VOIDBIOS(v_move(x,y), \
  257. X                    tputs(tgoto(CM, x, y), 1, faddch))
  258. X#define mvaddch(y,x,ch)    {move(y,x); addch(ch);}
  259. X#define refresh()    VOIDBIOS(;, wrefresh(stdscr))
  260. X#define wrefresh(w)    if ((w) != kbuf) VOIDBIOS((w) = kbuf, {ttywrite(kbuf, (unsigned)((w) - kbuf)); (w) = kbuf;}) else
  261. X#define wqrefresh(w)    if ((w) - kbuf > 2000) VOIDBIOS((w) = kbuf, {ttywrite(kbuf, (unsigned)((w) - kbuf)); (w) = kbuf;}) else
  262. X#define standout()    do_SO()
  263. X#define standend()    do_SE()
  264. X#define clrtoeol()    do_CE()
  265. X#define clrtobot()    do_CD()
  266. X#define insertln()    do_AL()
  267. X#define deleteln()    do_DL()
  268. X#define delch()        do_DC()
  269. X#define scrollok(w,b)
  270. X#define raw()
  271. X#define echo()
  272. X#define cbreak()
  273. X#define noraw()
  274. X#define noecho()
  275. X#define nocbreak()
  276. eof
  277. if test `wc -c <curses.h` -ne 8819
  278. then
  279. echo curses.h damaged!
  280. fi
  281. fi
  282.  
  283. if test -f cut.c -a "$1" != -f
  284. then
  285. echo Will not overwrite cut.c
  286. else
  287. echo Extracting cut.c
  288. sed 's/^X//' >cut.c <<\eof
  289. X/* cut.c */
  290. X
  291. X/* Author:
  292. X *    Steve Kirkendall
  293. X *    14407 SW Teal Blvd. #C
  294. X *    Beaverton, OR 97005
  295. X *    kirkenda@cs.pdx.edu
  296. X */
  297. X
  298. X
  299. X/* This file contains function which manipulate the cut buffers. */
  300. X
  301. X#include "config.h"
  302. X#include "vi.h"
  303. X#if TURBOC
  304. X#include <process.h>        /* needed for getpid */
  305. X#endif
  306. X#if TOS
  307. X#include <osbind.h>
  308. X#define    rename(a,b)    Frename(0,a,b)
  309. X#endif
  310. X
  311. X# define NANNONS    9    /* number of annonymous buffers */
  312. X
  313. Xstatic struct cutbuf
  314. X{
  315. X    short    *phys;    /* pointer to an array of #s of BLKs containing text */
  316. X    int    nblks;    /* number of blocks in phys[] array */
  317. X    int    start;    /* offset into first block of start of cut */
  318. X    int    end;    /* offset into last block of end of cut */
  319. X    int    fd;    /* fd of tmp file, or -1 to use tmpfd */
  320. X    char    lnmode;    /* boolean: line-mode cut? (as opposed to char-mode) */
  321. X}
  322. X    named[27],    /* cut buffers "a through "z and ". */
  323. X    annon[NANNONS];    /* annonymous cut buffers */
  324. X
  325. Xstatic char    cbname;    /* name chosen for next cut/paste operation */
  326. X
  327. X
  328. X#ifndef NO_RECYCLE
  329. X/* This function builds a list of all blocks needed in the current tmp file
  330. X * for the contents of cut buffers.
  331. X * !!! WARNING: if you have more than ~450000 bytes of text in all of the
  332. X * cut buffers, then this will fail disastrously, because buffer overflow
  333. X * is *not* allowed for.
  334. X */
  335. Xint cutneeds(need)
  336. X    BLK        *need;    /* this is where we deposit the list */
  337. X{
  338. X    struct cutbuf    *cb;    /* used to count through cut buffers */
  339. X    int        i;    /* used to count through blocks of a cut buffer */
  340. X    int        n;    /* total number of blocks in list */
  341. X
  342. X    n = 0;
  343. X
  344. X    /* first the named buffers... */
  345. X    for (cb = named; cb < &named[27]; cb++)
  346. X    {
  347. X        if (cb->fd > 0)
  348. X            continue;
  349. X
  350. X        for (i = cb->nblks; i-- > 0; )
  351. X        {
  352. X            need->n[n++] = cb->phys[i];
  353. X        }
  354. X    }
  355. X
  356. X    /* then the anonymous buffers */
  357. X    for (cb = annon; cb < &annon[NANNONS]; cb++)
  358. X    {
  359. X        if (cb->fd > 0)
  360. X            continue;
  361. X
  362. X        for (i = cb->nblks; i-- > 0; )
  363. X        {
  364. X            need->n[n++] = cb->phys[i];
  365. X        }
  366. X    }
  367. X
  368. X    return n;
  369. X}
  370. X#endif
  371. X
  372. X/* This function frees a cut buffer */
  373. Xstatic void cutfree(buf)
  374. X    struct cutbuf    *buf;
  375. X{
  376. X    char    cutfname[50];
  377. X    int    i;
  378. X
  379. X    /* return immediately if the buffer is already empty */
  380. X    if (buf->nblks <= 0)
  381. X    {
  382. X        return;
  383. X    }
  384. X
  385. X    /* else free up stuff */
  386. X    buf->nblks = 0;
  387. X#ifdef DEBUG
  388. X    if (!buf->phys)
  389. X        msg("cutfree() tried to free an NULL buf->phys pointer.");
  390. X#endif
  391. X    free((char *)buf->phys);
  392. X
  393. X    /* see if anybody else needs this tmp file */
  394. X    if (buf->fd >= 0)
  395. X    {
  396. X        for (i = 0; i < 27; i++)
  397. X        {
  398. X            if (named[i].nblks > 0 && named[i].fd == buf->fd)
  399. X            {
  400. X                break;
  401. X            }
  402. X        }
  403. X    }
  404. X
  405. X    /* if nobody else needs it, then discard the tmp file */
  406. X    if (buf->fd >= 0 && i == 27)
  407. X    {
  408. X        close(buf->fd);
  409. X#if MSDOS || TOS
  410. X        strcpy(cutfname, o_directory);
  411. X        if ((i = strlen(cutfname)) && !strchr(":/\\", cutfname[i-1]))
  412. X            cutfname[i++]=SLASH;
  413. X        sprintf(cutfname+i, CUTNAME+3, getpid(), buf->fd);
  414. X#else
  415. X        sprintf(cutfname, CUTNAME, o_directory, getpid(), buf->fd);
  416. X#endif
  417. X        unlink(cutfname);
  418. X    }
  419. X}
  420. X
  421. X/* This function is called when we are about to abort a tmp file.  If any
  422. X * cut buffers still need the file, then a copy of the file should be
  423. X * created for use by the cut buffers.
  424. X *
  425. X * To minimize the number of extra files lying around, only named cut buffers
  426. X * are preserved in a file switch; the annonymous buffers just go away.
  427. X */
  428. Xvoid cutswitch(tmpname)
  429. X    char    *tmpname; /* name of the tmp file */
  430. X{
  431. X    char    cutfname[50];    /* used to build a new name for the tmp file */
  432. X    int    fd;        /* a new fd for the current tmp file */
  433. X    int    i;
  434. X#if MSDOS || TOS
  435. X    int    j;
  436. X#endif
  437. X
  438. X    /* discard all annonymous cut buffers */
  439. X    for (i = 0; i < NANNONS; i++)
  440. X    {
  441. X        cutfree(&annon[i]);
  442. X    }
  443. X
  444. X    /* find the first named buffer that uses this tmp file */
  445. X    for (i = 0; i < 27; i++)
  446. X    {
  447. X        if (named[i].nblks > 0 && named[i].fd < 0)
  448. X        {
  449. X            break;
  450. X        }
  451. X    }
  452. X
  453. X    /* if none of them use this tmp file, then we're done */
  454. X    if (i == 27)
  455. X    {
  456. X        return;
  457. X    }
  458. X
  459. X    /* else we'll need this file and an fd a little longer */
  460. X#if MSDOS || TOS
  461. X    strcpy(cutfname, o_directory);
  462. X    if ((j = strlen(cutfname)) && !strchr(":/\\", cutfname[j-1]))
  463. X        cutfname[j++]=SLASH;
  464. X    close(tmpfd);
  465. X    fd = open(tmpname, O_RDONLY|O_BINARY);
  466. X    close(fd);
  467. X    sprintf(cutfname+j, CUTNAME+3, getpid(), fd);
  468. X    rename(tmpname, cutfname);
  469. X    fd = open(cutfname, O_RDONLY|O_BINARY);
  470. X    tmpfd = -1; /* we'll try to close this in tmp.c, but who cares? */
  471. X#else
  472. X    fd = dup(tmpfd);
  473. X# if OSK
  474. X    sprintf(cutfname, CUTNAME, "", getpid(), fd);
  475. X    if (!link(tmpname, &cutfname[1])) /* skip slash */
  476. X        unlink(tmpname);
  477. X# else    
  478. X    sprintf(cutfname, CUTNAME, o_directory, getpid(), fd);
  479. X    link(tmpname, cutfname) || unlink(tmpname);
  480. X# endif
  481. X#endif
  482. X
  483. X    /* have all cut buffers use the new fd instead */
  484. X    for (; i < 27; i++)
  485. X    {
  486. X        if (named[i].nblks > 0 && named[i].fd < 0)
  487. X        {
  488. X            named[i].fd = fd;
  489. X        }
  490. X    }
  491. X}
  492. X
  493. X/* This function should be called just before termination of vi */
  494. Xvoid cutend()
  495. X{
  496. X    int    i;
  497. X
  498. X    /* free all named cut buffers, since they might be forcing an older
  499. X     * tmp file to be retained.
  500. X     */
  501. X    for (i = 0; i < 27; i++)
  502. X    {
  503. X        cutfree(&named[i]);
  504. X    }
  505. X}
  506. X
  507. X
  508. X/* This function is used to select the cut buffer to be used next */
  509. Xvoid cutname(name)
  510. X    int    name;    /* a single character */
  511. X{
  512. X    cbname = name;
  513. X}
  514. X
  515. X
  516. X
  517. X
  518. X/* This function copies a selected segment of text to a cut buffer */
  519. Xvoid cut(from, to)
  520. X    MARK    from;        /* start of text to cut */
  521. X    MARK    to;        /* end of text to cut */
  522. X{
  523. X    int        first;    /* logical number of first block in cut */
  524. X    int        last;    /* logical number of last block used in cut */
  525. X    long        line;    /* a line number */
  526. X    int        lnmode;    /* boolean: will this be a line-mode cut? */
  527. X    MARK        delthru;/* end of text temporarily inserted for apnd */
  528. X    REG struct cutbuf *cb;
  529. X    REG long    l;
  530. X    REG int        i;
  531. X    REG char    *scan;
  532. X    char        *blkc;
  533. X
  534. X    /* detect whether this must be a line-mode cut or char-mode cut */
  535. X    if (markidx(from) == 0 && markidx(to) == 0)
  536. X        lnmode = TRUE;
  537. X    else
  538. X        lnmode = FALSE;
  539. X
  540. X    /* by default, we don't "delthru" anything */
  541. X    delthru = MARK_UNSET;
  542. X
  543. X    /* decide which cut buffer to use */
  544. X    if (!cbname)
  545. X    {
  546. X        /* free up the last annonymous cut buffer */
  547. X        cutfree(&annon[NANNONS - 1]);
  548. X
  549. X        /* shift the annonymous cut buffers */
  550. X        for (i = NANNONS - 1; i > 0; i--)
  551. X        {
  552. X            annon[i] = annon[i - 1];
  553. X        }
  554. X
  555. X        /* use the first annonymous cut buffer */
  556. X        cb = annon;
  557. X        cb->nblks = 0;
  558. X    }
  559. X    else if (cbname >= 'a' && cbname <= 'z')
  560. X    {
  561. X        cb = &named[cbname - 'a'];
  562. X        cutfree(cb);
  563. X    }
  564. X#ifndef CRUNCH
  565. X    else if (cbname >= 'A' && cbname <= 'Z')
  566. X    {
  567. X        cb = &named[cbname - 'A'];
  568. X        if (cb->nblks > 0)
  569. X        {
  570. X            /* resolve linemode/charmode differences */
  571. X            if (!lnmode && cb->lnmode)
  572. X            {
  573. X                from &= ~(BLKSIZE - 1);
  574. X                if (markidx(to) != 0 || to == from)
  575. X                {
  576. X                    to = to + BLKSIZE - markidx(to);
  577. X                }
  578. X                lnmode = TRUE;
  579. X            }
  580. X
  581. X            /* insert the old cut-buffer before the new text */
  582. X            mark[28] = to;
  583. X            delthru = paste(from, FALSE, TRUE);
  584. X            if (delthru == MARK_UNSET)
  585. X            {
  586. X                return;
  587. X            }
  588. X            delthru++;
  589. X            to = mark[28];
  590. X        }
  591. X        cutfree(cb);
  592. X    }
  593. X#endif /* not CRUNCH */
  594. X    else if (cbname == '.')
  595. X    {
  596. X        cb = &named[26];
  597. X        cutfree(cb);
  598. X    }
  599. X    else
  600. X    {
  601. X        msg("Invalid cut buffer name: \"%c", cbname);
  602. X        cbname = '\0';
  603. X        return;
  604. X    }
  605. X    cbname = '\0';
  606. X    cb->fd = -1;
  607. X
  608. X    /* detect whether we're doing a line mode cut */
  609. X    cb->lnmode = lnmode;
  610. X
  611. X    /* ---------- */
  612. X
  613. X    /* Reporting... */    
  614. X    if (markidx(from) == 0 && markidx(to) == 0)
  615. X    {
  616. X        rptlines = markline(to) - markline(from);
  617. X        rptlabel = "yanked";
  618. X    }
  619. X
  620. X    /* ---------- */
  621. X
  622. X    /* make sure each block has a physical disk address */
  623. X    blksync();
  624. X
  625. X    /* find the first block in the cut */
  626. X    line = markline(from);
  627. X    for (first = 1; line > lnum[first]; first++)
  628. X    {
  629. X    }
  630. X
  631. X    /* fetch text of the block containing that line */
  632. X    blkc = scan = blkget(first)->c;
  633. X
  634. X    /* find the mark in the block */
  635. X    for (l = lnum[first - 1]; ++l < line; )
  636. X    {
  637. X        while (*scan++ != '\n')
  638. X        {
  639. X        }
  640. X    }
  641. X    scan += markidx(from);
  642. X
  643. X    /* remember the offset of the start */
  644. X    cb->start = scan - blkc;
  645. X
  646. X    /* ---------- */
  647. X
  648. X    /* find the last block in the cut */
  649. X    line = markline(to);
  650. X    for (last = first; line > lnum[last]; last++)
  651. X    {
  652. X    }
  653. X
  654. X    /* fetch text of the block containing that line */
  655. X    if (last != first)
  656. X    {
  657. X        blkc = scan = blkget(last)->c;
  658. X    }
  659. X    else
  660. X    {
  661. X        scan = blkc;
  662. X    }
  663. X
  664. X    /* find the mark in the block */
  665. X    for (l = lnum[last - 1]; ++l < line; )
  666. X    {
  667. X        while (*scan++ != '\n')
  668. X        {
  669. X        }
  670. X    }
  671. X    if (markline(to) <= nlines)
  672. X    {
  673. X        scan += markidx(to);
  674. X    }
  675. X
  676. X    /* remember the offset of the end */
  677. X    cb->end = scan - blkc;
  678. X
  679. X    /* ------- */
  680. X
  681. X    /* remember the physical block numbers of all included blocks */
  682. X    cb->nblks = last - first;
  683. X    if (cb->end > 0)
  684. X    {
  685. X        cb->nblks++;
  686. X    }
  687. X#ifdef lint
  688. X    cb->phys = (short *)0;
  689. X#else
  690. X    cb->phys = (short *)malloc((unsigned)(cb->nblks * sizeof(short)));
  691. X#endif
  692. X    for (i = 0; i < cb->nblks; i++)
  693. X    {
  694. X        cb->phys[i] = hdr.n[first++];
  695. X    }
  696. X
  697. X#ifndef CRUNCH
  698. X    /* if we temporarily inserted text for appending, then delete that
  699. X     * text now -- before the user sees it.
  700. X     */
  701. X    if (delthru)
  702. X    {
  703. X        line = rptlines;
  704. X        delete(from, delthru);
  705. X        rptlines = line;
  706. X        rptlabel = "yanked";
  707. X    }
  708. X#endif /* not CRUNCH */
  709. X}
  710. X
  711. X
  712. Xstatic void readcutblk(cb, blkno)
  713. X    struct cutbuf    *cb;
  714. X    int        blkno;
  715. X{
  716. X    int        fd;    /* either tmpfd or cb->fd */
  717. X
  718. X    /* decide which fd to use */
  719. X    if (cb->fd >= 0)
  720. X    {
  721. X        fd = cb->fd;
  722. X    }
  723. X    else
  724. X    {
  725. X        fd = tmpfd;
  726. X    }
  727. X
  728. X    /* get the block */
  729. X    lseek(fd, (long)cb->phys[blkno] * (long)BLKSIZE, 0);
  730. X    if (read(fd, tmpblk.c, (unsigned)BLKSIZE) != BLKSIZE)
  731. X    {
  732. X        msg("Error reading back from tmp file for pasting!");
  733. X    }
  734. X}
  735. X
  736. X
  737. X/* This function inserts text from a cut buffer, and returns the MARK where
  738. X * insertion ended.  Return MARK_UNSET on errors.
  739. X */
  740. XMARK paste(at, after, retend)
  741. X    MARK    at;    /* where to insert the text */
  742. X    int    after;    /* boolean: insert after mark? (rather than before) */
  743. X    int    retend;    /* boolean: return end of text? (rather than start) */
  744. X{
  745. X    REG struct cutbuf    *cb;
  746. X    REG int            i;
  747. X
  748. X    /* decide which cut buffer to use */
  749. X    if (cbname >= 'A' && cbname <= 'Z')
  750. X    {
  751. X        cb = &named[cbname - 'A'];
  752. X    }
  753. X    else if (cbname >= 'a' && cbname <= 'z')
  754. X    {
  755. X        cb = &named[cbname - 'a'];
  756. X    }
  757. X    else if (cbname >= '1' && cbname <= '9')
  758. X    {
  759. X        cb = &annon[cbname - '1'];
  760. X    }
  761. X    else if (cbname == '.')
  762. X    {
  763. X        cb = &named[26];
  764. X    }
  765. X    else if (!cbname)
  766. X    {
  767. X        cb = annon;
  768. X    }
  769. X    else
  770. X    {
  771. X        msg("Invalid cut buffer name: \"%c", cbname);
  772. X        cbname = '\0';
  773. X        return MARK_UNSET;
  774. X    }
  775. X
  776. X    /* make sure it isn't empty */
  777. X    if (cb->nblks == 0)
  778. X    {
  779. X        if (cbname)
  780. X            msg("Cut buffer \"%c is empty", cbname);
  781. X        else
  782. X            msg("Cut buffer is empty");
  783. X        cbname = '\0';
  784. X        return MARK_UNSET;
  785. X    }
  786. X    cbname = '\0';
  787. X
  788. X    /* adjust the insertion MARK for "after" and line-mode cuts */
  789. X    if (cb->lnmode)
  790. X    {
  791. X        at &= ~(BLKSIZE - 1);
  792. X        if (after)
  793. X        {
  794. X            at += BLKSIZE;
  795. X        }
  796. X    }
  797. X    else if (after)
  798. X    {
  799. X        /* careful! if markidx(at) == 0 we might be pasting into an
  800. X         * empty line -- so we can't blindly increment "at".
  801. X         */
  802. X        if (markidx(at) == 0)
  803. X        {
  804. X            pfetch(markline(at));
  805. X            if (plen != 0)
  806. X            {
  807. X                at++;
  808. X            }
  809. X        }
  810. X        else
  811. X        {
  812. X            at++;
  813. X        }
  814. X    }
  815. X
  816. X    /* put a copy of the "at" mark in the mark[] array, so it stays in
  817. X     * sync with changes made via add().
  818. X     */
  819. X    mark[27] = at;
  820. X
  821. X    /* simple one-block paste? */
  822. X    if (cb->nblks == 1)
  823. X    {
  824. X        /* get the block */
  825. X        readcutblk(cb, 0);
  826. X
  827. X        /* isolate the text we need within it */
  828. X        if (cb->end)
  829. X        {
  830. X            tmpblk.c[cb->end] = '\0';
  831. X        }
  832. X
  833. X        /* insert it */
  834. X        ChangeText
  835. X        {
  836. X            add(at, &tmpblk.c[cb->start]);
  837. X        }
  838. X    }
  839. X    else
  840. X    {
  841. X        /* multi-block paste */
  842. X
  843. X        ChangeText
  844. X        {
  845. X            i = cb->nblks - 1;
  846. X
  847. X            /* add text from the last block first */
  848. X            if (cb->end > 0)
  849. X            {
  850. X                readcutblk(cb, i);
  851. X                tmpblk.c[cb->end] = '\0';
  852. X                add(at, tmpblk.c);
  853. X                i--;
  854. X            }
  855. X
  856. X            /* add intervening blocks */
  857. X            while (i > 0)
  858. X            {
  859. X                readcutblk(cb, i);
  860. X                add(at, tmpblk.c);
  861. X                i--;
  862. X            }
  863. X
  864. X            /* add text from the first cut block */
  865. X            readcutblk(cb, 0);
  866. X            add(at, &tmpblk.c[cb->start]);
  867. X        }
  868. X    }
  869. X
  870. X    /* Reporting... */
  871. X    rptlines = markline(mark[27]) - markline(at);
  872. X    rptlabel = "pasted";
  873. X
  874. X    /* return the mark at the beginning/end of inserted text */
  875. X    if (retend)
  876. X    {
  877. X        return mark[27] - 1L;
  878. X    }
  879. X    return at;
  880. X}
  881. X
  882. X
  883. X
  884. X
  885. X#ifndef NO_AT
  886. X
  887. X/* This function copies characters from a cut buffer into a string.
  888. X * It returns the number of characters in the cut buffer.  If the cut
  889. X * buffer is too large to fit in the string (i.e. if cb2str() returns
  890. X * a number >= size) then the characters will not have been copied.
  891. X * It returns 0 if the cut buffer is empty, and -1 for invalid cut buffers.
  892. X */
  893. Xint cb2str(name, buf, size)
  894. X    int    name;    /* the name of a cut-buffer to get: a-z only! */
  895. X    char    *buf;    /* where to put the string */
  896. X    unsigned size;    /* size of buf */
  897. X{
  898. X    REG struct cutbuf    *cb;
  899. X    REG char        *src;
  900. X    REG char        *dest;
  901. X
  902. X    /* decide which cut buffer to use */
  903. X    if (name >= 'a' && name <= 'z')
  904. X    {
  905. X        cb = &named[name - 'a'];
  906. X    }
  907. X    else
  908. X    {
  909. X        return -1;
  910. X    }
  911. X
  912. X    /* if the buffer is empty, return 0 */
  913. X    if (cb->nblks == 0)
  914. X    {
  915. X        return 0;
  916. X    }
  917. X
  918. X    /* !!! if not a single-block cut, then fail */
  919. X    if (cb->nblks != 1)
  920. X    {
  921. X        return size;
  922. X    }
  923. X
  924. X    /* if too big, return the size now, without doing anything */
  925. X    if (cb->end - cb->start >= size)
  926. X    {
  927. X        return cb->end - cb->start;
  928. X    }
  929. X
  930. X    /* get the block */
  931. X    readcutblk(cb, 0);
  932. X
  933. X    /* isolate the string within that blk */
  934. X    if (cb->start == 0)
  935. X    {
  936. X        tmpblk.c[cb->end] = '\0';
  937. X    }
  938. X    else
  939. X    {
  940. X        for (dest = tmpblk.c, src = dest + cb->start; src < tmpblk.c + cb->end; )
  941. X        {
  942. X            *dest++ = *src++;
  943. X        }
  944. X        *dest = '\0';
  945. X    }
  946. X
  947. X    /* copy the string into the buffer */
  948. X    if (buf != tmpblk.c)
  949. X    {
  950. X        strcpy(buf, tmpblk.c);
  951. X    }
  952. X
  953. X    /* return the length */
  954. X    return cb->end - cb->start;
  955. X}
  956. X#endif
  957. eof
  958. if test `wc -c <cut.c` -ne 13222
  959. then
  960. echo cut.c damaged!
  961. fi
  962. fi
  963.  
  964. if test -f ex.c -a "$1" != -f
  965. then
  966. echo Will not overwrite ex.c
  967. else
  968. echo Extracting ex.c
  969. sed 's/^X//' >ex.c <<\eof
  970. X/* ex.c */
  971. X
  972. X/* Author:
  973. X *    Steve Kirkendall
  974. X *    14407 SW Teal Blvd. #C
  975. X *    Beaverton, OR 97005
  976. X *    kirkenda@cs.pdx.edu
  977. X */
  978. X
  979. X
  980. X/* This file contains the code for reading ex commands. */
  981. X
  982. X#include "config.h"
  983. X#include <ctype.h>
  984. X#include "vi.h"
  985. X
  986. X#ifndef isascii
  987. X# define isascii(c) !((c)&~0x7f)
  988. X#endif
  989. X
  990. X/* This data type is used to describe the possible argument combinations */
  991. Xtypedef short ARGT;
  992. X#define FROM    1        /* allow a linespec */
  993. X#define    TO    2        /* allow a second linespec */
  994. X#define BANG    4        /* allow a ! after the command name */
  995. X#define EXTRA    8        /* allow extra args after command name */
  996. X#define XFILE    16        /* expand wildcards in extra part */
  997. X#define NOSPC    32        /* no spaces allowed in the extra part */
  998. X#define    DFLALL    64        /* default file range is 1,$ */
  999. X#define DFLNONE    128        /* no default file range */
  1000. X#define NODFL    256        /* do not default to the current file name */
  1001. X#define EXRCOK    512        /* can be in a .exrc file */
  1002. X#define NL    1024        /* if mode!=MODE_EX, then write a newline first */
  1003. X#define PLUS    2048        /* allow a line number, as in ":e +32 foo" */
  1004. X#define ZERO    4096        /* allow 0 to be given as a line number */
  1005. X#define FILES    (XFILE + EXTRA)    /* multiple extra files allowed */
  1006. X#define WORD1    (EXTRA + NOSPC)    /* one extra word allowed */
  1007. X#define FILE1    (FILES + NOSPC)    /* 1 file allowed, defaults to current file */
  1008. X#define NAMEDF    (FILE1 + NODFL)    /* 1 file allowed, defaults to "" */
  1009. X#define NAMEDFS    (FILES + NODFL)    /* multiple files allowed, default is "" */
  1010. X#define RANGE    (FROM + TO)    /* range of linespecs allowed */
  1011. X#define NONE    0        /* no args allowed at all */
  1012. X
  1013. X/* This array maps ex command names to command codes. The order in which
  1014. X * command names are listed below is significant -- ambiguous abbreviations
  1015. X * are always resolved to be the first possible match.  (e.g. "r" is taken
  1016. X * to mean "read", not "rewind", because "read" comes before "rewind")
  1017. X */
  1018. Xstatic struct
  1019. X{
  1020. X    char    *name;    /* name of the command */
  1021. X    CMD    code;    /* enum code of the command */
  1022. X    void    (*fn)();/* function which executes the command */
  1023. X    ARGT    argt;    /* command line arguments permitted/needed/used */
  1024. X}
  1025. X    cmdnames[] =
  1026. X{   /*    cmd name    cmd code    function    arguments */
  1027. X    {"append",    CMD_APPEND,    cmd_append,    FROM+ZERO    },
  1028. X#ifdef DEBUG
  1029. X    {"bug",        CMD_DEBUG,    cmd_debug,    RANGE+BANG+EXTRA+NL},
  1030. X#endif
  1031. X    {"change",    CMD_CHANGE,    cmd_append,    RANGE        },
  1032. X    {"delete",    CMD_DELETE,    cmd_delete,    RANGE+WORD1    },
  1033. X    {"edit",    CMD_EDIT,    cmd_edit,    BANG+FILE1+PLUS    },
  1034. X    {"file",    CMD_FILE,    cmd_file,    NAMEDF        },
  1035. X    {"global",    CMD_GLOBAL,    cmd_global,    RANGE+BANG+EXTRA+DFLALL},
  1036. X    {"insert",    CMD_INSERT,    cmd_append,    FROM        },
  1037. X    {"join",    CMD_INSERT,    cmd_join,    RANGE        },
  1038. X    {"k",        CMD_MARK,    cmd_mark,    FROM+WORD1    },
  1039. X    {"list",    CMD_LIST,    cmd_print,    RANGE+NL    },
  1040. X    {"move",    CMD_MOVE,    cmd_move,    RANGE+EXTRA    },
  1041. X    {"next",    CMD_NEXT,    cmd_next,    BANG+NAMEDFS    },
  1042. X    {"Next",    CMD_PREVIOUS,    cmd_next,    BANG        },
  1043. X    {"print",    CMD_PRINT,    cmd_print,    RANGE+NL    },
  1044. X    {"quit",    CMD_QUIT,    cmd_xit,    BANG        },
  1045. X    {"read",    CMD_READ,    cmd_read,    FROM+ZERO+NAMEDF},
  1046. X    {"substitute",    CMD_SUBSTITUTE,    cmd_substitute,    RANGE+EXTRA    },
  1047. X    {"to",        CMD_COPY,    cmd_move,    RANGE+EXTRA    },
  1048. X    {"undo",    CMD_UNDO,    cmd_undo,    NONE        },
  1049. X    {"vglobal",    CMD_VGLOBAL,    cmd_global,    RANGE+EXTRA+DFLALL},
  1050. X    {"write",    CMD_WRITE,    cmd_write,    RANGE+BANG+FILE1+DFLALL},
  1051. X    {"xit",        CMD_XIT,    cmd_xit,    BANG+NL        },
  1052. X    {"yank",    CMD_YANK,    cmd_delete,    RANGE+WORD1    },
  1053. X
  1054. X    {"!",        CMD_BANG,    cmd_shell,    EXRCOK+RANGE+NAMEDFS+DFLNONE+NL},
  1055. X    {"<",        CMD_SHIFTL,    cmd_shift,    RANGE        },
  1056. X    {">",        CMD_SHIFTR,    cmd_shift,    RANGE        },
  1057. X    {"=",        CMD_EQUAL,    cmd_file,    RANGE        },
  1058. X    {"&",        CMD_SUBAGAIN,    cmd_substitute,    RANGE        },
  1059. X#ifndef NO_AT
  1060. X    {"@",        CMD_AT,        cmd_at,        EXTRA        },
  1061. X#endif
  1062. X
  1063. X#ifndef NO_ABBR
  1064. X    {"abbreviate",    CMD_ABBR,    cmd_abbr,    EXRCOK+EXTRA    },
  1065. X#endif
  1066. X    {"args",    CMD_ARGS,    cmd_args,    EXRCOK+NAMEDFS    },
  1067. X#ifndef NO_ERRLIST
  1068. X    {"cc",        CMD_CC,        cmd_make,    BANG+FILES    },
  1069. X#endif
  1070. X    {"cd",        CMD_CD,        cmd_cd,        EXRCOK+NAMEDF    },
  1071. X    {"copy",    CMD_COPY,    cmd_move,    RANGE+EXTRA    },
  1072. X#ifndef NO_DIGRAPH
  1073. X    {"digraph",    CMD_DIGRAPH,    cmd_digraph,    EXRCOK+BANG+EXTRA},
  1074. X#endif
  1075. X#ifndef NO_ERRLIST
  1076. X    {"errlist",    CMD_ERRLIST,    cmd_errlist,    BANG+NAMEDF    },
  1077. X#endif
  1078. X    {"ex",        CMD_EDIT,    cmd_edit,    BANG+FILE1    },
  1079. X    {"map",        CMD_MAP,    cmd_map,    EXRCOK+BANG+EXTRA},
  1080. X#ifndef NO_MKEXRC
  1081. X    {"mkexrc",    CMD_MKEXRC,    cmd_mkexrc,    NAMEDF        },
  1082. X#endif
  1083. X    {"number",    CMD_NUMBER,    cmd_print,    RANGE+NL    },
  1084. X    {"put",        CMD_PUT,    cmd_put,    FROM+ZERO+WORD1    },
  1085. X    {"set",        CMD_SET,    cmd_set,    EXRCOK+EXTRA    },
  1086. X    {"shell",    CMD_SHELL,    cmd_shell,    NL        },
  1087. X    {"source",    CMD_SOURCE,    cmd_source,    EXRCOK+NAMEDF    },
  1088. X    {"tag",        CMD_TAG,    cmd_tag,    BANG+WORD1    },
  1089. X    {"version",    CMD_VERSION,    cmd_version,    EXRCOK+NONE    },
  1090. X    {"visual",    CMD_VISUAL,    cmd_visual,    NONE        },
  1091. X    {"wq",        CMD_WQUIT,    cmd_xit,    NL        },
  1092. X
  1093. X#ifdef DEBUG
  1094. X    {"debug",    CMD_DEBUG,    cmd_debug,    RANGE+BANG+EXTRA+NL},
  1095. X    {"validate",    CMD_VALIDATE,    cmd_validate,    BANG+NL        },
  1096. X#endif
  1097. X    {"chdir",    CMD_CD,        cmd_cd,        EXRCOK+NAMEDF    },
  1098. X#ifndef NO_ERRLIST
  1099. X    {"make",    CMD_MAKE,    cmd_make,    BANG+NAMEDFS    },
  1100. X#endif
  1101. X    {"mark",    CMD_MARK,    cmd_mark,    FROM+WORD1    },
  1102. X    {"previous",    CMD_PREVIOUS,    cmd_next,    BANG        },
  1103. X    {"rewind",    CMD_REWIND,    cmd_next,    BANG        },
  1104. X    {"unmap",    CMD_UNMAP,    cmd_map,    EXRCOK+BANG+EXTRA},
  1105. X#ifndef NO_ABBR
  1106. X    {"unabbreviate",CMD_UNABBR,    cmd_abbr,    EXRCOK+WORD1    },
  1107. X#endif
  1108. X
  1109. X    {(char *)0}
  1110. X};
  1111. X
  1112. X
  1113. X/* This function parses a search pattern - given a pointer to a / or ?,
  1114. X * it replaces the ending / or ? with a \0, and returns a pointer to the
  1115. X * stuff that came after the pattern.
  1116. X */
  1117. Xchar    *parseptrn(ptrn)
  1118. X    REG char    *ptrn;
  1119. X{
  1120. X    REG char     *scan;
  1121. X
  1122. X    for (scan = ptrn + 1;
  1123. X         *scan && *scan != *ptrn;
  1124. X         scan++)
  1125. X    {
  1126. X        /* allow backslashed versions of / and ? in the pattern */
  1127. X        if (*scan == '\\' && scan[1] != '\0')
  1128. X        {
  1129. X            scan++;
  1130. X        }
  1131. X    }
  1132. X    if (*scan)
  1133. X    {
  1134. X        *scan++ = '\0';
  1135. X    }
  1136. X
  1137. X    return scan;
  1138. X}
  1139. X
  1140. X
  1141. X/* This function parses a line specifier for ex commands */
  1142. Xchar *linespec(s, markptr)
  1143. X    REG char    *s;        /* start of the line specifier */
  1144. X    MARK        *markptr;    /* where to store the mark's value */
  1145. X{
  1146. X    long        num;
  1147. X    REG char    *t;
  1148. X
  1149. X    /* parse each ;-delimited clause of this linespec */
  1150. X    do
  1151. X    {
  1152. X        /* skip an initial ';', if any */
  1153. X        if (*s == ';')
  1154. X        {
  1155. X            s++;
  1156. X        }
  1157. X
  1158. X        /* skip leading spaces */
  1159. X        while (isascii(*s) && isspace(*s))
  1160. X        {
  1161. X            s++;
  1162. X        }
  1163. X    
  1164. X        /* dot means current position */
  1165. X        if (*s == '.')
  1166. X        {
  1167. X            s++;
  1168. X            *markptr = cursor;
  1169. X        }
  1170. X        /* '$' means the last line */
  1171. X        else if (*s == '$')
  1172. X        {
  1173. X            s++;
  1174. X            *markptr = MARK_LAST;
  1175. X        }
  1176. X        /* digit means an absolute line number */
  1177. X        else if (isascii(*s) && isdigit(*s))
  1178. X        {
  1179. X            for (num = 0; isascii(*s) && isdigit(*s); s++)
  1180. X            {
  1181. X                num = num * 10 + *s - '0';
  1182. X            }
  1183. X            *markptr = MARK_AT_LINE(num);
  1184. X        }
  1185. X        /* appostrophe means go to a set mark */
  1186. X        else if (*s == '\'')
  1187. X        {
  1188. X            s++;
  1189. X            *markptr = m_tomark(cursor, 1L, (int)*s);
  1190. X            s++;
  1191. X        }
  1192. X        /* slash means do a search */
  1193. X        else if (*s == '/' || *s == '?')
  1194. X        {
  1195. X            /* put a '\0' at the end of the search pattern */
  1196. X            t = parseptrn(s);
  1197. X    
  1198. X            /* search for the pattern */
  1199. X            *markptr &= ~(BLKSIZE - 1);
  1200. X            if (*s == '/')
  1201. X            {
  1202. X                pfetch(markline(*markptr));
  1203. X                if (plen > 0)
  1204. X                    *markptr += plen - 1;
  1205. X                *markptr = m_fsrch(*markptr, s);
  1206. X            }
  1207. X            else
  1208. X            {
  1209. X                *markptr = m_bsrch(*markptr, s);
  1210. X            }
  1211. X    
  1212. X            /* adjust command string pointer */
  1213. X            s = t;
  1214. X        }
  1215. X    
  1216. X        /* if linespec was faulty, quit now */
  1217. X        if (!*markptr)
  1218. X        {
  1219. X            return s;
  1220. X        }
  1221. X    
  1222. X        /* maybe add an offset */
  1223. X        t = s;
  1224. X        if (*t == '-' || *t == '+')
  1225. X        {
  1226. X            s++;
  1227. X            for (num = 0; *s >= '0' && *s <= '9'; s++)
  1228. X            {
  1229. X                num = num * 10 + *s - '0';
  1230. X            }
  1231. X            if (num == 0)
  1232. X            {
  1233. X                num = 1;
  1234. X            }
  1235. X            *markptr = m_updnto(*markptr, num, *t);
  1236. X        }
  1237. X    } while (*s == ';' || *s == '+' || *s == '-');
  1238. X
  1239. X    return s;
  1240. X}
  1241. X
  1242. X
  1243. X
  1244. X/* This function reads an ex command and executes it. */
  1245. Xvoid ex()
  1246. X{
  1247. X    char        cmdbuf[80];
  1248. X    REG int        cmdlen;
  1249. X    static long    oldline;
  1250. X    
  1251. X    significant = FALSE;
  1252. X    oldline = markline(cursor);
  1253. X
  1254. X    while (mode == MODE_EX)
  1255. X    {
  1256. X        /* read a line */
  1257. X        cmdlen = vgets(':', cmdbuf, sizeof cmdbuf);
  1258. X        if (cmdlen < 0)
  1259. X        {
  1260. X            return;
  1261. X        }
  1262. X
  1263. X        /* if empty line, assume ".+1" */
  1264. X        if (cmdlen == 0)
  1265. X        {
  1266. X            strcpy(cmdbuf, ".+1");
  1267. X            qaddch('\r');
  1268. X            clrtoeol();
  1269. X        }
  1270. X        else
  1271. X        {
  1272. X            addch('\n');
  1273. X        }
  1274. X        refresh();
  1275. X
  1276. X        /* parse & execute the command */
  1277. X        doexcmd(cmdbuf);
  1278. X
  1279. X        /* handle autoprint */
  1280. X        if (significant || markline(cursor) != oldline)
  1281. X        {
  1282. X            significant = FALSE;
  1283. X            oldline = markline(cursor);
  1284. X            if (*o_autoprint && mode == MODE_EX)
  1285. X            {
  1286. X                cmd_print(cursor, cursor, CMD_PRINT, FALSE, "");
  1287. X            }
  1288. X        }
  1289. X    }
  1290. X}
  1291. X
  1292. Xvoid doexcmd(cmdbuf)
  1293. X    char        *cmdbuf;    /* string containing an ex command */
  1294. X{
  1295. X    REG char    *scan;        /* used to scan thru cmdbuf */
  1296. X    MARK        frommark;    /* first linespec */
  1297. X    MARK        tomark;        /* second linespec */
  1298. X    REG int        cmdlen;        /* length of the command name given */
  1299. X    CMD        cmd;        /* what command is this? */
  1300. X    ARGT        argt;        /* argument types for this command */
  1301. X    short        forceit;    /* bang version of a command? */
  1302. X    REG int        cmdidx;        /* index of command */
  1303. X    REG char    *build;        /* used while copying filenames */
  1304. X    int        iswild;        /* boolean: filenames use wildcards? */
  1305. X    int        isdfl;        /* using default line ranges? */
  1306. X    int        didsub;        /* did we substitute file names for % or # */
  1307. X
  1308. X
  1309. X    /* ex commands can't be undone via the shift-U command */
  1310. X    U_line = 0L;
  1311. X
  1312. X    /* ignore command lines that start with a double-quote */
  1313. X    if (*cmdbuf == '"')
  1314. X    {
  1315. X        return;
  1316. X    }
  1317. X
  1318. X    /* permit extra colons at the start of the line */
  1319. X    while (*cmdbuf == ':')
  1320. X    {
  1321. X        cmdbuf++;
  1322. X    }
  1323. X
  1324. X    /* parse the line specifier */
  1325. X    scan = cmdbuf;
  1326. X    if (nlines < 1)
  1327. X    {
  1328. X        /* no file, so don't allow addresses */
  1329. X    }
  1330. X    else if (*scan == '%')
  1331. X    {
  1332. X        /* '%' means all lines */
  1333. X        frommark = MARK_FIRST;
  1334. X        tomark = MARK_LAST;
  1335. X        scan++;
  1336. X    }
  1337. X    else if (*scan == '0')
  1338. X    {
  1339. X        frommark = tomark = MARK_UNSET;
  1340. X        scan++;
  1341. X    }
  1342. X    else
  1343. X    {
  1344. X        frommark = cursor;
  1345. X        scan = linespec(scan, &frommark);
  1346. X        tomark = frommark;
  1347. X        if (frommark && *scan == ',')
  1348. X        {
  1349. X            scan++;
  1350. X            scan = linespec(scan, &tomark);
  1351. X        }
  1352. X        if (!tomark)
  1353. X        {
  1354. X            /* faulty line spec -- fault already described */
  1355. X            return;
  1356. X        }
  1357. X        if (frommark > tomark)
  1358. X        {
  1359. X            msg("first address exceeds the second");
  1360. X            return;
  1361. X        }
  1362. X    }
  1363. X    isdfl = (scan == cmdbuf);
  1364. X
  1365. X    /* skip whitespace */
  1366. X    while (isascii(*scan) && isspace(*scan))
  1367. X    {
  1368. X        scan++;
  1369. X    }
  1370. X
  1371. X    /* if no command, then just move the cursor to the mark */
  1372. X    if (!*scan)
  1373. X    {
  1374. X        cursor = tomark;
  1375. X        return;
  1376. X    }
  1377. X
  1378. X    /* figure out how long the command name is */
  1379. X    if (isascii(*scan) && !isalpha(*scan))
  1380. X    {
  1381. X        cmdlen = 1;
  1382. X    }
  1383. X    else
  1384. X    {
  1385. X        for (cmdlen = 1;
  1386. X             !isascii(scan[cmdlen]) || isalpha(scan[cmdlen]);
  1387. X             cmdlen++)
  1388. X        {
  1389. X        }
  1390. X    }
  1391. X
  1392. X    /* lookup the command code */
  1393. X    for (cmdidx = 0;
  1394. X         cmdnames[cmdidx].name && strncmp(scan, cmdnames[cmdidx].name, cmdlen);
  1395. X         cmdidx++)
  1396. X    {
  1397. X    }
  1398. X    argt = cmdnames[cmdidx].argt;
  1399. X    cmd = cmdnames[cmdidx].code;
  1400. X    if (cmd == CMD_NULL)
  1401. X    {
  1402. X#if OSK
  1403. X        msg("Unknown command \"%s\"", scan);
  1404. X#else
  1405. X        msg("Unknown command \"%.*s\"", cmdlen, scan);
  1406. X#endif
  1407. X        return;
  1408. X    }
  1409. X
  1410. X    /* if the command ended with a bang, set the forceit flag */
  1411. X    scan += cmdlen;
  1412. X    if ((argt & BANG) && *scan == '!')
  1413. X    {
  1414. X        scan++;
  1415. X        forceit = 1;
  1416. X    }
  1417. X    else
  1418. X    {
  1419. X        forceit = 0;
  1420. X    }
  1421. X
  1422. X    /* skip any more whitespace, to leave scan pointing to arguments */
  1423. X    while (isascii(*scan) && isspace(*scan))
  1424. X    {
  1425. X        scan++;
  1426. X    }
  1427. X
  1428. X    /* a couple of special cases for filenames */
  1429. X    if (argt & XFILE)
  1430. X    {
  1431. X        /* if names were given, process them */
  1432. X        if (*scan)
  1433. X        {
  1434. X            for (build = tmpblk.c, iswild = didsub = FALSE; *scan; scan++)
  1435. X            {
  1436. X                switch (*scan)
  1437. X                {
  1438. X                  case '%':
  1439. X                    if (!*origname)
  1440. X                    {
  1441. X                        msg("No filename to substitute for %%");
  1442. X                        return;
  1443. X                    }
  1444. X                    strcpy(build, origname);
  1445. X                    while (*build)
  1446. X                    {
  1447. X                        build++;
  1448. X                    }
  1449. X                    didsub = TRUE;
  1450. X                    break;
  1451. X    
  1452. X                  case '#':
  1453. X                    if (!*prevorig)
  1454. X                    {
  1455. X                        msg("No filename to substitute for #");
  1456. X                        return;
  1457. X                    }
  1458. X                    strcpy(build, prevorig);
  1459. X                    while (*build)
  1460. X                    {
  1461. X                        build++;
  1462. X                    }
  1463. X                    didsub = TRUE;
  1464. X                    break;
  1465. X    
  1466. X                  case '*':
  1467. X                  case '?':
  1468. X#if !(MSDOS || TOS)
  1469. X                  case '[':
  1470. X                  case '`':
  1471. X                  case '{': /* } */
  1472. X                  case '$':
  1473. X                  case '~':
  1474. X#endif
  1475. X                    *build++ = *scan;
  1476. X                    iswild = TRUE;
  1477. X                    break;
  1478. X
  1479. X                  default:
  1480. X                    *build++ = *scan;
  1481. X                }
  1482. X            }
  1483. X            *build = '\0';
  1484. X    
  1485. X            if (cmd == CMD_BANG
  1486. X             || cmd == CMD_READ && tmpblk.c[0] == '!'
  1487. X             || cmd == CMD_WRITE && tmpblk.c[0] == '!')
  1488. X            {
  1489. X                if (didsub)
  1490. X                {
  1491. X                    if (mode != MODE_EX)
  1492. X                    {
  1493. X                        addch('\n');
  1494. X                    }
  1495. X                    addstr(tmpblk.c);
  1496. X                    addch('\n');
  1497. X                    exrefresh();
  1498. X                }
  1499. X            }
  1500. X            else
  1501. X            {
  1502. X                if (iswild && tmpblk.c[0] != '>')
  1503. X                {
  1504. X                    scan = wildcard(tmpblk.c);
  1505. X                }
  1506. X            }
  1507. X        }
  1508. X        else /* no names given, maybe assume origname */
  1509. X        {
  1510. X            if (!(argt & NODFL))
  1511. X            {
  1512. X                strcpy(tmpblk.c, origname);
  1513. X            }
  1514. X            else
  1515. X            {
  1516. X                *tmpblk.c = '\0';
  1517. X            }
  1518. X        }
  1519. X
  1520. X        scan = tmpblk.c;
  1521. X    }
  1522. X
  1523. X    /* bad arguments? */
  1524. X    if (!(argt & EXRCOK) && nlines < 1L)
  1525. X    {
  1526. X        msg("Can't use the \"%s\" command in a %s file", cmdnames[cmdidx].name, EXRC);
  1527. X        return;
  1528. X    }
  1529. X    if (!(argt & (ZERO | EXRCOK)) && frommark == MARK_UNSET)
  1530. X    {
  1531. X        msg("Can't use address 0 with \"%s\" command.", cmdnames[cmdidx].name);
  1532. X        return;
  1533. X    }
  1534. X    if (!(argt & FROM) && frommark != cursor && nlines >= 1L)
  1535. X    {
  1536. X        msg("Can't use address with \"%s\" command.", cmdnames[cmdidx].name);
  1537. X        return;
  1538. X    }
  1539. X    if (!(argt & TO) && tomark != frommark && nlines >= 1L)
  1540. X    {
  1541. X        msg("Can't use a range with \"%s\" command.", cmdnames[cmdidx].name);
  1542. X        return;
  1543. X    }
  1544. X    if (!(argt & EXTRA) && *scan)
  1545. X    {
  1546. X        msg("Extra characters after \"%s\" command.", cmdnames[cmdidx].name);
  1547. X        return;
  1548. X    }
  1549. X    if ((argt & NOSPC) && !(cmd == CMD_READ && (forceit || *scan == '!')))
  1550. X    {
  1551. X        build = scan;
  1552. X#ifndef CRUNCH
  1553. X        if ((argt & PLUS) && *build == '+')
  1554. X        {
  1555. X            while (*build && !(isascii(*build) && isspace(*build)))
  1556. X            {
  1557. X                build++;
  1558. X            }
  1559. X            while (*build && isascii(*build) && isspace(*build))
  1560. X            {
  1561. X                build++;
  1562. X            }
  1563. X        }
  1564. X#endif /* not CRUNCH */
  1565. X        for (; *build; build++)
  1566. X        {
  1567. X            if (isspace(*build))
  1568. X            {
  1569. X                msg("Too many %s to \"%s\" command.",
  1570. X                    (argt & XFILE) ? "filenames" : "arguments",
  1571. X                    cmdnames[cmdidx].name);
  1572. X                return;
  1573. X            }
  1574. X        }
  1575. X    }
  1576. X
  1577. X    /* some commands have special default ranges */
  1578. X    if (isdfl && (argt & DFLALL))
  1579. X    {
  1580. X        frommark = MARK_FIRST;
  1581. X        tomark = MARK_LAST;
  1582. X    }
  1583. X    else if (isdfl && (argt & DFLNONE))
  1584. X    {
  1585. X        frommark = tomark = 0L;
  1586. X    }
  1587. X
  1588. X    /* write a newline if called from visual mode */
  1589. X    if ((argt & NL) && mode != MODE_EX && !exwrote)
  1590. X    {
  1591. X        addch('\n');
  1592. X        exrefresh();
  1593. X    }
  1594. X
  1595. X    /* act on the command */
  1596. X    (*cmdnames[cmdidx].fn)(frommark, tomark, cmd, forceit, scan);
  1597. X}
  1598. X
  1599. X
  1600. X/* This function executes EX commands from a file.  It returns 1 normally, or
  1601. X * 0 if the file could not be opened for reading.
  1602. X */
  1603. Xint doexrc(filename)
  1604. X    char    *filename;    /* name of a ".exrc" file */
  1605. X{
  1606. X    int    fd;        /* file descriptor */
  1607. X    int    len;        /* length of the ".exrc" file */
  1608. X    char    buf[MAXRCLEN];    /* buffer, holds the entire .exrc file */
  1609. X
  1610. X    /* open the file, read it, and close */
  1611. X    fd = open(filename, O_RDONLY);
  1612. X    if (fd < 0)
  1613. X    {
  1614. X        return 0;
  1615. X    }
  1616. X    len = tread(fd, buf, MAXRCLEN);
  1617. X    close(fd);
  1618. X
  1619. X    /* execute the string */
  1620. X    exstring(buf, len);
  1621. X
  1622. X    return 1;
  1623. X}
  1624. X
  1625. Xvoid exstring(buf, len)
  1626. X    char    *buf;    /* the commands to execute */
  1627. X    int    len;    /* the length of the string */
  1628. X{
  1629. X    char    *cmd;        /* start of a command */
  1630. X    char    *end;        /* used to search for the end of cmd */
  1631. X
  1632. X    /* find & do each command */
  1633. X    for (cmd = buf; cmd < &buf[len]; cmd = end + 1)
  1634. X    {
  1635. X        /* find the end of the command */
  1636. X        for (end = cmd; end < &buf[len] && *end != '\n' && *end != '|'; end++)
  1637. X        {
  1638. X        }
  1639. X        *end = '\0';
  1640. X
  1641. X        /* do it */
  1642. X        doexcmd(cmd);
  1643. X    }
  1644. X}
  1645. eof
  1646. if test `wc -c <ex.c` -ne 15130
  1647. then
  1648. echo ex.c damaged!
  1649. fi
  1650. fi
  1651.  
  1652. if test -f input.c -a "$1" != -f
  1653. then
  1654. echo Will not overwrite input.c
  1655. else
  1656. echo Extracting input.c
  1657. sed 's/^X//' >input.c <<\eof
  1658. X/* input.c */
  1659. X
  1660. X/* Author:
  1661. X *    Steve Kirkendall
  1662. X *    14407 SW Teal Blvd. #C
  1663. X *    Beaverton, OR 97005
  1664. X *    kirkenda@cs.pdx.edu
  1665. X */
  1666. X
  1667. X
  1668. X/* This file contains the input() function, which implements vi's INPUT mode.
  1669. X * It also contains the code that supports digraphs.
  1670. X */
  1671. X
  1672. X#include <ctype.h>
  1673. X#include "config.h"
  1674. X#include "vi.h"
  1675. X
  1676. X
  1677. X#ifndef NO_DIGRAPH
  1678. Xstatic struct _DIG
  1679. X{
  1680. X    struct _DIG    *next;
  1681. X    char        key1;
  1682. X    char        key2;
  1683. X    char        dig;
  1684. X    char        save;
  1685. X} *digs;
  1686. X
  1687. Xchar digraph(key1, key2)
  1688. X    char    key1;    /* the underlying character */
  1689. X    char    key2;    /* the second character */
  1690. X{
  1691. X    int        newkey;
  1692. X    REG struct _DIG    *dp;
  1693. X
  1694. X    /* if digraphs are disabled, then just return the new char */
  1695. X    if (!*o_digraph)
  1696. X    {
  1697. X        return key2;
  1698. X    }
  1699. X
  1700. X    /* remember the new key, so we can return it if this isn't a digraph */
  1701. X    newkey = key2;
  1702. X
  1703. X    /* sort key1 and key2, so that their original order won't matter */
  1704. X    if (key1 > key2)
  1705. X    {
  1706. X        key2 = key1;
  1707. X        key1 = newkey;
  1708. X    }
  1709. X
  1710. X    /* scan through the digraph chart */
  1711. X    for (dp = digs;
  1712. X         dp && (dp->key1 != key1 || dp->key2 != key2);
  1713. X         dp = dp->next)
  1714. X    {
  1715. X    }
  1716. X
  1717. X    /* if this combination isn't in there, just use the new key */
  1718. X    if (!dp)
  1719. X    {
  1720. X        return newkey;
  1721. X    }
  1722. X
  1723. X    /* else use the digraph key */
  1724. X    return dp->dig;
  1725. X}
  1726. X
  1727. X/* this function lists or defines digraphs */
  1728. Xvoid do_digraph(bang, extra)
  1729. X    int    bang;
  1730. X    char    extra[];
  1731. X{
  1732. X    int        dig;
  1733. X    REG struct _DIG    *dp;
  1734. X    struct _DIG    *prev;
  1735. X    static int    user_defined = FALSE; /* boolean: are all later digraphs user-defined? */
  1736. X    char        listbuf[8];
  1737. X
  1738. X    /* if "extra" is NULL, then we've reached the end of the built-ins */
  1739. X    if (!extra)
  1740. X    {
  1741. X        user_defined = TRUE;
  1742. X        return;
  1743. X    }
  1744. X
  1745. X    /* if no args, then display the existing digraphs */
  1746. X    if (*extra < ' ')
  1747. X    {
  1748. X        listbuf[0] = listbuf[1] = listbuf[2] = listbuf[5] = ' ';
  1749. X        listbuf[7] = '\0';
  1750. X        for (dig = 0, dp = digs; dp; dp = dp->next)
  1751. X        {
  1752. X            if (dp->save || bang)
  1753. X            {
  1754. X                dig += 7;
  1755. X                if (dig >= COLS)
  1756. X                {
  1757. X                    addch('\n');
  1758. X                    exrefresh();
  1759. X                    dig = 7;
  1760. X                }
  1761. X                listbuf[3] = dp->key1;
  1762. X                listbuf[4] = dp->key2;
  1763. X                listbuf[6] = dp->dig;
  1764. X                qaddstr(listbuf);
  1765. X            }
  1766. X        }
  1767. X        addch('\n');
  1768. X        exrefresh();
  1769. X        return;
  1770. X    }
  1771. X
  1772. X    /* make sure we have at least two characters */
  1773. X    if (!extra[1])
  1774. X    {
  1775. X        msg("Digraphs must be composed of two characters");
  1776. X        return;
  1777. X    }
  1778. X
  1779. X    /* sort key1 and key2, so that their original order won't matter */
  1780. X    if (extra[0] > extra[1])
  1781. X    {
  1782. X        dig = extra[0];
  1783. X        extra[0] = extra[1];
  1784. X        extra[1] = dig;
  1785. X    }
  1786. X
  1787. X    /* locate the new digraph character */
  1788. X    for (dig = 2; extra[dig] == ' ' || extra[dig] == '\t'; dig++)
  1789. X    {
  1790. X    }
  1791. X    dig = extra[dig];
  1792. X    if (!bang && dig)
  1793. X    {
  1794. X        dig |= 0x80;
  1795. X    }
  1796. X
  1797. X    /* search for the digraph */
  1798. X    for (prev = (struct _DIG *)0, dp = digs;
  1799. X         dp && (dp->key1 != extra[0] || dp->key2 != extra[1]);
  1800. X         prev = dp, dp = dp->next)
  1801. X    {
  1802. X    }
  1803. X
  1804. X    /* deleting the digraph? */
  1805. X    if (!dig)
  1806. X    {
  1807. X        if (!dp)
  1808. X        {
  1809. X#ifndef CRUNCH
  1810. X            msg("%c%c not a digraph", extra[0], extra[1]);
  1811. X#endif
  1812. X            return;
  1813. X        }
  1814. X        if (prev)
  1815. X            prev->next = dp->next;
  1816. X        else
  1817. X            digs = dp->next;
  1818. X        free(dp);
  1819. X        return;
  1820. X    }
  1821. X
  1822. X    /* if necessary, create a new digraph struct for the new digraph */
  1823. X    if (dig && !dp)
  1824. X    {
  1825. X        dp = (struct _DIG *)malloc(sizeof *dp);
  1826. X        if (!dp)
  1827. X        {
  1828. X            msg("Out of space in the digraph table");
  1829. X            return;
  1830. X        }
  1831. X        if (prev)
  1832. X            prev->next = dp;
  1833. X        else
  1834. X            digs = dp;
  1835. X        dp->next = (struct _DIG *)0;
  1836. X    }
  1837. X
  1838. X    /* assign it the new digraph value */
  1839. X    dp->key1 = extra[0];
  1840. X    dp->key2 = extra[1];
  1841. X    dp->dig = dig;
  1842. X    dp->save = user_defined;
  1843. X}
  1844. X
  1845. X# ifndef NO_MKEXRC
  1846. Xvoid savedigs(fd)
  1847. X    int        fd;
  1848. X{
  1849. X    static char    buf[] = "digraph! XX Y\n";
  1850. X    REG struct _DIG    *dp;
  1851. X
  1852. X    for (dp = digs; dp; dp = dp->next)
  1853. X    {
  1854. X        if (dp->save)
  1855. X        {
  1856. X            buf[9] = dp->key1;
  1857. X            buf[10] = dp->key2;
  1858. X            buf[12] = dp->dig;
  1859. X            write(fd, buf, (unsigned)14);
  1860. X        }
  1861. X    }
  1862. X}
  1863. X# endif
  1864. X#endif
  1865. X
  1866. X
  1867. X#ifndef NO_ABBR
  1868. Xstatic struct _AB
  1869. X{
  1870. X    struct _AB    *next;
  1871. X    char        *large;        /* the expanded form */
  1872. X    char        small[1];    /* the abbreviated form (appended to struct) */
  1873. X}
  1874. X    *abbrev;
  1875. X
  1876. X/* This functions lists or defines abbreviations */
  1877. Xvoid do_abbr(extra)
  1878. X    char    *extra;
  1879. X{
  1880. X    int        smlen;    /* length of the small form */
  1881. X    int        lrg;    /* index of the start of the large form */
  1882. X    REG struct _AB    *ab;    /* used to move through the abbrev list */
  1883. X    struct _AB    *prev;
  1884. X
  1885. X    /* no arguments? */
  1886. X    if (!*extra)
  1887. X    {
  1888. X        /* list all current abbreviations */
  1889. X        for (ab = abbrev; ab; ab = ab->next)
  1890. X        {
  1891. X            qaddstr("abbr ");
  1892. X            qaddstr(ab->small);
  1893. X            qaddch(' ');
  1894. X            qaddstr(ab->large);
  1895. X            addch('\n');
  1896. X            exrefresh();
  1897. X        }
  1898. X        return;
  1899. X    }
  1900. X
  1901. X    /* else one or more arguments.  Parse the first & look up in abbrev[] */
  1902. X    for (smlen = 0; extra[smlen] && isalnum(extra[smlen]); smlen++)
  1903. X    {
  1904. X    }
  1905. X    for (prev = (struct _AB *)0, ab = abbrev; ab; prev = ab, ab = ab->next)
  1906. X    {
  1907. X        if (!strncmp(extra, ab->small, smlen) && !ab->small[smlen])
  1908. X        {
  1909. X            break;
  1910. X        }
  1911. X    }
  1912. X
  1913. X    /* locate the start of the large form, if any */
  1914. X    for (lrg = smlen; extra[lrg] && isascii(extra[lrg]) && isspace(extra[lrg]); lrg++)
  1915. X    {
  1916. X    }
  1917. X
  1918. X    /* only one arg? */
  1919. X    if (!extra[lrg])
  1920. X    {
  1921. X        /* trying to undo an abbreviation which doesn't exist? */
  1922. X        if (!ab)
  1923. X        {
  1924. X#ifndef CRUNCH
  1925. X            msg("\"%s\" not an abbreviation", extra);
  1926. X#endif
  1927. X            return;
  1928. X        }
  1929. X
  1930. X        /* undo the abbreviation */
  1931. X        if (prev)
  1932. X            prev->next = ab->next;
  1933. X        else
  1934. X            abbrev = ab->next;
  1935. X        free(ab->large);
  1936. X        free(ab);
  1937. X
  1938. X        return;
  1939. X    }
  1940. X
  1941. X    /* multiple args - [re]define an abbreviation */
  1942. X    if (ab)
  1943. X    {
  1944. X        /* redefining - free the old large form */
  1945. X        free(ab->large);
  1946. X    }
  1947. X    else
  1948. X    {
  1949. X        /* adding a new definition - make a new struct */
  1950. X        ab = (struct _AB *)malloc((unsigned)(smlen + sizeof *ab));
  1951. X#ifndef CRUNCH
  1952. X        if (!ab)
  1953. X        {
  1954. X            msg("Out of memory -- Sorry");
  1955. X            return;
  1956. X        }
  1957. X#endif
  1958. X        strncpy(ab->small, extra, smlen);
  1959. X        ab->small[smlen] = '\0';
  1960. X        ab->next = (struct _AB *)0;
  1961. X        if (prev)
  1962. X            prev->next = ab;
  1963. X        else
  1964. X            abbrev = ab;
  1965. X    }
  1966. X
  1967. X    /* store the new form */
  1968. X    ab->large = (char *)malloc((unsigned)(strlen(&extra[lrg]) + 1));
  1969. X    strcpy(ab->large, &extra[lrg]);
  1970. X}
  1971. X
  1972. X
  1973. X# ifndef NO_MKEXRC
  1974. X/* This function is called from cmd_mkexrc() to save the abbreviations */
  1975. Xvoid saveabbr(fd)
  1976. X    int    fd;    /* fd to which the :abbr commands should be written */
  1977. X{
  1978. X    REG struct _AB    *ab;
  1979. X
  1980. X    for (ab = abbrev; ab; ab = ab->next)
  1981. X    {
  1982. X        twrite(fd, "abbr ", 5);
  1983. X        twrite(fd, ab->small, strlen(ab->small));
  1984. X        twrite(fd, " ", 1);
  1985. X        twrite(fd, ab->large, strlen(ab->large));
  1986. X        twrite(fd, "\n", 1);
  1987. X    }
  1988. X}
  1989. X# endif
  1990. X
  1991. X/* This function should be called before each char is inserted.  If the next
  1992. X * char is non-alphanumeric and we're at the end of a word, then that word
  1993. X * is checked against the abbrev[] array and expanded, if appropriate.  Upon
  1994. X * returning from this function, the new char still must be inserted.
  1995. X */
  1996. Xstatic MARK expandabbr(m, ch)
  1997. X    MARK        m;    /* the cursor position */
  1998. X    int        ch;    /* the character to insert */
  1999. X{
  2000. X    char        *word;    /* where the word starts */
  2001. X    int        len;    /* length of the word */
  2002. X    REG struct _AB    *ab;
  2003. X
  2004. X    /* if no abbreviations are in effect, or ch is aphanumeric, then
  2005. X     * don't do anything
  2006. X     */
  2007. X    if (!abbrev || !isascii(ch) || isalnum(ch))
  2008. X    {
  2009. X        return m;
  2010. X    }
  2011. X
  2012. X    /* see where the preceding word starts */
  2013. X    pfetch(markline(m));
  2014. X    for (word = ptext + markidx(m), len = 0;
  2015. X         --word >= ptext && (!isascii(*word) || isalnum(*word));
  2016. X         len++)
  2017. X    {
  2018. X    }
  2019. X    word++;
  2020. X
  2021. X    /* if zero-length, then it isn't a word, really -- so nothing */
  2022. X    if (len == 0)
  2023. X    {
  2024. X        return m;
  2025. X    }
  2026. X
  2027. X    /* look it up in the abbrev list */
  2028. X    for (ab = abbrev; ab; ab = ab->next)
  2029. X    {
  2030. X        if (!strncmp(ab->small, word, len) && !ab->small[len])
  2031. X        {
  2032. X            break;
  2033. X        }
  2034. X    }
  2035. X
  2036. X    /* not an abbreviation? then do nothing */
  2037. X    if (!ab)
  2038. X    {
  2039. X        return m;
  2040. X    }
  2041. X
  2042. X    /* else replace the small form with the large form */
  2043. X    add(m, ab->large);
  2044. X    delete(m - len, m);
  2045. X
  2046. X    /* return with the cursor after the end of the large form */
  2047. X    return m - len + strlen(ab->large);
  2048. X}
  2049. X#endif
  2050. X
  2051. X        
  2052. X/* This function allows the user to replace an existing (possibly zero-length)
  2053. X * chunk of text with typed-in text.  It returns the MARK of the last character
  2054. X * that the user typed in.
  2055. X */
  2056. XMARK input(from, to, when)
  2057. X    MARK    from;    /* where to start inserting text */
  2058. X    MARK    to;    /* extent of text to delete */
  2059. X    int    when;    /* either WHEN_VIINP or WHEN_VIREP */
  2060. X{
  2061. X    char    key[2];    /* key char followed by '\0' char */
  2062. X    char    *build;    /* used in building a newline+indent string */
  2063. X    char    *scan;    /* used while looking at the indent chars of a line */
  2064. X    MARK    m;    /* some place in the text */
  2065. X#ifndef NO_EXTENSIONS
  2066. X    int    quit = FALSE;    /* boolean: are we exiting after this? */
  2067. X#endif
  2068. X
  2069. X#ifdef DEBUG
  2070. X    /* if "from" and "to" are reversed, complain */
  2071. X    if (from > to)
  2072. X    {
  2073. X        msg("ERROR: input(%ld:%d, %ld:%d)",
  2074. X            markline(from), markidx(from),
  2075. X            markline(to), markidx(to));
  2076. X        return MARK_UNSET;
  2077. X    }
  2078. X#endif
  2079. X
  2080. X    key[1] = 0;
  2081. X
  2082. X    /* if we're replacing text with new text, save the old stuff */
  2083. X    /* (Alas, there is no easy way to save text for replace mode) */
  2084. X    if (from != to)
  2085. X    {
  2086. X        cut(from, to);
  2087. X    }
  2088. X
  2089. X    ChangeText
  2090. X    {
  2091. X        /* if doing a dot command, then reuse the previous text */
  2092. X        if (doingdot)
  2093. X        {
  2094. X            /* delete the text that's there now */
  2095. X            if (from != to)
  2096. X            {
  2097. X                delete(from, to);
  2098. X            }
  2099. X
  2100. X            /* insert the previous text */
  2101. X            cutname('.');
  2102. X            cursor = paste(from, FALSE, TRUE) + 1L;
  2103. X        }
  2104. X        else /* interactive version */
  2105. X        {
  2106. X            /* if doing a change within the line... */
  2107. X            if (from != to && markline(from) == markline(to))
  2108. X            {
  2109. X                /* mark the end of the text with a "$" */
  2110. X                change(to - 1, to, "$");
  2111. X            }
  2112. X            else
  2113. X            {
  2114. X                /* delete the old text right off */
  2115. X                if (from != to)
  2116. X                {
  2117. X                    delete(from, to);
  2118. X                }
  2119. X                to = from;
  2120. X            }
  2121. X
  2122. X            /* handle autoindent of the first line, maybe */
  2123. X            cursor = from;
  2124. X            if (*o_autoindent && markline(cursor) > 1L && markidx(cursor) == 0)
  2125. X            {
  2126. X                /* Only autoindent blank lines. */
  2127. X                pfetch(markline(cursor));
  2128. X                if (plen == 0)
  2129. X                {
  2130. X                    /* Okay, we really want to autoindent */
  2131. X                    pfetch(markline(cursor) - 1L);
  2132. X                    for (scan = ptext, build = tmpblk.c;
  2133. X                         *scan == ' ' || *scan == '\t';
  2134. X                         )
  2135. X                    {
  2136. X                        *build++ = *scan++;
  2137. X                    }
  2138. X                    if (build > tmpblk.c)
  2139. X                    {
  2140. X                        *build = '\0';
  2141. X                        add(cursor, tmpblk.c);
  2142. X                        cursor += (build - tmpblk.c);
  2143. X                    }
  2144. X                }
  2145. X            }
  2146. X
  2147. X            /* repeatedly add characters from the user */
  2148. X            for (;;)
  2149. X            {
  2150. X                /* Get a character */
  2151. X                redraw(cursor, TRUE);
  2152. X#ifdef DEBUG
  2153. X                msg("cursor=%ld.%d, to=%ld.%d",
  2154. X                    markline(cursor), markidx(cursor),
  2155. X                    markline(to), markidx(to));
  2156. X#endif
  2157. X                key[0] = getkey(when);
  2158. X
  2159. X                /* if whitespace & wrapmargin is set & we're
  2160. X                 * past the warpmargin, then change the
  2161. X                 * whitespace character into a newline
  2162. X                 */
  2163. X                if ((*key == ' ' || *key == '\t')
  2164. X                 && *o_wrapmargin != 0)
  2165. X                {
  2166. X                    pfetch(markline(cursor));
  2167. X                    if (idx2col(cursor, ptext, TRUE) > COLS - (*o_wrapmargin & 0xff))
  2168. X                    {
  2169. X                        *key = '\n';
  2170. X                    }
  2171. X                }
  2172. X
  2173. X                /* process it */
  2174. X                switch (*key)
  2175. X                {
  2176. X#ifndef NO_EXTENSIONS
  2177. X                  case 0: /* special movement mapped keys */
  2178. X                    *key = getkey(0);
  2179. X                    switch (*key)
  2180. X                    {
  2181. X                      case 'h':    m = m_left(cursor, 0L);        break;
  2182. X                      case 'j':
  2183. X                      case 'k':    m = m_updnto(cursor, 0L, *key);    break;
  2184. X                      case 'l':    m = cursor + 1;            break;
  2185. X                      case 'b':    m = m_bword(cursor, 0L);    break;
  2186. X                      case 'w':    m = m_fword(cursor, 0L);    break;
  2187. X                      case '^':    m = m_front(cursor, 0L);    break;
  2188. X                      case '$':    m = m_rear(cursor, 0L);        break;
  2189. X                      case ctrl('B'):
  2190. X                      case ctrl('F'):
  2191. X                            m = m_scroll(cursor, 0L, *key); break;
  2192. X                      case 'x':    m = v_xchar(cursor, 0L);    break;
  2193. X                      case 'i':    m = to = from = cursor;        break;
  2194. X                      default:    m = MARK_UNSET;            break;
  2195. X                    }
  2196. X                    /* adjust the moved cursor */
  2197. X                    m = adjmove(cursor, m, (*key == 'j' || *key == 'k' ? 0x20 : 0));
  2198. X                    if (*key == '$' || (*key == 'l' && m <= cursor))
  2199. X                    {
  2200. X                        m++;
  2201. X                    }
  2202. X                    /* if the cursor is reasonable, use it */
  2203. X                    if (m == MARK_UNSET)
  2204. X                    {
  2205. X                        beep();
  2206. X                    }
  2207. X                    else
  2208. X                    {
  2209. X                        if (to > cursor)
  2210. X                        {
  2211. X                            delete(cursor, to);
  2212. X                            redraw(cursor, TRUE);
  2213. X                        }
  2214. X                        from = to = cursor = m;
  2215. X                    }
  2216. X                    break;
  2217. X
  2218. X                  case ctrl('Z'):
  2219. X                    if (getkey(0) == ctrl('Z'))
  2220. X                    {
  2221. X                        quit = TRUE;
  2222. X                        goto BreakBreak;
  2223. X                    }
  2224. X                    break;
  2225. X#endif
  2226. X
  2227. X                  case ctrl('['):
  2228. X#ifndef NO_ABBR
  2229. X                    cursor = expandabbr(cursor, ctrl('['));
  2230. X#endif
  2231. X                    goto BreakBreak;
  2232. X
  2233. X                  case ctrl('U'):
  2234. X                    if (markline(cursor) == markline(from))
  2235. X                    {
  2236. X                        cursor = from;
  2237. X                    }
  2238. X                    else
  2239. X                    {
  2240. X                        cursor &= ~(BLKSIZE - 1);
  2241. X                    }
  2242. X                    break;
  2243. X
  2244. X                  case ctrl('D'):
  2245. X                  case ctrl('T'):
  2246. X                    if (to > cursor)
  2247. X                    {
  2248. X                        delete(cursor, to);
  2249. X                    }
  2250. X                    mark[27] = cursor;
  2251. X                    cmd_shift(cursor, cursor, *key == ctrl('D') ? CMD_SHIFTL : CMD_SHIFTR, TRUE, "");
  2252. X                    if (mark[27])
  2253. X                    {
  2254. X                        cursor = mark[27];
  2255. X                    }
  2256. X                    else
  2257. X                    {
  2258. X                        cursor = m_front(cursor, 0L);
  2259. X                    }
  2260. X                    to = cursor;
  2261. X                    break;
  2262. X
  2263. X                  case '\b':
  2264. X                    if (cursor <= from)
  2265. X                    {
  2266. X                        beep();
  2267. X                    }
  2268. X                    else if (markidx(cursor) == 0)
  2269. X                    {
  2270. X                        cursor -= BLKSIZE;
  2271. X                        pfetch(markline(cursor));
  2272. X                        cursor += plen;
  2273. X                    }
  2274. X                    else
  2275. X                    {
  2276. X                        cursor--;
  2277. X                    }
  2278. X                    break;
  2279. X
  2280. X                  case ctrl('W'):
  2281. X                    m = m_bword(cursor, 1L);
  2282. X                    if (markline(m) == markline(cursor) && m >= from)
  2283. X                    {
  2284. X                        cursor = m;
  2285. X                        if (from > cursor)
  2286. X                        {
  2287. X                            from = cursor;
  2288. X                        }
  2289. X                    }
  2290. X                    else
  2291. X                    {
  2292. X                        beep();
  2293. X                    }
  2294. X                    break;
  2295. X
  2296. X                  case '\n':
  2297. X#if OSK
  2298. X                  case '\l':
  2299. X#else                  
  2300. X                  case '\r':
  2301. X#endif
  2302. X#ifndef NO_ABBR
  2303. X                    cursor = expandabbr(cursor, '\n');
  2304. X#endif
  2305. X                    build = tmpblk.c;
  2306. X                    *build++ = '\n';
  2307. X                    if (*o_autoindent)
  2308. X                    {
  2309. X                        /* figure out indent for next line */
  2310. X                        pfetch(markline(cursor));
  2311. X                        for (scan = ptext; *scan == ' ' || *scan == '\t'; )
  2312. X                        {
  2313. X                            *build++ = *scan++;
  2314. X                        }
  2315. X
  2316. X                        /* remove indent from this line, if blank */
  2317. X                        if (!*scan && plen > 0)
  2318. X                        {
  2319. X                            to = cursor &= ~(BLKSIZE - 1);
  2320. X                            delete(cursor, cursor + plen);
  2321. X                        }
  2322. X                    }
  2323. X                    *build = 0;
  2324. X                    if (cursor >= to && when != WHEN_VIREP)
  2325. X                    {
  2326. X                        add(cursor, tmpblk.c);
  2327. X                    }
  2328. X                    else
  2329. X                    {
  2330. X                        change(cursor, to, tmpblk.c);
  2331. X                    }
  2332. X                    redraw(cursor, TRUE);
  2333. X                    to = cursor = (cursor & ~(BLKSIZE - 1))
  2334. X                            + BLKSIZE
  2335. X                            + (int)(build - tmpblk.c) - 1;
  2336. X                    break;
  2337. X
  2338. X                  case ctrl('A'):
  2339. X                  case ctrl('P'):
  2340. X                    if (cursor < to)
  2341. X                    {
  2342. X                        delete(cursor, to);
  2343. X                    }
  2344. X                    if (*key == ctrl('A'))
  2345. X                    {
  2346. X                        cutname('.');
  2347. X                    }
  2348. X                    to = cursor = paste(cursor, FALSE, TRUE) + 1L;
  2349. X                    break;
  2350. X
  2351. X                  case ctrl('V'):
  2352. X                    if (cursor >= to && when != WHEN_VIREP)
  2353. X                    {
  2354. X                        add(cursor, "^");
  2355. X                    }
  2356. X                    else
  2357. X                    {
  2358. X                        change(cursor, to, "^");
  2359. X                        to = cursor + 1;
  2360. X                    }
  2361. X                    redraw(cursor, TRUE);
  2362. X                    *key = getkey(0);
  2363. X                    if (*key == '\n')
  2364. X                    {
  2365. X                        /* '\n' too hard to handle */
  2366. X#if OSK
  2367. X                        *key = '\l';
  2368. X#else
  2369. X                        *key = '\r';
  2370. X#endif
  2371. X                    }
  2372. X                    change(cursor, cursor + 1, key);
  2373. X                    cursor++;
  2374. X                    if (cursor > to)
  2375. X                    {
  2376. X                        to = cursor;
  2377. X                    }
  2378. X                    break;
  2379. X
  2380. X                  case ctrl('L'):
  2381. X                  case ctrl('R'):
  2382. X                    redraw(MARK_UNSET, FALSE);
  2383. X                    break;
  2384. X
  2385. X                  default:
  2386. X                    if (cursor >= to && when != WHEN_VIREP)
  2387. X                    {
  2388. X#ifndef NO_ABBR
  2389. X                        cursor = expandabbr(cursor, *key);
  2390. X#endif
  2391. X                        add(cursor, key);
  2392. X                        cursor++;
  2393. X                        to = cursor;
  2394. X                    }
  2395. X                    else
  2396. X                    {
  2397. X                        pfetch(markline(cursor));
  2398. X                        if (markidx(cursor) == plen)
  2399. X                        {
  2400. X#ifndef NO_ABBR
  2401. X                            cursor = expandabbr(cursor, *key);
  2402. X#endif
  2403. X                            add(cursor, key);
  2404. X                        }
  2405. X                        else
  2406. X                        {
  2407. X#ifndef NO_DIGRAPH
  2408. X                            *key = digraph(ptext[markidx(cursor)], *key);
  2409. X#endif
  2410. X#ifndef NO_ABBR
  2411. X                            cursor = expandabbr(cursor, *key);
  2412. X#endif
  2413. X                            change(cursor, cursor + 1, key);
  2414. X                        }
  2415. X                        cursor++;
  2416. X                    }
  2417. X#ifndef NO_SHOWMATCH
  2418. X                    /* show matching "({[" if neceesary */
  2419. X                    if (*o_showmatch && strchr(")}]", *key))
  2420. X                    {
  2421. X                        redraw(cursor, TRUE);
  2422. X                        m = m_match(cursor - 1, 0L);
  2423. X                        if (markline(m) >= topline
  2424. X                         && markline(m) <= botline)
  2425. X                        {
  2426. X                            redraw(m, TRUE);
  2427. X                            refresh();
  2428. X                            sleep(1);
  2429. X                        }
  2430. X                    }
  2431. X#endif
  2432. X                } /* end switch(*key) */
  2433. X            } /* end for(;;) */
  2434. XBreakBreak:;
  2435. X
  2436. X            /* delete any excess characters */
  2437. X            if (cursor < to)
  2438. X            {
  2439. X                delete(cursor, to);
  2440. X            }
  2441. X
  2442. X        } /* end if doingdot else */
  2443. X
  2444. X    } /* end ChangeText */
  2445. X
  2446. X    /* put the new text into a cut buffer for possible reuse */
  2447. X    if (!doingdot)
  2448. X    {
  2449. X        blksync();
  2450. X        cutname('.');
  2451. X        cut(from, cursor);
  2452. X    }
  2453. X
  2454. X    /* move to last char that we inputted, unless it was newline */
  2455. X    if (markidx(cursor) != 0)
  2456. X    {
  2457. X        cursor--;
  2458. X    }
  2459. X    redraw(cursor, FALSE);
  2460. X
  2461. X#ifndef NO_EXTENSIONS
  2462. X    if (quit)
  2463. X    {
  2464. X        /* if this is a nested "do", then cut it short */
  2465. X        abortdo();
  2466. X
  2467. X        /* exit, unless we can't write out the file */
  2468. X        cursor = v_xit(cursor, 0L, 'Z');
  2469. X    }
  2470. X#endif
  2471. X
  2472. X    rptlines = 0L;
  2473. X    return cursor;
  2474. X}
  2475. eof
  2476. if test `wc -c <input.c` -ne 16368
  2477. then
  2478. echo input.c damaged!
  2479. fi
  2480. fi
  2481.  
  2482. if test -f main.c -a "$1" != -f
  2483. then
  2484. echo Will not overwrite main.c
  2485. else
  2486. echo Extracting main.c
  2487. sed 's/^X//' >main.c <<\eof
  2488. X/* main.c */
  2489. X
  2490. X/* Author:
  2491. X *    Steve Kirkendall
  2492. X *    14407 SW Teal Blvd. #C
  2493. X *    Beaverton, OR 97005
  2494. X *    kirkenda@cs.pdx.edu
  2495. X */
  2496. X
  2497. X
  2498. X/* This file contains the main() function of vi */
  2499. X
  2500. X#include "config.h"
  2501. X#include <signal.h>
  2502. X#include <setjmp.h>
  2503. X#include "vi.h"
  2504. X
  2505. Xextern        trapint(); /* defined below */
  2506. Xextern char    *getenv();
  2507. Xjmp_buf        jmpenv;
  2508. X
  2509. X#ifndef NO_DIGRAPH
  2510. Xstatic init_digraphs();
  2511. X#endif
  2512. X
  2513. X/*---------------------------------------------------------------------*/
  2514. X
  2515. Xvoid main(argc, argv)
  2516. X    int    argc;
  2517. X    char    *argv[];
  2518. X{
  2519. X    int    i;
  2520. X    char    *cmd = (char *)0;
  2521. X    char    *tag = (char *)0;
  2522. X    char    *err = (char *)0;
  2523. X    char    *str;
  2524. X#if MSDOS || TOS
  2525. X    char firstarg[256];
  2526. X#else
  2527. X    char *firstarg;
  2528. X#endif
  2529. X
  2530. X    /* set mode to MODE_VI or MODE_EX depending on program name */
  2531. X    switch (argv[0][strlen(argv[0]) - 1])
  2532. X    {
  2533. X      case 'x':            /* "ex" */
  2534. X        mode = MODE_EX;
  2535. X        break;
  2536. X
  2537. X      case 'w':            /* "view" */
  2538. X        mode = MODE_VI;
  2539. X        *o_readonly = TRUE;
  2540. X        break;
  2541. X#ifndef NO_EXTENSIONS
  2542. X      case 't':            /* "edit" or "input" */
  2543. X        mode = MODE_VI;
  2544. X        *o_inputmode = TRUE;
  2545. X        break;
  2546. X#endif
  2547. X      default:            /* "vi" or "elvis" */
  2548. X        mode = MODE_VI;
  2549. X    }
  2550. X
  2551. X#ifndef DEBUG
  2552. X# ifdef    SIGQUIT
  2553. X    /* normally, we ignore SIGQUIT.  SIGINT is trapped later */
  2554. X    signal(SIGQUIT, SIG_IGN);
  2555. X# endif
  2556. X#endif
  2557. X
  2558. X    /* temporarily ignore SIGINT */
  2559. X    signal(SIGINT, SIG_IGN);
  2560. X
  2561. X    /* start curses */
  2562. X    initscr();
  2563. X    cbreak();
  2564. X    noecho();
  2565. X    scrollok(stdscr, TRUE);
  2566. X
  2567. X    /* initialize the options */
  2568. X    initopts();
  2569. X
  2570. X    /* map the arrow keys.  The KU,KD,KL,and KR variables correspond to
  2571. X     * the :ku=: (etc.) termcap capabilities.  The variables are defined
  2572. X     * as part of the curses package.
  2573. X     */
  2574. X    if (has_KU) mapkey(has_KU, "k",    WHEN_VICMD|WHEN_INMV, "<Up>");
  2575. X    if (has_KD) mapkey(has_KD, "j",    WHEN_VICMD|WHEN_INMV, "<Down>");
  2576. X    if (has_KL) mapkey(has_KL, "h",    WHEN_VICMD|WHEN_INMV, "<Left>");
  2577. X    if (has_KR) mapkey(has_KR, "l",    WHEN_VICMD|WHEN_INMV, "<Right>");
  2578. X    if (has_HM) mapkey(has_HM, "^",    WHEN_VICMD|WHEN_INMV, "<Home>");
  2579. X    if (has_EN) mapkey(has_EN, "$",    WHEN_VICMD|WHEN_INMV, "<End>");
  2580. X    if (has_PU) mapkey(has_PU, "\002", WHEN_VICMD|WHEN_INMV, "<PgUp>");
  2581. X    if (has_PD) mapkey(has_PD, "\006", WHEN_VICMD|WHEN_INMV, "<PgDn>");
  2582. X#if MSDOS
  2583. X    if (*o_pcbios)
  2584. X    {
  2585. X        mapkey("#R", "i", WHEN_VICMD|WHEN_INMV,    "<Insrt>");
  2586. X        mapkey("#S", "x", WHEN_VICMD|WHEN_INMV,    "<Del>");
  2587. X        mapkey("#s", "B", WHEN_VICMD|WHEN_INMV,    "^<left>");
  2588. X        mapkey("#t", "W", WHEN_VICMD|WHEN_INMV,    "^<right>");
  2589. X    }
  2590. X#else
  2591. X    if (ERASEKEY != '\177')
  2592. X    {
  2593. X        mapkey("\177", "x", WHEN_VICMD|WHEN_INMV, "<Del>");
  2594. X    }
  2595. X#endif
  2596. X
  2597. X#ifndef NO_DIGRAPH
  2598. X    init_digraphs();
  2599. X#endif /* NO_DIGRAPH */
  2600. X
  2601. X    /* process any flags */
  2602. X    for (i = 1; i < argc && *argv[i] == '-'; i++)
  2603. X    {
  2604. X        switch (argv[i][1])
  2605. X        {
  2606. X          case 'R':    /* readonly */
  2607. X            *o_readonly = TRUE;
  2608. X            break;
  2609. X
  2610. X          case 'r':    /* recover */
  2611. X            msg("Use the `virec` program to recover lost files");
  2612. X            endmsgs();
  2613. X            refresh();
  2614. X            endwin();
  2615. X            exit(0);
  2616. X            break;
  2617. X
  2618. X          case 't':    /* tag */
  2619. X            if (argv[i][2])
  2620. X            {
  2621. X                tag = argv[i] + 2;
  2622. X            }
  2623. X            else
  2624. X            {
  2625. X                i++;
  2626. X                tag = argv[i];
  2627. X            }
  2628. X            break;
  2629. X
  2630. X          case 'v':    /* vi mode */
  2631. X            mode = MODE_VI;
  2632. X            break;
  2633. X
  2634. X          case 'e':    /* ex mode */
  2635. X            mode = MODE_EX;
  2636. X            break;
  2637. X#ifndef NO_EXTENSIONS
  2638. X          case 'i':    /* input mode */
  2639. X            *o_inputmode = TRUE;
  2640. X            break;
  2641. X#endif
  2642. X#ifndef NO_ERRLIST
  2643. X          case 'm':    /* use "errlist" as the errlist */
  2644. X            if (argv[i][2])
  2645. X            {
  2646. X                err = argv[i] + 2;
  2647. X            }
  2648. X            else if (i + 1 < argc)
  2649. X            {
  2650. X                i++;
  2651. X                err = argv[i];
  2652. X            }
  2653. X            else
  2654. X            {
  2655. X                err = "";
  2656. X            }
  2657. X            break;
  2658. X#endif
  2659. X          default:
  2660. X            msg("Ignoring unknown flag \"%s\"", argv[i]);
  2661. X        }
  2662. X    }
  2663. X
  2664. X    /* if we were given an initial ex command, save it... */
  2665. X    if (i < argc && *argv[i] == '+')
  2666. X    {
  2667. X        if (argv[i][1])
  2668. X        {
  2669. X            cmd = argv[i++] + 1;
  2670. X        }
  2671. X        else
  2672. X        {
  2673. X            cmd = "$"; /* "vi + file" means start at EOF */
  2674. X            i++;
  2675. X        }
  2676. X    }
  2677. X
  2678. X    /* the remaining args are file names. */
  2679. X    nargs = argc - i;
  2680. X    if (nargs > 0)
  2681. X    {
  2682. X#if ! ( MSDOS || TOS )
  2683. X        firstarg = argv[i];
  2684. X#endif
  2685. X        strcpy(args, argv[i]);
  2686. X        while (++i < argc && strlen(args) + 1 + strlen(argv[i]) < sizeof args)
  2687. X        {
  2688. X            strcat(args, " ");
  2689. X            strcat(args, argv[i]);
  2690. X        }
  2691. X    }
  2692. X#if ! ( MSDOS || TOS )
  2693. X    else
  2694. X    {
  2695. X        firstarg = "";
  2696. X    }
  2697. X#endif
  2698. X    argno = 0;
  2699. X
  2700. X#if MSDOS || TOS
  2701. X    if (nargs > 0)
  2702. X    {
  2703. X        strcpy(args, wildcard(args));
  2704. X        nargs = 1;
  2705. X        for (i = 0; args[i]; i++)
  2706. X        {
  2707. X            if (args[i] == ' ')
  2708. X            {
  2709. X                nargs++;
  2710. X            }
  2711. X        }
  2712. X        for (i = 0; args[i] && args[i] != ' '; i++)
  2713. X        {
  2714. X            firstarg[i] = args[i];
  2715. X        }
  2716. X        firstarg[i] = '\0';
  2717. X    }
  2718. X    else
  2719. X    {
  2720. X        firstarg[0] = '\0';
  2721. X    }
  2722. X#endif
  2723. X
  2724. X    /* perform the .exrc files and EXINIT environment variable */
  2725. X#ifdef SYSEXRC
  2726. X    doexrc(SYSEXRC);
  2727. X#endif
  2728. X#ifdef HMEXRC
  2729. X    str = getenv("HOME");
  2730. X    if (str)
  2731. X    {
  2732. X        sprintf(tmpblk.c, "%s%c%s", str, SLASH, HMEXRC);
  2733. X        doexrc(tmpblk.c);
  2734. X    }
  2735. X#endif
  2736. X    doexrc(EXRC);
  2737. X#ifdef EXINIT
  2738. X    str = getenv(EXINIT);
  2739. X    if (str)
  2740. X    {
  2741. X        exstring(str, strlen(str));
  2742. X    }
  2743. X#endif
  2744. X
  2745. X    /* search for a tag (or an error) now, if desired */
  2746. X    blkinit();
  2747. X    if (tag)
  2748. X    {
  2749. X        cmd_tag(MARK_FIRST, MARK_FIRST, CMD_TAG, 0, tag);
  2750. X    }
  2751. X#ifndef NO_ERRLIST
  2752. X    else if (err)
  2753. X    {
  2754. X        cmd_errlist(MARK_FIRST, MARK_FIRST, CMD_ERRLIST, 0, err);
  2755. X    }
  2756. X#endif
  2757. X
  2758. X    /* if no tag/err, or tag failed, then start with first arg */
  2759. X    if (tmpfd < 0 && tmpstart(firstarg) == 0 && *origname)
  2760. X    {
  2761. X        ChangeText
  2762. X        {
  2763. X        }
  2764. X        clrflag(file, MODIFIED);
  2765. X    }
  2766. X
  2767. X    /* now we do the immediate ex command that we noticed before */
  2768. X    if (cmd)
  2769. X    {
  2770. X        doexcmd(cmd);
  2771. X    }
  2772. X
  2773. X    /* repeatedly call ex() or vi() (depending on the mode) until the
  2774. X     * mode is set to MODE_QUIT
  2775. X     */
  2776. X    while (mode != MODE_QUIT)
  2777. X    {
  2778. X        if (setjmp(jmpenv))
  2779. X        {
  2780. X            /* Maybe we just aborted a change? */
  2781. X            abortdo();
  2782. X        }
  2783. X#if TURBOC
  2784. X        signal(SIGINT, (void(*)()) trapint);
  2785. X#else
  2786. X        signal(SIGINT, trapint);
  2787. X#endif
  2788. X
  2789. X        switch (mode)
  2790. X        {
  2791. X          case MODE_VI:
  2792. X            vi();
  2793. X            break;
  2794. X
  2795. X          case MODE_EX:
  2796. X            ex();
  2797. X            break;
  2798. X#ifdef DEBUG
  2799. X          default:
  2800. X            msg("mode = %d?", mode);
  2801. X            mode = MODE_QUIT;
  2802. X#endif
  2803. X        }
  2804. X    }
  2805. X
  2806. X    /* free up the cut buffers */
  2807. X    cutend();
  2808. X
  2809. X    /* end curses */
  2810. X#ifndef    NO_CURSORSHAPE
  2811. X    if (has_CQ)
  2812. X        do_CQ();
  2813. X#endif
  2814. X    endmsgs();
  2815. X    move(LINES - 1, 0);
  2816. X    clrtoeol();
  2817. X    refresh();
  2818. X    endwin();
  2819. X
  2820. X    exit(0);
  2821. X    /*NOTREACHED*/
  2822. X}
  2823. X
  2824. X
  2825. X/*ARGSUSED*/
  2826. Xint trapint(signo)
  2827. X    int    signo;
  2828. X{
  2829. X    resume_curses(FALSE);
  2830. X    abortdo();
  2831. X#if OSK
  2832. X    sigmask(-1);
  2833. X#endif
  2834. X#if TURBO_C
  2835. X    signal(signo, (void (*)())trapint);
  2836. X#else
  2837. X    signal(signo, trapint);
  2838. X#endif
  2839. X    longjmp(jmpenv, 1);
  2840. X
  2841. X    return 0;
  2842. X}
  2843. X
  2844. X
  2845. X#ifndef NO_DIGRAPH
  2846. X
  2847. X/* This stuff us used to build the default digraphs table. */
  2848. Xstatic char    digtable[][4] =
  2849. X{
  2850. X# if CS_IBMPC
  2851. X    "C,\200",    "u\"\1",    "e'\2",        "a^\3",
  2852. X    "a\"\4",    "a`\5",        "a@\6",        "c,\7",
  2853. X    "e^\10",    "e\"\211",    "e`\12",    "i\"\13",
  2854. X    "i^\14",    "i`\15",    "A\"\16",    "A@\17",
  2855. X    "E'\20",    "ae\21",    "AE\22",    "o^\23",
  2856. X    "o\"\24",    "o`\25",    "u^\26",    "u`\27",
  2857. X    "y\"\30",    "O\"\31",    "U\"\32",    "a'\240",
  2858. X    "i'!",        "o'\"",        "u'#",        "n~$",
  2859. X    "N~%",        "a-&",        "o-'",        "~?(",
  2860. X    "~!-",        "\"<.",        "\">/",
  2861. X#  if CS_SPECIAL
  2862. X    "2/+",        "4/,",        "^+;",        "^q<",
  2863. X    "^c=",        "^r>",        "^t?",        "pp]",
  2864. X    "^^^",        "oo_",        "*a`",        "*ba",
  2865. X    "*pc",        "*Sd",        "*se",        "*uf",
  2866. X    "*tg",        "*Ph",        "*Ti",        "*Oj",
  2867. X    "*dk",        "*Hl",        "*hm",        "*En",
  2868. X    "*No",        "eqp",        "pmq",        "ger",
  2869. X    "les",        "*It",        "*iu",        "*/v",
  2870. X    "*=w",        "sq{",        "^n|",        "^2}",
  2871. X    "^3~",        "^_\377",
  2872. X#  endif /* CS_SPECIAL */
  2873. X# endif /* CS_IBMPC */
  2874. X# if CS_LATIN1
  2875. X    "~!!",        "a-*",        "\">+",        "o-:",
  2876. X    "\"<>",        "~??",
  2877. X
  2878. X    "A`@",        "A'A",        "A^B",        "A~C",
  2879. X    "A\"D",        "A@E",        "AEF",        "C,G",
  2880. X    "E`H",        "E'I",        "E^J",        "E\"K",
  2881. X    "I`L",        "I'M",        "I^N",        "I\"O",
  2882. X    "-DP",        "N~Q",        "O`R",        "O'S",
  2883. X    "O^T",        "O~U",        "O\"V",        "O/X",
  2884. X    "U`Y",        "U'Z",        "U^[",        "U\"\\",
  2885. X    "Y'_",
  2886. X
  2887. X    "a``",        "a'a",        "a^b",        "a~c",
  2888. X    "a\"d",        "a@e",        "aef",        "c,g",
  2889. X    "e`h",        "e'i",        "e^j",        "e\"k",
  2890. X    "i`l",        "i'm",        "i^n",        "i\"o",
  2891. X    "-dp",        "n~q",        "o`r",        "o's",
  2892. X    "o^t",        "o~u",        "o\"v",        "o/x",
  2893. X    "u`y",        "u'z",        "u^{",        "u\"|",
  2894. X    "y'~",
  2895. X# endif /* CS_LATIN1 */
  2896. X    ""
  2897. X};
  2898. X
  2899. Xstatic init_digraphs()
  2900. X{
  2901. X    int    i;
  2902. X
  2903. X    for (i = 0; *digtable[i]; i++)
  2904. X    {
  2905. X        do_digraph(FALSE, digtable[i]);
  2906. X    }
  2907. X    do_digraph(FALSE, (char *)0);
  2908. X}
  2909. X#endif /* NO_DIGRAPH */
  2910. eof
  2911. if test `wc -c <main.c` -ne 7778
  2912. then
  2913. echo main.c damaged!
  2914. fi
  2915. fi
  2916.  
  2917. if test -f misc.c -a "$1" != -f
  2918. then
  2919. echo Will not overwrite misc.c
  2920. else
  2921. echo Extracting misc.c
  2922. sed 's/^X//' >misc.c <<\eof
  2923. X/* misc.c */
  2924. X
  2925. X/* Author:
  2926. X *    Steve Kirkendall
  2927. X *    14407 SW Teal Blvd. #C
  2928. X *    Beaverton, OR 97005
  2929. X *    kirkenda@cs.pdx.edu
  2930. X */
  2931. X
  2932. X
  2933. X/* This file contains functions which didn't seem happy anywhere else */
  2934. X
  2935. X#include "config.h"
  2936. X#include "vi.h"
  2937. X
  2938. X
  2939. X/* find a particular line & return a pointer to a copy of its text */
  2940. Xchar *fetchline(line)
  2941. X    long    line;    /* line number of the line to fetch */
  2942. X{
  2943. X    int        i;
  2944. X    REG char    *scan;    /* used to search for the line in a BLK */
  2945. X    long        l;    /* line number counter */
  2946. X    static BLK    buf;    /* holds ONLY the selected line (as string) */
  2947. X    REG char    *cpy;    /* used while copying the line */
  2948. X    static long    nextline;    /* }  These four variables are used */
  2949. X    static long    chglevel;    /*  } to implement a shortcut when  */
  2950. X    static char    *nextscan;    /*  } consecutive lines are fetched */
  2951. X    static long    nextlnum;    /* }                                */
  2952. X
  2953. X    /* can we do a shortcut? */
  2954. X    if (changes == chglevel && line == nextline)
  2955. X    {
  2956. X        scan = nextscan;
  2957. X    }
  2958. X    else
  2959. X    {
  2960. X        /* scan lnum[] to determine which block its in */
  2961. X        for (i = 1; line > lnum[i]; i++)
  2962. X        {
  2963. X        }
  2964. X        nextlnum = lnum[i];
  2965. X
  2966. X        /* fetch text of the block containing that line */
  2967. X        scan = blkget(i)->c;
  2968. X
  2969. X        /* find the line in the block */
  2970. X        for (l = lnum[i - 1]; ++l < line; )
  2971. X        {
  2972. X            while (*scan++ != '\n')
  2973. X            {
  2974. X            }
  2975. X        }
  2976. X    }
  2977. X
  2978. X    /* copy it into a block by itself, with no newline */
  2979. X    for (cpy = buf.c; *scan != '\n'; )
  2980. X    {
  2981. X        *cpy++ = *scan++;
  2982. X    }
  2983. X    *cpy = '\0';
  2984. X
  2985. X    /* maybe speed up the next call to fetchline() ? */
  2986. X    if (line < nextlnum)
  2987. X    {
  2988. X        nextline = line + 1;
  2989. X        chglevel = changes;
  2990. X        nextscan = scan + 1;
  2991. X    }
  2992. X    else
  2993. X    {
  2994. X        nextline = 0;
  2995. X    }
  2996. X
  2997. X    /* Calls to fetchline() interfere with calls to pfetch().  Make sure
  2998. X     * that pfetch() resets itself on its next invocation.
  2999. X     */
  3000. X    pchgs = 0L;
  3001. X
  3002. X    /* Return a pointer to the line's text */
  3003. X    return buf.c;
  3004. X}
  3005. X
  3006. X
  3007. X/* error message from the regexp code */
  3008. Xvoid regerror(txt)
  3009. X    char    *txt;    /* an error message */
  3010. X{
  3011. X    msg("RE error: %s", txt);
  3012. X}
  3013. X
  3014. X/* This function is equivelent to the pfetch() macro */
  3015. Xvoid    pfetch(l)
  3016. X    long    l;    /* line number of line to fetch */
  3017. X{
  3018. X    if(l != pline || changes != pchgs)
  3019. X    {
  3020. X        pline = (l);
  3021. X        ptext = fetchline(pline);
  3022. X        plen = strlen(ptext);
  3023. X        pchgs = changes;
  3024. X    }
  3025. X}
  3026. eof
  3027. if test `wc -c <misc.c` -ne 2166
  3028. then
  3029. echo misc.c damaged!
  3030. fi
  3031. fi
  3032.  
  3033. exit 0
  3034. -------------------------------------------------------------------------------
  3035. Steve Kirkendall     kirkenda@cs.pdx.edu      Grad student at Portland State U.
  3036.