Annotation of src/usr.bin/vim/ops.c, Revision 1.1
1.1 ! downsj 1: /* $OpenBSD$ */
! 2: /* vi:set ts=4 sw=4:
! 3: *
! 4: * VIM - Vi IMproved by Bram Moolenaar
! 5: *
! 6: * Do ":help uganda" in Vim to read copying and usage conditions.
! 7: * Do ":help credits" in Vim to see a list of people who contributed.
! 8: */
! 9:
! 10: /*
! 11: * ops.c: implementation of various operators: do_shift, do_delete, do_tilde,
! 12: * do_change, do_yank, do_put, do_join
! 13: */
! 14:
! 15: #include "vim.h"
! 16: #include "globals.h"
! 17: #include "proto.h"
! 18: #include "option.h"
! 19: #include "ops.h"
! 20:
! 21: /*
! 22: * Number of registers.
! 23: * 0 = unnamed register, for normal yanks and puts
! 24: * 1..9 = number registers, for deletes
! 25: * 10..35 = named registers
! 26: * 36 = delete register (-)
! 27: * 37 = GUI selection register (*). Only if USE_GUI defined
! 28: */
! 29: #ifdef USE_GUI
! 30: # define NUM_REGISTERS 38
! 31: #else
! 32: # define NUM_REGISTERS 37
! 33: #endif
! 34:
! 35: /*
! 36: * Symbolic names for some registers.
! 37: */
! 38: #define DELETION_REGISTER 36
! 39: #ifdef USE_GUI
! 40: # define GUI_SELECTION_REGISTER 37
! 41: #endif
! 42:
! 43: /*
! 44: * Each yank buffer is an array of pointers to lines.
! 45: */
! 46: static struct yankbuf
! 47: {
! 48: char_u **y_array; /* pointer to array of line pointers */
! 49: linenr_t y_size; /* number of lines in y_array */
! 50: char_u y_type; /* MLINE, MCHAR or MBLOCK */
! 51: } y_buf[NUM_REGISTERS];
! 52:
! 53: static struct yankbuf *y_current; /* ptr to current yank buffer */
! 54: static int yankappend; /* TRUE when appending */
! 55: static struct yankbuf *y_previous = NULL; /* ptr to last written yank buffr */
! 56:
! 57: /*
! 58: * structure used by block_prep, do_delete and do_yank for blockwise operators
! 59: */
! 60: struct block_def
! 61: {
! 62: int startspaces;
! 63: int endspaces;
! 64: int textlen;
! 65: char_u *textstart;
! 66: colnr_t textcol;
! 67: };
! 68:
! 69: static void get_yank_buffer __ARGS((int));
! 70: static int stuff_yank __ARGS((int, char_u *));
! 71: static void free_yank __ARGS((long));
! 72: static void free_yank_all __ARGS((void));
! 73: static void block_prep __ARGS((struct block_def *, linenr_t, int));
! 74: static int same_leader __ARGS((int, char_u *, int, char_u *));
! 75: static int fmt_end_block __ARGS((linenr_t, int *, char_u **));
! 76:
! 77: /*
! 78: * do_shift - handle a shift operation
! 79: */
! 80: void
! 81: do_shift(op, curs_top, amount)
! 82: int op;
! 83: int curs_top;
! 84: int amount;
! 85: {
! 86: register long i;
! 87: int first_char;
! 88:
! 89: if (u_save((linenr_t)(curwin->w_cursor.lnum - 1),
! 90: (linenr_t)(curwin->w_cursor.lnum + op_line_count)) == FAIL)
! 91: return;
! 92: for (i = op_line_count; --i >= 0; )
! 93: {
! 94: first_char = *ml_get_curline();
! 95: if (first_char == NUL) /* empty line */
! 96: curwin->w_cursor.col = 0;
! 97: /*
! 98: * Don't move the line right if it starts with # and p_si is set.
! 99: */
! 100: else
! 101: #if defined(SMARTINDENT) || defined(CINDENT)
! 102: if (first_char != '#' || (
! 103: # ifdef SMARTINDENT
! 104: !curbuf->b_p_si
! 105: # endif
! 106: # if defined(SMARTINDENT) && defined(CINDENT)
! 107: &&
! 108: # endif
! 109: # ifdef CINDENT
! 110: (!curbuf->b_p_cin || !in_cinkeys('#', ' ', TRUE))
! 111: # endif
! 112: ))
! 113: #endif
! 114: {
! 115: /* if (op_block_mode)
! 116: shift the block, not the whole line
! 117: else */
! 118: shift_line(op == LSHIFT, p_sr, amount);
! 119: }
! 120: ++curwin->w_cursor.lnum;
! 121: }
! 122:
! 123: if (curs_top) /* put cursor on first line, for ">>" */
! 124: {
! 125: curwin->w_cursor.lnum -= op_line_count;
! 126: beginline(MAYBE); /* shift_line() may have changed cursor.col */
! 127: }
! 128: else
! 129: --curwin->w_cursor.lnum; /* put cursor on last line, for ":>" */
! 130: updateScreen(CURSUPD);
! 131:
! 132: if (op_line_count > p_report)
! 133: smsg((char_u *)"%ld line%s %ced %d time%s", op_line_count,
! 134: plural(op_line_count), (op == RSHIFT) ? '>' : '<',
! 135: amount, plural((long)amount));
! 136: }
! 137:
! 138: /*
! 139: * shift the current line one shiftwidth left (if left != 0) or right
! 140: * leaves cursor on first blank in the line
! 141: */
! 142: void
! 143: shift_line(left, round, amount)
! 144: int left;
! 145: int round;
! 146: int amount;
! 147: {
! 148: register int count;
! 149: register int i, j;
! 150: int p_sw = (int)curbuf->b_p_sw;
! 151:
! 152: count = get_indent(); /* get current indent */
! 153:
! 154: if (round) /* round off indent */
! 155: {
! 156: i = count / p_sw; /* number of p_sw rounded down */
! 157: j = count % p_sw; /* extra spaces */
! 158: if (j && left) /* first remove extra spaces */
! 159: --amount;
! 160: if (left)
! 161: {
! 162: i -= amount;
! 163: if (i < 0)
! 164: i = 0;
! 165: }
! 166: else
! 167: i += amount;
! 168: count = i * p_sw;
! 169: }
! 170: else /* original vi indent */
! 171: {
! 172: if (left)
! 173: {
! 174: count -= p_sw * amount;
! 175: if (count < 0)
! 176: count = 0;
! 177: }
! 178: else
! 179: count += p_sw * amount;
! 180: }
! 181: set_indent(count, TRUE); /* set new indent */
! 182: }
! 183:
! 184: #if defined(LISPINDENT) || defined(CINDENT)
! 185: /*
! 186: * do_reindent - handle reindenting a block of lines for C or lisp.
! 187: *
! 188: * mechanism copied from do_shift, above
! 189: */
! 190: void
! 191: do_reindent(how)
! 192: int (*how) __ARGS((void));
! 193: {
! 194: register long i;
! 195: char_u *l;
! 196: int count;
! 197:
! 198: if (u_save((linenr_t)(curwin->w_cursor.lnum - 1),
! 199: (linenr_t)(curwin->w_cursor.lnum + op_line_count)) == FAIL)
! 200: return;
! 201:
! 202: for (i = op_line_count; --i >= 0 && !got_int; )
! 203: {
! 204: /* it's a slow thing to do, so give feedback so there's no worry that
! 205: * the computer's just hung. */
! 206:
! 207: if ((i % 50 == 0 || i == op_line_count - 1) && op_line_count > p_report)
! 208: smsg((char_u *)"%ld line%s to indent... ", i, plural(i));
! 209:
! 210: /*
! 211: * Be vi-compatible: For lisp indenting the first line is not
! 212: * indented, unless there is only one line.
! 213: */
! 214: #ifdef LISPINDENT
! 215: if (i != op_line_count - 1 || op_line_count == 1 ||
! 216: how != get_lisp_indent)
! 217: #endif
! 218: {
! 219: l = skipwhite(ml_get_curline());
! 220: if (*l == NUL) /* empty or blank line */
! 221: count = 0;
! 222: else
! 223: count = how(); /* get the indent for this line */
! 224:
! 225: set_indent(count, TRUE);
! 226: }
! 227: ++curwin->w_cursor.lnum;
! 228: }
! 229:
! 230: /* put cursor on first non-blank of indented line */
! 231: curwin->w_cursor.lnum -= op_line_count;
! 232: beginline(MAYBE);
! 233:
! 234: updateScreen(CURSUPD);
! 235:
! 236: if (op_line_count > p_report)
! 237: {
! 238: i = op_line_count - (i + 1);
! 239: smsg((char_u *)"%ld line%s indented ", i, plural(i));
! 240: }
! 241: }
! 242: #endif /* defined(LISPINDENT) || defined(CINDENT) */
! 243:
! 244: /*
! 245: * check if character is name of yank buffer
! 246: * Note: There is no check for 0 (default register), caller should do this
! 247: */
! 248: int
! 249: is_yank_buffer(c, writing)
! 250: int c;
! 251: int writing; /* if TRUE check for writable buffers */
! 252: {
! 253: if (c > '~')
! 254: return FALSE;
! 255: if (isalnum(c) || (!writing && vim_strchr((char_u *)".%:", c) != NULL) ||
! 256: c == '"' || c == '-'
! 257: #ifdef USE_GUI
! 258: || (gui.in_use && c == '*')
! 259: #endif
! 260: )
! 261: return TRUE;
! 262: return FALSE;
! 263: }
! 264:
! 265: /*
! 266: * Set y_current and yankappend, according to the value of yankbuffer.
! 267: *
! 268: * If yankbuffer is 0 and writing, use buffer 0
! 269: * If yankbuffer is 0 and reading, use previous buffer
! 270: */
! 271: static void
! 272: get_yank_buffer(writing)
! 273: int writing;
! 274: {
! 275: register int i;
! 276:
! 277: yankappend = FALSE;
! 278: if (((yankbuffer == 0 && !writing) || yankbuffer == '"') &&
! 279: y_previous != NULL)
! 280: {
! 281: y_current = y_previous;
! 282: return;
! 283: }
! 284: i = yankbuffer;
! 285: if (isdigit(i))
! 286: i -= '0';
! 287: else if (islower(i))
! 288: i -= 'a' - 10;
! 289: else if (isupper(i))
! 290: {
! 291: i -= 'A' - 10;
! 292: yankappend = TRUE;
! 293: }
! 294: else if (yankbuffer == '-')
! 295: i = DELETION_REGISTER;
! 296: #ifdef USE_GUI
! 297: else if (gui.in_use && yankbuffer == '*')
! 298: i = GUI_SELECTION_REGISTER;
! 299: #endif
! 300: else /* not 0-9, a-z, A-Z or '-': use buffer 0 */
! 301: i = 0;
! 302: y_current = &(y_buf[i]);
! 303: if (writing) /* remember the buffer we write into for do_put() */
! 304: y_previous = y_current;
! 305: }
! 306:
! 307: /*
! 308: * return TRUE if the current yank buffer has type MLINE
! 309: */
! 310: int
! 311: yank_buffer_mline()
! 312: {
! 313: if (yankbuffer != 0 && !is_yank_buffer(yankbuffer, FALSE))
! 314: return FALSE;
! 315: get_yank_buffer(FALSE);
! 316: return (y_current->y_type == MLINE);
! 317: }
! 318:
! 319: /*
! 320: * start or stop recording into a yank buffer
! 321: *
! 322: * return FAIL for failure, OK otherwise
! 323: */
! 324: int
! 325: do_record(c)
! 326: int c;
! 327: {
! 328: char_u *p;
! 329: static int bufname;
! 330: int retval;
! 331:
! 332: if (Recording == FALSE) /* start recording */
! 333: {
! 334: /* registers 0-9, a-z and " are allowed */
! 335: if (c > '~' || (!isalnum(c) && c != '"'))
! 336: retval = FAIL;
! 337: else
! 338: {
! 339: Recording = TRUE;
! 340: showmode();
! 341: bufname = c;
! 342: retval = OK;
! 343: }
! 344: }
! 345: else /* stop recording */
! 346: {
! 347: Recording = FALSE;
! 348: MSG("");
! 349: p = get_recorded();
! 350: if (p == NULL)
! 351: retval = FAIL;
! 352: else
! 353: retval = (stuff_yank(bufname, p));
! 354: }
! 355: return retval;
! 356: }
! 357:
! 358: /*
! 359: * stuff string 'p' into yank buffer 'bufname' (append if uppercase)
! 360: * 'p' is assumed to be alloced.
! 361: *
! 362: * return FAIL for failure, OK otherwise
! 363: */
! 364: static int
! 365: stuff_yank(bufname, p)
! 366: int bufname;
! 367: char_u *p;
! 368: {
! 369: char_u *lp;
! 370: char_u **pp;
! 371:
! 372: yankbuffer = bufname;
! 373: /* check for read-only buffer */
! 374: if (yankbuffer != 0 && !is_yank_buffer(yankbuffer, TRUE))
! 375: return FAIL;
! 376: get_yank_buffer(TRUE);
! 377: if (yankappend && y_current->y_array != NULL)
! 378: {
! 379: pp = &(y_current->y_array[y_current->y_size - 1]);
! 380: lp = lalloc((long_u)(STRLEN(*pp) + STRLEN(p) + 1), TRUE);
! 381: if (lp == NULL)
! 382: {
! 383: vim_free(p);
! 384: return FAIL;
! 385: }
! 386: STRCPY(lp, *pp);
! 387: STRCAT(lp, p);
! 388: vim_free(p);
! 389: vim_free(*pp);
! 390: *pp = lp;
! 391: }
! 392: else
! 393: {
! 394: free_yank_all();
! 395: if ((y_current->y_array =
! 396: (char_u **)alloc((unsigned)sizeof(char_u *))) == NULL)
! 397: {
! 398: vim_free(p);
! 399: return FAIL;
! 400: }
! 401: y_current->y_array[0] = p;
! 402: y_current->y_size = 1;
! 403: y_current->y_type = MCHAR; /* used to be MLINE, why? */
! 404: }
! 405: return OK;
! 406: }
! 407:
! 408: /*
! 409: * execute a yank buffer (register): copy it into the stuff buffer
! 410: *
! 411: * return FAIL for failure, OK otherwise
! 412: */
! 413: int
! 414: do_execbuf(c, colon, addcr)
! 415: int c;
! 416: int colon; /* insert ':' before each line */
! 417: int addcr; /* always add '\n' to end of line */
! 418: {
! 419: static int lastc = NUL;
! 420: long i;
! 421: char_u *p;
! 422: int truncated;
! 423: int retval;
! 424:
! 425:
! 426: if (c == '@') /* repeat previous one */
! 427: c = lastc;
! 428: if (c == '%' || !is_yank_buffer(c, FALSE)) /* check for valid buffer */
! 429: return FAIL;
! 430: lastc = c;
! 431:
! 432: if (c == ':') /* use last command line */
! 433: {
! 434: if (last_cmdline == NULL)
! 435: {
! 436: EMSG(e_nolastcmd);
! 437: return FAIL;
! 438: }
! 439: vim_free(new_last_cmdline); /* don't keep the cmdline containing @: */
! 440: new_last_cmdline = NULL;
! 441: if (ins_typebuf((char_u *)"\n", FALSE, 0, TRUE) == FAIL)
! 442: return FAIL;
! 443: if (ins_typebuf(last_cmdline, FALSE, 0, TRUE) == FAIL)
! 444: return FAIL;
! 445: if (ins_typebuf((char_u *)":", FALSE, 0, TRUE) == FAIL)
! 446: return FAIL;
! 447: }
! 448: else if (c == '.') /* use last inserted text */
! 449: {
! 450: p = get_last_insert();
! 451: if (p == NULL)
! 452: {
! 453: EMSG(e_noinstext);
! 454: return FAIL;
! 455: }
! 456: i = STRLEN(p);
! 457: if (i > 0 && p[i - 1] == ESC) /* remove trailing ESC */
! 458: {
! 459: p[i - 1] = NUL;
! 460: truncated = TRUE;
! 461: }
! 462: else
! 463: truncated = FALSE;
! 464: retval = ins_typebuf(p, FALSE, 0, TRUE);
! 465: if (truncated)
! 466: p[i - 1] = ESC;
! 467: return retval;
! 468: }
! 469: else
! 470: {
! 471: yankbuffer = c;
! 472: get_yank_buffer(FALSE);
! 473: if (y_current->y_array == NULL)
! 474: return FAIL;
! 475:
! 476: /*
! 477: * Insert lines into typeahead buffer, from last one to first one.
! 478: */
! 479: for (i = y_current->y_size; --i >= 0; )
! 480: {
! 481: /* insert newline between lines and after last line if type is MLINE */
! 482: if (y_current->y_type == MLINE || i < y_current->y_size - 1
! 483: || addcr)
! 484: {
! 485: if (ins_typebuf((char_u *)"\n", FALSE, 0, TRUE) == FAIL)
! 486: return FAIL;
! 487: }
! 488: if (ins_typebuf(y_current->y_array[i], FALSE, 0, TRUE) == FAIL)
! 489: return FAIL;
! 490: if (colon && ins_typebuf((char_u *)":", FALSE, 0, TRUE) == FAIL)
! 491: return FAIL;
! 492: }
! 493: Exec_reg = TRUE; /* disable the 'q' command */
! 494: }
! 495: return OK;
! 496: }
! 497:
! 498: /*
! 499: * Insert a yank buffer: copy it into the Read buffer.
! 500: * Used by CTRL-R command and middle mouse button in insert mode.
! 501: *
! 502: * return FAIL for failure, OK otherwise
! 503: */
! 504: int
! 505: insertbuf(c)
! 506: int c;
! 507: {
! 508: long i;
! 509: int retval = OK;
! 510:
! 511: /*
! 512: * It is possible to get into an endless loop by having CTRL-R a in
! 513: * register a and then, in insert mode, doing CTRL-R a.
! 514: * If you hit CTRL-C, the loop will be broken here.
! 515: */
! 516: mch_breakcheck();
! 517: if (got_int)
! 518: return FAIL;
! 519:
! 520: /* check for valid buffer */
! 521: if (c != NUL && !is_yank_buffer(c, FALSE))
! 522: return FAIL;
! 523:
! 524: #ifdef USE_GUI
! 525: if (c == '*')
! 526: gui_get_selection(); /* may fill * register */
! 527: #endif
! 528:
! 529: if (c == '.') /* insert last inserted text */
! 530: retval = stuff_inserted(NUL, 1L, TRUE);
! 531: else if (c == '%') /* insert file name */
! 532: {
! 533: if (check_fname() == FAIL)
! 534: return FAIL;
! 535: stuffReadbuff(curbuf->b_xfilename);
! 536: }
! 537: else if (c == ':') /* insert last command line */
! 538: {
! 539: if (last_cmdline == NULL)
! 540: {
! 541: EMSG(e_nolastcmd);
! 542: return FAIL;
! 543: }
! 544: stuffReadbuff(last_cmdline);
! 545: }
! 546: else /* name or number register */
! 547: {
! 548: yankbuffer = c;
! 549: get_yank_buffer(FALSE);
! 550: if (y_current->y_array == NULL)
! 551: retval = FAIL;
! 552: else
! 553: {
! 554:
! 555: for (i = 0; i < y_current->y_size; ++i)
! 556: {
! 557: stuffReadbuff(y_current->y_array[i]);
! 558: /* insert newline between lines and after last line if type is
! 559: * MLINE */
! 560: if (y_current->y_type == MLINE || i < y_current->y_size - 1)
! 561: stuffReadbuff((char_u *)"\n");
! 562: }
! 563: }
! 564: }
! 565:
! 566: return retval;
! 567: }
! 568:
! 569: /*
! 570: * paste a yank buffer into the command line.
! 571: * used by CTRL-R command in command-line mode
! 572: * insertbuf() can't be used here, because special characters from the
! 573: * register contents will be interpreted as commands.
! 574: *
! 575: * return FAIL for failure, OK otherwise
! 576: */
! 577: int
! 578: cmdline_paste(c)
! 579: int c;
! 580: {
! 581: long i;
! 582:
! 583: if (!is_yank_buffer(c, FALSE)) /* check for valid buffer */
! 584: return FAIL;
! 585:
! 586: #ifdef USE_GUI
! 587: if (c == '*')
! 588: gui_get_selection();
! 589: #endif
! 590:
! 591: if (c == '.') /* insert last inserted text */
! 592: return FAIL; /* Unimplemented */
! 593:
! 594: if (c == '%') /* insert file name */
! 595: {
! 596: if (check_fname() == FAIL)
! 597: return FAIL;
! 598: return put_on_cmdline(curbuf->b_xfilename, -1, TRUE);
! 599: }
! 600:
! 601: if (c == ':') /* insert last command line */
! 602: {
! 603: if (last_cmdline == NULL)
! 604: return FAIL;
! 605: return put_on_cmdline(last_cmdline, -1, TRUE);
! 606: }
! 607:
! 608: yankbuffer = c;
! 609: get_yank_buffer(FALSE);
! 610: if (y_current->y_array == NULL)
! 611: return FAIL;
! 612:
! 613: for (i = 0; i < y_current->y_size; ++i)
! 614: {
! 615: put_on_cmdline(y_current->y_array[i], -1, FALSE);
! 616:
! 617: /* insert ^M between lines and after last line if type is MLINE */
! 618: if (y_current->y_type == MLINE || i < y_current->y_size - 1)
! 619: put_on_cmdline((char_u *)"\r", 1, FALSE);
! 620: }
! 621: return OK;
! 622: }
! 623:
! 624: /*
! 625: * do_delete - handle a delete operation
! 626: */
! 627: void
! 628: do_delete()
! 629: {
! 630: register int n;
! 631: linenr_t lnum;
! 632: char_u *ptr;
! 633: char_u *newp, *oldp;
! 634: linenr_t old_lcount = curbuf->b_ml.ml_line_count;
! 635: int did_yank = FALSE;
! 636: struct block_def bd;
! 637:
! 638: if (curbuf->b_ml.ml_flags & ML_EMPTY) /* nothing to do */
! 639: return;
! 640:
! 641: /*
! 642: * Imitate the strange Vi behaviour: If the delete spans more than one line
! 643: * and op_motion_type == MCHAR and the result is a blank line, make the delete
! 644: * linewise. Don't do this for the change command.
! 645: */
! 646: if (op_motion_type == MCHAR && op_line_count > 1 && op_type == DELETE)
! 647: {
! 648: ptr = ml_get(curbuf->b_op_end.lnum) + curbuf->b_op_end.col +
! 649: op_inclusive;
! 650: ptr = skipwhite(ptr);
! 651: if (*ptr == NUL && inindent(0))
! 652: op_motion_type = MLINE;
! 653: }
! 654:
! 655: /*
! 656: * Check for trying to delete (e.g. "D") in an empty line.
! 657: * Note: For change command it is ok.
! 658: */
! 659: if (op_motion_type == MCHAR && op_line_count == 1 &&
! 660: op_type == DELETE && *ml_get(curbuf->b_op_start.lnum) == NUL)
! 661: {
! 662: beep_flush();
! 663: return;
! 664: }
! 665:
! 666: /*
! 667: * Do a yank of whatever we're about to delete.
! 668: * If a yank buffer was specified, put the deleted text into that buffer
! 669: */
! 670: if (yankbuffer != 0)
! 671: {
! 672: /* check for read-only buffer */
! 673: if (!is_yank_buffer(yankbuffer, TRUE))
! 674: {
! 675: beep_flush();
! 676: return;
! 677: }
! 678: get_yank_buffer(TRUE); /* yank into specified buffer */
! 679: if (do_yank(TRUE, FALSE) == OK) /* yank without message */
! 680: did_yank = TRUE;
! 681: }
! 682:
! 683: /*
! 684: * Put deleted text into register 1 and shift number buffers if
! 685: * the delete contains a line break, or when a yankbuffer has been specified!
! 686: */
! 687: if (yankbuffer != 0 || op_motion_type == MLINE || op_line_count > 1)
! 688: {
! 689: y_current = &y_buf[9];
! 690: free_yank_all(); /* free buffer nine */
! 691: for (n = 9; n > 1; --n)
! 692: y_buf[n] = y_buf[n - 1];
! 693: y_previous = y_current = &y_buf[1];
! 694: y_buf[1].y_array = NULL; /* set buffer one to empty */
! 695: yankbuffer = 0;
! 696: }
! 697: else if (yankbuffer == 0) /* yank into unnamed buffer */
! 698: {
! 699: yankbuffer = '-'; /* use special delete buffer */
! 700: get_yank_buffer(TRUE);
! 701: yankbuffer = 0;
! 702: }
! 703:
! 704: if (yankbuffer == 0 && do_yank(TRUE, FALSE) == OK)
! 705: did_yank = TRUE;
! 706:
! 707: /*
! 708: * If there's too much stuff to fit in the yank buffer, then get a
! 709: * confirmation before doing the delete. This is crude, but simple. And it
! 710: * avoids doing a delete of something we can't put back if we want.
! 711: */
! 712: if (!did_yank)
! 713: {
! 714: if (ask_yesno((char_u *)"cannot yank; delete anyway", TRUE) != 'y')
! 715: {
! 716: emsg(e_abort);
! 717: return;
! 718: }
! 719: }
! 720:
! 721: /*
! 722: * block mode delete
! 723: */
! 724: if (op_block_mode)
! 725: {
! 726: if (u_save((linenr_t)(curbuf->b_op_start.lnum - 1),
! 727: (linenr_t)(curbuf->b_op_end.lnum + 1)) == FAIL)
! 728: return;
! 729:
! 730: for (lnum = curwin->w_cursor.lnum;
! 731: curwin->w_cursor.lnum <= curbuf->b_op_end.lnum;
! 732: ++curwin->w_cursor.lnum)
! 733: {
! 734: block_prep(&bd, curwin->w_cursor.lnum, TRUE);
! 735: if (bd.textlen == 0) /* nothing to delete */
! 736: continue;
! 737:
! 738: /*
! 739: * If we delete a TAB, it may be replaced by several characters.
! 740: * Thus the number of characters may increase!
! 741: */
! 742: n = bd.textlen - bd.startspaces - bd.endspaces; /* number of chars deleted */
! 743: oldp = ml_get_curline();
! 744: newp = alloc_check((unsigned)STRLEN(oldp) + 1 - n);
! 745: if (newp == NULL)
! 746: continue;
! 747: /* copy up to deleted part */
! 748: vim_memmove(newp, oldp, (size_t)bd.textcol);
! 749: /* insert spaces */
! 750: copy_spaces(newp + bd.textcol, (size_t)(bd.startspaces + bd.endspaces));
! 751: /* copy the part after the deleted part */
! 752: oldp += bd.textcol + bd.textlen;
! 753: vim_memmove(newp + bd.textcol + bd.startspaces + bd.endspaces,
! 754: oldp, STRLEN(oldp) + 1);
! 755: /* replace the line */
! 756: ml_replace(curwin->w_cursor.lnum, newp, FALSE);
! 757: }
! 758: curwin->w_cursor.lnum = lnum;
! 759: CHANGED;
! 760: updateScreen(VALID_TO_CURSCHAR);
! 761: op_line_count = 0; /* no lines deleted */
! 762: }
! 763: else if (op_motion_type == MLINE)
! 764: {
! 765: if (op_type == CHANGE)
! 766: {
! 767: /* Delete the lines except the first one.
! 768: * Temporarily move the cursor to the next line.
! 769: * Save the current line number, if the last line is deleted
! 770: * it may be changed.
! 771: */
! 772: if (op_line_count > 1)
! 773: {
! 774: lnum = curwin->w_cursor.lnum;
! 775: ++curwin->w_cursor.lnum;
! 776: dellines((long)(op_line_count - 1), TRUE, TRUE);
! 777: curwin->w_cursor.lnum = lnum;
! 778: }
! 779: if (u_save_cursor() == FAIL)
! 780: return;
! 781: if (curbuf->b_p_ai) /* don't delete indent */
! 782: {
! 783: beginline(TRUE); /* put cursor on first non-white */
! 784: did_ai = TRUE; /* delete the indent when ESC hit */
! 785: }
! 786: truncate_line(FALSE);
! 787: if (curwin->w_cursor.col > 0)
! 788: --curwin->w_cursor.col; /* put cursor on last char in line */
! 789: }
! 790: else
! 791: {
! 792: dellines(op_line_count, TRUE, TRUE);
! 793: }
! 794: u_clearline(); /* "U" command should not be possible after "dd" */
! 795: beginline(TRUE);
! 796: }
! 797: else if (op_line_count == 1) /* delete characters within one line */
! 798: {
! 799: if (u_save_cursor() == FAIL)
! 800: return;
! 801: /* if 'cpoptions' contains '$', display '$' at end of change */
! 802: if (vim_strchr(p_cpo, CPO_DOLLAR) != NULL && op_type == CHANGE &&
! 803: curbuf->b_op_end.lnum == curwin->w_cursor.lnum && !op_is_VIsual)
! 804: display_dollar(curbuf->b_op_end.col - !op_inclusive);
! 805: n = curbuf->b_op_end.col - curbuf->b_op_start.col + 1 - !op_inclusive;
! 806: while (n-- > 0)
! 807: if (delchar(TRUE) == FAIL)
! 808: break;
! 809: }
! 810: else /* delete characters between lines */
! 811: {
! 812: if (u_save_cursor() == FAIL) /* save first line for undo */
! 813: return;
! 814: truncate_line(TRUE); /* delete from cursor to end of line */
! 815:
! 816: curbuf->b_op_start = curwin->w_cursor; /* remember curwin->w_cursor */
! 817: ++curwin->w_cursor.lnum;
! 818: /* includes save for undo */
! 819: dellines((long)(op_line_count - 2), TRUE, TRUE);
! 820:
! 821: if (u_save_cursor() == FAIL) /* save last line for undo */
! 822: return;
! 823: n = curbuf->b_op_end.col - !op_inclusive;
! 824: curwin->w_cursor.col = 0;
! 825: while (n-- >= 0) /* delete from start of line until op_end */
! 826: if (delchar(TRUE) == FAIL)
! 827: break;
! 828: curwin->w_cursor = curbuf->b_op_start; /* restore curwin->w_cursor */
! 829: (void)do_join(FALSE, curs_rows() == OK);
! 830: }
! 831:
! 832: if ((op_motion_type == MCHAR && op_line_count == 1) || op_type == CHANGE)
! 833: {
! 834: if (dollar_vcol)
! 835: must_redraw = 0; /* don't want a redraw now */
! 836: cursupdate();
! 837: if (!dollar_vcol)
! 838: updateline();
! 839: }
! 840: else if (!global_busy) /* no need to update screen for :global */
! 841: updateScreen(CURSUPD);
! 842:
! 843: msgmore(curbuf->b_ml.ml_line_count - old_lcount);
! 844:
! 845: /* correct op_end for deleted text (for "']" command) */
! 846: if (op_block_mode)
! 847: curbuf->b_op_end.col = curbuf->b_op_start.col;
! 848: else
! 849: curbuf->b_op_end = curbuf->b_op_start;
! 850: }
! 851:
! 852: /*
! 853: * do_tilde - handle the (non-standard vi) tilde operator
! 854: */
! 855: void
! 856: do_tilde()
! 857: {
! 858: FPOS pos;
! 859: struct block_def bd;
! 860:
! 861: if (u_save((linenr_t)(curbuf->b_op_start.lnum - 1),
! 862: (linenr_t)(curbuf->b_op_end.lnum + 1)) == FAIL)
! 863: return;
! 864:
! 865: pos = curbuf->b_op_start;
! 866: if (op_block_mode) /* Visual block mode */
! 867: {
! 868: for (; pos.lnum <= curbuf->b_op_end.lnum; ++pos.lnum)
! 869: {
! 870: block_prep(&bd, pos.lnum, FALSE);
! 871: pos.col = bd.textcol;
! 872: while (--bd.textlen >= 0)
! 873: {
! 874: swapchar(&pos);
! 875: if (inc(&pos) == -1) /* at end of file */
! 876: break;
! 877: }
! 878: }
! 879: }
! 880: else /* not block mode */
! 881: {
! 882: if (op_motion_type == MLINE)
! 883: {
! 884: pos.col = 0;
! 885: curbuf->b_op_end.col = STRLEN(ml_get(curbuf->b_op_end.lnum));
! 886: if (curbuf->b_op_end.col)
! 887: --curbuf->b_op_end.col;
! 888: }
! 889: else if (!op_inclusive)
! 890: dec(&(curbuf->b_op_end));
! 891:
! 892: while (ltoreq(pos, curbuf->b_op_end))
! 893: {
! 894: swapchar(&pos);
! 895: if (inc(&pos) == -1) /* at end of file */
! 896: break;
! 897: }
! 898: }
! 899:
! 900: if (op_motion_type == MCHAR && op_line_count == 1 && !op_block_mode)
! 901: {
! 902: cursupdate();
! 903: updateline();
! 904: }
! 905: else
! 906: updateScreen(CURSUPD);
! 907:
! 908: if (op_line_count > p_report)
! 909: smsg((char_u *)"%ld line%s ~ed",
! 910: op_line_count, plural(op_line_count));
! 911: }
! 912:
! 913: /*
! 914: * If op_type == UPPER: make uppercase,
! 915: * if op_type == LOWER: make lowercase,
! 916: * else swap case of character at 'pos'
! 917: */
! 918: void
! 919: swapchar(pos)
! 920: FPOS *pos;
! 921: {
! 922: int c;
! 923:
! 924: c = gchar(pos);
! 925: if (islower(c) && op_type != LOWER)
! 926: {
! 927: pchar(*pos, toupper(c));
! 928: CHANGED;
! 929: }
! 930: else if (isupper(c) && op_type != UPPER)
! 931: {
! 932: pchar(*pos, tolower(c));
! 933: CHANGED;
! 934: }
! 935: }
! 936:
! 937: /*
! 938: * do_change - handle a change operation
! 939: *
! 940: * return TRUE if edit() returns because of a CTRL-O command
! 941: */
! 942: int
! 943: do_change()
! 944: {
! 945: register colnr_t l;
! 946:
! 947: l = curbuf->b_op_start.col;
! 948: if (op_motion_type == MLINE)
! 949: {
! 950: l = 0;
! 951: can_si = TRUE; /* It's like opening a new line, do si */
! 952: }
! 953:
! 954: if (!op_empty)
! 955: do_delete(); /* delete the text and take care of undo */
! 956:
! 957: if ((l > curwin->w_cursor.col) && !lineempty(curwin->w_cursor.lnum))
! 958: inc_cursor();
! 959:
! 960: #ifdef LISPINDENT
! 961: if (op_motion_type == MLINE)
! 962: {
! 963: if (curbuf->b_p_lisp && curbuf->b_p_ai)
! 964: fixthisline(get_lisp_indent);
! 965: # ifdef CINDENT
! 966: else if (curbuf->b_p_cin)
! 967: fixthisline(get_c_indent);
! 968: # endif
! 969: }
! 970: #endif
! 971:
! 972: op_type = NOP; /* don't want op_type == CHANGED in Insert mode */
! 973: return edit(NUL, FALSE, (linenr_t)1);
! 974: }
! 975:
! 976: /*
! 977: * set all the yank buffers to empty (called from main())
! 978: */
! 979: void
! 980: init_yank()
! 981: {
! 982: register int i;
! 983:
! 984: for (i = 0; i < NUM_REGISTERS; ++i)
! 985: y_buf[i].y_array = NULL;
! 986: }
! 987:
! 988: /*
! 989: * Free "n" lines from the current yank buffer.
! 990: * Called for normal freeing and in case of error.
! 991: */
! 992: static void
! 993: free_yank(n)
! 994: long n;
! 995: {
! 996: if (y_current->y_array != NULL)
! 997: {
! 998: register long i;
! 999:
! 1000: for (i = n; --i >= 0; )
! 1001: {
! 1002: if ((i & 1023) == 1023) /* this may take a while */
! 1003: {
! 1004: /*
! 1005: * This message should never cause a hit-return message.
! 1006: * Overwrite this message with any next message.
! 1007: */
! 1008: ++no_wait_return;
! 1009: smsg((char_u *)"freeing %ld lines", i + 1);
! 1010: --no_wait_return;
! 1011: msg_didout = FALSE;
! 1012: msg_col = 0;
! 1013: }
! 1014: vim_free(y_current->y_array[i]);
! 1015: }
! 1016: vim_free(y_current->y_array);
! 1017: y_current->y_array = NULL;
! 1018: if (n >= 1000)
! 1019: MSG("");
! 1020: }
! 1021: }
! 1022:
! 1023: static void
! 1024: free_yank_all()
! 1025: {
! 1026: free_yank(y_current->y_size);
! 1027: }
! 1028:
! 1029: /*
! 1030: * Yank the text between curwin->w_cursor and startpos into a yank buffer.
! 1031: * If we are to append ("uppercase), we first yank into a new yank buffer and
! 1032: * then concatenate the old and the new one (so we keep the old one in case
! 1033: * of out-of-memory).
! 1034: *
! 1035: * return FAIL for failure, OK otherwise
! 1036: */
! 1037: int
! 1038: do_yank(deleting, mess)
! 1039: int deleting;
! 1040: int mess;
! 1041: {
! 1042: long i; /* index in y_array[] */
! 1043: struct yankbuf *curr; /* copy of y_current */
! 1044: struct yankbuf newbuf; /* new yank buffer when appending */
! 1045: char_u **new_ptr;
! 1046: register linenr_t lnum; /* current line number */
! 1047: long j;
! 1048: int yanktype = op_motion_type;
! 1049: long yanklines = op_line_count;
! 1050: linenr_t yankendlnum = curbuf->b_op_end.lnum;
! 1051:
! 1052: char_u *pnew;
! 1053: struct block_def bd;
! 1054:
! 1055: /* check for read-only buffer */
! 1056: if (yankbuffer != 0 && !is_yank_buffer(yankbuffer, TRUE))
! 1057: {
! 1058: beep_flush();
! 1059: return FAIL;
! 1060: }
! 1061: if (!deleting) /* do_delete() already set y_current */
! 1062: get_yank_buffer(TRUE);
! 1063:
! 1064: curr = y_current;
! 1065: /* append to existing contents */
! 1066: if (yankappend && y_current->y_array != NULL)
! 1067: y_current = &newbuf;
! 1068: else
! 1069: free_yank_all(); /* free previously yanked lines */
! 1070:
! 1071: /*
! 1072: * If the cursor was in column 1 before and after the movement, and the
! 1073: * operator is not inclusive, the yank is always linewise.
! 1074: */
! 1075: if (op_motion_type == MCHAR && curbuf->b_op_start.col == 0 &&
! 1076: !op_inclusive && curbuf->b_op_end.col == 0 && yanklines > 1)
! 1077: {
! 1078: yanktype = MLINE;
! 1079: --yankendlnum;
! 1080: --yanklines;
! 1081: }
! 1082:
! 1083: y_current->y_size = yanklines;
! 1084: y_current->y_type = yanktype; /* set the yank buffer type */
! 1085: y_current->y_array = (char_u **)lalloc((long_u)(sizeof(char_u *) *
! 1086: yanklines), TRUE);
! 1087:
! 1088: if (y_current->y_array == NULL)
! 1089: {
! 1090: y_current = curr;
! 1091: return FAIL;
! 1092: }
! 1093:
! 1094: i = 0;
! 1095: lnum = curbuf->b_op_start.lnum;
! 1096:
! 1097: /*
! 1098: * Visual block mode
! 1099: */
! 1100: if (op_block_mode)
! 1101: {
! 1102: y_current->y_type = MBLOCK; /* set the yank buffer type */
! 1103: for ( ; lnum <= yankendlnum; ++lnum)
! 1104: {
! 1105: block_prep(&bd, lnum, FALSE);
! 1106:
! 1107: if ((pnew = alloc(bd.startspaces + bd.endspaces +
! 1108: bd.textlen + 1)) == NULL)
! 1109: goto fail;
! 1110: y_current->y_array[i++] = pnew;
! 1111:
! 1112: copy_spaces(pnew, (size_t)bd.startspaces);
! 1113: pnew += bd.startspaces;
! 1114:
! 1115: vim_memmove(pnew, bd.textstart, (size_t)bd.textlen);
! 1116: pnew += bd.textlen;
! 1117:
! 1118: copy_spaces(pnew, (size_t)bd.endspaces);
! 1119: pnew += bd.endspaces;
! 1120:
! 1121: *pnew = NUL;
! 1122: }
! 1123: }
! 1124: else
! 1125: {
! 1126: /*
! 1127: * there are three parts for non-block mode:
! 1128: * 1. if yanktype != MLINE yank last part of the top line
! 1129: * 2. yank the lines between op_start and op_end, inclusive when
! 1130: * yanktype == MLINE
! 1131: * 3. if yanktype != MLINE yank first part of the bot line
! 1132: */
! 1133: if (yanktype != MLINE)
! 1134: {
! 1135: if (yanklines == 1) /* op_start and op_end on same line */
! 1136: {
! 1137: j = curbuf->b_op_end.col - curbuf->b_op_start.col +
! 1138: 1 - !op_inclusive;
! 1139: if ((y_current->y_array[0] = strnsave(ml_get(lnum) +
! 1140: curbuf->b_op_start.col, (int)j)) == NULL)
! 1141: {
! 1142: fail:
! 1143: free_yank(i); /* free the allocated lines */
! 1144: y_current = curr;
! 1145: return FAIL;
! 1146: }
! 1147: goto success;
! 1148: }
! 1149: if ((y_current->y_array[0] = strsave(ml_get(lnum++) +
! 1150: curbuf->b_op_start.col)) == NULL)
! 1151: goto fail;
! 1152: ++i;
! 1153: }
! 1154:
! 1155: while (yanktype == MLINE ? (lnum <= yankendlnum) : (lnum < yankendlnum))
! 1156: {
! 1157: if ((y_current->y_array[i] = strsave(ml_get(lnum++))) == NULL)
! 1158: goto fail;
! 1159: ++i;
! 1160: }
! 1161: if (yanktype != MLINE)
! 1162: {
! 1163: if ((y_current->y_array[i] = strnsave(ml_get(yankendlnum),
! 1164: curbuf->b_op_end.col + 1 - !op_inclusive)) == NULL)
! 1165: goto fail;
! 1166: }
! 1167: }
! 1168:
! 1169: success:
! 1170: if (curr != y_current) /* append the new block to the old block */
! 1171: {
! 1172: new_ptr = (char_u **)lalloc((long_u)(sizeof(char_u *) *
! 1173: (curr->y_size + y_current->y_size)), TRUE);
! 1174: if (new_ptr == NULL)
! 1175: goto fail;
! 1176: for (j = 0; j < curr->y_size; ++j)
! 1177: new_ptr[j] = curr->y_array[j];
! 1178: vim_free(curr->y_array);
! 1179: curr->y_array = new_ptr;
! 1180:
! 1181: if (yanktype == MLINE) /* MLINE overrides MCHAR and MBLOCK */
! 1182: curr->y_type = MLINE;
! 1183:
! 1184: /* concatenate the last line of the old block with the first line of
! 1185: * the new block */
! 1186: if (curr->y_type == MCHAR)
! 1187: {
! 1188: pnew = lalloc((long_u)(STRLEN(curr->y_array[curr->y_size - 1])
! 1189: + STRLEN(y_current->y_array[0]) + 1), TRUE);
! 1190: if (pnew == NULL)
! 1191: {
! 1192: i = y_current->y_size - 1;
! 1193: goto fail;
! 1194: }
! 1195: STRCPY(pnew, curr->y_array[--j]);
! 1196: STRCAT(pnew, y_current->y_array[0]);
! 1197: vim_free(curr->y_array[j]);
! 1198: vim_free(y_current->y_array[0]);
! 1199: curr->y_array[j++] = pnew;
! 1200: i = 1;
! 1201: }
! 1202: else
! 1203: i = 0;
! 1204: while (i < y_current->y_size)
! 1205: curr->y_array[j++] = y_current->y_array[i++];
! 1206: curr->y_size = j;
! 1207: vim_free(y_current->y_array);
! 1208: y_current = curr;
! 1209: }
! 1210: if (mess) /* Display message about yank? */
! 1211: {
! 1212: if (yanktype == MCHAR && !op_block_mode)
! 1213: --yanklines;
! 1214: if (yanklines > p_report)
! 1215: {
! 1216: cursupdate(); /* redisplay now, so message is not deleted */
! 1217: smsg((char_u *)"%ld line%s yanked", yanklines, plural(yanklines));
! 1218: }
! 1219: }
! 1220:
! 1221: return OK;
! 1222: }
! 1223:
! 1224: /*
! 1225: * put contents of register into the text
! 1226: * For ":put" command count == -1.
! 1227: */
! 1228: void
! 1229: do_put(dir, count, fix_indent)
! 1230: int dir; /* BACKWARD for 'P', FORWARD for 'p' */
! 1231: long count;
! 1232: int fix_indent; /* make indent look nice */
! 1233: {
! 1234: char_u *ptr;
! 1235: char_u *newp, *oldp;
! 1236: int yanklen;
! 1237: int oldlen;
! 1238: int totlen = 0; /* init for gcc */
! 1239: linenr_t lnum;
! 1240: colnr_t col;
! 1241: long i; /* index in y_array[] */
! 1242: int y_type;
! 1243: long y_size;
! 1244: char_u **y_array;
! 1245: long nr_lines = 0;
! 1246: colnr_t vcol;
! 1247: int delcount;
! 1248: int incr = 0;
! 1249: long j;
! 1250: FPOS new_cursor;
! 1251: int indent;
! 1252: int orig_indent = 0; /* init for gcc */
! 1253: int indent_diff = 0; /* init for gcc */
! 1254: int first_indent = TRUE;
! 1255: FPOS old_pos;
! 1256: struct block_def bd;
! 1257: char_u *insert_string = NULL;
! 1258:
! 1259: #ifdef USE_GUI
! 1260: if (yankbuffer == '*')
! 1261: gui_get_selection();
! 1262: #endif
! 1263:
! 1264: if (fix_indent)
! 1265: orig_indent = get_indent();
! 1266:
! 1267: curbuf->b_op_start = curwin->w_cursor; /* default for "'[" command */
! 1268: if (dir == FORWARD)
! 1269: curbuf->b_op_start.col++;
! 1270: curbuf->b_op_end = curwin->w_cursor; /* default for "']" command */
! 1271:
! 1272: /*
! 1273: * Using inserted text works differently, because the buffer includes
! 1274: * special characters (newlines, etc.).
! 1275: */
! 1276: if (yankbuffer == '.')
! 1277: {
! 1278: (void)stuff_inserted((dir == FORWARD ? (count == -1 ? 'o' : 'a') :
! 1279: (count == -1 ? 'O' : 'i')), count, FALSE);
! 1280: return;
! 1281: }
! 1282:
! 1283: /*
! 1284: * For '%' (file name) and ':' (last command line) we have to create a
! 1285: * fake yank buffer.
! 1286: */
! 1287: if (yankbuffer == '%') /* use file name */
! 1288: {
! 1289: if (check_fname() == FAIL)
! 1290: return;
! 1291: insert_string = curbuf->b_xfilename;
! 1292: }
! 1293: else if (yankbuffer == ':') /* use last command line */
! 1294: {
! 1295: if (last_cmdline == NULL)
! 1296: {
! 1297: EMSG(e_nolastcmd);
! 1298: return;
! 1299: }
! 1300: insert_string = last_cmdline;
! 1301: }
! 1302:
! 1303: if (insert_string != NULL)
! 1304: {
! 1305: y_type = MCHAR; /* use fake one-line yank buffer */
! 1306: y_size = 1;
! 1307: y_array = &insert_string;
! 1308: }
! 1309: else
! 1310: {
! 1311: get_yank_buffer(FALSE);
! 1312:
! 1313: y_type = y_current->y_type;
! 1314: y_size = y_current->y_size;
! 1315: y_array = y_current->y_array;
! 1316: }
! 1317:
! 1318: if (count == -1) /* :put command */
! 1319: {
! 1320: y_type = MLINE;
! 1321: count = 1;
! 1322: }
! 1323:
! 1324: if (y_size == 0 || y_array == NULL)
! 1325: {
! 1326: EMSG2("Nothing in register %s", transchar(yankbuffer));
! 1327: return;
! 1328: }
! 1329:
! 1330: if (y_type == MBLOCK)
! 1331: {
! 1332: lnum = curwin->w_cursor.lnum + y_size + 1;
! 1333: if (lnum > curbuf->b_ml.ml_line_count)
! 1334: lnum = curbuf->b_ml.ml_line_count + 1;
! 1335: if (u_save(curwin->w_cursor.lnum - 1, lnum) == FAIL)
! 1336: return;
! 1337: }
! 1338: else if (u_save_cursor() == FAIL)
! 1339: return;
! 1340:
! 1341: yanklen = STRLEN(y_array[0]);
! 1342: CHANGED;
! 1343:
! 1344: lnum = curwin->w_cursor.lnum;
! 1345: col = curwin->w_cursor.col;
! 1346:
! 1347: /*
! 1348: * block mode
! 1349: */
! 1350: if (y_type == MBLOCK)
! 1351: {
! 1352: if (dir == FORWARD && gchar_cursor() != NUL)
! 1353: {
! 1354: getvcol(curwin, &curwin->w_cursor, NULL, NULL, &col);
! 1355: ++col;
! 1356: ++curwin->w_cursor.col;
! 1357: }
! 1358: else
! 1359: getvcol(curwin, &curwin->w_cursor, &col, NULL, NULL);
! 1360: for (i = 0; i < y_size; ++i)
! 1361: {
! 1362: bd.startspaces = 0;
! 1363: bd.endspaces = 0;
! 1364: bd.textcol = 0;
! 1365: vcol = 0;
! 1366: delcount = 0;
! 1367:
! 1368: /* add a new line */
! 1369: if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
! 1370: {
! 1371: ml_append(curbuf->b_ml.ml_line_count, (char_u *)"",
! 1372: (colnr_t)1, FALSE);
! 1373: ++nr_lines;
! 1374: }
! 1375: oldp = ml_get_curline();
! 1376: oldlen = STRLEN(oldp);
! 1377: for (ptr = oldp; vcol < col && *ptr; ++ptr)
! 1378: {
! 1379: /* Count a tab for what it's worth (if list mode not on) */
! 1380: incr = lbr_chartabsize(ptr, (colnr_t)vcol);
! 1381: vcol += incr;
! 1382: ++bd.textcol;
! 1383: }
! 1384: if (vcol < col) /* line too short, padd with spaces */
! 1385: {
! 1386: bd.startspaces = col - vcol;
! 1387: }
! 1388: else if (vcol > col)
! 1389: {
! 1390: bd.endspaces = vcol - col;
! 1391: bd.startspaces = incr - bd.endspaces;
! 1392: --bd.textcol;
! 1393: delcount = 1;
! 1394: }
! 1395: yanklen = STRLEN(y_array[i]);
! 1396: totlen = count * yanklen + bd.startspaces + bd.endspaces;
! 1397: newp = alloc_check((unsigned)totlen + oldlen + 1);
! 1398: if (newp == NULL)
! 1399: break;
! 1400: /* copy part up to cursor to new line */
! 1401: ptr = newp;
! 1402: vim_memmove(ptr, oldp, (size_t)bd.textcol);
! 1403: ptr += bd.textcol;
! 1404: /* may insert some spaces before the new text */
! 1405: copy_spaces(ptr, (size_t)bd.startspaces);
! 1406: ptr += bd.startspaces;
! 1407: /* insert the new text */
! 1408: for (j = 0; j < count; ++j)
! 1409: {
! 1410: vim_memmove(ptr, y_array[i], (size_t)yanklen);
! 1411: ptr += yanklen;
! 1412: }
! 1413: /* may insert some spaces after the new text */
! 1414: copy_spaces(ptr, (size_t)bd.endspaces);
! 1415: ptr += bd.endspaces;
! 1416: /* move the text after the cursor to the end of the line. */
! 1417: vim_memmove(ptr, oldp + bd.textcol + delcount,
! 1418: (size_t)(oldlen - bd.textcol - delcount + 1));
! 1419: ml_replace(curwin->w_cursor.lnum, newp, FALSE);
! 1420:
! 1421: ++curwin->w_cursor.lnum;
! 1422: if (i == 0)
! 1423: curwin->w_cursor.col += bd.startspaces;
! 1424: }
! 1425: /* for "']" command */
! 1426: curbuf->b_op_end.lnum = curwin->w_cursor.lnum - 1;
! 1427: curbuf->b_op_end.col = bd.textcol + totlen - 1;
! 1428: curwin->w_cursor.lnum = lnum;
! 1429: cursupdate();
! 1430: updateScreen(VALID_TO_CURSCHAR);
! 1431: }
! 1432: else /* not block mode */
! 1433: {
! 1434: if (y_type == MCHAR)
! 1435: {
! 1436: /* if type is MCHAR, FORWARD is the same as BACKWARD on the next char */
! 1437: if (dir == FORWARD && gchar_cursor() != NUL)
! 1438: {
! 1439: ++col;
! 1440: if (yanklen)
! 1441: {
! 1442: ++curwin->w_cursor.col;
! 1443: ++curbuf->b_op_end.col;
! 1444: }
! 1445: }
! 1446: new_cursor = curwin->w_cursor;
! 1447: }
! 1448: else if (dir == BACKWARD)
! 1449: /* if type is MLINE, BACKWARD is the same as FORWARD on the previous line */
! 1450: --lnum;
! 1451:
! 1452: /*
! 1453: * simple case: insert into current line
! 1454: */
! 1455: if (y_type == MCHAR && y_size == 1)
! 1456: {
! 1457: totlen = count * yanklen;
! 1458: if (totlen)
! 1459: {
! 1460: oldp = ml_get(lnum);
! 1461: newp = alloc_check((unsigned)(STRLEN(oldp) + totlen + 1));
! 1462: if (newp == NULL)
! 1463: return; /* alloc() will give error message */
! 1464: vim_memmove(newp, oldp, (size_t)col);
! 1465: ptr = newp + col;
! 1466: for (i = 0; i < count; ++i)
! 1467: {
! 1468: vim_memmove(ptr, y_array[0], (size_t)yanklen);
! 1469: ptr += yanklen;
! 1470: }
! 1471: vim_memmove(ptr, oldp + col, STRLEN(oldp + col) + 1);
! 1472: ml_replace(lnum, newp, FALSE);
! 1473: /* put cursor on last putted char */
! 1474: curwin->w_cursor.col += (colnr_t)(totlen - 1);
! 1475: }
! 1476: curbuf->b_op_end = curwin->w_cursor;
! 1477: updateline();
! 1478: }
! 1479: else
! 1480: {
! 1481: while (--count >= 0)
! 1482: {
! 1483: i = 0;
! 1484: if (y_type == MCHAR)
! 1485: {
! 1486: /*
! 1487: * Split the current line in two at the insert position.
! 1488: * First insert y_array[size - 1] in front of second line.
! 1489: * Then append y_array[0] to first line.
! 1490: */
! 1491: ptr = ml_get(lnum) + col;
! 1492: totlen = STRLEN(y_array[y_size - 1]);
! 1493: newp = alloc_check((unsigned)(STRLEN(ptr) + totlen + 1));
! 1494: if (newp == NULL)
! 1495: goto error;
! 1496: STRCPY(newp, y_array[y_size - 1]);
! 1497: STRCAT(newp, ptr);
! 1498: /* insert second line */
! 1499: ml_append(lnum, newp, (colnr_t)0, FALSE);
! 1500: vim_free(newp);
! 1501:
! 1502: oldp = ml_get(lnum);
! 1503: newp = alloc_check((unsigned)(col + yanklen + 1));
! 1504: if (newp == NULL)
! 1505: goto error;
! 1506: /* copy first part of line */
! 1507: vim_memmove(newp, oldp, (size_t)col);
! 1508: /* append to first line */
! 1509: vim_memmove(newp + col, y_array[0], (size_t)(yanklen + 1));
! 1510: ml_replace(lnum, newp, FALSE);
! 1511:
! 1512: curwin->w_cursor.lnum = lnum;
! 1513: i = 1;
! 1514: }
! 1515:
! 1516: while (i < y_size)
! 1517: {
! 1518: if ((y_type != MCHAR || i < y_size - 1) &&
! 1519: ml_append(lnum, y_array[i], (colnr_t)0, FALSE) == FAIL)
! 1520: goto error;
! 1521: lnum++;
! 1522: i++;
! 1523: if (fix_indent)
! 1524: {
! 1525: old_pos = curwin->w_cursor;
! 1526: curwin->w_cursor.lnum = lnum;
! 1527: ptr = ml_get(lnum);
! 1528: #if defined(SMARTINDENT) || defined(CINDENT)
! 1529: if (*ptr == '#'
! 1530: # ifdef SMARTINDENT
! 1531: && curbuf->b_p_si
! 1532: # endif
! 1533: # ifdef CINDENT
! 1534: && curbuf->b_p_cin && in_cinkeys('#', ' ', TRUE)
! 1535: # endif
! 1536: )
! 1537:
! 1538: indent = 0; /* Leave # lines at start */
! 1539: else
! 1540: #endif
! 1541: if (*ptr == NUL)
! 1542: indent = 0; /* Ignore empty lines */
! 1543: else if (first_indent)
! 1544: {
! 1545: indent_diff = orig_indent - get_indent();
! 1546: indent = orig_indent;
! 1547: first_indent = FALSE;
! 1548: }
! 1549: else if ((indent = get_indent() + indent_diff) < 0)
! 1550: indent = 0;
! 1551: set_indent(indent, TRUE);
! 1552: curwin->w_cursor = old_pos;
! 1553: }
! 1554: ++nr_lines;
! 1555: }
! 1556: }
! 1557:
! 1558: /* put '] at last inserted character */
! 1559: curbuf->b_op_end.lnum = lnum;
! 1560: col = STRLEN(y_array[y_size - 1]);
! 1561: if (col > 1)
! 1562: curbuf->b_op_end.col = col - 1;
! 1563: else
! 1564: curbuf->b_op_end.col = 0;
! 1565:
! 1566: if (y_type == MLINE)
! 1567: {
! 1568: curwin->w_cursor.col = 0;
! 1569: if (dir == FORWARD)
! 1570: {
! 1571: updateScreen(NOT_VALID); /* recomp. curwin->w_botline */
! 1572: ++curwin->w_cursor.lnum;
! 1573: }
! 1574: /* put cursor on first non-blank in last inserted line */
! 1575: beginline(TRUE);
! 1576: }
! 1577: else /* put cursor on first inserted character */
! 1578: {
! 1579: curwin->w_cursor = new_cursor;
! 1580: }
! 1581:
! 1582: error:
! 1583: if (y_type == MLINE) /* for '[ */
! 1584: {
! 1585: curbuf->b_op_start.col = 0;
! 1586: if (dir == FORWARD)
! 1587: curbuf->b_op_start.lnum++;
! 1588: }
! 1589: mark_adjust(curbuf->b_op_start.lnum + (y_type == MCHAR),
! 1590: MAXLNUM, nr_lines, 0L);
! 1591: updateScreen(CURSUPD);
! 1592: }
! 1593: }
! 1594:
! 1595: msgmore(nr_lines);
! 1596: curwin->w_set_curswant = TRUE;
! 1597: }
! 1598:
! 1599: /* Return the character name of the register with the given number */
! 1600: int
! 1601: get_register_name(num)
! 1602: int num;
! 1603: {
! 1604: if (num == -1)
! 1605: return '"';
! 1606: else if (num < 10)
! 1607: return num + '0';
! 1608: else if (num == DELETION_REGISTER)
! 1609: return '-';
! 1610: #ifdef USE_GUI
! 1611: else if (num == GUI_SELECTION_REGISTER)
! 1612: return '*';
! 1613: #endif
! 1614: else
! 1615: return num + 'a' - 10;
! 1616: }
! 1617:
! 1618: /*
! 1619: * display the contents of the yank buffers
! 1620: */
! 1621: void
! 1622: do_dis(arg)
! 1623: char_u *arg;
! 1624: {
! 1625: register int i, n;
! 1626: register long j;
! 1627: register char_u *p;
! 1628: register struct yankbuf *yb;
! 1629: char_u name;
! 1630:
! 1631: if (arg != NULL && *arg == NUL)
! 1632: arg = NULL;
! 1633:
! 1634: set_highlight('t'); /* Highlight title */
! 1635: start_highlight();
! 1636: MSG_OUTSTR("\n--- Registers ---");
! 1637: stop_highlight();
! 1638: for (i = -1; i < NUM_REGISTERS; ++i)
! 1639: {
! 1640: if (i == -1)
! 1641: {
! 1642: if (y_previous != NULL)
! 1643: yb = y_previous;
! 1644: else
! 1645: yb = &(y_buf[0]);
! 1646: }
! 1647: else
! 1648: yb = &(y_buf[i]);
! 1649: name = get_register_name(i);
! 1650: if (yb->y_array != NULL && (arg == NULL ||
! 1651: vim_strchr(arg, name) != NULL))
! 1652: {
! 1653: msg_outchar('\n');
! 1654: msg_outchar('"');
! 1655: msg_outchar(name);
! 1656: MSG_OUTSTR(" ");
! 1657:
! 1658: n = (int)Columns - 6;
! 1659: for (j = 0; j < yb->y_size && n > 1; ++j)
! 1660: {
! 1661: if (j)
! 1662: {
! 1663: MSG_OUTSTR("^J");
! 1664: n -= 2;
! 1665: }
! 1666: for (p = yb->y_array[j]; *p && (n -= charsize(*p)) >= 0; ++p)
! 1667: msg_outtrans_len(p, 1);
! 1668: }
! 1669: flushbuf(); /* show one line at a time */
! 1670: }
! 1671: }
! 1672:
! 1673: /*
! 1674: * display last inserted text
! 1675: */
! 1676: if ((p = get_last_insert()) != NULL &&
! 1677: (arg == NULL || vim_strchr(arg, '.') != NULL))
! 1678: {
! 1679: MSG_OUTSTR("\n\". ");
! 1680: dis_msg(p, TRUE);
! 1681: }
! 1682:
! 1683: /*
! 1684: * display last command line
! 1685: */
! 1686: if (last_cmdline != NULL && (arg == NULL || vim_strchr(arg, ':') != NULL))
! 1687: {
! 1688: MSG_OUTSTR("\n\": ");
! 1689: dis_msg(last_cmdline, FALSE);
! 1690: }
! 1691:
! 1692: /*
! 1693: * display current file name
! 1694: */
! 1695: if (curbuf->b_xfilename != NULL &&
! 1696: (arg == NULL || vim_strchr(arg, '%') != NULL))
! 1697: {
! 1698: MSG_OUTSTR("\n\"% ");
! 1699: dis_msg(curbuf->b_xfilename, FALSE);
! 1700: }
! 1701: }
! 1702:
! 1703: /*
! 1704: * display a string for do_dis()
! 1705: * truncate at end of screen line
! 1706: */
! 1707: void
! 1708: dis_msg(p, skip_esc)
! 1709: char_u *p;
! 1710: int skip_esc; /* if TRUE, ignore trailing ESC */
! 1711: {
! 1712: int n;
! 1713:
! 1714: n = (int)Columns - 6;
! 1715: while (*p && !(*p == ESC && skip_esc && *(p + 1) == NUL) &&
! 1716: (n -= charsize(*p)) >= 0)
! 1717: msg_outtrans_len(p++, 1);
! 1718: }
! 1719:
! 1720: /*
! 1721: * join 'count' lines (minimal 2), including u_save()
! 1722: */
! 1723: void
! 1724: do_do_join(count, insert_space, redraw)
! 1725: long count;
! 1726: int insert_space;
! 1727: int redraw; /* can redraw, curwin->w_col valid */
! 1728: {
! 1729: if (u_save((linenr_t)(curwin->w_cursor.lnum - 1),
! 1730: (linenr_t)(curwin->w_cursor.lnum + count)) == FAIL)
! 1731: return;
! 1732:
! 1733: if (count > 10)
! 1734: redraw = FALSE; /* don't redraw each small change */
! 1735: while (--count > 0)
! 1736: {
! 1737: line_breakcheck();
! 1738: if (got_int || do_join(insert_space, redraw) == FAIL)
! 1739: {
! 1740: beep_flush();
! 1741: break;
! 1742: }
! 1743: }
! 1744: if (redraw)
! 1745: redraw_later(VALID_TO_CURSCHAR);
! 1746: else
! 1747: redraw_later(NOT_VALID);
! 1748:
! 1749: /*
! 1750: * Need to update the screen if the line where the cursor is became too
! 1751: * long to fit on the screen.
! 1752: */
! 1753: cursupdate();
! 1754: }
! 1755:
! 1756: /*
! 1757: * Join two lines at the cursor position.
! 1758: *
! 1759: * return FAIL for failure, OK ohterwise
! 1760: */
! 1761: int
! 1762: do_join(insert_space, redraw)
! 1763: int insert_space;
! 1764: int redraw; /* should only be TRUE when curwin->w_row valid */
! 1765: {
! 1766: char_u *curr;
! 1767: char_u *next;
! 1768: char_u *newp;
! 1769: int endcurr1, endcurr2;
! 1770: int currsize; /* size of the current line */
! 1771: int nextsize; /* size of the next line */
! 1772: int spaces; /* number of spaces to insert */
! 1773: int rows_to_del = 0;/* number of rows on screen to delete */
! 1774: linenr_t t;
! 1775:
! 1776: if (curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count)
! 1777: return FAIL; /* can't join on last line */
! 1778:
! 1779: if (redraw)
! 1780: rows_to_del = plines_m(curwin->w_cursor.lnum,
! 1781: curwin->w_cursor.lnum + 1);
! 1782:
! 1783: curr = ml_get_curline();
! 1784: currsize = STRLEN(curr);
! 1785: endcurr1 = endcurr2 = NUL;
! 1786: if (currsize > 0)
! 1787: {
! 1788: endcurr1 = *(curr + currsize - 1);
! 1789: if (currsize > 1)
! 1790: endcurr2 = *(curr + currsize - 2);
! 1791: }
! 1792:
! 1793: next = ml_get((linenr_t)(curwin->w_cursor.lnum + 1));
! 1794: spaces = 0;
! 1795: if (insert_space)
! 1796: {
! 1797: next = skipwhite(next);
! 1798: spaces = 1;
! 1799: if (*next == ')' || currsize == 0)
! 1800: spaces = 0;
! 1801: else
! 1802: {
! 1803: if (endcurr1 == ' ' || endcurr1 == TAB)
! 1804: {
! 1805: spaces = 0;
! 1806: if (currsize > 1)
! 1807: endcurr1 = endcurr2;
! 1808: }
! 1809: if (p_js && vim_strchr((char_u *)".!?", endcurr1) != NULL)
! 1810: spaces = 2;
! 1811: }
! 1812: }
! 1813: nextsize = STRLEN(next);
! 1814:
! 1815: newp = alloc_check((unsigned)(currsize + nextsize + spaces + 1));
! 1816: if (newp == NULL)
! 1817: return FAIL;
! 1818:
! 1819: /*
! 1820: * Insert the next line first, because we already have that pointer.
! 1821: * Curr has to be obtained again, because getting next will have
! 1822: * invalidated it.
! 1823: */
! 1824: vim_memmove(newp + currsize + spaces, next, (size_t)(nextsize + 1));
! 1825:
! 1826: curr = ml_get_curline();
! 1827: vim_memmove(newp, curr, (size_t)currsize);
! 1828:
! 1829: copy_spaces(newp + currsize, (size_t)spaces);
! 1830:
! 1831: ml_replace(curwin->w_cursor.lnum, newp, FALSE);
! 1832:
! 1833: /*
! 1834: * Delete the following line. To do this we move the cursor there
! 1835: * briefly, and then move it back. After dellines() the cursor may
! 1836: * have moved up (last line deleted), so the current lnum is kept in t.
! 1837: */
! 1838: t = curwin->w_cursor.lnum;
! 1839: ++curwin->w_cursor.lnum;
! 1840: dellines(1L, FALSE, FALSE);
! 1841: curwin->w_cursor.lnum = t;
! 1842:
! 1843: /*
! 1844: * the number of rows on the screen is reduced by the difference
! 1845: * in number of rows of the two old lines and the one new line
! 1846: */
! 1847: if (redraw)
! 1848: {
! 1849: rows_to_del -= plines(curwin->w_cursor.lnum);
! 1850: if (rows_to_del > 0)
! 1851: win_del_lines(curwin, curwin->w_cline_row + curwin->w_cline_height,
! 1852: rows_to_del, TRUE, TRUE);
! 1853: }
! 1854:
! 1855: /*
! 1856: * go to first character of the joined line
! 1857: */
! 1858: if (currsize == 0)
! 1859: curwin->w_cursor.col = 0;
! 1860: else
! 1861: {
! 1862: curwin->w_cursor.col = currsize - 1;
! 1863: (void)oneright();
! 1864: }
! 1865: CHANGED;
! 1866:
! 1867: return OK;
! 1868: }
! 1869:
! 1870: /*
! 1871: * Return TRUE if the two comment leaders given are the same. The cursor is
! 1872: * in the first line. White-space is ignored. Note that the whole of
! 1873: * 'leader1' must match 'leader2_len' characters from 'leader2' -- webb
! 1874: */
! 1875: static int
! 1876: same_leader(leader1_len, leader1_flags, leader2_len, leader2_flags)
! 1877: int leader1_len;
! 1878: char_u *leader1_flags;
! 1879: int leader2_len;
! 1880: char_u *leader2_flags;
! 1881: {
! 1882: int idx1 = 0, idx2 = 0;
! 1883: char_u *p;
! 1884: char_u *line1;
! 1885: char_u *line2;
! 1886:
! 1887: if (leader1_len == 0)
! 1888: return (leader2_len == 0);
! 1889:
! 1890: /*
! 1891: * If first leader has 'f' flag, the lines can be joined only if the
! 1892: * second line does not have a leader.
! 1893: * If first leader has 'e' flag, the lines can never be joined.
! 1894: * If fist leader has 's' flag, the lines can only be joined if there is
! 1895: * some text after it and the second line has the 'm' flag.
! 1896: */
! 1897: if (leader1_flags != NULL)
! 1898: {
! 1899: for (p = leader1_flags; *p && *p != ':'; ++p)
! 1900: {
! 1901: if (*p == COM_FIRST)
! 1902: return (leader2_len == 0);
! 1903: if (*p == COM_END)
! 1904: return FALSE;
! 1905: if (*p == COM_START)
! 1906: {
! 1907: if (*(ml_get_curline() + leader1_len) == NUL)
! 1908: return FALSE;
! 1909: if (leader2_flags == NULL || leader2_len == 0)
! 1910: return FALSE;
! 1911: for (p = leader2_flags; *p && *p != ':'; ++p)
! 1912: if (*p == COM_MIDDLE)
! 1913: return TRUE;
! 1914: return FALSE;
! 1915: }
! 1916: }
! 1917: }
! 1918:
! 1919: /*
! 1920: * Get current line and next line, compare the leaders.
! 1921: * The first line has to be saved, only one line can be locked at a time.
! 1922: */
! 1923: line1 = strsave(ml_get_curline());
! 1924: if (line1 != NULL)
! 1925: {
! 1926: for (idx1 = 0; vim_iswhite(line1[idx1]); ++idx1)
! 1927: ;
! 1928: line2 = ml_get(curwin->w_cursor.lnum + 1);
! 1929: for (idx2 = 0; idx2 < leader2_len; ++idx2)
! 1930: {
! 1931: if (!vim_iswhite(line2[idx2]))
! 1932: {
! 1933: if (line1[idx1++] != line2[idx2])
! 1934: break;
! 1935: }
! 1936: else
! 1937: while (vim_iswhite(line1[idx1]))
! 1938: ++idx1;
! 1939: }
! 1940: vim_free(line1);
! 1941: }
! 1942: return (idx2 == leader2_len && idx1 == leader1_len);
! 1943: }
! 1944:
! 1945: /*
! 1946: * implementation of the format operator 'Q'
! 1947: */
! 1948: void
! 1949: do_format()
! 1950: {
! 1951: long old_line_count = curbuf->b_ml.ml_line_count;
! 1952: int prev_is_blank = FALSE;
! 1953: int is_end_block = TRUE;
! 1954: int next_is_end_block;
! 1955: int leader_len = 0; /* init for gcc */
! 1956: int next_leader_len;
! 1957: char_u *leader_flags = NULL;
! 1958: char_u *next_leader_flags;
! 1959: int advance = TRUE;
! 1960: int second_indent = -1;
! 1961: int do_second_indent;
! 1962: int first_par_line = TRUE;
! 1963:
! 1964: if (u_save((linenr_t)(curwin->w_cursor.lnum - 1),
! 1965: (linenr_t)(curwin->w_cursor.lnum + op_line_count)) == FAIL)
! 1966: return;
! 1967:
! 1968: /* check for 'q' and '2' in 'formatoptions' */
! 1969: fo_do_comments = has_format_option(FO_Q_COMS);
! 1970: do_second_indent = has_format_option(FO_Q_SECOND);
! 1971:
! 1972: /*
! 1973: * get info about the previous and current line.
! 1974: */
! 1975: if (curwin->w_cursor.lnum > 1)
! 1976: is_end_block = fmt_end_block(curwin->w_cursor.lnum - 1,
! 1977: &next_leader_len, &next_leader_flags);
! 1978: next_is_end_block = fmt_end_block(curwin->w_cursor.lnum,
! 1979: &next_leader_len, &next_leader_flags);
! 1980:
! 1981: curwin->w_cursor.lnum--;
! 1982: while (--op_line_count >= 0)
! 1983: {
! 1984: /*
! 1985: * Advance to next block.
! 1986: */
! 1987: if (advance)
! 1988: {
! 1989: curwin->w_cursor.lnum++;
! 1990: prev_is_blank = is_end_block;
! 1991: is_end_block = next_is_end_block;
! 1992: leader_len = next_leader_len;
! 1993: leader_flags = next_leader_flags;
! 1994: }
! 1995:
! 1996: /*
! 1997: * The last line to be formatted.
! 1998: */
! 1999: if (op_line_count == 0)
! 2000: {
! 2001: next_is_end_block = TRUE;
! 2002: next_leader_len = 0;
! 2003: next_leader_flags = NULL;
! 2004: }
! 2005: else
! 2006: next_is_end_block = fmt_end_block(curwin->w_cursor.lnum + 1,
! 2007: &next_leader_len, &next_leader_flags);
! 2008: advance = TRUE;
! 2009:
! 2010: /*
! 2011: * For the first line of a paragraph, check indent of second line.
! 2012: * Don't do this for comments and empty lines.
! 2013: */
! 2014: if (first_par_line && do_second_indent &&
! 2015: prev_is_blank && !is_end_block &&
! 2016: curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count &&
! 2017: leader_len == 0 && next_leader_len == 0 &&
! 2018: !lineempty(curwin->w_cursor.lnum + 1))
! 2019: second_indent = get_indent_lnum(curwin->w_cursor.lnum + 1);
! 2020:
! 2021: /*
! 2022: * Skip end-of-block (blank) lines
! 2023: */
! 2024: if (is_end_block)
! 2025: {
! 2026: }
! 2027: /*
! 2028: * If we have got to the end of a paragraph, format it.
! 2029: */
! 2030: else if (next_is_end_block || !same_leader(leader_len, leader_flags,
! 2031: next_leader_len, next_leader_flags))
! 2032: {
! 2033: /* replace indent in first line with minimal number of tabs and
! 2034: * spaces, according to current options */
! 2035: set_indent(get_indent(), TRUE);
! 2036:
! 2037: /* put cursor on last non-space */
! 2038: coladvance(MAXCOL);
! 2039: while (curwin->w_cursor.col && vim_isspace(gchar_cursor()))
! 2040: dec_cursor();
! 2041: curs_columns(FALSE); /* update curwin->w_virtcol */
! 2042:
! 2043: /* do the formatting */
! 2044: State = INSERT; /* for Opencmd() */
! 2045: insertchar(NUL, TRUE, second_indent);
! 2046: State = NORMAL;
! 2047: first_par_line = TRUE;
! 2048: second_indent = -1;
! 2049: }
! 2050: else
! 2051: {
! 2052: /*
! 2053: * Still in same paragraph, so join the lines together.
! 2054: * But first delete the comment leader from the second line.
! 2055: */
! 2056: advance = FALSE;
! 2057: curwin->w_cursor.lnum++;
! 2058: curwin->w_cursor.col = 0;
! 2059: while (next_leader_len--)
! 2060: delchar(FALSE);
! 2061: curwin->w_cursor.lnum--;
! 2062: if (do_join(TRUE, FALSE) == FAIL)
! 2063: {
! 2064: beep_flush();
! 2065: break;
! 2066: }
! 2067: first_par_line = FALSE;
! 2068: }
! 2069: }
! 2070: fo_do_comments = FALSE;
! 2071: /*
! 2072: * Leave the cursor at the first non-blank of the last formatted line.
! 2073: * If the cursor was move one line back (e.g. with "Q}") go to the next
! 2074: * line, so "." will do the next lines.
! 2075: */
! 2076: if (op_end_adjusted && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
! 2077: ++curwin->w_cursor.lnum;
! 2078: beginline(TRUE);
! 2079: updateScreen(NOT_VALID);
! 2080: msgmore(curbuf->b_ml.ml_line_count - old_line_count);
! 2081: }
! 2082:
! 2083: /*
! 2084: * Blank lines, and lines containing only the comment leader, are left
! 2085: * untouched by the formatting. The function returns TRUE in this
! 2086: * case. It also returns TRUE when a line starts with the end of a comment
! 2087: * ('e' in comment flags), so that this line is skipped, and not joined to the
! 2088: * previous line. A new paragraph starts after a blank line, or when the
! 2089: * comment leader changes -- webb.
! 2090: */
! 2091: static int
! 2092: fmt_end_block(lnum, leader_len, leader_flags)
! 2093: linenr_t lnum;
! 2094: int *leader_len;
! 2095: char_u **leader_flags;
! 2096: {
! 2097: char_u *flags = NULL; /* init for GCC */
! 2098: char_u *ptr;
! 2099:
! 2100: ptr = ml_get(lnum);
! 2101: *leader_len = get_leader_len(ptr, leader_flags);
! 2102:
! 2103: if (*leader_len > 0)
! 2104: {
! 2105: /*
! 2106: * Search for 'e' flag in comment leader flags.
! 2107: */
! 2108: flags = *leader_flags;
! 2109: while (*flags && *flags != ':' && *flags != COM_END)
! 2110: ++flags;
! 2111: }
! 2112:
! 2113: return (ptr[*leader_len] == NUL ||
! 2114: (*leader_len > 0 && *flags == COM_END) ||
! 2115: startPS(lnum, NUL, FALSE));
! 2116: }
! 2117:
! 2118: /*
! 2119: * prepare a few things for block mode yank/delete/tilde
! 2120: *
! 2121: * for delete:
! 2122: * - textlen includes the first/last char to be (partly) deleted
! 2123: * - start/endspaces is the number of columns that are taken by the
! 2124: * first/last deleted char minus the number of columns that have to be deleted.
! 2125: * for yank and tilde:
! 2126: * - textlen includes the first/last char to be wholly yanked
! 2127: * - start/endspaces is the number of columns of the first/last yanked char
! 2128: * that are to be yanked.
! 2129: */
! 2130: static void
! 2131: block_prep(bd, lnum, is_del)
! 2132: struct block_def *bd;
! 2133: linenr_t lnum;
! 2134: int is_del;
! 2135: {
! 2136: colnr_t vcol;
! 2137: int incr = 0;
! 2138: char_u *pend;
! 2139: char_u *pstart;
! 2140:
! 2141: bd->startspaces = 0;
! 2142: bd->endspaces = 0;
! 2143: bd->textlen = 0;
! 2144: bd->textcol = 0;
! 2145: vcol = 0;
! 2146: pstart = ml_get(lnum);
! 2147: while (vcol < op_start_vcol && *pstart)
! 2148: {
! 2149: /* Count a tab for what it's worth (if list mode not on) */
! 2150: incr = lbr_chartabsize(pstart, (colnr_t)vcol);
! 2151: vcol += incr;
! 2152: ++pstart;
! 2153: ++bd->textcol;
! 2154: }
! 2155: if (vcol < op_start_vcol) /* line too short */
! 2156: {
! 2157: if (!is_del)
! 2158: bd->endspaces = op_end_vcol - op_start_vcol + 1;
! 2159: }
! 2160: else /* vcol >= op_start_vcol */
! 2161: {
! 2162: bd->startspaces = vcol - op_start_vcol;
! 2163: if (is_del && vcol > op_start_vcol)
! 2164: bd->startspaces = incr - bd->startspaces;
! 2165: pend = pstart;
! 2166: if (vcol > op_end_vcol) /* it's all in one character */
! 2167: {
! 2168: bd->startspaces = op_end_vcol - op_start_vcol + 1;
! 2169: if (is_del)
! 2170: bd->startspaces = incr - bd->startspaces;
! 2171: }
! 2172: else
! 2173: {
! 2174: while (vcol <= op_end_vcol && *pend)
! 2175: {
! 2176: /* Count a tab for what it's worth (if list mode not on) */
! 2177: incr = lbr_chartabsize(pend, (colnr_t)vcol);
! 2178: vcol += incr;
! 2179: ++pend;
! 2180: }
! 2181: if (vcol < op_end_vcol && !is_del) /* line too short */
! 2182: {
! 2183: bd->endspaces = op_end_vcol - vcol;
! 2184: }
! 2185: else if (vcol > op_end_vcol)
! 2186: {
! 2187: bd->endspaces = vcol - op_end_vcol - 1;
! 2188: if (!is_del && pend != pstart && bd->endspaces)
! 2189: --pend;
! 2190: }
! 2191: }
! 2192: if (is_del && bd->startspaces)
! 2193: {
! 2194: --pstart;
! 2195: --bd->textcol;
! 2196: }
! 2197: bd->textlen = (int)(pend - pstart);
! 2198: }
! 2199: bd->textstart = pstart;
! 2200: }
! 2201:
! 2202: #define NUMBUFLEN 30
! 2203:
! 2204: /*
! 2205: * add or subtract 'Prenum1' from a number in a line
! 2206: * 'command' is CTRL-A for add, CTRL-X for subtract
! 2207: *
! 2208: * return FAIL for failure, OK otherwise
! 2209: */
! 2210: int
! 2211: do_addsub(command, Prenum1)
! 2212: int command;
! 2213: linenr_t Prenum1;
! 2214: {
! 2215: register int col;
! 2216: char_u buf[NUMBUFLEN];
! 2217: int hex; /* 'X': hexadecimal; '0': octal */
! 2218: static int hexupper = FALSE; /* 0xABC */
! 2219: long n;
! 2220: char_u *ptr;
! 2221: int i;
! 2222: int c;
! 2223: int zeros = 0; /* number of leading zeros */
! 2224: int digits = 0; /* number of digits in the number */
! 2225:
! 2226: ptr = ml_get_curline();
! 2227: col = curwin->w_cursor.col;
! 2228:
! 2229: /* first check if we are on a hexadecimal number */
! 2230: while (col > 0 && isxdigit(ptr[col]))
! 2231: --col;
! 2232: if (col > 0 && (ptr[col] == 'X' || ptr[col] == 'x') &&
! 2233: ptr[col - 1] == '0' && isxdigit(ptr[col + 1]))
! 2234: --col; /* found hexadecimal number */
! 2235: else
! 2236: {
! 2237: /* first search forward and then backward for start of number */
! 2238: col = curwin->w_cursor.col;
! 2239:
! 2240: while (ptr[col] != NUL && !isdigit(ptr[col]))
! 2241: ++col;
! 2242:
! 2243: while (col > 0 && isdigit(ptr[col - 1]))
! 2244: --col;
! 2245: }
! 2246:
! 2247: if (isdigit(ptr[col]) && u_save_cursor() == OK)
! 2248: {
! 2249: ptr = ml_get_curline(); /* get it again, because
! 2250: u_save may have changed it */
! 2251: curwin->w_set_curswant = TRUE;
! 2252:
! 2253: hex = 0; /* default is decimal */
! 2254: if (ptr[col] == '0') /* could be hex or octal */
! 2255: {
! 2256: hex = TO_UPPER(ptr[col + 1]); /* assume hexadecimal */
! 2257: if (hex != 'X' || !isxdigit(ptr[col + 2]))
! 2258: {
! 2259: if (isdigit(hex))
! 2260: hex = '0'; /* octal */
! 2261: else
! 2262: hex = 0; /* 0 by itself is decimal */
! 2263: }
! 2264: }
! 2265:
! 2266: if (!hex && col > 0 && ptr[col - 1] == '-')
! 2267: --col;
! 2268:
! 2269: ptr += col;
! 2270: /*
! 2271: * we copy the number into a buffer because some versions of sscanf
! 2272: * cannot handle characters with the upper bit set, making some special
! 2273: * characters handled like digits.
! 2274: */
! 2275: for (i = 0; *ptr && !(*ptr & 0x80) && i < NUMBUFLEN - 1; ++i)
! 2276: buf[i] = *ptr++;
! 2277: buf[i] = NUL;
! 2278:
! 2279: if (hex == '0')
! 2280: sscanf((char *)buf, "%lo", &n);
! 2281: else if (hex)
! 2282: sscanf((char *)buf + 2, "%lx", &n); /* "%X" doesn't work! */
! 2283: else
! 2284: n = atol((char *)buf);
! 2285:
! 2286: if (command == Ctrl('A'))
! 2287: n += Prenum1;
! 2288: else
! 2289: n -= Prenum1;
! 2290:
! 2291: if (hex == 'X') /* skip the '0x' */
! 2292: col += 2;
! 2293: else if (hex == '0')
! 2294: col++; /* skip the '0' */
! 2295: curwin->w_cursor.col = col;
! 2296:
! 2297: c = gchar_cursor();
! 2298: do /* delete the old number */
! 2299: {
! 2300: if (digits == 0 && c == '0')
! 2301: ++zeros; /* count the number of leading zeros */
! 2302: else
! 2303: ++digits; /* count the number of digits */
! 2304: if (isalpha(c))
! 2305: {
! 2306: if (isupper(c))
! 2307: hexupper = TRUE;
! 2308: else
! 2309: hexupper = FALSE;
! 2310: }
! 2311: (void)delchar(FALSE);
! 2312: c = gchar_cursor();
! 2313: }
! 2314: while (hex ? (hex == '0' ? c >= '0' && c <= '7' :
! 2315: isxdigit(c)) : isdigit(c));
! 2316:
! 2317: if (hex == 0)
! 2318: sprintf((char *)buf, "%ld", n);
! 2319: else
! 2320: {
! 2321: if (hex == '0')
! 2322: sprintf((char *)buf, "%lo", n);
! 2323: else if (hex && hexupper)
! 2324: sprintf((char *)buf, "%lX", n);
! 2325: else if (hex)
! 2326: sprintf((char *)buf, "%lx", n);
! 2327: /* adjust number of zeros to the new number of digits, so the
! 2328: * total length of the number remains the same */
! 2329: if (zeros)
! 2330: {
! 2331: zeros += digits - STRLEN(buf);
! 2332: if (zeros > 0)
! 2333: {
! 2334: vim_memmove(buf + zeros, buf, STRLEN(buf) + 1);
! 2335: for (col = 0; zeros > 0; --zeros)
! 2336: buf[col++] = '0';
! 2337: }
! 2338: }
! 2339: }
! 2340: ins_str(buf); /* insert the new number */
! 2341: --curwin->w_cursor.col;
! 2342: updateline();
! 2343: return OK;
! 2344: }
! 2345: else
! 2346: {
! 2347: beep_flush();
! 2348: return FAIL;
! 2349: }
! 2350: }
! 2351:
! 2352: #ifdef VIMINFO
! 2353: int
! 2354: read_viminfo_register(line, fp, force)
! 2355: char_u *line;
! 2356: FILE *fp;
! 2357: int force;
! 2358: {
! 2359: int eof;
! 2360: int do_it = TRUE;
! 2361: int size;
! 2362: int limit;
! 2363: int i;
! 2364: int set_prev = FALSE;
! 2365: char_u *str;
! 2366: char_u **array = NULL;
! 2367:
! 2368: /* We only get here (hopefully) if line[0] == '"' */
! 2369: str = line + 1;
! 2370: if (*str == '"')
! 2371: {
! 2372: set_prev = TRUE;
! 2373: str++;
! 2374: }
! 2375: if (!isalnum(*str) && *str != '-')
! 2376: {
! 2377: EMSG2("viminfo: Illegal register name in line %s", line);
! 2378: do_it = FALSE;
! 2379: }
! 2380: yankbuffer = *str++;
! 2381: get_yank_buffer(FALSE);
! 2382: yankbuffer = 0;
! 2383: if (!force && y_current->y_array != NULL)
! 2384: do_it = FALSE;
! 2385: size = 0;
! 2386: limit = 100; /* Optimized for registers containing <= 100 lines */
! 2387: if (do_it)
! 2388: {
! 2389: if (set_prev)
! 2390: y_previous = y_current;
! 2391: vim_free(y_current->y_array);
! 2392: array = y_current->y_array =
! 2393: (char_u **)alloc((unsigned)(limit * sizeof(char_u *)));
! 2394: str = skipwhite(str);
! 2395: if (STRNCMP(str, "CHAR", 4) == 0)
! 2396: y_current->y_type = MCHAR;
! 2397: else if (STRNCMP(str, "BLOCK", 5) == 0)
! 2398: y_current->y_type = MBLOCK;
! 2399: else
! 2400: y_current->y_type = MLINE;
! 2401: }
! 2402: while (!(eof = vim_fgets(line, LSIZE, fp)) && line[0] == TAB)
! 2403: {
! 2404: if (do_it)
! 2405: {
! 2406: if (size >= limit)
! 2407: {
! 2408: y_current->y_array = (char_u **)
! 2409: alloc((unsigned)(limit * 2 * sizeof(char_u *)));
! 2410: for (i = 0; i < limit; i++)
! 2411: y_current->y_array[i] = array[i];
! 2412: vim_free(array);
! 2413: limit *= 2;
! 2414: array = y_current->y_array;
! 2415: }
! 2416: viminfo_readstring(line);
! 2417: str = strsave(line + 1);
! 2418: if (str != NULL)
! 2419: array[size++] = str;
! 2420: else
! 2421: do_it = FALSE;
! 2422: }
! 2423: }
! 2424: if (do_it)
! 2425: {
! 2426: if (size == 0)
! 2427: {
! 2428: vim_free(array);
! 2429: y_current->y_array = NULL;
! 2430: }
! 2431: else if (size < limit)
! 2432: {
! 2433: y_current->y_array =
! 2434: (char_u **)alloc((unsigned)(size * sizeof(char_u *)));
! 2435: for (i = 0; i < size; i++)
! 2436: y_current->y_array[i] = array[i];
! 2437: vim_free(array);
! 2438: }
! 2439: y_current->y_size = size;
! 2440: }
! 2441: return eof;
! 2442: }
! 2443:
! 2444: void
! 2445: write_viminfo_registers(fp)
! 2446: FILE *fp;
! 2447: {
! 2448: int i, j;
! 2449: char_u *type;
! 2450: char_u c;
! 2451: int num_lines;
! 2452: int max_num_lines;
! 2453:
! 2454: fprintf(fp, "\n# Registers:\n");
! 2455:
! 2456: max_num_lines = get_viminfo_parameter('"');
! 2457: if (max_num_lines == 0)
! 2458: return;
! 2459: for (i = 0; i < NUM_REGISTERS; i++)
! 2460: {
! 2461: if (y_buf[i].y_array == NULL)
! 2462: continue;
! 2463: #ifdef USE_GUI
! 2464: /* Skip '*' register, we don't want it back next time */
! 2465: if (i == GUI_SELECTION_REGISTER)
! 2466: continue;
! 2467: #endif
! 2468: switch (y_buf[i].y_type)
! 2469: {
! 2470: case MLINE:
! 2471: type = (char_u *)"LINE";
! 2472: break;
! 2473: case MCHAR:
! 2474: type = (char_u *)"CHAR";
! 2475: break;
! 2476: case MBLOCK:
! 2477: type = (char_u *)"BLOCK";
! 2478: break;
! 2479: default:
! 2480: sprintf((char *)IObuff, "Unknown register type %d",
! 2481: y_buf[i].y_type);
! 2482: emsg(IObuff);
! 2483: type = (char_u *)"LINE";
! 2484: break;
! 2485: }
! 2486: if (y_previous == &y_buf[i])
! 2487: fprintf(fp, "\"");
! 2488: if (i == DELETION_REGISTER)
! 2489: c = '-';
! 2490: else if (i < 10)
! 2491: c = '0' + i;
! 2492: else
! 2493: c = 'a' + i - 10;
! 2494: fprintf(fp, "\"%c\t%s\n", c, type);
! 2495: num_lines = y_buf[i].y_size;
! 2496:
! 2497: /* If max_num_lines < 0, then we save ALL the lines in the register */
! 2498: if (max_num_lines > 0 && num_lines > max_num_lines)
! 2499: num_lines = max_num_lines;
! 2500: for (j = 0; j < num_lines; j++)
! 2501: {
! 2502: putc('\t', fp);
! 2503: viminfo_writestring(fp, y_buf[i].y_array[j]);
! 2504: }
! 2505: }
! 2506: }
! 2507: #endif /* VIMINFO */
! 2508:
! 2509: #if defined(USE_GUI) || defined(PROTO)
! 2510: /*
! 2511: * Text selection stuff that uses the GUI selection register '*'. When using a
! 2512: * GUI this may be text from another window, otherwise it is the last text we
! 2513: * had highlighted with VIsual mode. With mouse support, clicking the middle
! 2514: * button performs the paste, otherwise you will need to do <"*p>.
! 2515: */
! 2516:
! 2517: void
! 2518: gui_free_selection()
! 2519: {
! 2520: struct yankbuf *y_ptr = y_current;
! 2521:
! 2522: y_current = &y_buf[GUI_SELECTION_REGISTER]; /* '*' register */
! 2523: free_yank_all();
! 2524: y_current->y_size = 0;
! 2525: y_current = y_ptr;
! 2526: }
! 2527:
! 2528: /*
! 2529: * Get the selected text and put it in the gui text register '*'.
! 2530: */
! 2531: void
! 2532: gui_get_selection()
! 2533: {
! 2534: struct yankbuf *old_y_previous, *old_y_current;
! 2535: char_u old_yankbuffer;
! 2536: FPOS old_cursor, old_visual;
! 2537: int old_op_type;
! 2538:
! 2539: if (gui.selection.owned)
! 2540: {
! 2541: if (y_buf[GUI_SELECTION_REGISTER].y_array != NULL)
! 2542: return;
! 2543:
! 2544: /* Get the text between gui.selection.start & gui.selection.end */
! 2545: old_y_previous = y_previous;
! 2546: old_y_current = y_current;
! 2547: old_yankbuffer = yankbuffer;
! 2548: old_cursor = curwin->w_cursor;
! 2549: old_visual = VIsual;
! 2550: old_op_type = op_type;
! 2551: yankbuffer = '*';
! 2552: op_type = YANK;
! 2553: do_pending_operator('y', NUL, FALSE, NULL, NULL, 0, TRUE, TRUE);
! 2554: y_previous = old_y_previous;
! 2555: y_current = old_y_current;
! 2556: yankbuffer = old_yankbuffer;
! 2557: curwin->w_cursor = old_cursor;
! 2558: VIsual = old_visual;
! 2559: op_type = old_op_type;
! 2560: }
! 2561: else
! 2562: {
! 2563: gui_free_selection();
! 2564:
! 2565: /* Try to get selected text from another window */
! 2566: gui_request_selection();
! 2567: }
! 2568: }
! 2569:
! 2570: /* Convert from the GUI selection string into the '*' register */
! 2571: void
! 2572: gui_yank_selection(type, str, len)
! 2573: int type;
! 2574: char_u *str;
! 2575: long_u len;
! 2576: {
! 2577: struct yankbuf *y_ptr = &y_buf[GUI_SELECTION_REGISTER]; /* '*' register */
! 2578: int lnum;
! 2579: int start;
! 2580: int i;
! 2581:
! 2582: gui_free_selection();
! 2583:
! 2584: /* Count the number of lines within the string */
! 2585: y_ptr->y_size = 1;
! 2586: for (i = 0; i < len; i++)
! 2587: if (str[i] == '\n')
! 2588: y_ptr->y_size++;
! 2589:
! 2590: if (type != MCHAR && i > 0 && str[i - 1] == '\n')
! 2591: y_ptr->y_size--;
! 2592:
! 2593: y_ptr->y_array = (char_u **)lalloc(y_ptr->y_size * sizeof(char_u *), TRUE);
! 2594: if (y_ptr->y_array == NULL)
! 2595: return;
! 2596: y_ptr->y_type = type;
! 2597: lnum = 0;
! 2598: start = 0;
! 2599: for (i = 0; i < len; i++)
! 2600: {
! 2601: if (str[i] == NUL)
! 2602: str[i] = '\n';
! 2603: else if (str[i] == '\n')
! 2604: {
! 2605: str[i] = NUL;
! 2606: if (type == MCHAR || i != len - 1)
! 2607: {
! 2608: if ((y_ptr->y_array[lnum] = strsave(str + start)) == NULL)
! 2609: {
! 2610: y_ptr->y_size = lnum;
! 2611: return;
! 2612: }
! 2613: lnum++;
! 2614: start = i + 1;
! 2615: }
! 2616: }
! 2617: }
! 2618: if ((y_ptr->y_array[lnum] = alloc(i - start + 1)) == NULL)
! 2619: return;
! 2620: if (i - start > 0)
! 2621: STRNCPY(y_ptr->y_array[lnum], str + start, i - start);
! 2622: y_ptr->y_array[lnum][i - start] = NUL;
! 2623: y_ptr->y_size = lnum + 1;
! 2624: }
! 2625:
! 2626: /*
! 2627: * Convert the '*' register into a GUI selection string returned in *str with
! 2628: * length *len.
! 2629: */
! 2630: int
! 2631: gui_convert_selection(str, len)
! 2632: char_u **str;
! 2633: long_u *len;
! 2634: {
! 2635: struct yankbuf *y_ptr = &y_buf[GUI_SELECTION_REGISTER]; /* '*' register */
! 2636: char_u *p;
! 2637: int lnum;
! 2638: int i, j;
! 2639:
! 2640: *str = NULL;
! 2641: *len = 0;
! 2642: if (y_ptr->y_array == NULL)
! 2643: return -1;
! 2644:
! 2645: for (i = 0; i < y_ptr->y_size; i++)
! 2646: *len += STRLEN(y_ptr->y_array[i]) + 1;
! 2647:
! 2648: /*
! 2649: * Don't want newline character at end of last line if we're in MCHAR mode.
! 2650: */
! 2651: if (y_ptr->y_type == MCHAR && *len > 1)
! 2652: (*len)--;
! 2653:
! 2654: p = *str = lalloc(*len, TRUE);
! 2655: if (p == NULL)
! 2656: return -1;
! 2657: lnum = 0;
! 2658: for (i = 0, j = 0; i < *len; i++, j++)
! 2659: {
! 2660: if (y_ptr->y_array[lnum][j] == '\n')
! 2661: p[i] = NUL;
! 2662: else if (y_ptr->y_array[lnum][j] == NUL)
! 2663: {
! 2664: p[i] = '\n';
! 2665: lnum++;
! 2666: j = -1;
! 2667: }
! 2668: else
! 2669: p[i] = y_ptr->y_array[lnum][j];
! 2670: }
! 2671: return y_ptr->y_type;
! 2672: }
! 2673: #endif /* USE_GUI || PROTO */