home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 3 / 3505 < prev    next >
Internet Message Format  |  1991-06-19  |  56KB

  1. From: pgf@cayman.COM (Paul Fox)
  2. Newsgroups: alt.sources
  3. Subject: Vile 08/17 - vi feel-alike (multi-window)
  4. Message-ID: <4527@cayman.COM>
  5. Date: 7 Jun 91 22:09:42 GMT
  6.  
  7. #!/bin/sh
  8. # this is vileshar.08 (part 8 of Vile)
  9. # do not concatenate these parts, unpack them in order with /bin/sh
  10. # file input.c continued
  11. #
  12. if test ! -r _shar_seq_.tmp; then
  13.     echo 'Please unpack part 1 first!'
  14.     exit 1
  15. fi
  16. (read Scheck
  17.  if test "$Scheck" != 8; then
  18.     echo Please unpack part "$Scheck" next!
  19.     exit 1
  20.  else
  21.     exit 0
  22.  fi
  23. ) < _shar_seq_.tmp || exit 1
  24. echo 'x - continuing file input.c'
  25. sed 's/^X//' << 'SHAR_EOF' >> 'input.c' &&
  26. X * macro throw the prompt away, and return the remembered response. This
  27. X * lets macros run at full speed. The reply is always terminated by a carriage
  28. X * return. Handle erase, kill, and abort keys.
  29. X */
  30. X
  31. mlreply(prompt, buf, bufn)
  32. char *prompt;
  33. char *buf;
  34. {
  35. X    return kbd_string(prompt, buf, bufn, '\n',EXPAND);
  36. }
  37. X
  38. /* as above, but don't expand special punctuation, like #, %, ~, etc. */
  39. mlreply_no_exp(prompt, buf, bufn)
  40. char *prompt;
  41. char *buf;
  42. {
  43. X    return kbd_string(prompt, buf, bufn, '\n',NO_EXPAND);
  44. }
  45. X
  46. /*    kcod2key:    translate 10-bit keycode to single key value */
  47. /* probably defined as a macro in estruct.h */
  48. #ifndef kcod2key
  49. kcod2key(c)
  50. int c;
  51. {
  52. X    return c & 0x7f;
  53. }
  54. #endif
  55. X
  56. X
  57. /* the numbered buffer names increment each time they are referenced */
  58. incr_dot_kregnum()
  59. {
  60. X    if (dotcmdmode == PLAY) {
  61. X        if (isdigit(*dotcmdptr) && *dotcmdptr < '9')
  62. X            (*dotcmdptr)++;
  63. X    }
  64. }
  65. X
  66. int tungotc = -1;
  67. X
  68. tungetc(c)
  69. {
  70. X    tungotc = c;
  71. }
  72. X
  73. tpeekc()
  74. {
  75. X    return tungotc;
  76. }
  77. X
  78. /*    tgetc:    Get a key from the terminal driver, resolve any keyboard
  79. X        macro action                    */
  80. int 
  81. tgetc()
  82. {
  83. X    int c;    /* fetched character */
  84. X
  85. X    if (dotcmdmode == PLAY) {
  86. X        
  87. X        if (interrupted) {
  88. X            dotcmdmode = STOP;
  89. X            return (kcod2key(abortc));
  90. X        }
  91. X
  92. X        /* if there is some left... */
  93. X        if (dotcmdptr < dotcmdend)
  94. X            return(*dotcmdptr++);
  95. X
  96. X        /* at the end of last repitition? */
  97. X        if (--dotcmdrep < 1) {
  98. X            dotcmdmode = RECORD;
  99. X            tmpcmdptr = &tmpcmdm[0];
  100. X            tmpcmdend = tmpcmdptr;
  101. #if    VISMAC == 0
  102. X            /* force a screen update after all is done */
  103. X            update(FALSE);
  104. #endif
  105. X        } else {
  106. X
  107. X            /* reset the macro to the begining for the next rep */
  108. X            dotcmdptr = &dotcmdm[0];
  109. X            return((int)*dotcmdptr++);
  110. X        }
  111. X    } else if (kbdmode == PLAY) {
  112. X    /* if we are playing a keyboard macro back, */
  113. X
  114. X        /* if there is some left... */
  115. X        if (kbdptr < kbdend)
  116. X            return((int)*kbdptr++);
  117. X
  118. X        /* at the end of last repitition? */
  119. X        if (--kbdrep < 1) {
  120. X            kbdmode = STOP;
  121. #if    VISMAC == 0
  122. X            /* force a screen update after all is done */
  123. X            update(FALSE);
  124. #endif
  125. X        } else {
  126. X
  127. X            /* reset the macro to the begining for the next rep */
  128. X            kbdptr = &kbdm[0];
  129. X            return((int)*kbdptr++);
  130. X        }
  131. X    }
  132. X
  133. X
  134. X    if (tungotc >= 0) {
  135. X        c = tungotc;
  136. X        tungotc = -1;
  137. X    } else { /* fetch a character from the terminal driver */
  138. X        interrupted = 0;
  139. X        c = TTgetc();
  140. X        if (c == -1 || c == kcod2key(intrc)) {
  141. X            c = kcod2key(abortc);
  142. X            return lastkey = c;
  143. X        }
  144. X    }
  145. X
  146. X    /* save it if we need to */
  147. X    if (dotcmdmode == RECORD) {
  148. X        *tmpcmdptr++ = c;
  149. X        tmpcmdend = tmpcmdptr;
  150. X
  151. X        /* don't overrun the buffer  */
  152. X        /* (we're recording, so must be using tmp) */
  153. X        if (tmpcmdptr == &tmpcmdm[NKBDM - 1]) {
  154. X            dotcmdmode = STOP;
  155. X            TTbeep();
  156. X        }
  157. X    }
  158. X
  159. X    /* save it if we need to */
  160. X    if (kbdmode == RECORD) {
  161. X        *kbdptr++ = c;
  162. X        kbdend = kbdptr;
  163. X
  164. X        /* don't overrun the buffer */
  165. X        if (kbdptr == &kbdm[NKBDM - 1]) {
  166. X            kbdmode = STOP;
  167. X            TTbeep();
  168. X        }
  169. X    }
  170. X
  171. X    /* and finally give the char back */
  172. X    /* record it for $lastkey */
  173. X    return(lastkey = c);
  174. }
  175. X
  176. /*    KBD_KEY:    Get one keystroke. The only prefix legal here
  177. X            is the SPEC prefix.  */
  178. kbd_key()
  179. {
  180. X    int    c;
  181. X
  182. X    /* get a keystroke */
  183. X        c = tgetc();
  184. X
  185. #if    MSDOS | ST520
  186. X    if (c == 0) {            /* Apply SPEC prefix    */
  187. X            c = tgetc();
  188. X        if (insertmode) continue;
  189. X        return(last1key = SPEC | c);
  190. X    }
  191. #endif
  192. X
  193. #if    AMIGA
  194. X    /* apply SPEC prefix */
  195. X    if ((unsigned)c == 155) {
  196. X        int    d;
  197. X        c = tgetc();
  198. X
  199. X        /* first try to see if it is a cursor key */
  200. X        if ((c >= 'A' && c <= 'D') || c == 'S' || c == 'T') {
  201. X            if (insertmode) continue;
  202. X            return(last1key = SPEC | c);
  203. X        }
  204. X
  205. X        /* next, a 2 char sequence */
  206. X        d = tgetc();
  207. X        if (d == '~') {
  208. X            if (insertmode) continue;
  209. X            return(last1key = SPEC | c);
  210. X        }
  211. X
  212. X        /* decode a 3 char sequence */
  213. X        c = d + ' ';
  214. X        /* if a shifted function key, eat the tilde */
  215. X        if (d >= '0' && d <= '9')
  216. X            d = tgetc();
  217. X        if (insertmode) continue;
  218. X        return(last1key = SPEC | c);
  219. X    }
  220. #endif
  221. X
  222. #if  WANGPC
  223. X    if (c == 0x1F) {    /* Apply SPEC prefix    */
  224. X            c = tgetc();
  225. X        if (insertmode) continue;
  226. X        return(last1key = SPEC | c);
  227. X    }
  228. #endif
  229. X
  230. X        return (last1key = c);
  231. }
  232. X
  233. /*    KBD_SEQ:    Get a command sequence (multiple keystrokes) from 
  234. X        the keyboard.
  235. X        Process all applicable prefix keys.
  236. X        Set lastcmd for commands which want stuttering.
  237. */
  238. kbd_seq()
  239. {
  240. X    int c;        /* fetched keystroke */
  241. X
  242. X    /* get initial character */
  243. X    c = kbd_key();
  244. X
  245. X    /* process CTLA prefix */
  246. X    if (c == cntl_a) {
  247. X        c = kbd_key();
  248. #if BEFORE
  249. X            if (islower(c))        /* Force to upper */
  250. X                    c = toupper(c);
  251. #endif
  252. X        return (lastcmd = CTLA | c);
  253. X    }
  254. X
  255. X    /* process CTLX prefix */
  256. X    if (c == cntl_x) {
  257. X        c = kbd_key();
  258. X        return (lastcmd = CTLX | c);
  259. X    }
  260. X
  261. X    /* otherwise, just return it */
  262. X    return (lastcmd = c);
  263. }
  264. X
  265. screen_string(buf,bufn,inclchartype)
  266. char *buf;
  267. {
  268. X    register int i = 0;
  269. X    register int s = TRUE;
  270. X
  271. X    setmark();
  272. X    while (s == TRUE && i < bufn && 
  273. X            curwp->w_doto != llength(curwp->w_dotp)) {
  274. X        buf[i] = lgetc(curwp->w_dotp, curwp->w_doto);
  275. X        if (!istype(inclchartype, buf[i]))
  276. X            break;
  277. X        s = forwchar(FALSE, 1);
  278. X        i++;
  279. X    }
  280. X    buf[i] = '\0';
  281. X    swapmark();
  282. X
  283. X    return buf[0] != '\0';
  284. }
  285. X
  286. /*    A more generalized prompt/reply function allowing the caller
  287. X    to specify a terminator other than '\n'.  Both are accepted.
  288. X    Assumes the buffer already contains a valid (possibly
  289. X    null) string to use as the default response.
  290. */
  291. kbd_string(prompt, buf, bufn, eolchar, expand)
  292. char *prompt;
  293. char *buf;
  294. int eolchar;
  295. {
  296. X    register int cpos;    /* current character position in string */
  297. X    register int c;
  298. X    register int quotef;    /* are we quoting the next char? */
  299. X    int firstchar = TRUE;
  300. X
  301. X    if (clexec)
  302. X        return nextarg(buf);
  303. X
  304. X    lineinput = TRUE;
  305. X
  306. X    cpos = 0;
  307. X    quotef = FALSE;
  308. X
  309. X
  310. X    /* prompt the user for the input string */
  311. X    mlwrite(prompt);
  312. X    /* put out the default response, which comes in already in the
  313. X        buffer */
  314. X    while((c = buf[cpos]) != '\0' && cpos < bufn-1) {
  315. X        if (!isprint(c)) {
  316. X            if (disinp)
  317. X                TTputc('^');
  318. X            ++ttcol;
  319. X            c = toalpha(c);
  320. X        }
  321. X
  322. X        if (disinp)
  323. X            TTputc(c);
  324. X        ++ttcol;
  325. X        ++cpos;
  326. X    }
  327. X    TTflush();
  328. X
  329. X    for (;;) {
  330. X        /* get a character from the user */
  331. X        c = kbd_key();
  332. X
  333. X        /* If it is a <ret>, change it to a <NL> */
  334. X        if (c == '\r' && quotef == FALSE)
  335. X            c = '\n';
  336. X
  337. X        /* if they hit the line terminate, wrap it up */
  338. X        /* don't allow newlines in the string -- they cause real
  339. X            problems, especially when searching for patterns
  340. X            containing them -pgf */
  341. X        /* never a newline, and only eolchar if ^V or \ precedes it */
  342. X        if (c == '\n' || (c == eolchar && 
  343. X            quotef == FALSE && cpos > 0 && buf[cpos-1] != '\\'))
  344. X        {
  345. X            if (buf[cpos] != '\0')
  346. X                buf[cpos++] = 0;
  347. X
  348. X            lineinput = FALSE;
  349. X            /* if buffer is empty, return FALSE */
  350. X            if (buf[0] == 0)
  351. X                return(FALSE);
  352. X
  353. X            return(TRUE);
  354. X        }
  355. X
  356. #if     NeWS    /* make sure cursor is where we think it is before output */
  357. X        TTmove(ttrow,ttcol) ;
  358. #endif
  359. X        /* change from command form back to character form */
  360. X        c = kcod2key(c);
  361. X        
  362. X        if (c == kcod2key(abortc) && quotef == FALSE) {
  363. X            buf[cpos] = 0;
  364. X            esc(FALSE, 0);
  365. X            TTflush();
  366. X            lineinput = FALSE;
  367. X            return ABORT;
  368. X        } else if (isbackspace(c) && quotef==FALSE) {
  369. X            /* rubout/erase */
  370. X            if (cpos != 0) {
  371. X                outstring("\b \b");
  372. X                --ttcol;
  373. X
  374. X                if (!isprint(buf[--cpos])) {
  375. X                    outstring("\b \b");
  376. X                    --ttcol;
  377. X                }
  378. X
  379. X                TTflush();
  380. X            } else {
  381. X                buf[0] = 0;
  382. X                mlerase();
  383. X                lineinput = FALSE;
  384. X                return FALSE;
  385. X            }
  386. X
  387. X        } else if (c == kcod2key(killc) && quotef == FALSE) {
  388. X            /* C-U, kill */
  389. X        killit:
  390. X            while (cpos != 0) {
  391. X                outstring("\b \b");
  392. X                --ttcol;
  393. X
  394. X                if (!isprint(buf[--cpos])) {
  395. X                    outstring("\b \b");
  396. X                    --ttcol;
  397. X                }
  398. X            }
  399. X            TTflush();
  400. X
  401. X        } else if (expand == EXPAND) {
  402. X            /* we prefer to expand to filenames, but a buffer name
  403. X                will do */
  404. X            char *cp = NULL;
  405. X            char *hist_lookup();
  406. X            if (firstchar == TRUE) {
  407. X                tungetc(c);
  408. X                goto killit;
  409. X            }
  410. X            switch(c) {
  411. X            case '%':
  412. X                cp = curbp->b_fname;
  413. X                if (!*cp || isspace(*cp))
  414. X                    cp = curbp->b_bname;
  415. X                break;
  416. X            case '#':
  417. X                cp = hist_lookup(1);  /* returns buffer name */
  418. X                if (cp) {
  419. X                    /* but we want a file */
  420. X                    BUFFER *bp;
  421. X                    bp = bfind(cp,NO_CREAT,0);
  422. X                    cp = bp->b_fname;
  423. X                    if (!*cp || isspace(*cp)) {
  424. X                        /* oh well, use the buffer */
  425. X                        cp = bp->b_bname;
  426. X                    }
  427. X                }
  428. X                break;
  429. X            /* case tocntrl('W'): */
  430. X            case ':':
  431. X                {
  432. X                char str[80];
  433. X                 if (screen_string(str, 80, _path))
  434. X                    cp = str;
  435. X                break;
  436. X                }
  437. X            default:
  438. X                goto trymore;
  439. X            }
  440. X            
  441. X            if (!cp) {
  442. X                TTbeep();
  443. X                continue;
  444. X            }
  445. X            while (cpos < bufn-1 && (c = *cp++)) {
  446. X                buf[cpos++] = c;
  447. X                if (!isprint(c)) {
  448. X                    outstring("^");
  449. X                    ++ttcol;
  450. X                    c = toalpha(c);
  451. X                }
  452. X                if (disinp)
  453. X                    TTputc(c);
  454. X                ++ttcol;
  455. X            }
  456. X            TTflush();
  457. X        } else {
  458. X        trymore:
  459. X            if (c == kcod2key(quotec) && quotef == FALSE) {
  460. X                quotef = TRUE;
  461. X            } else {
  462. X                quotef = FALSE;
  463. X                if (firstchar == TRUE) {
  464. X                    tungetc(c);
  465. X                    goto killit;
  466. X                }
  467. X                if (cpos < bufn-1) {
  468. X                    buf[cpos++] = c;
  469. X
  470. X                    if (!isprint(c)) {
  471. X                        outstring("^");
  472. X                        ++ttcol;
  473. X                        c = toalpha(c);
  474. X                    }
  475. X
  476. X                    if (disinp)
  477. X                        TTputc(c);
  478. X
  479. X                    ++ttcol;
  480. X                    TTflush();
  481. X                }
  482. X            }
  483. X        }
  484. X        firstchar = FALSE;
  485. X    }
  486. }
  487. X
  488. outstring(s)    /* output a string of input characters */
  489. char *s;    /* string to output */
  490. {
  491. X    if (disinp)
  492. X        while (*s)
  493. X            TTputc(*s++);
  494. }
  495. X
  496. ostring(s)    /* output a string of output characters */
  497. char *s;    /* string to output */
  498. {
  499. X    if (discmd)
  500. X        while (*s)
  501. X            TTputc(*s++);
  502. }
  503. SHAR_EOF
  504. echo 'File input.c is complete' &&
  505. chmod 0444 input.c ||
  506. echo 'restore of input.c failed'
  507. Wc_c="`wc -c < 'input.c'`"
  508. test 10225 -eq "$Wc_c" ||
  509.     echo 'input.c: original size 10225, current size' "$Wc_c"
  510. # ============= isearch.c ==============
  511. echo 'x - extracting isearch.c (Text)'
  512. sed 's/^X//' << 'SHAR_EOF' > 'isearch.c' &&
  513. /* vile note, 6/1/91, pgf -- I haven't tried this code in a long time */
  514. /*
  515. X * The functions in this file implement commands that perform incremental
  516. X * searches in the forward and backward directions.  This "ISearch" command
  517. X * is intended to emulate the same command from the original EMACS 
  518. X * implementation (ITS).  Contains references to routines internal to
  519. X * SEARCH.C.
  520. X *
  521. X * REVISION HISTORY:
  522. X *
  523. X *    D. R. Banks 9-May-86
  524. X *    - added ITS EMACSlike ISearch
  525. X *
  526. X *    John M. Gamble 5-Oct-86
  527. X *    - Made iterative search use search.c's scanner() routine.
  528. X *      This allowed the elimination of bakscan().
  529. X *    - Put isearch constants into estruct.h
  530. X *    - Eliminated the passing of 'status' to scanmore() and
  531. X *      checknext(), since there were no circumstances where
  532. X *      it ever equalled FALSE.
  533. X */
  534. X
  535. X
  536. #include        <stdio.h>
  537. #include    "estruct.h"
  538. #include        "edef.h"
  539. X
  540. #if    ISRCH
  541. X
  542. extern int thescanner();        /* Handy search routine */
  543. extern int eq();            /* Compare chars, match case */
  544. X
  545. /* A couple of "own" variables for re-eat */
  546. X
  547. int    (*saved_get_char)();        /* Get character routine */
  548. int    eaten_char = -1;        /* Re-eaten char */
  549. X
  550. /* A couple more "own" variables for the command string */
  551. X
  552. int    cmd_buff[CMDBUFLEN];        /* Save the command args here */
  553. int    cmd_offset;            /* Current offset into command buff */
  554. int    cmd_reexecute = -1;        /* > 0 if re-executing command */
  555. X
  556. X
  557. /*
  558. X * Subroutine to do incremental reverse search.  It actually uses the
  559. X * same code as the normal incremental search, as both can go both ways.
  560. X */
  561. int risearch(f, n)
  562. {
  563. X    LINE *curline;            /* Current line on entry          */
  564. X    int  curoff;            /* Current offset on entry          */
  565. X
  566. X    /* remember the initial . on entry: */
  567. X
  568. X    curline = curwp->w_dotp;        /* Save the current line pointer      */
  569. X    curoff  = curwp->w_doto;        /* Save the current offset          */
  570. X
  571. X    /* Make sure the search doesn't match where we already are:              */
  572. X
  573. X    backchar(TRUE, 1);            /* Back up a character              */
  574. X
  575. #if    NeWS
  576. X    newsimmediateon() ;
  577. #endif
  578. X
  579. X    if (!(isearch(f, -n)))        /* Call ISearch backwards          */
  580. X    {                    /* If error in search:              */
  581. X    curwp->w_dotp = curline;    /* Reset the line pointer          */
  582. X    curwp->w_doto = curoff;        /*  and the offset to original value  */
  583. X    curwp->w_flag |= WFMOVE;    /* Say we've moved              */
  584. X    update(FALSE);            /* And force an update              */
  585. X    mlwrite ("[search failed]");    /* Say we died                  */
  586. X    TTbeep();
  587. X    } else
  588. X    mlerase ();            /* If happy, just erase the cmd line  */
  589. X
  590. #if    NeWS
  591. X    newsimmediateoff() ;
  592. #endif
  593. }
  594. X
  595. /* Again, but for the forward direction */
  596. X
  597. int fisearch(f, n)
  598. {
  599. X    LINE *curline;            /* Current line on entry          */
  600. X    int  curoff;            /* Current offset on entry          */
  601. X
  602. X    /* remember the initial . on entry: */
  603. X
  604. X    curline = curwp->w_dotp;        /* Save the current line pointer      */
  605. X    curoff  = curwp->w_doto;        /* Save the current offset          */
  606. X
  607. X    /* do the search */
  608. X
  609. #if    NeWS
  610. X    newsimmediateon() ;
  611. #endif
  612. X
  613. X    if (!(isearch(f, n)))        /* Call ISearch forwards          */
  614. X    {                    /* If error in search:              */
  615. X    curwp->w_dotp = curline;    /* Reset the line pointer          */
  616. X    curwp->w_doto = curoff;        /*  and the offset to original value  */
  617. X    curwp->w_flag |= WFMOVE;    /* Say we've moved              */
  618. X    update(FALSE);            /* And force an update              */
  619. X    mlwrite ("[search failed]");    /* Say we died                  */
  620. X    TTbeep();
  621. X    } else
  622. X    mlerase ();            /* If happy, just erase the cmd line  */
  623. X
  624. #if    NeWS
  625. X    newsimmediateoff() ;
  626. #endif
  627. }
  628. X
  629. /*
  630. X * Subroutine to do an incremental search.  In general, this works similarly
  631. X * to the older micro-emacs search function, except that the search happens
  632. X * as each character is typed, with the screen and cursor updated with each
  633. X * new search character.
  634. X *
  635. X * While searching forward, each successive character will leave the cursor
  636. X * at the end of the entire matched string.  Typing a Control-S or Control-X
  637. X * will cause the next occurrence of the string to be searched for (where the
  638. X * next occurrence does NOT overlap the current occurrence).  A Control-R will
  639. X * change to a backwards search, META will terminate the search and Control-G
  640. X * will abort the search.  Rubout will back up to the previous match of the
  641. X * string, or if the starting point is reached first, it will delete the
  642. X * last character from the search string.
  643. X *
  644. X * While searching backward, each successive character will leave the cursor
  645. X * at the beginning of the matched string.  Typing a Control-R will search
  646. X * backward for the next occurrence of the string.  Control-S or Control-X
  647. X * will revert the search to the forward direction.  In general, the reverse
  648. X * incremental search is just like the forward incremental search inverted.
  649. X *
  650. X * In all cases, if the search fails, the user will be feeped, and the search
  651. X * will stall until the pattern string is edited back into something that
  652. X * exists (or until the search is aborted).
  653. X */
  654. isearch(f, n)
  655. {
  656. X    int            status;        /* Search status */
  657. X    int            col;        /* prompt column */
  658. X    register int    cpos;        /* character number in search string  */
  659. X    register int    c;        /* current input character */
  660. X    char        pat_save[NPAT];    /* Saved copy of the old pattern str  */
  661. X    LINE        *curline;    /* Current line on entry          */
  662. X    int            curoff;        /* Current offset on entry          */
  663. X    int            init_direction;    /* The initial search direction          */
  664. X
  665. X    /* Initialize starting conditions */
  666. X
  667. X    cmd_reexecute = -1;        /* We're not re-executing (yet?)      */
  668. X    cmd_offset = 0;            /* Start at the beginning of the buff */
  669. X    cmd_buff[0] = '\0';        /* Init the command buffer          */
  670. X    strncpy (pat_save, pat, NPAT);    /* Save the old pattern string          */
  671. X    curline = curwp->w_dotp;        /* Save the current line pointer      */
  672. X    curoff  = curwp->w_doto;        /* Save the current offset          */
  673. X    init_direction = n;            /* Save the initial search direction  */
  674. X    setboundry(FALSE,NULL,0,0);        /* keep thescanner() finite */
  675. X
  676. X    /* This is a good place to start a re-execution: */
  677. X
  678. start_over:
  679. X
  680. X    /* ask the user for the text of a pattern */
  681. X    col = promptpattern("ISearch: ");        /* Prompt, remember the col   */
  682. X
  683. X    cpos = 0;                    /* Start afresh              */
  684. X    status = TRUE;                /* Assume everything's cool   */
  685. X
  686. X    /*
  687. X       Get the first character in the pattern.  If we get an initial Control-S
  688. X       or Control-R, re-use the old search string and find the first occurrence
  689. X     */
  690. X
  691. X    c = kcod2key(get_char());            /* Get the first character    */
  692. X    if ((c == IS_FORWARD) ||
  693. X        (c == IS_REVERSE))            /* Reuse old search string?   */
  694. X    {
  695. X        for (cpos = 0; pat[cpos] != 0; cpos++)    /* Yup, find the length          */
  696. X            col = echochar(pat[cpos],col);    /*  and re-echo the string    */
  697. X    if (c == IS_REVERSE) {            /* forward search?          */
  698. X        n = -1;                /* No, search in reverse      */
  699. X        backchar (TRUE, 1);            /* Be defensive about EOB     */
  700. X    } else
  701. X        n = 1;                /* Yes, search forward          */
  702. X    status = scanmore(pat, n);        /* Do the search          */
  703. X    c = kcod2key(get_char());        /* Get another character      */
  704. X    }
  705. X
  706. X    /* Top of the per character loop */
  707. X            
  708. X    for (;;)                    /* ISearch per character loop */
  709. X    {
  710. X    /* Check for special characters first: */
  711. X    /* Most cases here change the search */
  712. X
  713. X    if (c == kcod2key(abortc))            /* Want to quit searching?    */
  714. X        return (TRUE);            /* Quit searching now          */
  715. X
  716. X    if (isbackspace(c))
  717. X         c = '\b';
  718. X
  719. X    if (c == kcod2key(quotec))            /* quote character?          */
  720. X        c = kcod2key(get_char());        /* Get the next char          */
  721. X
  722. X    switch (c)                /* dispatch on the input char */
  723. X    {
  724. X      case IS_REVERSE:            /* If backward search          */
  725. X      case IS_FORWARD:            /* If forward search          */
  726. X        if (c == IS_REVERSE)        /* If reverse search          */
  727. X        n = -1;                /* Set the reverse direction  */
  728. X        else                /* Otherwise,               */
  729. X        n = 1;                /*  go forward              */
  730. X        status = scanmore(pat, n);        /* Start the search again     */
  731. X        c = kcod2key(get_char());        /* Get the next char          */
  732. X        continue;                /* Go continue with the search*/
  733. X
  734. X      case '\r':                /* Carriage return          */
  735. X        c = '\n';                /* Make it a new line          */
  736. X        break;                /* Make sure we use it          */
  737. X
  738. X      case '\t':                /* Generically allowed          */
  739. X      case '\n':                /*  controlled characters     */
  740. X        break;                /* Make sure we use it          */
  741. X
  742. X      case '\b':                /*  or if a Rubout:          */
  743. X        if (cmd_offset <= 1)        /* Anything to delete?          */
  744. X        return (TRUE);            /* No, just exit          */
  745. X        --cmd_offset;            /* Back up over the Rubout    */
  746. X        cmd_buff[--cmd_offset] = '\0';    /* Yes, delete last char   */
  747. X        curwp->w_dotp = curline;        /* Reset the line pointer     */
  748. X        curwp->w_doto = curoff;        /*  and the offset          */
  749. X        n = init_direction;            /* Reset the search direction */
  750. X        strncpy (pat, pat_save, NPAT);    /* Restore the old search str */
  751. X        cmd_reexecute = 0;            /* Start the whole mess over  */
  752. X        goto start_over;            /* Let it take care of itself */
  753. X
  754. X      /* Presumably a quasi-normal character comes here */
  755. X
  756. X      default:                /* All other chars              */
  757. X        if (c < ' ')            /* Is it printable?          */
  758. X        {                    /* Nope.              */
  759. X        reeat (c);            /* Re-eat the char          */
  760. X        return (TRUE);            /* And return the last status */
  761. X        }
  762. X    }  /* Switch */
  763. X
  764. X    /* I guess we got something to search for, so search for it          */
  765. X
  766. X    pat[cpos++] = c;            /* put the char in the buffer */
  767. X    if (cpos >= NPAT)            /* too many chars in string?  */
  768. X    {                    /* Yup.  Complain about it    */
  769. X        mlwrite("? Search string too long");
  770. X        return(TRUE);            /* Return an error          */
  771. X    }
  772. X    pat[cpos] = 0;                /* null terminate the buffer  */
  773. X    col = echochar(c,col);            /* Echo the character          */
  774. X    if (!status) {                /* If we lost last time          */
  775. X        TTbeep();                /* Feep again              */
  776. X        TTflush();                /* see that the feep feeps    */
  777. X    } else                    /* Otherwise, we must have won*/
  778. X        if (!(status = checknext(c, pat, n))) /* See if match          */
  779. X        status = scanmore(pat, n);    /*  or find the next match    */
  780. X    c = kcod2key(get_char());        /* Get the next char          */
  781. X    } /* for {;;} */
  782. }
  783. X
  784. /*
  785. X * Trivial routine to insure that the next character in the search string is
  786. X * still true to whatever we're pointing to in the buffer.  This routine will
  787. X * not attempt to move the "point" if the match fails, although it will 
  788. X * implicitly move the "point" if we're forward searching, and find a match,
  789. X * since that's the way forward isearch works.
  790. X *
  791. X * If the compare fails, we return FALSE and assume the caller will call
  792. X * scanmore or something.
  793. X */
  794. X
  795. int checknext (chr, patrn, dir)    /* Check next character in search string */
  796. char    chr;            /* Next char to look for         */
  797. char    *patrn;            /* The entire search string (incl chr)   */
  798. int    dir;            /* Search direction             */
  799. {
  800. X    register LINE *curline;        /* current line during scan          */
  801. X    register int curoff;        /* position within current line          */
  802. X    register int buffchar;        /* character at current position      */
  803. X    int status;                /* how well things go              */
  804. X
  805. X
  806. X    /* setup the local scan pointer to current "." */
  807. X
  808. X    curline = curwp->w_dotp;        /* Get the current line structure     */
  809. X    curoff  = curwp->w_doto;        /* Get the offset within that line    */
  810. X
  811. X    if (dir > 0)            /* If searching forward              */
  812. X    {
  813. X        if (curoff == llength(curline)) /* If at end of line              */
  814. X        {
  815. X        curline = lforw(curline);    /* Skip to the next line          */
  816. X        if (curline == curbp->b_linep)
  817. X        return (FALSE);        /* Abort if at end of buffer          */
  818. X        curoff = 0;            /* Start at the beginning of the line */
  819. X        buffchar = '\n';        /* And say the next char is NL          */
  820. X    } else
  821. X        buffchar = lgetc(curline, curoff++); /* Get the next char          */
  822. X    if (status = eq(buffchar, chr))    /* Is it what we're looking for?      */
  823. X    {
  824. X        curwp->w_dotp = curline;    /* Yes, set the buffer's point          */
  825. X        curwp->w_doto = curoff;    /*  to the matched character          */
  826. X        curwp->w_flag |= WFMOVE;    /* Say that we've moved              */
  827. X    }
  828. X    return (status);        /* And return the status          */
  829. X    } else                /* Else, if reverse search:          */
  830. X    return (match_pat (patrn));    /* See if we're in the right place    */
  831. }
  832. X
  833. /*
  834. X * This hack will search for the next occurrence of <pat> in the buffer, either
  835. X * forward or backward.  It is called with the status of the prior search
  836. X * attempt, so that it knows not to bother if it didn't work last time.  If
  837. X * we can't find any more matches, "point" is left where it was before.  If
  838. X * we do find a match, "point" will be at the end of the matched string for
  839. X * forward searches and at the beginning of the matched string for reverse
  840. X * searches.
  841. X */
  842. int scanmore(patrn, dir)    /* search forward or back for a pattern          */
  843. char    *patrn;            /* string to scan for                  */
  844. int    dir;            /* direction to search                  */
  845. {
  846. X    int    sts;            /* search status              */
  847. X
  848. X        if (dir < 0)                /* reverse search?          */
  849. X        {
  850. X        rvstrcpy(tap, patrn);        /* Put reversed string in tap */
  851. X        sts = thescanner(tap, REVERSE, PTBEG, FALSE);
  852. X    }
  853. X    else     /* Nope. Go forward   */
  854. X        sts = thescanner(patrn, FORWARD, PTEND, FALSE);
  855. X
  856. X    if (!sts)
  857. X    {
  858. X        TTbeep();        /* Feep if search fails       */
  859. X        TTflush();        /* see that the feep feeps    */
  860. X    }
  861. X
  862. X    return(sts);                /* else, don't even try          */
  863. }
  864. X
  865. /*
  866. X * The following is a worker subroutine used by the reverse search.  It
  867. X * compares the pattern string with the characters at "." for equality. If
  868. X * any characters mismatch, it will return FALSE.
  869. X *
  870. X * This isn't used for forward searches, because forward searches leave "."
  871. X * at the end of the search string (instead of in front), so all that needs to
  872. X * be done is match the last char input.
  873. X */
  874. X
  875. int match_pat (patrn)    /* See if the pattern string matches string at "."   */
  876. char    *patrn;        /* String to match to buffer                 */
  877. {
  878. X    register int  i;            /* Generic loop index/offset          */
  879. X    register int buffchar;        /* character at current position      */
  880. X    register LINE *curline;        /* current line during scan          */
  881. X    register int curoff;        /* position within current line          */
  882. X
  883. X    /* setup the local scan pointer to current "." */
  884. X
  885. X    curline = curwp->w_dotp;        /* Get the current line structure     */
  886. X    curoff  = curwp->w_doto;        /* Get the offset within that line    */
  887. X
  888. X    /* top of per character compare loop: */
  889. X
  890. X    for (i = 0; i < strlen(patrn); i++)    /* Loop for all characters in patrn   */
  891. X    {
  892. X        if (curoff == llength(curline)) /* If at end of line              */
  893. X        {
  894. X        curline = lforw(curline);    /* Skip to the next line          */
  895. X        curoff = 0;            /* Start at the beginning of the line */
  896. X        if (curline == curbp->b_linep)
  897. X        return (FALSE);        /* Abort if at end of buffer          */
  898. X        buffchar = '\n';        /* And say the next char is NL          */
  899. X    } else
  900. X        buffchar = lgetc(curline, curoff++); /* Get the next char          */
  901. X    if (!eq(buffchar, patrn[i]))    /* Is it what we're looking for?      */
  902. X        return (FALSE);        /* Nope, just punt it then          */
  903. X    }
  904. X    return (TRUE);            /* Everything matched? Let's celebrate*/
  905. }
  906. X
  907. /* Routine to prompt for I-Search string. */
  908. X
  909. int promptpattern(prompt)
  910. char *prompt;
  911. {
  912. X    char tpat[NPAT+20];
  913. X
  914. X    strcpy(tpat, prompt);        /* copy prompt to output string */
  915. X    strcat(tpat, " [");            /* build new prompt string */
  916. X    expandp(pat, &tpat[strlen(tpat)], NPAT/2);    /* add old pattern */
  917. X    strcat(tpat, "]: ");
  918. X
  919. X    /* check to see if we are executing a command line */
  920. X    if (!clexec) {
  921. X    mlwrite(tpat);
  922. X    }
  923. X    return(strlen(tpat));
  924. }
  925. X
  926. /* routine to echo i-search characters */
  927. X
  928. int echochar(c,col)
  929. int    c;    /* character to be echoed */
  930. int    col;    /* column to be echoed in */
  931. {
  932. X    movecursor(term.t_nrow,col);        /* Position the cursor          */
  933. X    if (!isprint(c)) {             /* control char            */
  934. X    TTputc('^');        /* Yes, output prefix          */
  935. X    TTputc(toalpha(c));        /* Make it "^X"              */
  936. X    col++;            /* Count this char          */
  937. X    } else {
  938. X    TTputc(c);            /* Otherwise, output raw char */
  939. X    }
  940. X    TTflush();                /* Flush the output          */
  941. X    return(++col);            /* return the new column no   */
  942. }
  943. X
  944. /*
  945. X * Routine to get the next character from the input stream.  If we're reading
  946. X * from the real terminal, force a screen update before we get the char. 
  947. X * Otherwise, we must be re-executing the command string, so just return the
  948. X * next character.
  949. X */
  950. X
  951. int get_char ()
  952. {
  953. X    int    c;                /* A place to get a character          */
  954. X
  955. X    /* See if we're re-executing: */
  956. X
  957. X    if (cmd_reexecute >= 0)        /* Is there an offset?              */
  958. X    if ((c = cmd_buff[cmd_reexecute++]) != 0)
  959. X        return (c);            /* Yes, return any character          */
  960. X
  961. X    /* We're not re-executing (or aren't any more).  Try for a real char      */
  962. X
  963. X    cmd_reexecute = -1;        /* Say we're in real mode again          */
  964. X    update(FALSE);            /* Pretty up the screen              */
  965. X    if (cmd_offset >= CMDBUFLEN-1)    /* If we're getting too big ...          */
  966. X    {
  967. X    mlwrite ("? command too long");    /* Complain loudly and bitterly          */
  968. X    return (abortc);            /* And force a quit              */
  969. X    }
  970. X    c = kbd_key();        /* Get the next character          */
  971. X    cmd_buff[cmd_offset++] = c; /* Save the char for next time        */
  972. X    cmd_buff[cmd_offset] = '\0';/* And terminate the buffer          */
  973. X    return (c);                /* Return the character              */
  974. }
  975. X
  976. /*
  977. X * Hacky routine to re-eat a character.  This will save the character to be
  978. X * re-eaten by redirecting the input call to a routine here.  Hack, etc.
  979. X */
  980. X
  981. /* Come here on the next term.t_getchar call: */
  982. X
  983. int uneat()
  984. {
  985. X    int c;
  986. X
  987. X    term.t_getchar = saved_get_char;    /* restore the routine address          */
  988. X    c = eaten_char;            /* Get the re-eaten char          */
  989. X    eaten_char = -1;            /* Clear the old char              */
  990. X    return(c);                /* and return the last char          */
  991. }
  992. X
  993. int reeat(c)
  994. int    c;
  995. {
  996. X    if (eaten_char != -1)        /* If we've already been here          */
  997. X    return/*(NULL)*/;        /* Don't do it again              */
  998. X    eaten_char = c;            /* Else, save the char for later      */
  999. X    saved_get_char = term.t_getchar;    /* Save the char get routine          */
  1000. X    term.t_getchar = uneat;        /* Replace it with ours              */
  1001. }
  1002. #else
  1003. isearch()
  1004. {
  1005. }
  1006. #endif
  1007. SHAR_EOF
  1008. chmod 0444 isearch.c ||
  1009. echo 'restore of isearch.c failed'
  1010. Wc_c="`wc -c < 'isearch.c'`"
  1011. test 18075 -eq "$Wc_c" ||
  1012.     echo 'isearch.c: original size 18075, current size' "$Wc_c"
  1013. # ============= line.c ==============
  1014. echo 'x - extracting line.c (Text)'
  1015. sed 's/^X//' << 'SHAR_EOF' > 'line.c' &&
  1016. /*
  1017. X * The functions in this file are a general set of line management utilities.
  1018. X * They are the only routines that touch the text. They also touch the buffer
  1019. X * and window structures, to make sure that the necessary updating gets done.
  1020. X * There are routines in this file that handle the kill register too. It isn't
  1021. X * here for any good reason.
  1022. X *
  1023. X * Note that this code only updates the dot and mark values in the window list.
  1024. X * Since all the code acts on the current window, the buffer that we are
  1025. X * editing must be being displayed, which means that "b_nwnd" is non zero,
  1026. X * which means that the dot and mark values in the buffer headers are nonsense.
  1027. X */
  1028. X
  1029. #include    <stdio.h>
  1030. #include    "estruct.h"
  1031. #include    "edef.h"
  1032. X
  1033. #define roundup(n) ((n+NBLOCK-1) & ~(NBLOCK-1))
  1034. /*
  1035. X * This routine allocates a block of memory large enough to hold a LINE
  1036. X * containing "used" characters. The block is always rounded up a bit. Return
  1037. X * a pointer to the new block, or NULL if there isn't any memory left. Print a
  1038. X * message in the message line if no space.
  1039. X */
  1040. LINE *
  1041. lalloc(used)
  1042. register int    used;
  1043. {
  1044. X    register LINE    *lp;
  1045. X    register int    size;
  1046. X
  1047. X    /* lalloc(-1) is used by undo for placeholders */
  1048. X    if (used < 0)  {
  1049. X        size = 0;
  1050. X    } else {
  1051. X        size = roundup(used);
  1052. X        if (size == 0)            /* Assume that an empty */
  1053. X            size = NBLOCK;        /* line is for type-in. */
  1054. X    }
  1055. X    /* malloc 4 less, because struct LINE is 4 too big */
  1056. X    if ((lp = (LINE *) malloc(sizeof(LINE))) == NULL) {
  1057. X        mlwrite("[OUT OF MEMORY]");
  1058. X        return NULL;
  1059. X    }
  1060. X    if ((lp->l_text = malloc(size)) == NULL) {
  1061. X        mlwrite("[OUT OF MEMORY]");
  1062. X        free((char *)lp);
  1063. X        return NULL;
  1064. X    }
  1065. X    lp->l_size = size;
  1066. X    lp->l_used = used;
  1067. X    lsetclear(lp);
  1068. X    lp->l_nxtundo = NULL;
  1069. X    return (lp);
  1070. }
  1071. X
  1072. lfree(lp)
  1073. register LINE *lp;
  1074. {
  1075. X    if (lp->l_text)
  1076. X        free(lp->l_text);
  1077. X    free((char *)lp);
  1078. }
  1079. X
  1080. /*
  1081. X * Delete line "lp". Fix all of the links that might point at it (they are
  1082. X * moved to offset 0 of the next line. Unlink the line from whatever buffer it
  1083. X * might be in. The buffers are updated too; the magic
  1084. X * conditions described in the above comments don't hold here.
  1085. X * Memory is not released, so line can be saved in undo stacks.
  1086. X */
  1087. lremove(bp,lp)
  1088. register BUFFER *bp;
  1089. register LINE    *lp;
  1090. {
  1091. X    register WINDOW *wp;
  1092. X
  1093. X    wp = wheadp;
  1094. X    while (wp != NULL) {
  1095. X        if (wp->w_linep == lp)
  1096. X            wp->w_linep = lp->l_fp;
  1097. X        if (wp->w_dotp    == lp) {
  1098. X            wp->w_dotp  = lp->l_fp;
  1099. X            wp->w_doto  = 0;
  1100. X        }
  1101. X        if (wp->w_mkp == lp) {
  1102. X            wp->w_mkp = lp->l_fp;
  1103. X            wp->w_mko = 0;
  1104. X        }
  1105. #if 0
  1106. X        if (wp->w_ldmkp == lp) {
  1107. X            wp->w_ldmkp = lp->l_fp;
  1108. X            wp->w_ldmko = 0;
  1109. X        }
  1110. #endif
  1111. X        wp = wp->w_wndp;
  1112. X    }
  1113. X    if (bp->b_nwnd == 0) {
  1114. X        if (bp->b_dotp    == lp) {
  1115. X            bp->b_dotp = lp->l_fp;
  1116. X            bp->b_doto = 0;
  1117. X        }
  1118. X        if (bp->b_markp == lp) {
  1119. X            bp->b_markp = lp->l_fp;
  1120. X            bp->b_marko = 0;
  1121. X        }
  1122. #if 0
  1123. X        if (bp->b_ldmkp == lp) {
  1124. X            bp->b_ldmkp = lp->l_fp;
  1125. X            bp->b_ldmko = 0;
  1126. X        }
  1127. #endif
  1128. X    }
  1129. #if 0
  1130. X    if (bp->b_nmmarks != NULL) { /* fix the named marks */
  1131. X        int i;
  1132. X        struct MARK *mp;
  1133. X        for (i = 0; i < 26; i++) {
  1134. X            mp = &(bp->b_nmmarks[i]);
  1135. X            if (mp->markp == lp) {
  1136. X                mp->markp = lp->l_fp;
  1137. X                mp->marko = 0;
  1138. X            }
  1139. X        }
  1140. X    }
  1141. #endif
  1142. X    lp->l_bp->l_fp = lp->l_fp;
  1143. X    lp->l_fp->l_bp = lp->l_bp;
  1144. }
  1145. X
  1146. /*
  1147. X * This routine gets called when a character is changed in place in the current
  1148. X * buffer. It updates all of the required flags in the buffer and window
  1149. X * system. The flag used is passed as an argument; if the buffer is being
  1150. X * displayed in more than 1 window we change EDIT to HARD. Set MODE if the
  1151. X * mode line needs to be updated (the "*" has to be set).
  1152. X */
  1153. lchange(flag)
  1154. register int    flag;
  1155. {
  1156. X    register WINDOW *wp;
  1157. X
  1158. X    if (curbp->b_nwnd != 1) {         /* Ensure hard.     */
  1159. X        flag |= WFHARD;
  1160. X    }
  1161. X    if ((curbp->b_flag&BFCHG) == 0) {    /* First change, so    */
  1162. X        flag |= WFMODE;         /* update mode lines.    */
  1163. X        curbp->b_flag |= BFCHG;
  1164. X    }
  1165. X    wp = wheadp;
  1166. X    while (wp != NULL) {
  1167. X        if (wp->w_bufp == curbp)
  1168. X            wp->w_flag |= flag;
  1169. X        wp = wp->w_wndp;
  1170. X    }
  1171. }
  1172. X
  1173. insspace(f, n)    /* insert spaces forward into text */
  1174. int f, n;    /* default flag and numeric argument */
  1175. {
  1176. X    linsert(n, ' ');
  1177. X    backchar(f, n);
  1178. }
  1179. X
  1180. /*
  1181. X * Insert "n" copies of the character "c" at the current location of dot. In
  1182. X * the easy case all that happens is the text is stored in the line. In the
  1183. X * hard case, the line has to be reallocated. When the window list is updated,
  1184. X * take special care; I screwed it up once. You always update dot in the
  1185. X * current window. You update mark, and a dot in another window, if it is
  1186. X * greater than the place where you did the insert. Return TRUE if all is
  1187. X * well, and FALSE on errors.
  1188. X */
  1189. linsert(n, c)
  1190. {
  1191. X    register char    *cp1;
  1192. X    register char    *cp2;
  1193. X    register LINE    *lp1;
  1194. X    register LINE    *lp2;
  1195. X    register LINE    *lp3;
  1196. X    register int    doto;
  1197. X    register int    i;
  1198. X    register WINDOW *wp;
  1199. X    register char    *ntext;
  1200. X    int nsize;
  1201. X
  1202. X    lchange(WFEDIT);
  1203. X    lp1 = curwp->w_dotp;            /* Current line     */
  1204. X    if (lp1 == curbp->b_linep) {        /* At the end: special    */
  1205. X        if (curwp->w_doto != 0) {
  1206. X            mlwrite("bug: linsert");
  1207. X            return (FALSE);
  1208. X        }
  1209. X        if ((lp2=lalloc(n)) == NULL)    /* Allocate new line    */
  1210. X            return (FALSE);
  1211. X        copy_for_undo(lp1->l_bp); /* don't want preundodot to point
  1212. X                       *    at a new line if this is the
  1213. X                       *    first change */
  1214. X        lp3 = lp1->l_bp;        /* Previous line    */
  1215. X        lp3->l_fp = lp2;        /* Link in        */
  1216. X        lp2->l_fp = lp1;
  1217. X        lp1->l_bp = lp2;
  1218. X        lp2->l_bp = lp3;
  1219. X        for (i=0; i<n; ++i)
  1220. X            lp2->l_text[i] = c;
  1221. X        curwp->w_dotp = lp2;
  1222. X        curwp->w_doto = n;
  1223. X        tag_for_undo(lp2);
  1224. X        return (TRUE);
  1225. X    }
  1226. X    doto = curwp->w_doto;            /* Save for later.    */
  1227. X    if (lp1->l_used+n > lp1->l_size) {    /* Hard: reallocate    */
  1228. X        copy_for_undo(lp1);
  1229. X        /* first, create the new image */
  1230. X        if ((ntext=malloc(nsize = roundup(lp1->l_used+n))) == NULL)
  1231. X            return (FALSE);
  1232. X        memcpy(&ntext[0],      &lp1->l_text[0],    doto);
  1233. X        memset(&ntext[doto],   c, n);
  1234. X        memcpy(&ntext[doto+n], &lp1->l_text[doto], lp1->l_used-doto );
  1235. X        free((char *)lp1->l_text);
  1236. X        lp1->l_text = ntext;
  1237. X        lp1->l_size = nsize;
  1238. X        lp1->l_used += n;
  1239. X    } else {                /* Easy: in place    */
  1240. X        copy_for_undo(lp1);
  1241. X        /* don't used memcpy:  overlapping regions.... */
  1242. X        lp1->l_used += n;
  1243. X        cp2 = &lp1->l_text[lp1->l_used];
  1244. X        cp1 = cp2-n;
  1245. X        while (cp1 != &lp1->l_text[doto])
  1246. X            *--cp2 = *--cp1;
  1247. X        for (i=0; i<n; ++i)        /* Add the characters    */
  1248. X            lp1->l_text[doto+i] = c;
  1249. X    }
  1250. X    wp = wheadp;                /* Update windows    */
  1251. X    while (wp != NULL) {
  1252. X        if (wp->w_dotp == lp1) {
  1253. X            if (wp==curwp || wp->w_doto>doto)
  1254. X                wp->w_doto += n;
  1255. X        }
  1256. X        if (wp->w_mkp == lp1) {
  1257. X            if (wp->w_mko > doto)
  1258. X                wp->w_mko += n;
  1259. X        }
  1260. X        if (wp->w_ldmkp == lp1) {
  1261. X            if (wp->w_ldmko > doto)
  1262. X                wp->w_ldmko += n;
  1263. X        }
  1264. X        wp = wp->w_wndp;
  1265. X    }
  1266. X    if (curbp->b_nmmarks != NULL) { /* fix the named marks */
  1267. X        struct MARK *mp;
  1268. X        for (i = 0; i < 26; i++) {
  1269. X            mp = &(curbp->b_nmmarks[i]);
  1270. X            if (mp->markp == lp1) {
  1271. X                if (mp->marko > doto)
  1272. X                    mp->marko += n;
  1273. X            }
  1274. X        }
  1275. X    }
  1276. X    return (TRUE);
  1277. }
  1278. X
  1279. /*
  1280. X * Insert a newline into the buffer at the current location of dot in the
  1281. X * current window. The funny ass-backwards way it does things is not a botch;
  1282. X * it just makes the last line in the file not a special case. Return TRUE if
  1283. X * everything works out and FALSE on error (memory allocation failure). The
  1284. X * update of dot and mark is a bit easier then in the above case, because the
  1285. X * split forces more updating.
  1286. X */
  1287. lnewline()
  1288. {
  1289. X    register char    *cp1;
  1290. X    register char    *cp2;
  1291. X    register LINE    *lp1;
  1292. X    register LINE    *lp2;
  1293. X    register int    doto;
  1294. X    register WINDOW *wp;
  1295. X
  1296. X    lchange(WFHARD|WFINS);
  1297. X    lp1  = curwp->w_dotp;            /* Get the address and    */
  1298. X    doto = curwp->w_doto;            /* offset of "."    */
  1299. X    if (lp1 != curbp->b_linep)
  1300. X        copy_for_undo(lp1);
  1301. X    if ((lp2=lalloc(doto)) == NULL)     /* New first half line    */
  1302. X        return (FALSE);
  1303. X    cp1 = &lp1->l_text[0];            /* Shuffle text around    */
  1304. X    cp2 = &lp2->l_text[0];
  1305. X    while (cp1 != &lp1->l_text[doto])
  1306. X        *cp2++ = *cp1++;
  1307. X    cp2 = &lp1->l_text[0];
  1308. X    while (cp1 != &lp1->l_text[lp1->l_used])
  1309. X        *cp2++ = *cp1++;
  1310. X    lp1->l_used -= doto;
  1311. X    /* put lp2 in above lp1 */
  1312. X    lp2->l_bp = lp1->l_bp;
  1313. X    lp1->l_bp = lp2;
  1314. X    lp2->l_bp->l_fp = lp2;
  1315. X    lp2->l_fp = lp1;
  1316. X    tag_for_undo(lp2);
  1317. X    dumpuline(lp1);
  1318. X    wp = wheadp;                /* Windows        */
  1319. X    while (wp != NULL) {
  1320. X        if (wp->w_linep == lp1)
  1321. X            wp->w_linep = lp2;
  1322. X        if (wp->w_dotp == lp1) {
  1323. X            if (wp->w_doto < doto)
  1324. X                wp->w_dotp = lp2;
  1325. X            else
  1326. X                wp->w_doto -= doto;
  1327. X        }
  1328. X        if (wp->w_mkp == lp1) {
  1329. X            if (wp->w_mko < doto)
  1330. X                wp->w_mkp = lp2;
  1331. X            else
  1332. X                wp->w_mko -= doto;
  1333. X        }
  1334. X        if (wp->w_ldmkp == lp1) {
  1335. X            if (wp->w_ldmko < doto)
  1336. X                wp->w_ldmkp = lp2;
  1337. X            else
  1338. X                wp->w_ldmko -= doto;
  1339. X        }
  1340. X        wp = wp->w_wndp;
  1341. X    }
  1342. X    if (curbp->b_nmmarks != NULL) { /* fix the named marks */
  1343. X        int i;
  1344. X        struct MARK *mp;
  1345. X        for (i = 0; i < 26; i++) {
  1346. X            mp = &(curbp->b_nmmarks[i]);
  1347. X            if (mp->markp == lp1) {
  1348. X                if (mp->marko < doto)
  1349. X                    mp->markp = lp2;
  1350. X                else
  1351. X                    mp->marko -= doto;
  1352. X            }
  1353. X        }
  1354. X    }
  1355. X    return (TRUE);
  1356. }
  1357. X
  1358. /*
  1359. X * This function deletes "n" bytes, starting at dot. It understands how do deal
  1360. X * with end of lines, etc. It returns TRUE if all of the characters were
  1361. X * deleted, and FALSE if they were not (because dot ran into the end of the
  1362. X * buffer. The "kflag" is TRUE if the text should be put in the kill buffer.
  1363. X */
  1364. ldelete(n, kflag)
  1365. long n;     /* # of chars to delete */
  1366. int kflag;    /* put killed text in kill buffer flag */
  1367. {
  1368. X    register char    *cp1;
  1369. X    register char    *cp2;
  1370. X    register LINE    *dotp;
  1371. X    register LINE    *nlp;
  1372. X    register int    doto;
  1373. X    register int    chunk;
  1374. X    register WINDOW *wp;
  1375. X    register int i,s;
  1376. X
  1377. X    while (n != 0) {
  1378. X        dotp = curwp->w_dotp;
  1379. X        doto = curwp->w_doto;
  1380. X        if (dotp == curbp->b_linep)    /* Hit end of buffer.    */
  1381. X            return (FALSE);
  1382. X        chunk = dotp->l_used-doto;    /* Size of chunk.    */
  1383. X        if (chunk > (int)n)
  1384. X            chunk = (int)n;
  1385. X        if (chunk == 0) {        /* End of line, merge.    */
  1386. X            lchange(WFHARD|WFKILLS);
  1387. X            /* first take out any whole lines below this one */
  1388. X            nlp = lforw(dotp);
  1389. X            while (nlp != curbp->b_linep && llength(nlp)+1 < n) {
  1390. X                if (kflag) {
  1391. X                    s = kinsert('\n');
  1392. X                    for (i = 0; i < llength(nlp) && 
  1393. X                                s == TRUE; i++)
  1394. X                        s = kinsert(lgetc(nlp,i));
  1395. X                    if (s != TRUE)
  1396. X                        return(FALSE);
  1397. X                }
  1398. X                lremove(curbp,nlp);
  1399. X                toss_to_undo(nlp);
  1400. X                n -= llength(nlp)+1;
  1401. X                nlp = lforw(dotp);
  1402. X            }
  1403. X            if ((s = ldelnewline()) != TRUE)
  1404. X                return (s);
  1405. X            if (kflag && (s = kinsert('\n')) != TRUE)
  1406. X                return (s);
  1407. X            --n;
  1408. X            continue;
  1409. X        }
  1410. X        lchange(WFEDIT);
  1411. X        copy_for_undo(dotp);
  1412. X        cp1 = &dotp->l_text[doto];    /* Scrunch text.    */
  1413. X        cp2 = cp1 + chunk;
  1414. X        if (kflag) {        /* Kill?        */
  1415. X            while (cp1 != cp2) {
  1416. X                if ((s = kinsert(*cp1)) != TRUE)
  1417. X                    return (s);
  1418. X                ++cp1;
  1419. X            }
  1420. X            cp1 = &dotp->l_text[doto];
  1421. X        }
  1422. X        while (cp2 != &dotp->l_text[dotp->l_used])
  1423. X            *cp1++ = *cp2++;
  1424. X        dotp->l_used -= chunk;
  1425. X        wp = wheadp;            /* Fix windows        */
  1426. X        while (wp != NULL) {
  1427. X            if (wp->w_dotp==dotp && wp->w_doto > doto) {
  1428. X                wp->w_doto -= chunk;
  1429. X                if (wp->w_doto < doto)
  1430. X                    wp->w_doto = doto;
  1431. X            }
  1432. X            if (wp->w_mkp==dotp && wp->w_mko > doto) {
  1433. X                wp->w_mko -= chunk;
  1434. X                if (wp->w_mko < doto)
  1435. X                    wp->w_mko = doto;
  1436. X            }
  1437. X            if (wp->w_ldmkp==dotp && wp->w_ldmko > doto) {
  1438. X                wp->w_ldmko -= chunk;
  1439. X                if (wp->w_ldmko < doto)
  1440. X                    wp->w_ldmko = doto;
  1441. X            }
  1442. X            wp = wp->w_wndp;
  1443. X        }
  1444. X        if (curbp->b_nmmarks != NULL) { /* fix the named marks */
  1445. X            struct MARK *mp;
  1446. X            for (i = 0; i < 26; i++) {
  1447. X                mp = &(curbp->b_nmmarks[i]);
  1448. X                if (mp->markp==dotp && mp->marko > doto) {
  1449. X                    mp->marko -= chunk;
  1450. X                    if (mp->marko < doto)
  1451. X                        mp->marko = doto;
  1452. X                }
  1453. X            }
  1454. X        }
  1455. X        n -= chunk;
  1456. X    }
  1457. X    return (TRUE);
  1458. }
  1459. X
  1460. /* getctext:    grab and return a string with the text of
  1461. X        the current line
  1462. */
  1463. X
  1464. char *getctext()
  1465. X
  1466. {
  1467. X    register LINE *lp;    /* line to copy */
  1468. X    register int size;    /* length of line to return */
  1469. X    register char *sp;    /* string pointer into line */
  1470. X    register char *dp;    /* string pointer into returned line */
  1471. X    char rline[NSTRING];    /* line to return */
  1472. X
  1473. X    /* find the contents of the current line and its length */
  1474. X    lp = curwp->w_dotp;
  1475. X    sp = lp->l_text;
  1476. X    size = lp->l_used;
  1477. X    if (size >= NSTRING)
  1478. X        size = NSTRING - 1;
  1479. X
  1480. X    /* copy it across */
  1481. X    dp = rline;
  1482. X    while (size--)
  1483. X        *dp++ = *sp++;
  1484. X    *dp = 0;
  1485. X    return(rline);
  1486. }
  1487. X
  1488. #if ! SMALLER
  1489. /* putctext:    replace the current line with the passed in text    */
  1490. X
  1491. putctext(iline)
  1492. char *iline;    /* contents of new line */
  1493. {
  1494. X    register int status;
  1495. X
  1496. X    /* delete the current line */
  1497. X    curwp->w_doto = 0;    /* starting at the beginning of the line */
  1498. X    if ((status = deltoeol(TRUE, 1)) != TRUE)
  1499. X        return(status);
  1500. X
  1501. X    /* insert the new line */
  1502. X    while (*iline) {
  1503. X        if (*iline == '\n') {
  1504. X            if (lnewline() != TRUE)
  1505. X                return(FALSE);
  1506. X        } else {
  1507. X            if (linsert(1, *iline) != TRUE)
  1508. X                return(FALSE);
  1509. X        }
  1510. X        ++iline;
  1511. X    }
  1512. X    status = lnewline();
  1513. X    backline(TRUE, 1);
  1514. X    return(status);
  1515. }
  1516. #endif
  1517. X
  1518. /*
  1519. X * Delete a newline. Join the current line with the next line. If the next line
  1520. X * is the magic header line always return TRUE; merging the last line with the
  1521. X * header line can be thought of as always being a successful operation, even
  1522. X * if nothing is done, and this makes the kill buffer work "right". Easy cases
  1523. X * can be done by shuffling data around. Hard cases require that lines be moved
  1524. X * about in memory. Return FALSE on error and TRUE if all looks ok. Called by
  1525. X * "ldelete" only.
  1526. X */
  1527. ldelnewline()
  1528. {
  1529. X    register char    *cp1;
  1530. X    register char    *cp2;
  1531. X    register LINE    *lp1;
  1532. X    register LINE    *lp2;
  1533. X    register LINE    *lp3;
  1534. X    register WINDOW *wp;
  1535. X
  1536. X    lp1 = curwp->w_dotp;
  1537. X    /* if the current line is empty, remove it */
  1538. X    if (lp1->l_used == 0) {        /* Blank line.        */
  1539. X        lremove(curbp,lp1);
  1540. X        toss_to_undo(lp1);
  1541. X        return (TRUE);
  1542. X    }
  1543. X    lp2 = lp1->l_fp;
  1544. X    /* if the next line is empty, that's "currline\n\n", so we
  1545. X        remove the second \n by deleting the next line */
  1546. X    /* but never delete the newline on the last non-empty line */
  1547. X    if (lp2 == curbp->b_linep)
  1548. X        return (TRUE);
  1549. X    else if (lp2->l_used == 0) {
  1550. X        /* next line blank? */
  1551. X        lremove(curbp,lp2);
  1552. X        toss_to_undo(lp2);
  1553. X        return (TRUE);
  1554. X    }
  1555. X    /* no room in line above, make room */
  1556. X    if (lp2->l_used > lp1->l_size-lp1->l_used) {
  1557. X        char *ntext;
  1558. X        int nsize;
  1559. X        copy_for_undo(lp1);
  1560. X        /* first, create the new image */
  1561. X        if ((ntext=malloc(nsize = roundup(lp1->l_used + lp2->l_used)))
  1562. X                                 == NULL)
  1563. X            return (FALSE);
  1564. X        memcpy(&ntext[0],      &lp1->l_text[0],    lp1->l_used);
  1565. X        free((char *)lp1->l_text);
  1566. X        lp1->l_text = ntext;
  1567. X    }
  1568. X    cp1 = &lp1->l_text[lp1->l_used];
  1569. X    cp2 = &lp2->l_text[0];
  1570. X    while (cp2 != &lp2->l_text[lp2->l_used])
  1571. X        *cp1++ = *cp2++;
  1572. X    /* check all windows for references to the deleted line */
  1573. X    wp = wheadp;
  1574. X    while (wp != NULL) {
  1575. X        if (wp->w_linep == lp2)
  1576. X            wp->w_linep = lp1;
  1577. X        if (wp->w_dotp == lp2) {
  1578. X            wp->w_dotp  = lp1;
  1579. X            wp->w_doto += lp1->l_used;
  1580. X        }
  1581. X        if (wp->w_mkp == lp2) {
  1582. X            wp->w_mkp  = lp1;
  1583. X            wp->w_mko += lp1->l_used;
  1584. X        }
  1585. X        if (wp->w_ldmkp == lp2) {
  1586. X            wp->w_ldmkp  = lp1;
  1587. X            wp->w_ldmko += lp1->l_used;
  1588. X        }
  1589. X        wp = wp->w_wndp;
  1590. X    }
  1591. X    if (curbp->b_nmmarks != NULL) { /* fix the named marks */
  1592. X        int i;
  1593. X        struct MARK *mp;
  1594. X        for (i = 0; i < 26; i++) {
  1595. X            mp = &(curbp->b_nmmarks[i]);
  1596. X            if (mp->markp == lp2) {
  1597. X                mp->markp  = lp1;
  1598. X                mp->marko += lp1->l_used;
  1599. X            }
  1600. X        }
  1601. X    }
  1602. X    lp1->l_used += lp2->l_used;
  1603. X    lp1->l_fp = lp2->l_fp;
  1604. X    lp2->l_fp->l_bp = lp1;
  1605. X    dumpuline(lp1);
  1606. X    toss_to_undo(lp2);
  1607. X    return (TRUE);
  1608. }
  1609. X
  1610. /*
  1611. X * Delete all of the text saved in the kill buffer. Called by commands when a
  1612. X * new kill context is being created. The kill buffer array is released, just
  1613. X * in case the buffer has grown to immense size. No errors.
  1614. X */
  1615. kdelete()
  1616. {
  1617. X
  1618. X    if ((kregflag & KAPPEND) != 0)
  1619. X        kregflag = KAPPEND;
  1620. X    else
  1621. X        kregflag = KNEEDCLEAN;
  1622. X
  1623. }
  1624. X
  1625. /*
  1626. X * Insert a character to the kill buffer, allocating new chunks as needed.
  1627. X * Return TRUE if all is well, and FALSE on errors.
  1628. X */
  1629. X
  1630. kinsert(c)
  1631. int c;        /* character to insert in the kill buffer */
  1632. {
  1633. X    KILL *nchunk;    /* ptr to newly malloced chunk */
  1634. X    KILLREG *kbp = &kbs[ukb];
  1635. X
  1636. X    if ((kregflag & KNEEDCLEAN) && kbs[ukb].kbufh != NULL) {
  1637. X        KILL *kp;    /* ptr to scan kill buffer chunk list */
  1638. X
  1639. X        /* first, delete all the chunks */
  1640. X        kbs[ukb].kbufp = kbs[ukb].kbufh;
  1641. X        while (kbs[ukb].kbufp != NULL) {
  1642. X            kp = kbs[ukb].kbufp->d_next;
  1643. X            free((char *)(kbs[ukb].kbufp));
  1644. X            kbs[ukb].kbufp = kp;
  1645. X        }
  1646. X
  1647. X        /* and reset all the kill buffer pointers */
  1648. X        kbs[ukb].kbufh = kbs[ukb].kbufp = NULL;
  1649. X        kbs[ukb].kused = KBLOCK;             
  1650. X
  1651. X    }
  1652. X    kregflag &= ~KNEEDCLEAN;
  1653. X    kbs[ukb].kbflag = kregflag;
  1654. X
  1655. X    /* check to see if we need a new chunk */
  1656. X    if (kbp->kused >= KBLOCK || kbp->kbufh == NULL) {
  1657. X        if ((nchunk = (KILL *)malloc(sizeof(KILL))) == NULL)
  1658. X            return(FALSE);
  1659. X        if (kbp->kbufh == NULL)    /* set head ptr if first time */
  1660. X            kbp->kbufh = nchunk;
  1661. X        /* point the current to this new one */
  1662. X        if (kbp->kbufp != NULL)
  1663. X            kbp->kbufp->d_next = nchunk;
  1664. X        kbp->kbufp = nchunk;
  1665. X        kbp->kbufp->d_next = NULL;
  1666. X        kbp->kused = 0;
  1667. X    }
  1668. X
  1669. X    /* and now insert the character */
  1670. X    kbp->kbufp->d_chunk[kbp->kused++] = c;
  1671. X    return(TRUE);
  1672. }
  1673. X
  1674. /* select one of the named registers for use with the following command */
  1675. /*  this could actually be handled as a command prefix, in kbdseq(), much
  1676. X    the way ^X-cmd and META-cmd are done, except that we need to be
  1677. X    able to accept any of
  1678. X         3"adw    "a3dw    "ad3w
  1679. X    to delete 3 words into register a.  So this routine gives us an
  1680. X    easy way to handle the second case.  (The third case is handled in
  1681. X    operators(), the first in main())
  1682. */
  1683. usekreg(f,n)
  1684. {
  1685. X    int c, status;
  1686. X
  1687. X    /* take care of incrementing the buffer number, if we're replaying
  1688. X        a command via 'dot' */
  1689. X    incr_dot_kregnum();
  1690. X
  1691. X    c = kbd_key();
  1692. X
  1693. X    if (isdigit(c))
  1694. X        ukb = c - '0';
  1695. X    else if (islower(c))
  1696. X        ukb = c - 'a' + 10;  /* named buffs are in 10 through 36 */
  1697. X    else if (isupper(c)) {
  1698. X        ukb = c - 'A' + 10;
  1699. X        kregflag |= KAPPEND;
  1700. X    } else {
  1701. X        TTbeep();
  1702. X        return (FALSE);
  1703. X    }
  1704. X
  1705. X    /* get the next command from the keyboard */
  1706. X    c = kbd_seq();
  1707. X
  1708. X    /* allow second chance for entering counts */
  1709. X    if (f == FALSE) {
  1710. X        do_num_proc(&c,&f,&n);
  1711. X        do_rept_arg_proc(&c,&f,&n);
  1712. X    }
  1713. X
  1714. X    /* and execute the command */
  1715. X    status = execute(kcod2fnc(c), f, n);
  1716. X
  1717. X    ukb = 0;
  1718. X    kregflag = 0;
  1719. X
  1720. X    return(status);
  1721. X    
  1722. }
  1723. X
  1724. /* buffers 0 through 9 are circulated automatically for full-line deletes */
  1725. /* we re-use one of them until the KLINES flag is on, then we advance */
  1726. /* to the next */
  1727. kregcirculate(killing)
  1728. {
  1729. X    static lastkb; /* index of the real "0 */
  1730. X
  1731. X    if (ukb >= 10) /* then the user specified a lettered buffer */
  1732. X        return;
  1733. X
  1734. X    /* we only allow killing into the real "0 */
  1735. X    /* ignore any other buffer spec */
  1736. X    if (killing) {
  1737. X        if ((kbs[lastkb].kbflag & KLINES) && 
  1738. X            ! (kbs[lastkb].kbflag & KYANK)) {
  1739. X            if (--lastkb < 0) lastkb = 9;
  1740. X            kbs[lastkb].kbflag = 0;
  1741. X        }
  1742. X        ukb = lastkb;
  1743. X    } else {
  1744. X        /* let 0 pass unmolested -- it is the default */
  1745. X        if (ukb == 0) {
  1746. X            ukb = lastkb; 
  1747. X        } else {
  1748. X        /* for the others, if the current "0 has lines in it, it
  1749. X            must be `"1', else "1 is `"1'.  get it? */
  1750. X            if (kbs[lastkb].kbflag & KLINES)
  1751. X                ukb = (lastkb + ukb - 1) % 10;
  1752. X            else
  1753. X                ukb = (lastkb + ukb) % 10;
  1754. X        }
  1755. X    }
  1756. X    
  1757. }
  1758. X
  1759. putbefore(f,n)
  1760. {
  1761. X    return doput(f,n,FALSE,FALSE);
  1762. }
  1763. X
  1764. putafter(f,n)
  1765. {
  1766. X    return doput(f,n,TRUE,FALSE);
  1767. }
  1768. X
  1769. lineputbefore(f,n)
  1770. {
  1771. X    return doput(f,n,FALSE,TRUE);
  1772. }
  1773. X
  1774. lineputafter(f,n)
  1775. {
  1776. X    return doput(f,n,TRUE,TRUE);
  1777. }
  1778. X
  1779. X
  1780. doput(f,n,after,putlines)
  1781. {
  1782. X    int s, oukb, lining;
  1783. X    
  1784. X    if (!f)
  1785. X        n = 1;
  1786. X        
  1787. X    oukb = ukb;
  1788. X    kregcirculate(FALSE);
  1789. X    if (kbs[ukb].kbufh == NULL) {
  1790. X        if (ukb != 0)
  1791. X            mlwrite("Nothing in register %c", 
  1792. X                (oukb<10)? oukb+'0' : oukb-10+'a');
  1793. X        TTbeep();
  1794. X        return(FALSE);
  1795. X    }
  1796. X    lining = (putlines == TRUE || (kbs[ukb].kbflag & KLINES));
  1797. X    if (lining) {
  1798. X        if (after && curwp->w_dotp != curbp->b_linep)
  1799. X            curwp->w_dotp = lforw(curwp->w_dotp);
  1800. X        curwp->w_doto = 0;
  1801. X    } else {
  1802. X        if (after && curwp->w_doto != llength(curwp->w_dotp))
  1803. X            forwchar(TRUE,1);
  1804. X    }
  1805. X    setmark();
  1806. X    s = put(n,lining);
  1807. X    if (s == TRUE)
  1808. X        swapmark();
  1809. X    if (curwp->w_dotp == curbp->b_linep)
  1810. X        curwp->w_dotp = lback(curwp->w_dotp);
  1811. X    if (lining)
  1812. X        firstnonwhite(FALSE,0);
  1813. X    ukb = 0;
  1814. X    return (s);
  1815. }
  1816. X
  1817. /*
  1818. X * Put text back from the kill register.
  1819. X */
  1820. put(n,aslines)
  1821. {
  1822. X    register int    c;
  1823. X    register int    i;
  1824. X    int wasnl, suppressnl;
  1825. X    register char    *sp;    /* pointer into string to insert */
  1826. X    KILL *kp;        /* pointer into kill register */
  1827. X    
  1828. X    if (n < 0)
  1829. X        return FALSE;
  1830. X        
  1831. X    /* make sure there is something to put */
  1832. X    if (kbs[ukb].kbufh == NULL)
  1833. X        return TRUE;        /* not an error, just nothing */
  1834. X
  1835. X    suppressnl = FALSE;
  1836. X    wasnl = FALSE;
  1837. X
  1838. X    /* for each time.... */
  1839. X    while (n--) {
  1840. X        kp = kbs[ukb].kbufh;
  1841. X        while (kp != NULL) {
  1842. X            if (kp->d_next == NULL)
  1843. X                i = kbs[ukb].kused;
  1844. X            else
  1845. X                i = KBLOCK;
  1846. X            sp = kp->d_chunk;
  1847. X            while (i--) {
  1848. X                if ((c = *sp++) == '\n') {
  1849. X                    if (lnewline() != TRUE)
  1850. X                        return FALSE;
  1851. X                    wasnl = TRUE;
  1852. X                } else {
  1853. X                    if (curwp->w_dotp == curbp->b_linep)
  1854. X                        suppressnl = TRUE;
  1855. X                    if (linsert(1, c) != TRUE)
  1856. X                        return FALSE;
  1857. X                    wasnl = FALSE;
  1858. X                }
  1859. X            }
  1860. X            kp = kp->d_next;
  1861. X        }
  1862. X        if (wasnl) {
  1863. X            if (suppressnl) {
  1864. X                if (ldelnewline() != TRUE)
  1865. X                    return FALSE;
  1866. X            }
  1867. X        } else {
  1868. X            if (aslines && !suppressnl) {
  1869. X                if (lnewline() != TRUE)
  1870. X                    return FALSE;
  1871. X            }
  1872. X        }
  1873. X    }
  1874. X        curwp->w_flag |= WFHARD;
  1875. X    return (TRUE);
  1876. }
  1877. SHAR_EOF
  1878. chmod 0444 line.c ||
  1879. echo 'restore of line.c failed'
  1880. Wc_c="`wc -c < 'line.c'`"
  1881. test 20714 -eq "$Wc_c" ||
  1882.     echo 'line.c: original size 20714, current size' "$Wc_c"
  1883. # ============= lock.c ==============
  1884. echo 'x - extracting lock.c (Text)'
  1885. sed 's/^X//' << 'SHAR_EOF' > 'lock.c' &&
  1886. /*    LOCK:    File locking command routines for MicroEMACS
  1887. X        written by Daniel Lawrence
  1888. X                                */
  1889. X
  1890. #include <stdio.h>
  1891. #include "estruct.h"
  1892. #include "edef.h"
  1893. X
  1894. #if    FILOCK
  1895. #if    BSD
  1896. #include <sys/errno.h>
  1897. X
  1898. extern int sys_nerr;        /* number of system error messages defined */
  1899. extern char *sys_errlist[];    /* list of message texts */
  1900. extern int errno;        /* current error */
  1901. X
  1902. char *lname[NLOCKS];    /* names of all locked files */
  1903. int numlocks;        /* # of current locks active */
  1904. X
  1905. /* lockchk:    check a file for locking and add it to the list */
  1906. X
  1907. lockchk(fname)
  1908. X
  1909. char *fname;    /* file to check for a lock */
  1910. X
  1911. {
  1912. X    register int i;        /* loop indexes */
  1913. X    register int status;    /* return status */
  1914. X    char *undolock();
  1915. X
  1916. X    /* check to see if that file is already locked here */
  1917. X    if (numlocks > 0)
  1918. X        for (i=0; i < numlocks; ++i)
  1919. X            if (strcmp(fname, lname[i]) == 0)
  1920. X                return(TRUE);
  1921. X
  1922. X    /* if we have a full locking table, bitch and leave */
  1923. X    if (numlocks == NLOCKS) {
  1924. X        mlwrite("LOCK ERROR: Lock table full");
  1925. X        return(ABORT);
  1926. X    }
  1927. X
  1928. X    /* next, try to lock it */
  1929. X    status = lock(fname);
  1930. X    if (status == ABORT)    /* file is locked, no override */
  1931. X        return(ABORT);
  1932. X    if (status == FALSE)    /* locked, overriden, dont add to table */
  1933. X        return(TRUE);
  1934. X
  1935. X    /* we have now locked it, add it to our table */
  1936. X    lname[++numlocks - 1] = malloc(strlen(fname) + 1);
  1937. X    if (lname[numlocks - 1] == NULL) {    /* malloc failure */
  1938. X        undolock(fname);        /* free the lock */
  1939. X        mlwrite("Cannot lock, out of memory");
  1940. X        --numlocks;
  1941. X        return(ABORT);
  1942. X    }
  1943. X
  1944. X    /* everthing is cool, add it to the table */
  1945. X    strcpy(lname[numlocks-1], fname);
  1946. X    return(TRUE);
  1947. }
  1948. X
  1949. /*    lockrel:    release all the file locks so others may edit */
  1950. X
  1951. lockrel()
  1952. X
  1953. {
  1954. X    register int i;        /* loop index */
  1955. X    register int status;    /* status of locks */
  1956. X    register int s;        /* status of one unlock */
  1957. X
  1958. X    status = TRUE;
  1959. X    if (numlocks > 0)
  1960. X        for (i=0; i < numlocks; ++i) {
  1961. X            if ((s = unlock(lname[i])) != TRUE)
  1962. X                status = s;
  1963. X            free(lname[i]);
  1964. X        }
  1965. X    numlocks = 0;
  1966. X    return(status);
  1967. }
  1968. X
  1969. /* lock:    Check and lock a file from access by others
  1970. X        returns    TRUE = files was not locked and now is
  1971. X            FALSE = file was locked and overridden
  1972. X            ABORT = file was locked, abort command
  1973. */
  1974. X
  1975. lock(fname)
  1976. X
  1977. char *fname;    /* file name to lock */
  1978. X
  1979. {
  1980. X    register char *locker;    /* lock error message */
  1981. X    register int status;    /* return status */
  1982. X    char msg[NSTRING];    /* message string */
  1983. X    char *dolock();
  1984. X
  1985. X    /* attempt to lock the file */
  1986. X    locker = dolock(fname);
  1987. X    if (locker == NULL)    /* we win */
  1988. X        return(TRUE);
  1989. X
  1990. X    /* file failed...abort */
  1991. X    if (strncmp(locker, "LOCK", 4) == 0) {
  1992. X        lckerror(locker);
  1993. X        return(ABORT);
  1994. X    }
  1995. X
  1996. X    /* someone else has it....override? */
  1997. X    strcpy(msg, "File in use by ");
  1998. X    strcat(msg, locker);
  1999. X    strcat(msg, ", overide?");
  2000. X    status = mlyesno(msg);        /* ask them */
  2001. X    if (status == TRUE)
  2002. X        return(FALSE);
  2003. X    else
  2004. X        return(ABORT);
  2005. }
  2006. X
  2007. /*    unlock:    Unlock a file
  2008. X        this only warns the user if it fails
  2009. X                            */
  2010. X
  2011. unlock(fname)
  2012. X
  2013. char *fname;    /* file to unlock */
  2014. X
  2015. {
  2016. X    register char *locker;    /* undolock return string */
  2017. X    char *undolock();
  2018. X
  2019. X    /* unclock and return */
  2020. X    locker = undolock(fname);
  2021. X    if (locker == NULL)
  2022. X        return(TRUE);
  2023. X
  2024. X    /* report the error and come back */
  2025. X    lckerror(locker);
  2026. X    return(FALSE);
  2027. }
  2028. X
  2029. lckerror(errstr)    /* report a lock error */
  2030. X
  2031. char *errstr;        /* lock error string to print out */
  2032. X
  2033. {
  2034. X    char obuf[NSTRING];    /* output buffer for error message */
  2035. X
  2036. X    strcpy(obuf, errstr);
  2037. X    strcat(obuf, " - ");
  2038. X    if (errno < sys_nerr)
  2039. X        strcat(obuf, sys_errlist[errno]);
  2040. X    else
  2041. X        strcat(obuf, "[can not get system error message]");
  2042. X    mlwrite(obuf);
  2043. }
  2044. #endif
  2045. #else
  2046. lckhello()    /* dummy function */
  2047. {
  2048. }
  2049. #endif
  2050. SHAR_EOF
  2051. chmod 0444 lock.c ||
  2052. echo 'restore of lock.c failed'
  2053. Wc_c="`wc -c < 'lock.c'`"
  2054. test 3557 -eq "$Wc_c" ||
  2055.     echo 'lock.c: original size 3557, current size' "$Wc_c"
  2056. # ============= main.c ==============
  2057. echo 'x - extracting main.c (Text)'
  2058. sed 's/^X//' << 'SHAR_EOF' > 'main.c' &&
  2059. /*
  2060. X *    This used to be MicroEMACS 3.9
  2061. X *             written by Dave G. Conroy.
  2062. X *            substatially modified by Daniel M. Lawrence
  2063. X *
  2064. X *    (C)opyright 1987 by Daniel M. Lawrence
  2065. X *    MicroEMACS 3.9 can be copied and distributed freely for any
  2066. X *    non-commercial purposes. MicroEMACS 3.9 can only be incorporated
  2067. X *    into commercial software with the permission of the current author.
  2068. X *
  2069. X *    Turned into "VI Like Emacs", a.k.a. vile, by Paul Fox
  2070. SHAR_EOF
  2071. true || echo 'restore of main.c failed'
  2072. echo 'End of Vile part 8'
  2073. echo 'File main.c is continued in part 9'
  2074. echo 9 > _shar_seq_.tmp
  2075. exit 0
  2076. -- 
  2077.         paul fox, pgf@cayman.com, (617)494-1999
  2078.         Cayman Systems, 26 Landsdowne St., Cambridge, MA 02139
  2079.