1 /* $OpenBSD: line.c,v 1.54 2014/11/16 04:16:41 guenther Exp $ */ 2 3 /* This file is in the public domain. */ 4 5 /* 6 * Text line handling. 7 * 8 * The functions in this file are a general set of line management 9 * utilities. They are the only routines that touch the text. They 10 * also touch the buffer and window structures to make sure that the 11 * necessary updating gets done. 12 * 13 * Note that this code only updates the dot and mark values in the window 14 * list. Since all the code acts on the current window, the buffer that 15 * we are editing must be displayed, which means that "b_nwnd" is non-zero, 16 * which means that the dot and mark values in the buffer headers are 17 * nonsense. 18 */ 19 20 #include "def.h" 21 22 #include <limits.h> 23 #include <stdlib.h> 24 #include <string.h> 25 26 /* 27 * Allocate a new line of size `used'. lrealloc() can be called if the line 28 * ever needs to grow beyond that. 29 */ 30 struct line * 31 lalloc(int used) 32 { 33 struct line *lp; 34 35 if ((lp = malloc(sizeof(*lp))) == NULL) 36 return (NULL); 37 lp->l_text = NULL; 38 lp->l_size = 0; 39 lp->l_used = used; /* XXX */ 40 if (lrealloc(lp, used) == FALSE) { 41 free(lp); 42 return (NULL); 43 } 44 return (lp); 45 } 46 47 int 48 lrealloc(struct line *lp, int newsize) 49 { 50 char *tmp; 51 52 if (lp->l_size < newsize) { 53 if ((tmp = realloc(lp->l_text, newsize)) == NULL) 54 return (FALSE); 55 lp->l_text = tmp; 56 lp->l_size = newsize; 57 } 58 return (TRUE); 59 } 60 61 /* 62 * Delete line "lp". Fix all of the links that might point to it (they are 63 * moved to offset 0 of the next line. Unlink the line from whatever buffer 64 * it might be in, and release the memory. The buffers are updated too; the 65 * magic conditions described in the above comments don't hold here. 66 */ 67 void 68 lfree(struct line *lp) 69 { 70 struct buffer *bp; 71 struct mgwin *wp; 72 73 for (wp = wheadp; wp != NULL; wp = wp->w_wndp) { 74 if (wp->w_linep == lp) 75 wp->w_linep = lp->l_fp; 76 if (wp->w_dotp == lp) { 77 wp->w_dotp = lp->l_fp; 78 wp->w_doto = 0; 79 } 80 if (wp->w_markp == lp) { 81 wp->w_markp = lp->l_fp; 82 wp->w_marko = 0; 83 } 84 } 85 for (bp = bheadp; bp != NULL; bp = bp->b_bufp) { 86 if (bp->b_nwnd == 0) { 87 if (bp->b_dotp == lp) { 88 bp->b_dotp = lp->l_fp; 89 bp->b_doto = 0; 90 } 91 if (bp->b_markp == lp) { 92 bp->b_markp = lp->l_fp; 93 bp->b_marko = 0; 94 } 95 } 96 } 97 lp->l_bp->l_fp = lp->l_fp; 98 lp->l_fp->l_bp = lp->l_bp; 99 if (lp->l_text != NULL) 100 free(lp->l_text); 101 free(lp); 102 } 103 104 /* 105 * This routine is called when a character changes in place in the current 106 * buffer. It updates all of the required flags in the buffer and window 107 * system. The flag used is passed as an argument; if the buffer is being 108 * displayed in more than 1 window we change EDIT to HARD. Set MODE if the 109 * mode line needs to be updated (the "*" has to be set). 110 */ 111 void 112 lchange(int flag) 113 { 114 struct mgwin *wp; 115 116 /* update mode lines if this is the first change. */ 117 if ((curbp->b_flag & BFCHG) == 0) { 118 flag |= WFMODE; 119 curbp->b_flag |= BFCHG; 120 } 121 for (wp = wheadp; wp != NULL; wp = wp->w_wndp) { 122 if (wp->w_bufp == curbp) { 123 wp->w_rflag |= flag; 124 if (wp != curwp) 125 wp->w_rflag |= WFFULL; 126 } 127 } 128 } 129 130 /* 131 * Insert "n" bytes from "s" at the current location of dot. 132 * In the easy case all that happens is the text is stored in the line. 133 * In the hard case, the line has to be reallocated. When the window list 134 * is updated, take special care; I screwed it up once. You always update 135 * dot in the current window. You update mark and a dot in another window 136 * if it is greater than the place where you did the insert. Return TRUE 137 * if all is well, and FALSE on errors. 138 */ 139 int 140 linsert_str(const char *s, int n) 141 { 142 struct line *lp1; 143 struct mgwin *wp; 144 RSIZE i; 145 int doto, k; 146 147 if ((k = checkdirty(curbp)) != TRUE) 148 return (k); 149 150 if (curbp->b_flag & BFREADONLY) { 151 dobeep(); 152 ewprintf("Buffer is read only"); 153 return (FALSE); 154 } 155 156 if (!n) 157 return (TRUE); 158 159 lchange(WFFULL); 160 161 /* current line */ 162 lp1 = curwp->w_dotp; 163 164 /* special case for the end */ 165 if (lp1 == curbp->b_headp) { 166 struct line *lp2, *lp3; 167 168 /* now should only happen in empty buffer */ 169 if (curwp->w_doto != 0) 170 panic("bug: linsert_str"); 171 /* allocate a new line */ 172 if ((lp2 = lalloc(n)) == NULL) 173 return (FALSE); 174 /* previous line */ 175 lp3 = lp1->l_bp; 176 /* link in */ 177 lp3->l_fp = lp2; 178 lp2->l_fp = lp1; 179 lp1->l_bp = lp2; 180 lp2->l_bp = lp3; 181 for (i = 0; i < n; ++i) 182 lp2->l_text[i] = s[i]; 183 for (wp = wheadp; wp != NULL; wp = wp->w_wndp) { 184 if (wp->w_linep == lp1) 185 wp->w_linep = lp2; 186 if (wp->w_dotp == lp1) 187 wp->w_dotp = lp2; 188 if (wp->w_markp == lp1) 189 wp->w_markp = lp2; 190 } 191 undo_add_insert(lp2, 0, n); 192 curwp->w_doto = n; 193 return (TRUE); 194 } 195 /* save for later */ 196 doto = curwp->w_doto; 197 198 if ((lp1->l_used + n) > lp1->l_size) { 199 if (lrealloc(lp1, lp1->l_used + n) == FALSE) 200 return (FALSE); 201 } 202 lp1->l_used += n; 203 if (lp1->l_used != n) 204 memmove(&lp1->l_text[doto + n], &lp1->l_text[doto], 205 lp1->l_used - n - doto); 206 207 /* Add the characters */ 208 for (i = 0; i < n; ++i) 209 lp1->l_text[doto + i] = s[i]; 210 for (wp = wheadp; wp != NULL; wp = wp->w_wndp) { 211 if (wp->w_dotp == lp1) { 212 if (wp == curwp || wp->w_doto > doto) 213 wp->w_doto += n; 214 } 215 if (wp->w_markp == lp1) { 216 if (wp->w_marko > doto) 217 wp->w_marko += n; 218 } 219 } 220 undo_add_insert(curwp->w_dotp, doto, n); 221 return (TRUE); 222 } 223 224 /* 225 * Insert "n" copies of the character "c" at the current location of dot. 226 * In the easy case all that happens is the text is stored in the line. 227 * In the hard case, the line has to be reallocated. When the window list 228 * is updated, take special care; I screwed it up once. You always update 229 * dot in the current window. You update mark and a dot in another window 230 * if it is greater than the place where you did the insert. Return TRUE 231 * if all is well, and FALSE on errors. 232 */ 233 int 234 linsert(int n, int c) 235 { 236 struct line *lp1; 237 struct mgwin *wp; 238 RSIZE i; 239 int doto; 240 int s; 241 242 if (!n) 243 return (TRUE); 244 245 if ((s = checkdirty(curbp)) != TRUE) 246 return (s); 247 248 if (curbp->b_flag & BFREADONLY) { 249 dobeep(); 250 ewprintf("Buffer is read only"); 251 return (FALSE); 252 } 253 254 lchange(WFEDIT); 255 256 /* current line */ 257 lp1 = curwp->w_dotp; 258 259 /* special case for the end */ 260 if (lp1 == curbp->b_headp) { 261 struct line *lp2, *lp3; 262 263 /* now should only happen in empty buffer */ 264 if (curwp->w_doto != 0) { 265 dobeep(); 266 ewprintf("bug: linsert"); 267 return (FALSE); 268 } 269 /* allocate a new line */ 270 if ((lp2 = lalloc(n)) == NULL) 271 return (FALSE); 272 /* previous line */ 273 lp3 = lp1->l_bp; 274 /* link in */ 275 lp3->l_fp = lp2; 276 lp2->l_fp = lp1; 277 lp1->l_bp = lp2; 278 lp2->l_bp = lp3; 279 for (i = 0; i < n; ++i) 280 lp2->l_text[i] = c; 281 for (wp = wheadp; wp != NULL; wp = wp->w_wndp) { 282 if (wp->w_linep == lp1) 283 wp->w_linep = lp2; 284 if (wp->w_dotp == lp1) 285 wp->w_dotp = lp2; 286 if (wp->w_markp == lp1) 287 wp->w_markp = lp2; 288 } 289 undo_add_insert(lp2, 0, n); 290 curwp->w_doto = n; 291 return (TRUE); 292 } 293 /* save for later */ 294 doto = curwp->w_doto; 295 296 if ((lp1->l_used + n) > lp1->l_size) { 297 if (lrealloc(lp1, lp1->l_used + n) == FALSE) 298 return (FALSE); 299 } 300 lp1->l_used += n; 301 if (lp1->l_used != n) 302 memmove(&lp1->l_text[doto + n], &lp1->l_text[doto], 303 lp1->l_used - n - doto); 304 305 /* Add the characters */ 306 for (i = 0; i < n; ++i) 307 lp1->l_text[doto + i] = c; 308 for (wp = wheadp; wp != NULL; wp = wp->w_wndp) { 309 if (wp->w_dotp == lp1) { 310 if (wp == curwp || wp->w_doto > doto) 311 wp->w_doto += n; 312 } 313 if (wp->w_markp == lp1) { 314 if (wp->w_marko > doto) 315 wp->w_marko += n; 316 } 317 } 318 undo_add_insert(curwp->w_dotp, doto, n); 319 return (TRUE); 320 } 321 322 /* 323 * Do the work of inserting a newline at the given line/offset. 324 * If mark is on the current line, we may have to move the markline 325 * to keep line numbers in sync. 326 * lnewline_at assumes the current buffer is writable. Checking for 327 * this fact should be done by the caller. 328 */ 329 int 330 lnewline_at(struct line *lp1, int doto) 331 { 332 struct line *lp2; 333 struct mgwin *wp; 334 int nlen, tcurwpdotline; 335 336 lchange(WFFULL); 337 338 curwp->w_bufp->b_lines++; 339 /* Check if mark is past dot (even on current line) */ 340 if (curwp->w_markline > curwp->w_dotline || 341 (curwp->w_dotline == curwp->w_markline && 342 curwp->w_marko >= doto)) 343 curwp->w_markline++; 344 345 tcurwpdotline = curwp->w_dotline; 346 347 /* If start of line, allocate a new line instead of copying */ 348 if (doto == 0) { 349 /* new first part */ 350 if ((lp2 = lalloc(0)) == NULL) 351 return (FALSE); 352 lp2->l_bp = lp1->l_bp; 353 lp1->l_bp->l_fp = lp2; 354 lp2->l_fp = lp1; 355 lp1->l_bp = lp2; 356 for (wp = wheadp; wp != NULL; wp = wp->w_wndp) { 357 if (wp->w_linep == lp1) 358 wp->w_linep = lp2; 359 if (wp->w_dotline >= tcurwpdotline) 360 wp->w_dotline++; 361 } 362 undo_add_boundary(FFRAND, 1); 363 undo_add_insert(lp2, 0, 1); 364 undo_add_boundary(FFRAND, 1); 365 return (TRUE); 366 } 367 368 /* length of new part */ 369 nlen = llength(lp1) - doto; 370 371 /* new second half line */ 372 if ((lp2 = lalloc(nlen)) == NULL) 373 return (FALSE); 374 if (nlen != 0) 375 bcopy(&lp1->l_text[doto], &lp2->l_text[0], nlen); 376 lp1->l_used = doto; 377 lp2->l_bp = lp1; 378 lp2->l_fp = lp1->l_fp; 379 lp1->l_fp = lp2; 380 lp2->l_fp->l_bp = lp2; 381 /* Windows */ 382 for (wp = wheadp; wp != NULL; wp = wp->w_wndp) { 383 if (wp->w_dotp == lp1 && wp->w_doto >= doto) { 384 wp->w_dotp = lp2; 385 wp->w_doto -= doto; 386 wp->w_dotline++; 387 } else if (wp->w_dotline > tcurwpdotline) 388 wp->w_dotline++; 389 if (wp->w_markp == lp1 && wp->w_marko >= doto) { 390 wp->w_markp = lp2; 391 wp->w_marko -= doto; 392 } 393 } 394 undo_add_boundary(FFRAND, 1); 395 undo_add_insert(lp1, llength(lp1), 1); 396 undo_add_boundary(FFRAND, 1); 397 return (TRUE); 398 } 399 400 /* 401 * Insert a newline into the buffer at the current location of dot in the 402 * current window. 403 */ 404 int 405 lnewline(void) 406 { 407 int s; 408 409 if ((s = checkdirty(curbp)) != TRUE) 410 return (s); 411 if (curbp->b_flag & BFREADONLY) { 412 dobeep(); 413 ewprintf("Buffer is read only"); 414 return (FALSE); 415 } 416 return (lnewline_at(curwp->w_dotp, curwp->w_doto)); 417 } 418 419 /* 420 * This function deletes "n" bytes, starting at dot. (actually, n+1, as the 421 * newline is included) It understands how to deal with end of lines, etc. 422 * It returns TRUE if all of the characters were deleted, and FALSE if 423 * they were not (because dot ran into the end of the buffer). 424 * The "kflag" indicates either no insertion, or direction of insertion 425 * into the kill buffer. 426 */ 427 int 428 ldelete(RSIZE n, int kflag) 429 { 430 struct line *dotp; 431 RSIZE chunk; 432 struct mgwin *wp; 433 int doto; 434 char *cp1, *cp2; 435 size_t len; 436 char *sv = NULL; 437 int end; 438 int s; 439 int rval = FALSE; 440 441 if ((s = checkdirty(curbp)) != TRUE) 442 return (s); 443 if (curbp->b_flag & BFREADONLY) { 444 dobeep(); 445 ewprintf("Buffer is read only"); 446 goto out; 447 } 448 len = n; 449 if ((sv = calloc(1, len + 1)) == NULL) 450 goto out; 451 end = 0; 452 453 undo_add_delete(curwp->w_dotp, curwp->w_doto, n, (kflag & KREG)); 454 455 while (n != 0) { 456 dotp = curwp->w_dotp; 457 doto = curwp->w_doto; 458 /* Hit the end of the buffer */ 459 if (dotp == curbp->b_headp) 460 goto out; 461 /* Size of the chunk */ 462 chunk = dotp->l_used - doto; 463 464 if (chunk > n) 465 chunk = n; 466 /* End of line, merge */ 467 if (chunk == 0) { 468 if (dotp == blastlp(curbp)) 469 goto out; 470 lchange(WFFULL); 471 if (ldelnewline() == FALSE) 472 goto out; 473 end = strlcat(sv, "\n", len + 1); 474 --n; 475 continue; 476 } 477 lchange(WFEDIT); 478 /* Scrunch text */ 479 cp1 = &dotp->l_text[doto]; 480 memcpy(&sv[end], cp1, chunk); 481 end += chunk; 482 sv[end] = '\0'; 483 for (cp2 = cp1 + chunk; cp2 < &dotp->l_text[dotp->l_used]; 484 cp2++) 485 *cp1++ = *cp2; 486 dotp->l_used -= (int)chunk; 487 for (wp = wheadp; wp != NULL; wp = wp->w_wndp) { 488 if (wp->w_dotp == dotp && wp->w_doto >= doto) { 489 /* NOSTRICT */ 490 wp->w_doto -= chunk; 491 if (wp->w_doto < doto) 492 wp->w_doto = doto; 493 } 494 if (wp->w_markp == dotp && wp->w_marko >= doto) { 495 /* NOSTRICT */ 496 wp->w_marko -= chunk; 497 if (wp->w_marko < doto) 498 wp->w_marko = doto; 499 } 500 } 501 n -= chunk; 502 } 503 if (kchunk(sv, (RSIZE)len, kflag) != TRUE) 504 goto out; 505 rval = TRUE; 506 out: 507 free(sv); 508 return (rval); 509 } 510 511 /* 512 * Delete a newline and join the current line with the next line. If the next 513 * line is the magic header line always return TRUE; merging the last line 514 * with the header line can be thought of as always being a successful 515 * operation. Even if nothing is done, this makes the kill buffer work 516 * "right". If the mark is past the dot (actually, markline > dotline), 517 * decrease the markline accordingly to keep line numbers in sync. 518 * Easy cases can be done by shuffling data around. Hard cases 519 * require that lines be moved about in memory. Return FALSE on error and 520 * TRUE if all looks ok. We do not update w_dotline here, as deletes are done 521 * after moves. 522 */ 523 int 524 ldelnewline(void) 525 { 526 struct line *lp1, *lp2, *lp3; 527 struct mgwin *wp; 528 int s; 529 530 if ((s = checkdirty(curbp)) != TRUE) 531 return (s); 532 if (curbp->b_flag & BFREADONLY) { 533 dobeep(); 534 ewprintf("Buffer is read only"); 535 return (FALSE); 536 } 537 538 lp1 = curwp->w_dotp; 539 lp2 = lp1->l_fp; 540 /* at the end of the buffer */ 541 if (lp2 == curbp->b_headp) 542 return (TRUE); 543 /* Keep line counts in sync */ 544 curwp->w_bufp->b_lines--; 545 if (curwp->w_markline > curwp->w_dotline) 546 curwp->w_markline--; 547 if (lp2->l_used <= lp1->l_size - lp1->l_used) { 548 bcopy(&lp2->l_text[0], &lp1->l_text[lp1->l_used], lp2->l_used); 549 for (wp = wheadp; wp != NULL; wp = wp->w_wndp) { 550 if (wp->w_linep == lp2) 551 wp->w_linep = lp1; 552 if (wp->w_dotp == lp2) { 553 wp->w_dotp = lp1; 554 wp->w_doto += lp1->l_used; 555 } 556 if (wp->w_markp == lp2) { 557 wp->w_markp = lp1; 558 wp->w_marko += lp1->l_used; 559 } 560 } 561 lp1->l_used += lp2->l_used; 562 lp1->l_fp = lp2->l_fp; 563 lp2->l_fp->l_bp = lp1; 564 free(lp2); 565 return (TRUE); 566 } 567 if ((lp3 = lalloc(lp1->l_used + lp2->l_used)) == NULL) 568 return (FALSE); 569 bcopy(&lp1->l_text[0], &lp3->l_text[0], lp1->l_used); 570 bcopy(&lp2->l_text[0], &lp3->l_text[lp1->l_used], lp2->l_used); 571 lp1->l_bp->l_fp = lp3; 572 lp3->l_fp = lp2->l_fp; 573 lp2->l_fp->l_bp = lp3; 574 lp3->l_bp = lp1->l_bp; 575 for (wp = wheadp; wp != NULL; wp = wp->w_wndp) { 576 if (wp->w_linep == lp1 || wp->w_linep == lp2) 577 wp->w_linep = lp3; 578 if (wp->w_dotp == lp1) 579 wp->w_dotp = lp3; 580 else if (wp->w_dotp == lp2) { 581 wp->w_dotp = lp3; 582 wp->w_doto += lp1->l_used; 583 } 584 if (wp->w_markp == lp1) 585 wp->w_markp = lp3; 586 else if (wp->w_markp == lp2) { 587 wp->w_markp = lp3; 588 wp->w_marko += lp1->l_used; 589 } 590 } 591 free(lp1); 592 free(lp2); 593 return (TRUE); 594 } 595 596 /* 597 * Replace plen characters before dot with argument string. Control-J 598 * characters in st are interpreted as newlines. There is a casehack 599 * disable flag (normally it likes to match case of replacement to what 600 * was there). 601 */ 602 int 603 lreplace(RSIZE plen, char *st) 604 { 605 RSIZE rlen; /* replacement length */ 606 int s; 607 608 if ((s = checkdirty(curbp)) != TRUE) 609 return (s); 610 if (curbp->b_flag & BFREADONLY) { 611 dobeep(); 612 ewprintf("Buffer is read only"); 613 return (FALSE); 614 } 615 undo_boundary_enable(FFRAND, 0); 616 617 (void)backchar(FFARG | FFRAND, (int)plen); 618 (void)ldelete(plen, KNONE); 619 620 rlen = strlen(st); 621 region_put_data(st, rlen); 622 lchange(WFFULL); 623 624 undo_boundary_enable(FFRAND, 1); 625 return (TRUE); 626 } 627 628 /* 629 * Allocate and return the supplied line as a C string 630 */ 631 char * 632 linetostr(const struct line *ln) 633 { 634 int len; 635 char *line; 636 637 len = llength(ln); 638 if (len == INT_MAX) /* (len + 1) overflow */ 639 return (NULL); 640 641 if ((line = malloc(len + 1)) == NULL) 642 return (NULL); 643 644 (void)memcpy(line, ltext(ln), len); 645 line[len] = '\0'; 646 647 return (line); 648 } 649