home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume41 / vim / part15 < prev    next >
Text File  |  1993-12-21  |  35KB  |  1,555 lines

  1. Newsgroups: comp.sources.misc
  2. From: mool@oce.nl (Bram Moolenaar)
  3. Subject: v41i065:  vim - Vi IMitation editor, v2.0, Part15/25
  4. Message-ID: <1993Dec21.172340.1130@sparky.sterling.com>
  5. X-Md4-Signature: aa30a595ebc088b885e76028f4c2934e
  6. Keywords: utility, editor, vi, vim
  7. Sender: kent@sparky.sterling.com (Kent Landfield)
  8. Organization: Sterling Software
  9. Date: Tue, 21 Dec 1993 17:23:40 GMT
  10. Approved: kent@sparky.sterling.com
  11.  
  12. Submitted-by: mool@oce.nl (Bram Moolenaar)
  13. Posting-number: Volume 41, Issue 65
  14. Archive-name: vim/part15
  15. Environment: UNIX, AMIGA, MS-DOS
  16. Supersedes: vim: Volume 37, Issue 1-24
  17.  
  18. #! /bin/sh
  19. # This is a shell archive.  Remove anything before this line, then unpack
  20. # it by saving it into a file and typing "sh file".  To overwrite existing
  21. # files, type "sh file -c".  You can also feed this as standard input via
  22. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  23. # will see the following message at the end:
  24. #        "End of archive 15 (of 25)."
  25. # Contents:  vim/src/ops.c
  26. # Wrapped by mool@oce-rd2 on Wed Dec 15 09:50:07 1993
  27. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  28. if test -f 'vim/src/ops.c' -a "${1}" != "-c" ; then 
  29.   echo shar: Will not clobber existing file \"'vim/src/ops.c'\"
  30. else
  31. echo shar: Extracting \"'vim/src/ops.c'\" \(31254 characters\)
  32. sed "s/^X//" >'vim/src/ops.c' <<'END_OF_FILE'
  33. X/* vi:ts=4:sw=4
  34. X *
  35. X * VIM - Vi IMproved
  36. X *
  37. X * Code Contributions By:    Bram Moolenaar            mool@oce.nl
  38. X *                            Tim Thompson            twitch!tjt
  39. X *                            Tony Andrews            onecom!wldrdg!tony 
  40. X *                            G. R. (Fred) Walter        watmath!watcgl!grwalter 
  41. X */
  42. X
  43. X/*
  44. X * ops.c: implementation of various operators: doshift, dodelete, dotilde,
  45. X *          dochange, doyank, doput, dojoin
  46. X */
  47. X
  48. X#include "vim.h"
  49. X#include "globals.h"
  50. X#include "proto.h"
  51. X#include "param.h"
  52. X#include "ops.h"
  53. X
  54. X/*
  55. X * We have one yank buffer for normal yanks and puts, nine yank buffers for
  56. X * deletes and 26 yank buffers for use by name.
  57. X * Each yank buffer is an array of pointers to lines.
  58. X */
  59. Xstatic struct yankbuf
  60. X{
  61. X    char        **y_array;        /* pointer to array of line pointers */
  62. X    linenr_t     y_size;         /* number of lines in y_array */
  63. X    char        y_type;         /* MLINE, MCHAR or MBLOCK */
  64. X} y_buf[36];                    /* 0..9 = number buffers, 10..35 = char buffers */
  65. X
  66. Xstatic struct    yankbuf *y_current;        /* ptr to current yank buffer */
  67. Xstatic int        yankappend;                /* TRUE when appending */
  68. Xstatic struct    yankbuf *y_previous = NULL; /* ptr to last written yank buffer */
  69. X
  70. Xstatic void        get_yank_buffer __ARGS((int));
  71. Xstatic int        stuff_yank __ARGS((int, char *));
  72. Xstatic void        free_yank __ARGS((long));
  73. Xstatic void        free_yank_all __ARGS((void));
  74. Xstatic void        block_prep __ARGS((linenr_t, int));
  75. X
  76. X/* variables use by block_prep, dodelete and doyank */
  77. Xstatic int        startspaces;
  78. Xstatic int        endspaces;
  79. Xstatic int        textlen;
  80. Xstatic char        *textstart;
  81. Xstatic colnr_t    textcol;
  82. X
  83. X/*
  84. X * doshift - handle a shift operation
  85. X */
  86. X    void
  87. Xdoshift(op)
  88. X    int             op;
  89. X{
  90. X    register long i;
  91. X
  92. X    if (!u_save((linenr_t)(Curpos.lnum - 1), (linenr_t)(Curpos.lnum + nlines)))
  93. X        return;
  94. X
  95. X    Curpos.lnum += nlines;        /* start with last line, leave cursor on first */
  96. X    for (i = nlines; --i >= 0; )
  97. X        if (lineempty(--Curpos.lnum))
  98. X            Curpos.col = 0;
  99. X        else
  100. X        {
  101. X            /* if (Visual_block)
  102. X                    shift the block, not the whole line
  103. X            else */
  104. X                shift_line(op == LSHIFT, p_sr);
  105. X        }
  106. X
  107. X    updateScreen(CURSUPD);
  108. X
  109. X    if (nlines > p_report)
  110. X        smsg("%ld line%s %ced", nlines, plural(nlines),
  111. X                                    (op == RSHIFT) ? '>' : '<');
  112. X}
  113. X
  114. X/*
  115. X * shift the current line one shiftwidth left (if left != 0) or right
  116. X * leaves cursor on first blank in the line
  117. X */
  118. X    void
  119. Xshift_line(left, round)
  120. X    int left;
  121. X    int    round;
  122. X{
  123. X    register int count;
  124. X    register int i, j;
  125. X
  126. X    count = get_indent();            /* get current indent */
  127. X
  128. X    if (round)                        /* round off indent */
  129. X    {
  130. X        i = count / (int)p_sw;        /* compute new indent */
  131. X        j = count % (int)p_sw;
  132. X        if (j)
  133. X        {
  134. X            if (!left)
  135. X                ++i;
  136. X        }
  137. X        else if (left)
  138. X        {
  139. X            if (i)
  140. X                --i;
  141. X        }
  142. X        else
  143. X            ++i;
  144. X        count = i * (int)p_sw;
  145. X    }
  146. X    else                /* original vi indent */
  147. X    {
  148. X        if (left)
  149. X        {
  150. X            count -= (int)p_sw;
  151. X            if (count < 0)
  152. X                count = 0;
  153. X        }
  154. X        else
  155. X            count += (int)p_sw;
  156. X    }
  157. X    set_indent(count, TRUE);        /* set new indent */
  158. X}
  159. X
  160. X/*
  161. X * Set y_current and yankappend, according to the value of yankbuffer.
  162. X */
  163. X    static void
  164. Xget_yank_buffer(writing)
  165. X    int        writing;
  166. X{
  167. X    register int i;
  168. X
  169. X    yankappend = FALSE;
  170. X    if (((yankbuffer == 0 && !writing) || yankbuffer == '"') && y_previous != NULL)
  171. X    {
  172. X        y_current = y_previous;
  173. X        return;
  174. X    }
  175. X    i = yankbuffer;
  176. X    if (isdigit(i))
  177. X        i -= '0';
  178. X    else if (islower(i))
  179. X        i -= 'a' - 10;
  180. X    else if (isupper(i))
  181. X    {
  182. X        i -= 'A' - 10;
  183. X        yankappend = TRUE;
  184. X    }
  185. X    else            /* not 0-9, a-z or A-Z: use buffer 0 */
  186. X        i = 0;
  187. X    y_current = &(y_buf[i]);
  188. X    if (writing)        /* remember the buffer we write into for doput() */
  189. X        y_previous = y_current;
  190. X}
  191. X
  192. X/*
  193. X * (stop) recording into a yank buffer
  194. X */
  195. X    int
  196. Xdorecord(c)
  197. X    int c;
  198. X{
  199. X    char *p;
  200. X    static int bufname;
  201. X
  202. X    if (Recording == FALSE)         /* start recording */
  203. X    {
  204. X        if (!isalnum(c) && c != '"')    /* registers 0-9, a-z and " are allowed */
  205. X            return FALSE;
  206. X        Recording = TRUE;
  207. X        showmode();
  208. X        bufname = c;
  209. X        return TRUE;
  210. X    }
  211. X    else                            /* stop recording */
  212. X    {
  213. X        Recording = FALSE;
  214. X        msg("");
  215. X            /* the trailing 'q' command will not have been put in the buffer */
  216. X        p = (char *)get_recorded();
  217. X        if (p == NULL)
  218. X            return FALSE;
  219. X        return (stuff_yank(bufname, p));
  220. X    }
  221. X}
  222. X
  223. X/*
  224. X * stuff string 'p' into yank buffer 'bufname' (append if uppercase)
  225. X * 'p' is assumed to be alloced.
  226. X */
  227. X    static int
  228. Xstuff_yank(bufname, p)
  229. X    int bufname;
  230. X    char *p;
  231. X{
  232. X    char *lp;
  233. X    char **pp;
  234. X
  235. X    yankbuffer = bufname;
  236. X    if (yankbuffer == '.' || yankbuffer == '%')        /* read-only buffer */
  237. X        return FALSE;
  238. X    get_yank_buffer(TRUE);
  239. X    if (yankappend && y_current->y_array != NULL)
  240. X    {
  241. X        pp = &(y_current->y_array[y_current->y_size - 1]);
  242. X        lp = lalloc((u_long)(strlen(*pp) + strlen(p) + 1), TRUE);
  243. X        if (lp == NULL)
  244. X        {
  245. X            free(p);
  246. X            return FALSE;
  247. X        }
  248. X        strcpy(lp, *pp);
  249. X        strcat(lp, p);
  250. X        free(p);
  251. X        free(*pp);
  252. X        *pp = lp;
  253. X    }
  254. X    else
  255. X    {
  256. X        free_yank_all();
  257. X        if ((y_current->y_array = (char **)alloc((unsigned)sizeof(char *))) == NULL)
  258. X        {
  259. X            free(p);
  260. X            return FALSE;
  261. X        }
  262. X        y_current->y_array[0] = p;
  263. X        y_current->y_size = 1;
  264. X        y_current->y_type = MCHAR;    /* used to be MLINE, why? */
  265. X    }
  266. X    return TRUE;
  267. X}
  268. X
  269. X/*
  270. X * execute a yank buffer (register): copy it into the stuff buffer
  271. X */
  272. X    int
  273. Xdoexecbuf(c)
  274. X    int c;
  275. X{
  276. X    static int lastc = NUL;
  277. X    long i;
  278. X
  279. X    if (c == '@')            /* repeat previous one */
  280. X        c = lastc;
  281. X
  282. X    lastc = c;
  283. X    if (!isalnum(c) && c != '"')        /* registers 0-9, a-z and " are allowed */
  284. X        return FALSE;
  285. X
  286. X    yankbuffer = c;
  287. X    get_yank_buffer(FALSE);
  288. X    if (y_current->y_array == NULL)
  289. X        return FALSE;
  290. X
  291. X    for (i = y_current->y_size; --i >= 0; )
  292. X    {
  293. X    /* insert newline between lines and after last line if type is MLINE */
  294. X        if (y_current->y_type == MLINE || i < y_current->y_size - 1)
  295. X        {
  296. X            if (ins_typestr("\n", FALSE) < 0)
  297. X                return FALSE;
  298. X        }
  299. X        if (ins_typestr(y_current->y_array[i], FALSE) < 0)
  300. X            return FALSE;
  301. X    }
  302. X    Exec_reg = TRUE;        /* disable the 'q' command */
  303. X    return TRUE;
  304. X}
  305. X
  306. X/*
  307. X * insert a yank buffer: copy it into the Read buffer
  308. X */
  309. X    int
  310. Xinsertbuf(c)
  311. X    int c;
  312. X{
  313. X    long i;
  314. X
  315. X    if (c == '%')                        /* insert file name */
  316. X    {
  317. X        if (check_fname())
  318. X            return FALSE;
  319. X        stuffReadbuff(xFilename);
  320. X        return TRUE;
  321. X    }
  322. X
  323. X    if (!isalnum(c) && c != '"')        /* registers 0-9, a-z and " are allowed */
  324. X        return FALSE;
  325. X
  326. X    yankbuffer = c;
  327. X    get_yank_buffer(FALSE);
  328. X    if (y_current->y_array == NULL)
  329. X        return FALSE;
  330. X
  331. X    for (i = 0; i < y_current->y_size; ++i)
  332. X    {
  333. X        stuffReadbuff(y_current->y_array[i]);
  334. X    /* insert newline between lines and after last line if type is MLINE */
  335. X        if (y_current->y_type == MLINE || i < y_current->y_size - 1)
  336. X            stuffReadbuff("\n");
  337. X    }
  338. X    return TRUE;
  339. X}
  340. X
  341. X/*
  342. X * dodelete - handle a delete operation
  343. X */
  344. X    void
  345. Xdodelete()
  346. X{
  347. X    register int    n;
  348. X    linenr_t        lnum;
  349. X    char            *ptr;
  350. X    linenr_t        old_lcount = line_count;
  351. X
  352. X    /*
  353. X     * Imitate the strange Vi behaviour: If the delete spans more than one line
  354. X     * and mtype == MCHAR and the result is a blank line, make the delete
  355. X     * linewise. Don't do this for the change command.
  356. X     */
  357. X    if (mtype == MCHAR && nlines > 1 && operator == DELETE)
  358. X    {
  359. X        ptr = nr2ptr(endop.lnum) + endop.col + mincl;
  360. X        skipspace(&ptr);
  361. X        if (*ptr == NUL && startinmargin())
  362. X            mtype = MLINE;
  363. X    }
  364. X
  365. X        /*
  366. X         * Shift number buffers if there is no yankbuffer defined and we do a
  367. X         * delete that contains a line break.
  368. X         */
  369. X    if (yankbuffer == 0 && (mtype == MLINE || nlines > 1))
  370. X    {
  371. X        y_current = &y_buf[9];
  372. X        free_yank_all();                /* free buffer nine */
  373. X        for (n = 9; n > 1; --n)
  374. X            y_buf[n] = y_buf[n - 1];
  375. X        y_previous = y_current = &y_buf[1];
  376. X        y_buf[1].y_array = NULL;        /* set buffer one to empty */
  377. X    }
  378. X    else if (yankbuffer == '.' || yankbuffer == '%')    /* read-only buffer */
  379. X    {
  380. X        beep();
  381. X        return;
  382. X    }
  383. X    else                                /* yank into specified buffer */
  384. X        get_yank_buffer(TRUE);
  385. X
  386. X    /*
  387. X     * Do a yank of whatever we're about to delete. If there's too much stuff
  388. X     * to fit in the yank buffer, then get a confirmation before doing the
  389. X     * delete. This is crude, but simple. And it avoids doing a delete of
  390. X     * something we can't put back if we want.
  391. X     */
  392. X    if (!doyank(TRUE))
  393. X    {
  394. X        if (ask_yesno("cannot yank; delete anyway") != 'y')
  395. X        {
  396. X            emsg(e_abort);
  397. X            return;
  398. X        }
  399. X    }
  400. X
  401. X/*
  402. X * block mode
  403. X */
  404. X    if (Visual_block)
  405. X    {
  406. X        if (!u_save((linenr_t)(startop.lnum - 1), (linenr_t)(endop.lnum + 1)))
  407. X            return;
  408. X
  409. X        for (lnum = Curpos.lnum; Curpos.lnum <= endop.lnum; ++Curpos.lnum)
  410. X        {
  411. X            block_prep(Curpos.lnum, TRUE);
  412. X            if (textlen == 0)        /* nothing to delete */
  413. X                continue;
  414. X
  415. X        /*
  416. X         * If we delete a TAB, it may be replaced by several characters.
  417. X         * Thus the number of characters may increase!
  418. X         */
  419. X            n = textlen - startspaces - endspaces;
  420. X        /* number of characters increases - make room */
  421. X            if (n < 0 && !canincrease(-n))
  422. X                continue;
  423. X            ptr = nr2ptr(Curpos.lnum) + textcol;
  424. X        /* copy the part after the deleted part */
  425. X            memmove(ptr + startspaces + endspaces, ptr + textlen, strlen(ptr + textlen) + 1);
  426. X        /* insert spaces */
  427. X            copy_spaces(ptr, (size_t)(startspaces + endspaces));
  428. X            if (n > 0)
  429. X                canincrease(0);
  430. X        }
  431. X        Curpos.lnum = lnum;
  432. X        CHANGED;
  433. X        updateScreen(VALID_TO_CURSCHAR);
  434. X        nlines = 0;        /* no lines deleted */
  435. X    }
  436. X    else if (mtype == MLINE)
  437. X    {
  438. X        if (operator == CHANGE)
  439. X        {
  440. X            dellines((long)(nlines - 1), TRUE, TRUE);
  441. X            if (!u_saveCurpos())
  442. X                return;
  443. X            while (delchar(TRUE));        /* slow but simple */
  444. X        }
  445. X        else
  446. X        {
  447. X            dellines(nlines, TRUE, TRUE);
  448. X        }
  449. X        u_clearline();    /* "U" command should not be possible after "dd" */
  450. X    }
  451. X    else if (nlines == 1)        /* delete characters within one line */
  452. X    {
  453. X        if (!u_saveCurpos())
  454. X            return;
  455. X        n = endop.col - startop.col + 1 - !mincl;
  456. X        while (n-- > 0)
  457. X            if (!delchar(TRUE))
  458. X                break;
  459. X    }
  460. X    else                        /* delete characters between lines */
  461. X    {
  462. X        if (!u_saveCurpos())    /* save first line for undo */
  463. X            return;
  464. X        n = Curpos.col;
  465. X        while (Curpos.col >= n)    /* delete from cursor to end of line */
  466. X            if (!delchar(TRUE))
  467. X                break;
  468. X
  469. X        startop = Curpos;        /* remember Curpos */
  470. X        ++Curpos.lnum;
  471. X        dellines((long)(nlines - 2), TRUE, TRUE);    /* includes save for undo */
  472. X
  473. X        if (!u_saveCurpos())    /* save last line for undo */
  474. X            return;
  475. X        n = endop.col - !mincl;
  476. X        Curpos.col = 0;
  477. X        while (n-- >= 0)        /* delete from start of line until endop */
  478. X            if (!delchar(TRUE))
  479. X                break;
  480. X        Curpos = startop;        /* restore Curpos */
  481. X        dojoin(FALSE, TRUE);
  482. X    }
  483. X
  484. X    if ((mtype == MCHAR && nlines == 1) || operator == CHANGE)
  485. X    {
  486. X        cursupdate();
  487. X        updateline();
  488. X    }
  489. X    else
  490. X        updateScreen(CURSUPD);
  491. X
  492. X    msgmore(line_count - old_lcount);
  493. X
  494. X        /* correct endop for deleted text (for "']" command) */
  495. X    if (Visual_block)
  496. X        endop.col = startop.col;
  497. X    else
  498. X        endop = startop;
  499. X}
  500. X
  501. X/*
  502. X * dotilde - handle the (non-standard vi) tilde operator
  503. X */
  504. X    void
  505. Xdotilde()
  506. X{
  507. X    FPOS pos;
  508. X
  509. X    if (!u_save((linenr_t)(startop.lnum - 1), (linenr_t)(endop.lnum + 1)))
  510. X        return;
  511. X
  512. X    pos = startop;
  513. X    if (Visual_block)        /* block mode */
  514. X    {
  515. X        for (; pos.lnum <= endop.lnum; ++pos.lnum)
  516. X        {
  517. X            block_prep(pos.lnum, FALSE);
  518. X            pos.col = textcol;
  519. X            while (--textlen >= 0)
  520. X            {
  521. X                swapchar(&pos);
  522. X                if (inc(&pos) == -1)    /* at end of file */
  523. X                    break;
  524. X            }
  525. X        }
  526. X    }
  527. X    else            /* not block mode */
  528. X    {
  529. X        if (mtype == MLINE)
  530. X        {
  531. X                pos.col = 0;
  532. X                endop.col = strlen(nr2ptr(endop.lnum));
  533. X                if (endop.col)
  534. X                        --endop.col;
  535. X        }
  536. X        else if (!mincl)
  537. X            dec(&endop);
  538. X
  539. X        while (ltoreq(pos, endop))
  540. X        {
  541. X            swapchar(&pos);
  542. X            if (inc(&pos) == -1)    /* at end of file */
  543. X                break;
  544. X        }
  545. X    }
  546. X
  547. X    if (mtype == MCHAR && nlines == 1 && !Visual_block)
  548. X    {
  549. X        cursupdate();
  550. X        updateline();
  551. X    }
  552. X    else
  553. X        updateScreen(CURSUPD);
  554. X
  555. X    if (nlines > p_report)
  556. X            smsg("%ld line%s ~ed", nlines, plural(nlines));
  557. X}
  558. X
  559. X/*
  560. X * If operator == UPPER: make uppercase,
  561. X * if operator == LOWER: make lowercase,
  562. X * else swap case of character at 'pos'
  563. X */
  564. X    void
  565. Xswapchar(pos)
  566. X    FPOS    *pos;
  567. X{
  568. X    int        c;
  569. X
  570. X    c = gchar(pos);
  571. X    if (islower(c) && operator != LOWER)
  572. X    {
  573. X        pchar(*pos, toupper(c));
  574. X        CHANGED;
  575. X    }
  576. X    else if (isupper(c) && operator != UPPER)
  577. X    {
  578. X        pchar(*pos, tolower(c));
  579. X        CHANGED;
  580. X    }
  581. X}
  582. X
  583. X/*
  584. X * dochange - handle a change operation
  585. X */
  586. X    void
  587. Xdochange()
  588. X{
  589. X    register colnr_t            l;
  590. X
  591. X    l = startop.col;
  592. X
  593. X    if (!no_op)
  594. X        dodelete();
  595. X
  596. X    if ((l > Curpos.col) && !lineempty(Curpos.lnum))
  597. X        incCurpos();
  598. X
  599. X    startinsert(NUL, FALSE, (linenr_t)1);
  600. X}
  601. X
  602. X/*
  603. X * set all the yank buffers to empty (called from main())
  604. X */
  605. X    void
  606. Xinit_yank()
  607. X{
  608. X        register int i;
  609. X
  610. X        for (i = 0; i < 36; ++i)
  611. X                y_buf[i].y_array = NULL;
  612. X}
  613. X
  614. X/*
  615. X * Free "n" lines from the current yank buffer.
  616. X * Called for normal freeing and in case of error.
  617. X */
  618. X    static void
  619. Xfree_yank(n)
  620. X    long n;
  621. X{
  622. X    if (y_current->y_array != NULL)
  623. X    {
  624. X        register long i;
  625. X
  626. X        for (i = n; --i >= 0; )
  627. X        {
  628. X            if (i % 1000 == 999)                    /* this may take a while */
  629. X                smsg("freeing %ld lines", i + 1);
  630. X            free(y_current->y_array[i]);
  631. X        }
  632. X        free((char *)y_current->y_array);
  633. X        y_current->y_array = NULL;
  634. X        if (n >= 1000)
  635. X            msg("");
  636. X    }
  637. X}
  638. X
  639. X    static void
  640. Xfree_yank_all()
  641. X{
  642. X        free_yank(y_current->y_size);
  643. X}
  644. X
  645. X/*
  646. X * Yank the text between Curpos and startpos into a yank buffer.
  647. X * If we are to append ("uppercase), we first yank into a new yank buffer and
  648. X * then concatenate the old and the new one (so we keep the old one in case
  649. X * of out-of-memory).
  650. X */
  651. X    int
  652. Xdoyank(deleting)
  653. X    int deleting;
  654. X{
  655. X    long                 i;                /* index in y_array[] */
  656. X    struct yankbuf        *curr;            /* copy of y_current */
  657. X    struct yankbuf        new;             /* new yank buffer when appending */
  658. X    char                **new_ptr;
  659. X    register linenr_t    lnum;            /* current line number */
  660. X    long                 j;
  661. X    int                    yanktype = mtype;
  662. X    long                yanklines = nlines;
  663. X    linenr_t            yankendlnum = endop.lnum;
  664. X
  665. X    char                *pnew;
  666. X
  667. X    if (yankbuffer == '.' || yankbuffer == '%')            /* read-only buffer */
  668. X    {
  669. X        beep();
  670. X        return FALSE;
  671. X    }
  672. X    if (!deleting)                    /* dodelete() already set y_current */
  673. X        get_yank_buffer(TRUE);
  674. X
  675. X    curr = y_current;
  676. X    if (yankappend && y_current->y_array != NULL) /* append to existing contents */
  677. X        y_current = &new;
  678. X    else
  679. X        free_yank_all();        /* free previously yanked lines */
  680. X
  681. X/*
  682. X * If the cursor was in column 1 before and after the movement, the
  683. X * yank is always linewise.
  684. X */
  685. X    if (mtype == MCHAR && startop.col == 0 && endop.col == 0 && nlines > 1)
  686. X    {
  687. X        yanktype = MLINE;
  688. X        if (mincl == FALSE && yankendlnum > startop.lnum)
  689. X        {
  690. X            --yankendlnum;
  691. X            --yanklines;
  692. X        }
  693. X    }
  694. X
  695. X    y_current->y_size = yanklines;
  696. X    y_current->y_type = yanktype;    /* set the yank buffer type */
  697. X    y_current->y_array = (char **)lalloc((u_long)(sizeof(char *) * yanklines), TRUE);
  698. X
  699. X    if (y_current->y_array == NULL)
  700. X    {
  701. X        y_current = curr;
  702. X        return FALSE;
  703. X    }
  704. X
  705. X    i = 0;
  706. X    lnum = startop.lnum;
  707. X
  708. X    if (Visual_block)
  709. X    {
  710. X/*
  711. X * block mode
  712. X */
  713. X        y_current->y_type = MBLOCK;    /* set the yank buffer type */
  714. X        for ( ; lnum <= yankendlnum; ++lnum)
  715. X        {
  716. X            block_prep(lnum, FALSE);
  717. X            if ((pnew = alloc(startspaces + endspaces + textlen + 1)) == NULL)
  718. X                goto fail;
  719. X            y_current->y_array[i++] = pnew;
  720. X            copy_spaces(pnew, (size_t)startspaces);
  721. X            pnew += startspaces;
  722. X            strncpy(pnew, textstart, (size_t)textlen);
  723. X            pnew += textlen;
  724. X            copy_spaces(pnew, (size_t)endspaces);
  725. X            pnew += endspaces;
  726. X            *pnew = NUL;
  727. X        }
  728. X    }
  729. X    else
  730. X    {
  731. X/*
  732. X * there are three parts for non-block mode:
  733. X * 1. if yanktype != MLINE yank last part of the top line
  734. X * 2. yank the lines between startop and endop, inclusive when yanktype == MLINE
  735. X * 3. if yanktype != MLINE yank first part of the bot line
  736. X */
  737. X        if (yanktype != MLINE)
  738. X        {
  739. X            if (yanklines == 1)        /* startop and endop on same line */
  740. X            {
  741. X                    j = endop.col - startop.col + 1 - !mincl;
  742. X                    if ((y_current->y_array[0] = strnsave(nr2ptr(lnum) + startop.col, (int)j)) == NULL)
  743. X                    {
  744. X    fail:
  745. X                            free_yank(i);    /* free the lines that we allocated */
  746. X                            y_current = curr;
  747. X                            return FALSE;
  748. X                    }
  749. X                    goto success;
  750. X            }
  751. X            if ((y_current->y_array[0] = strsave(nr2ptr(lnum++) + startop.col)) == NULL)
  752. X                    goto fail;
  753. X            ++i;
  754. X        }
  755. X
  756. X        while (yanktype == MLINE ? (lnum <= yankendlnum) : (lnum < yankendlnum))
  757. X        {
  758. X            if ((y_current->y_array[i] = strsave(nr2ptr(lnum++))) == NULL)
  759. X                    goto fail;
  760. X            ++i;
  761. X        }
  762. X        if (yanktype != MLINE)
  763. X        {
  764. X            if ((y_current->y_array[i] = strnsave(nr2ptr(yankendlnum), endop.col + 1 - !mincl)) == NULL)
  765. X                    goto fail;
  766. X        }
  767. X    }
  768. X
  769. Xsuccess:
  770. X    if (curr != y_current)        /* append the new block to the old block */
  771. X    {
  772. X        new_ptr = (char **)lalloc((u_long)(sizeof(char *) * (curr->y_size + y_current->y_size)), TRUE);
  773. X        if (new_ptr == NULL)
  774. X                goto fail;
  775. X        for (j = 0; j < curr->y_size; ++j)
  776. X                new_ptr[j] = curr->y_array[j];
  777. X        free(curr->y_array);
  778. X        curr->y_array = new_ptr;
  779. X
  780. X        if (yanktype == MLINE)     /* MLINE overrides MCHAR and MBLOCK */
  781. X                curr->y_type = MLINE;
  782. X        if (curr->y_type == MCHAR)        /* concatenate the last line of the old
  783. X                                        block with the first line of the new block */
  784. X        {
  785. X                new_ptr = (char **)lalloc((u_long)(strlen(curr->y_array[curr->y_size - 1]) + strlen(y_current->y_array[0]) + 1), TRUE);
  786. X                if (new_ptr == NULL)
  787. X                {
  788. X                        i = y_current->y_size - 1;
  789. X                        goto fail;
  790. X                }
  791. X                strcpy((char *)new_ptr, curr->y_array[--j]);
  792. X                strcat((char *)new_ptr, y_current->y_array[0]);
  793. X                free(curr->y_array[j]);
  794. X                free(y_current->y_array[0]);
  795. X                curr->y_array[j++] = (char *)new_ptr;
  796. X                i = 1;
  797. X        }
  798. X        else
  799. X                i = 0;
  800. X        while (i < y_current->y_size)
  801. X                curr->y_array[j++] = y_current->y_array[i++];
  802. X        curr->y_size = j;
  803. X        free(y_current->y_array);
  804. X        y_current = curr;
  805. X    }
  806. X    if (operator == YANK)        /* don't do this when deleting */
  807. X    {
  808. X        if (yanktype == MCHAR && !Visual_block)
  809. X            --yanklines;
  810. X        if (yanklines > p_report)
  811. X        {
  812. X            cursupdate();        /* redisplay now, so message is not deleted */
  813. X            smsg("%ld line%s yanked", yanklines, plural(yanklines));
  814. X        }
  815. X    }
  816. X
  817. X    return TRUE;
  818. X}
  819. X
  820. X    void
  821. Xdoput(dir, count)
  822. X    int dir;
  823. X    long count;
  824. X{
  825. X    char        *ptr, *ep;
  826. X    int         newlen;
  827. X    int            totlen = 0;        /* init for gcc */
  828. X    linenr_t    lnum;
  829. X    int            col;
  830. X    long         i;        /* index in y_array[] */
  831. X    int         y_type;
  832. X    long         y_size;
  833. X    char        **y_array;
  834. X    long         nlines = 0;
  835. X    int            vcol;
  836. X    int            delchar;
  837. X    int            incr = 0;
  838. X    long        j;
  839. X    FPOS        newCurpos;
  840. X    int            commandchar;
  841. X    char        temp[2];
  842. X
  843. X    startop = Curpos;            /* default for "'[" command */
  844. X    if (dir == FORWARD)
  845. X        startop.col++;
  846. X    endop = Curpos;                /* default for "']" command */
  847. X    commandchar = (dir == FORWARD ? (count == -1 ? 'o' : 'a') : (count == -1 ? 'O' : 'i'));
  848. X    if (yankbuffer == '.')        /* use inserted text */
  849. X    {
  850. X        stuff_inserted(commandchar, count, FALSE);
  851. X        return;
  852. X    }
  853. X    else if (yankbuffer == '%')    /* use file name */
  854. X    {
  855. X        if (!check_fname())
  856. X        {
  857. X            stuffcharReadbuff(commandchar);
  858. X            stuffReadbuff(xFilename);
  859. X            stuffcharReadbuff(ESC);
  860. X        }
  861. X        return;
  862. X    }
  863. X    get_yank_buffer(FALSE);
  864. X
  865. X    y_type = y_current->y_type;
  866. X    y_size = y_current->y_size;
  867. X    y_array = y_current->y_array;
  868. X
  869. X    if (count == -1)        /* :put command */
  870. X    {
  871. X        y_type = MLINE;
  872. X        count = 1;
  873. X    }
  874. X
  875. X    if (y_size == 0 || y_array == NULL)
  876. X    {
  877. X        temp[0] = yankbuffer;
  878. X        temp[1] = NUL;
  879. X        emsg2("Nothing in register %s", temp);
  880. X        return;
  881. X    }
  882. X
  883. X    if (y_type == MBLOCK)
  884. X    {
  885. X        lnum = Curpos.lnum + y_size + 1;
  886. X        if (lnum > line_count)
  887. X            lnum = line_count + 1;
  888. X        if (!u_save(Curpos.lnum - 1, lnum))
  889. X            return;
  890. X    }
  891. X    else if (!u_saveCurpos())
  892. X        return;
  893. X
  894. X    newlen = strlen(y_array[0]);
  895. X    CHANGED;
  896. X
  897. X    lnum = Curpos.lnum;
  898. X    col = Curpos.col;
  899. X
  900. X/*
  901. X * block mode
  902. X */
  903. X    if (y_type == MBLOCK)
  904. X    {
  905. X        if (dir == FORWARD && gcharCurpos() != NUL)
  906. X        {
  907. X            col = getvcol(&Curpos, 3) + 1;
  908. X            ++Curpos.col;
  909. X        }
  910. X        else
  911. X            col = getvcol(&Curpos, 2);
  912. X        for (i = 0; i < y_size; ++i)
  913. X        {
  914. X            startspaces = 0;
  915. X            endspaces = 0;
  916. X            textcol = 0;
  917. X            vcol = 0;
  918. X            delchar = 0;
  919. X
  920. X        /* add a new line */
  921. X            if (Curpos.lnum > line_count)
  922. X            {
  923. X                ep = alloc_line(0);
  924. X                if (ep == NULL)
  925. X                        goto error;
  926. X                appendline(line_count, ep);
  927. X                ++nlines;
  928. X            }
  929. X            ptr = nr2ptr(Curpos.lnum);
  930. X            while (vcol < col && *ptr)
  931. X            {
  932. X                /* Count a tab for what it's worth (if list mode not on) */
  933. X                incr = chartabsize(*ptr, vcol);
  934. X                vcol += incr;
  935. X                ++ptr;
  936. X                ++textcol;
  937. X            }
  938. X            if (vcol < col)    /* line too short, padd with spaces */
  939. X            {
  940. X                startspaces = col - vcol;
  941. X            }
  942. X            else if (vcol > col)
  943. X            {
  944. X                endspaces = vcol - col;
  945. X                startspaces = incr - endspaces;
  946. X                --textcol;
  947. X                delchar = 1;
  948. X            }
  949. X            newlen = strlen(y_array[i]);
  950. X            totlen = count * newlen + startspaces + endspaces;
  951. X            if (!canincrease(totlen))
  952. X                break;
  953. X            ptr = nr2ptr(Curpos.lnum) + textcol;
  954. X
  955. X        /* move the text after the cursor to the end of the line. */
  956. X            memmove(ptr + totlen - delchar, ptr, strlen(ptr) + 1);
  957. X        /* may insert some spaces before the new text */
  958. X            copy_spaces(ptr, (size_t)startspaces);
  959. X            ptr += startspaces;
  960. X        /* insert the new text */
  961. X            for (j = 0; j < count; ++j)
  962. X            {
  963. X                    strncpy(ptr, y_array[i], (size_t)newlen);
  964. X                    ptr += newlen;
  965. X            }
  966. X        /* may insert some spaces after the new text */
  967. X            copy_spaces(ptr, (size_t)endspaces);
  968. X
  969. X            ++Curpos.lnum;
  970. X            if (i == 0)
  971. X                Curpos.col += startspaces;
  972. X        }
  973. X        endop.lnum = Curpos.lnum - 1;        /* for "']" command */
  974. X        endop.col = textcol + totlen - 1;
  975. X        Curpos.lnum = lnum;
  976. X        cursupdate();
  977. X        updateScreen(VALID_TO_CURSCHAR);
  978. X    }
  979. X    else        /* not block mode */
  980. X    {
  981. X        if (y_type == MCHAR)
  982. X        {
  983. X    /* if type is MCHAR, FORWARD is the same as BACKWARD on the next character */
  984. X            if (dir == FORWARD && gcharCurpos() != NUL)
  985. X            {
  986. X                ++col;
  987. X                if (newlen)
  988. X                {
  989. X                    ++Curpos.col;
  990. X                    ++endop.col;
  991. X                }
  992. X            }
  993. X            newCurpos = Curpos;
  994. X        }
  995. X        else if (dir == BACKWARD)
  996. X    /* if type is MLINE, BACKWARD is the same as FORWARD on the previous line */
  997. X            --lnum;
  998. X        else    /* type == MLINE, dir == FORWARD */
  999. X        {
  1000. X            startop.col = 0;
  1001. X            startop.lnum++;
  1002. X        }
  1003. X
  1004. X/*
  1005. X * simple case: insert into current line
  1006. X */
  1007. X        if (y_type == MCHAR && y_size == 1)
  1008. X        {
  1009. X            i = count * newlen;
  1010. X            if (i)
  1011. X            {
  1012. X                if (!canincrease((int)i))
  1013. X                    return;                 /* alloc() will give error message */
  1014. X                ep = nr2ptr(lnum) + col;
  1015. X                memmove(ep + i, ep, strlen(ep) + 1);
  1016. X                    Curpos.col += (colnr_t)(i - 1);    /* put cursor on last putted char */
  1017. X                for (i = 0; i < count; ++i)
  1018. X                {
  1019. X                    strncpy(ep, y_array[0], (size_t)newlen);
  1020. X                    ep += newlen;
  1021. X                }
  1022. X            }
  1023. X            endop = Curpos;
  1024. X            updateline();
  1025. X        }
  1026. X        else
  1027. X        {
  1028. X            if (y_type == MCHAR)
  1029. X                --y_size;
  1030. X            while (--count >= 0)
  1031. X            {
  1032. X                i = 0;
  1033. X                if (y_type == MCHAR)
  1034. X                {
  1035. X                    /*
  1036. X                     * Split the current line in two at the insert position.
  1037. X                     * Append y_array[0] to first line.
  1038. X                     * Insert y_array[size - 1] in front of second line.
  1039. X                     */
  1040. X                    ptr = nr2ptr(lnum) + col;
  1041. X                    col = strlen(y_array[y_size]);
  1042. X                    ep = alloc_line((unsigned)(strlen(ptr) + col));
  1043. X                    if (ep == NULL)
  1044. X                        goto error;
  1045. X                    strcpy(ep, y_array[y_size]);
  1046. X                    strcat(ep, ptr);
  1047. X                    appendline(lnum, ep);            /* insert in second line */
  1048. X                    ++nlines;
  1049. X                    *ptr = NUL;
  1050. X                    Curpos.lnum = lnum;
  1051. X                    if (!canincrease(newlen))        /* lnum == Curpos.lnum! */
  1052. X                        goto error;
  1053. X                    strcat(nr2ptr(lnum), y_array[0]);/* append to first line */
  1054. X                    i = 1;
  1055. X                }
  1056. X
  1057. X                while (i < y_size)
  1058. X                {
  1059. X                    ep = save_line(y_array[i++]);
  1060. X                    if (ep == NULL)
  1061. X                        goto error;
  1062. X                    appendline(lnum++, ep);
  1063. X                    ++nlines;
  1064. X                }
  1065. X                if (y_type == MCHAR)
  1066. X                    ++lnum;     /* lnum is now number of line below inserted lines */
  1067. X            }
  1068. X
  1069. X            endop.lnum = lnum;        /* for "']" command */
  1070. X            if (y_type == MLINE)
  1071. X            {
  1072. X                Curpos.col = 0;
  1073. X                endop.col = 0;
  1074. X                if (dir == FORWARD)
  1075. X                {
  1076. X                    updateScreen(NOT_VALID);        /* recompute Botline */
  1077. X                    ++Curpos.lnum;
  1078. X                }
  1079. X                    /* put cursor on first non-blank in last inserted line */
  1080. X                beginline(TRUE);
  1081. X            }
  1082. X            else        /* put cursor on first inserted character */
  1083. X            {
  1084. X                if (col > 1)
  1085. X                    endop.col = col - 1;
  1086. X                else
  1087. X                    endop.col = 0;
  1088. X                Curpos = newCurpos;
  1089. X            }
  1090. X
  1091. Xerror:
  1092. X            updateScreen(CURSUPD);
  1093. X        }
  1094. X    }
  1095. X
  1096. X    msgmore(nlines);
  1097. X    set_want_col = TRUE;
  1098. X}
  1099. X
  1100. X/*
  1101. X * display the contents of the yank buffers
  1102. X */
  1103. X    void
  1104. Xdodis()
  1105. X{
  1106. X    register int i, n;
  1107. X    register long j;
  1108. X    register char *p;
  1109. X    register struct yankbuf *yb;
  1110. X
  1111. X#ifdef AMIGA
  1112. X    settmode(0);            /* set cooked mode so output can be halted */
  1113. X#endif
  1114. X    for (i = -1; i < 36; ++i)
  1115. X    {
  1116. X        if (i == -1)
  1117. X        {
  1118. X            if (y_previous != NULL)
  1119. X                yb = y_previous;
  1120. X            else
  1121. X                yb = &(y_buf[0]);
  1122. X        }
  1123. X        else
  1124. X            yb = &(y_buf[i]);
  1125. X        if (yb->y_array != NULL)
  1126. X        {
  1127. X            if (i == -1)
  1128. X                outstrn("\"\"");
  1129. X            else
  1130. X            {
  1131. X                outchar('"');
  1132. X                if (i < 10)
  1133. X                    outchar(i + '0');
  1134. X                else
  1135. X                    outchar(i + 'a' - 10);
  1136. X            }
  1137. X            outchar(' ');
  1138. X
  1139. X            n = (int)Columns - 4;
  1140. X            for (j = 0; j < yb->y_size && n > 0; ++j)
  1141. X            {
  1142. X                if (j)
  1143. X                {
  1144. X                    outstrn("^J");
  1145. X                    n -= 2;
  1146. X                }
  1147. X                for (p = yb->y_array[j]; *p && n > 0; ++p)
  1148. X                {
  1149. X                    outstrn(transchar(*p));
  1150. X                    n -= charsize(*p);
  1151. X                }
  1152. X            }
  1153. X            outchar('\n');
  1154. X            flushbuf();
  1155. X        }
  1156. X    }
  1157. X#ifdef AMIGA
  1158. X    settmode(1);
  1159. X#endif
  1160. X    wait_return(TRUE);
  1161. X}
  1162. X
  1163. X/*
  1164. X * join 'count' lines (minimal 2), including u_save()
  1165. X */
  1166. X    void
  1167. Xdodojoin(count, insert_space, redraw)
  1168. X    long    count;
  1169. X    int        insert_space;
  1170. X    int        redraw;
  1171. X{
  1172. X    if (!u_save((linenr_t)(Curpos.lnum - 1), (linenr_t)(Curpos.lnum + count)))
  1173. X        return;
  1174. X
  1175. X    while (--count > 0)
  1176. X        if (!dojoin(insert_space, redraw))
  1177. X        {
  1178. X                beep();
  1179. X                break;
  1180. X        }
  1181. X
  1182. X    if (redraw)
  1183. X        updateScreen(VALID_TO_CURSCHAR);
  1184. X}
  1185. X
  1186. X    int
  1187. Xdojoin(insert_space, redraw)
  1188. X    int            insert_space;
  1189. X    int            redraw;
  1190. X{
  1191. X    char        *curr;
  1192. X    char        *next;
  1193. X    char        *endcurr;
  1194. X    int         currsize;        /* size of the current line */
  1195. X    int         nextsize;        /* size of the next line */
  1196. X    int            spaces;            /* number of spaces to insert */
  1197. X    int            rows_to_del;    /* number of rows on screen to delete */
  1198. X    linenr_t    t;
  1199. X
  1200. X    if (Curpos.lnum == line_count)        /* on last line */
  1201. X        return FALSE;
  1202. X
  1203. X    rows_to_del = plines_m(Curpos.lnum, Curpos.lnum + 1);
  1204. X    curr = nr2ptr(Curpos.lnum);
  1205. X    currsize = strlen(curr);
  1206. X    next = nr2ptr((linenr_t)(Curpos.lnum + 1));
  1207. X    spaces = 0;
  1208. X    if (insert_space)
  1209. X    {
  1210. X        skipspace(&next);
  1211. X        spaces = 1;
  1212. X        if (*next == ')' || currsize == 0)
  1213. X            spaces = 0;
  1214. X        else
  1215. X        {
  1216. X            endcurr = curr + currsize - 1;
  1217. X            if (*endcurr == ' ' || *endcurr == TAB)
  1218. X            {
  1219. X                spaces = 0;
  1220. X                if (currsize > 1)
  1221. X                    --endcurr;
  1222. X            }
  1223. X            if (p_js && strchr(".!?", *endcurr) != NULL)
  1224. X                spaces = 2;
  1225. X        }
  1226. X    }
  1227. X    nextsize = strlen(next);
  1228. X    if (!canincrease(nextsize + spaces))
  1229. X        return FALSE;
  1230. X
  1231. X    /*
  1232. X     * Append the spaces and the next line. Curr has to be obtained again,
  1233. X     * because canincrease() will have changed the pointer.
  1234. X     */
  1235. X    curr = nr2ptr(Curpos.lnum) + currsize;
  1236. X    while (spaces--)
  1237. X        *curr++ = ' ';
  1238. X    strcpy(curr, next);
  1239. X
  1240. X    /*
  1241. X     * Delete the following line. To do this we move the cursor there
  1242. X     * briefly, and then move it back. After dellines() the cursor may
  1243. X     * have moved up (last line deleted), so the current lnum is kept in t.
  1244. X     */
  1245. X    t = Curpos.lnum;
  1246. X    ++Curpos.lnum;
  1247. X    dellines(1L, FALSE, FALSE);
  1248. X    Curpos.lnum = t;
  1249. X
  1250. X    /*
  1251. X     * the number of rows on the screen is reduced by the difference
  1252. X     * in number of rows of the two old lines and the one new line
  1253. X     */
  1254. X    if (redraw)
  1255. X    {
  1256. X        rows_to_del -= plines(Curpos.lnum);
  1257. X        if (rows_to_del > 0)
  1258. X            s_del(Cursrow, rows_to_del, TRUE);
  1259. X    }
  1260. X
  1261. X     /*
  1262. X     * go to first character of the joined line
  1263. X     */
  1264. X    if (currsize == 0)
  1265. X        Curpos.col = 0;
  1266. X    else
  1267. X    {
  1268. X        Curpos.col = currsize - 1;
  1269. X        oneright();
  1270. X    }
  1271. X    CHANGED;
  1272. X
  1273. X    return TRUE;
  1274. X}
  1275. X
  1276. X/*
  1277. X * implementation of the format operator 'Q'
  1278. X */
  1279. X    void
  1280. Xdoformat()
  1281. X{
  1282. X        /* prepare undo and join the lines */
  1283. X    dodojoin((long)nlines, TRUE, FALSE);
  1284. X
  1285. X        /* put cursor on last non-space */
  1286. X    coladvance(MAXCOL);
  1287. X    while (Curpos.col && isspace(gcharCurpos()))
  1288. X        decCurpos();
  1289. X    curs_columns(FALSE);            /* update Cursvcol */
  1290. X
  1291. X        /* do the formatting */
  1292. X    State = INSERT;        /* for Opencmd() */
  1293. X    insertchar(NUL);
  1294. X    State = NORMAL;
  1295. X    updateScreen(NOT_VALID);
  1296. X}
  1297. X
  1298. X    void
  1299. Xstartinsert(initstr, startln, count)
  1300. X    int            initstr;
  1301. X    int         startln;        /* if set, insert at start of line */
  1302. X    long         count;
  1303. X{
  1304. X    Insstart = Curpos;
  1305. X    if (startln)
  1306. X        Insstart.col = 0;
  1307. X
  1308. X    if (initstr != NUL)
  1309. X    {
  1310. X            ResetRedobuff();
  1311. X            AppendNumberToRedobuff(count);
  1312. X            AppendCharToRedobuff(initstr);
  1313. X    }
  1314. X
  1315. X    if (initstr == 'R')
  1316. X        State = REPLACE;
  1317. X    else
  1318. X        State = INSERT;
  1319. X
  1320. X    if (p_smd)
  1321. X        showmode();
  1322. X
  1323. X    change_warning();        /* give a warning if readonly */
  1324. X    edit(count);
  1325. X}
  1326. X
  1327. X/*
  1328. X * prepare a few things for block mode yank/delete/tilde
  1329. X *
  1330. X * for delete:
  1331. X * - textlen includes the first/last char to be (partly) deleted
  1332. X * - start/endspaces is the number of columns that are taken by the
  1333. X *     first/last deleted char minus the number of columns that have to be deleted.
  1334. X * for yank and tilde:
  1335. X * - textlen includes the first/last char to be wholly yanked
  1336. X * - start/endspaces is the number of columns of the first/last yanked char
  1337. X *   that are to be yanked.
  1338. X */
  1339. X    static void
  1340. Xblock_prep(lnum, delete)
  1341. X    linenr_t    lnum;
  1342. X    int            delete;
  1343. X{
  1344. X    int            vcol;
  1345. X    int            incr = 0;
  1346. X    char        *pend;
  1347. X
  1348. X    startspaces = 0;
  1349. X    endspaces = 0;
  1350. X    textlen = 0;
  1351. X    textcol = 0;
  1352. X    vcol = 0;
  1353. X    textstart = nr2ptr(lnum);
  1354. X    while (vcol < startvcol && *textstart)
  1355. X    {
  1356. X        /* Count a tab for what it's worth (if list mode not on) */
  1357. X        incr = chartabsize(*textstart, vcol);
  1358. X        vcol += incr;
  1359. X        ++textstart;
  1360. X        ++textcol;
  1361. X    }
  1362. X    if (vcol < startvcol)    /* line too short */
  1363. X    {
  1364. X        if (!delete)
  1365. X            endspaces = endvcol - startvcol + 1;
  1366. X    }
  1367. X    else /* vcol >= startvcol */
  1368. X    {
  1369. X        startspaces = vcol - startvcol;
  1370. X        if (delete && vcol > startvcol)
  1371. X            startspaces = incr - startspaces;
  1372. X        pend = textstart;
  1373. X        while (vcol <= endvcol && *pend)
  1374. X        {
  1375. X            /* Count a tab for what it's worth (if list mode not on) */
  1376. X            incr = chartabsize(*pend, vcol);
  1377. X            vcol += incr;
  1378. X            ++pend;
  1379. X        }
  1380. X        if (vcol < endvcol && !delete)    /* line too short */
  1381. X        {
  1382. X            endspaces = endvcol - vcol;
  1383. X        }
  1384. X        else if (vcol > endvcol)
  1385. X        {
  1386. X            if (delete)
  1387. X                endspaces = vcol - endvcol - 1;
  1388. X            else if (pend != textstart)
  1389. X            {
  1390. X                endspaces = incr - (vcol - endvcol);
  1391. X                if (endspaces)
  1392. X                    --pend;
  1393. X            }
  1394. X        }
  1395. X        if (delete && startspaces)
  1396. X        {
  1397. X            --textstart;
  1398. X            --textcol;
  1399. X        }
  1400. X        textlen = (int)(pend - textstart);
  1401. X    }
  1402. X}
  1403. X
  1404. X    int
  1405. Xdoaddsub(c, Prenum1)
  1406. X    int            c;
  1407. X    linenr_t    Prenum1;
  1408. X{
  1409. X    register int     col;
  1410. X    char            buf[30];
  1411. X    int                hex;        /* 'x' or 'X': hexadecimal; '0': octal */
  1412. X    static int        hexupper = FALSE;    /* 0xABC */
  1413. X    long            n;
  1414. X    char            *ptr;
  1415. X
  1416. X    ptr = nr2ptr(Curpos.lnum);
  1417. X    col = Curpos.col;
  1418. X
  1419. X        /* first check if we are on a hexadecimal number */
  1420. X    while (col > 0 && isxdigit(ptr[col]))
  1421. X        --col;
  1422. X    if (col > 0 && (ptr[col] == 'X' || ptr[col] == 'x') &&
  1423. X                        ptr[col - 1] == '0' && isxdigit(ptr[col + 1]))
  1424. X        --col;        /* found hexadecimal number */
  1425. X    else
  1426. X    {
  1427. X        /* first search forward and then backward for start of number */
  1428. X        col = Curpos.col;
  1429. X
  1430. X        while (ptr[col] != NUL && !isdigit(ptr[col]))
  1431. X            ++col;
  1432. X
  1433. X        while (col > 0 && isdigit(ptr[col - 1]))
  1434. X            --col;
  1435. X    }
  1436. X
  1437. X    if (isdigit(ptr[col]) && u_saveCurpos())
  1438. X    {
  1439. X        set_want_col = TRUE;
  1440. X
  1441. X        if (ptr[col] != '0')
  1442. X            hex = 0;                /* decimal */
  1443. X        else
  1444. X        {
  1445. X            hex = TO_UPPER(ptr[col + 1]);        /* assume hexadecimal */
  1446. X            if (hex != 'X' || !isxdigit(ptr[col + 2]))
  1447. X            {
  1448. X                if (isdigit(hex))
  1449. X                    hex = '0';        /* octal */
  1450. X                else
  1451. X                    hex = 0;        /* 0 by itself is decimal */
  1452. X            }
  1453. X        }
  1454. X
  1455. X        if (!hex && col > 0 && ptr[col - 1] == '-')
  1456. X            --col;
  1457. X
  1458. X        ptr += col;
  1459. X        if (hex == '0')
  1460. X            sscanf(ptr, "%lo", &n);
  1461. X        else if (hex)
  1462. X            sscanf(ptr, "%lx", &n);    /* "%X" doesn't work! */
  1463. X        else
  1464. X            n = atol(ptr);
  1465. X
  1466. X        if (c == Ctrl('A'))
  1467. X            n += Prenum1;
  1468. X        else
  1469. X            n -= Prenum1;
  1470. X
  1471. X        if (hex == 'X')                    /* skip the '0x' */
  1472. X            col += 2;
  1473. X        Curpos.col = col;
  1474. X        do                                /* delete the old number */
  1475. X        {
  1476. X            if (isalpha(c))
  1477. X            {
  1478. X                if (isupper(c))
  1479. X                    hexupper = TRUE;
  1480. X                else
  1481. X                    hexupper = FALSE;
  1482. X            }
  1483. X            delchar(FALSE);
  1484. X            c = gcharCurpos();
  1485. X        }
  1486. X        while (hex ? (hex == '0' ? c >= '0' && c <= '7' : isxdigit(c)) : isdigit(c));
  1487. X
  1488. X        if (hex == '0')
  1489. X            sprintf(buf, "0%lo", n);
  1490. X        else if (hexupper)
  1491. X            sprintf(buf, "%lX", n);
  1492. X        else if (hex)
  1493. X            sprintf(buf, "%lx", n);
  1494. X        else
  1495. X            sprintf(buf, "%ld", n);
  1496. X        insstr(buf);                    /* insert the new number */
  1497. X        --Curpos.col;
  1498. X        updateline();
  1499. X        return TRUE;
  1500. X    }
  1501. X    else
  1502. X    {
  1503. X        beep();
  1504. X        return FALSE;
  1505. X    }
  1506. X}
  1507. X
  1508. X/*
  1509. X * Return TRUE if startop is on or before the first non-blank character in the line
  1510. X */
  1511. X    int
  1512. Xstartinmargin()
  1513. X{
  1514. X    int        n;
  1515. X    char    *ptr;
  1516. X
  1517. X    n = 0;
  1518. X    for (ptr = nr2ptr(startop.lnum); *ptr && isspace(*ptr); ++ptr)
  1519. X        ++n;
  1520. X    return (n >= startop.col);
  1521. X}
  1522. END_OF_FILE
  1523. if test 31254 -ne `wc -c <'vim/src/ops.c'`; then
  1524.     echo shar: \"'vim/src/ops.c'\" unpacked with wrong size!
  1525. fi
  1526. chmod +x 'vim/src/ops.c'
  1527. # end of 'vim/src/ops.c'
  1528. fi
  1529. echo shar: End of archive 15 \(of 25\).
  1530. cp /dev/null ark15isdone
  1531. MISSING=""
  1532. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 ; do
  1533.     if test ! -f ark${I}isdone ; then
  1534.     MISSING="${MISSING} ${I}"
  1535.     fi
  1536. done
  1537. if test "${MISSING}" = "" ; then
  1538.     echo You have unpacked all 25 archives.
  1539.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1540. else
  1541.     echo You still need to unpack the following archives:
  1542.     echo "        " ${MISSING}
  1543. fi
  1544. ##  End of shell archive.
  1545. exit 0
  1546.  
  1547. ===============================================================================
  1548. Bram Moolenaar                             | DISCLAIMER:  This  note  does  not
  1549. Oce Nederland B.V., Research & Development | necessarily represent the position
  1550. p.o. box 101, 5900 MA  Venlo               | of  Oce-Nederland  B.V.  Therefore
  1551. The Netherlands        phone +31 77 594077 | no liability or responsibility for
  1552. UUCP: mool@oce.nl        fax +31 77 595473 | whatever will be accepted.
  1553.  
  1554. exit 0 # Just in case...
  1555.