Annotation of src/usr.bin/mg/line.c, Revision 1.32
1.32 ! kjell 1: /* $OpenBSD: line.c,v 1.31 2005/11/21 19:47:23 deraadt Exp $ */
1.23 kjell 2:
3: /* This file is in the public domain. */
1.5 niklas 4:
1.1 deraadt 5: /*
6: * Text line handling.
1.8 mickey 7: *
1.4 millert 8: * The functions in this file are a general set of line management
1.8 mickey 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. There are routines in this file that
1.4 millert 12: * handle the kill buffer too. It isn't here for any good reason.
1.1 deraadt 13: *
1.8 mickey 14: * Note that this code only updates the dot and mark values in the window
15: * list. Since all the code acts on the current window, the buffer that
16: * we are editing must be displayed, which means that "b_nwnd" is non-zero,
17: * which means that the dot and mark values in the buffer headers are
1.1 deraadt 18: * nonsense.
19: */
20:
1.4 millert 21: #include "def.h"
22:
1.32 ! kjell 23: #include <stdlib.h>
! 24: #include <string.h>
! 25:
1.4 millert 26: /*
1.8 mickey 27: * The number of bytes member from the start of the structure type should be
1.4 millert 28: * computed at compile time.
29: */
1.1 deraadt 30:
31: #ifndef KBLOCK
1.3 millert 32: #define KBLOCK 256 /* Kill buffer block size. */
1.1 deraadt 33: #endif
34:
1.4 millert 35: static char *kbufp = NULL; /* Kill buffer data. */
36: static RSIZE kused = 0; /* # of bytes used in KB. */
37: static RSIZE ksize = 0; /* # of bytes allocated in KB. */
38: static RSIZE kstart = 0; /* # of first used byte in KB. */
39:
1.12 millert 40: static int kgrow(int);
1.1 deraadt 41:
42: /*
1.9 vincent 43: * Allocate a new line of size `used'. lrealloc() can be called if the line
44: * ever needs to grow beyond that.
1.1 deraadt 45: */
1.28 deraadt 46: struct line *
1.9 vincent 47: lalloc(int used)
1.3 millert 48: {
1.28 deraadt 49: struct line *lp;
1.1 deraadt 50:
1.22 db 51: if ((lp = malloc(sizeof(*lp))) == NULL)
52: return (NULL);
1.9 vincent 53: lp->l_text = NULL;
54: lp->l_size = 0;
55: lp->l_used = used; /* XXX */
56: if (lrealloc(lp, used) == FALSE) {
57: free(lp);
1.22 db 58: return (NULL);
1.1 deraadt 59: }
1.22 db 60: return (lp);
1.1 deraadt 61: }
62:
1.9 vincent 63: int
1.28 deraadt 64: lrealloc(struct line *lp, int newsize)
1.1 deraadt 65: {
1.9 vincent 66: char *tmp;
1.1 deraadt 67:
1.18 millert 68: if (lp->l_size < newsize) {
69: if ((tmp = realloc(lp->l_text, newsize)) == NULL)
1.22 db 70: return (FALSE);
1.18 millert 71: lp->l_text = tmp;
72: lp->l_size = newsize;
73: }
1.22 db 74: return (TRUE);
1.1 deraadt 75: }
76:
77: /*
1.4 millert 78: * Delete line "lp". Fix all of the links that might point to it (they are
1.8 mickey 79: * moved to offset 0 of the next line. Unlink the line from whatever buffer
80: * it might be in, and release the memory. The buffers are updated too; the
1.4 millert 81: * magic conditions described in the above comments don't hold here.
1.1 deraadt 82: */
1.6 art 83: void
1.28 deraadt 84: lfree(struct line *lp)
1.3 millert 85: {
1.28 deraadt 86: struct buffer *bp;
87: struct mgwin *wp;
1.1 deraadt 88:
1.3 millert 89: for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
1.1 deraadt 90: if (wp->w_linep == lp)
91: wp->w_linep = lp->l_fp;
1.3 millert 92: if (wp->w_dotp == lp) {
93: wp->w_dotp = lp->l_fp;
94: wp->w_doto = 0;
1.1 deraadt 95: }
96: if (wp->w_markp == lp) {
97: wp->w_markp = lp->l_fp;
98: wp->w_marko = 0;
99: }
100: }
1.3 millert 101: for (bp = bheadp; bp != NULL; bp = bp->b_bufp) {
1.1 deraadt 102: if (bp->b_nwnd == 0) {
1.3 millert 103: if (bp->b_dotp == lp) {
1.1 deraadt 104: bp->b_dotp = lp->l_fp;
105: bp->b_doto = 0;
106: }
107: if (bp->b_markp == lp) {
108: bp->b_markp = lp->l_fp;
109: bp->b_marko = 0;
110: }
111: }
112: }
113: lp->l_bp->l_fp = lp->l_fp;
114: lp->l_fp->l_bp = lp->l_bp;
1.9 vincent 115: if (lp->l_text != NULL)
116: free(lp->l_text);
117: free(lp);
1.1 deraadt 118: }
119:
120: /*
1.8 mickey 121: * This routine is called when a character changes in place in the current
122: * buffer. It updates all of the required flags in the buffer and window
123: * system. The flag used is passed as an argument; if the buffer is being
124: * displayed in more than 1 window we change EDIT to HARD. Set MODE if the
1.4 millert 125: * mode line needs to be updated (the "*" has to be set).
1.1 deraadt 126: */
1.6 art 127: void
1.15 vincent 128: lchange(int flag)
1.3 millert 129: {
1.28 deraadt 130: struct mgwin *wp;
1.1 deraadt 131:
1.4 millert 132: /* update mode lines if this is the first change. */
133: if ((curbp->b_flag & BFCHG) == 0) {
134: flag |= WFMODE;
1.1 deraadt 135: curbp->b_flag |= BFCHG;
136: }
1.3 millert 137: for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
1.1 deraadt 138: if (wp->w_bufp == curbp) {
139: wp->w_flag |= flag;
1.3 millert 140: if (wp != curwp)
141: wp->w_flag |= WFHARD;
1.1 deraadt 142: }
143: }
144: }
145:
146: /*
1.20 vincent 147: * Insert "n" bytes from "s" at the current location of dot.
148: * In the easy case all that happens is the text is stored in the line.
149: * In the hard case, the line has to be reallocated. When the window list
150: * is updated, take special care; I screwed it up once. You always update
151: * dot in the current window. You update mark and a dot in another window
152: * if it is greater than the place where you did the insert. Return TRUE
153: * if all is well, and FALSE on errors.
154: */
155: int
156: linsert_str(const char *s, int n)
157: {
1.28 deraadt 158: struct line *lp1;
159: struct mgwin *wp;
1.20 vincent 160: RSIZE i;
161: int doto;
162:
163: if (curbp->b_flag & BFREADONLY) {
164: ewprintf("Buffer is read only");
1.22 db 165: return (FALSE);
1.20 vincent 166: }
167:
168: if (!n)
169: return (TRUE);
170:
171: lchange(WFHARD);
172:
173: /* current line */
174: lp1 = curwp->w_dotp;
175:
176: /* special case for the end */
177: if (lp1 == curbp->b_linep) {
1.28 deraadt 178: struct line *lp2, *lp3;
1.20 vincent 179:
180: /* now should only happen in empty buffer */
181: if (curwp->w_doto != 0)
182: panic("bug: linsert_str");
183: /* allocate a new line */
184: if ((lp2 = lalloc(n)) == NULL)
1.22 db 185: return (FALSE);
1.20 vincent 186: /* previous line */
187: lp3 = lp1->l_bp;
188: /* link in */
189: lp3->l_fp = lp2;
190: lp2->l_fp = lp1;
191: lp1->l_bp = lp2;
192: lp2->l_bp = lp3;
193: for (i = 0; i < n; ++i)
194: lp2->l_text[i] = s[i];
195: for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
196: if (wp->w_linep == lp1)
197: wp->w_linep = lp2;
198: if (wp->w_dotp == lp1)
199: wp->w_dotp = lp2;
200: if (wp->w_markp == lp1)
201: wp->w_markp = lp2;
202: }
203: undo_add_insert(lp2, 0, n);
204: curwp->w_doto = n;
1.22 db 205: return (TRUE);
1.20 vincent 206: }
207: /* save for later */
208: doto = curwp->w_doto;
209:
210: if ((lp1->l_used + n) > lp1->l_size) {
211: if (lrealloc(lp1, lp1->l_used + n) == FALSE)
1.22 db 212: return (FALSE);
1.20 vincent 213: }
214: lp1->l_used += n;
215: if (lp1->l_used != n)
216: memmove(&lp1->l_text[doto + n], &lp1->l_text[doto],
217: lp1->l_used - n - doto);
218:
219: /* Add the characters */
220: for (i = 0; i < n; ++i)
221: lp1->l_text[doto + i] = s[i];
222: for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
223: if (wp->w_dotp == lp1) {
224: if (wp == curwp || wp->w_doto > doto)
225: wp->w_doto += n;
226: }
227: if (wp->w_markp == lp1) {
228: if (wp->w_marko > doto)
229: wp->w_marko += n;
230: }
231: }
232: undo_add_insert(curwp->w_dotp, doto, n);
1.22 db 233: return (TRUE);
1.20 vincent 234: }
235:
236: /*
1.8 mickey 237: * Insert "n" copies of the character "c" at the current location of dot.
238: * In the easy case all that happens is the text is stored in the line.
239: * In the hard case, the line has to be reallocated. When the window list
240: * is updated, take special care; I screwed it up once. You always update
1.4 millert 241: * dot in the current window. You update mark and a dot in another window
242: * if it is greater than the place where you did the insert. Return TRUE
1.1 deraadt 243: * if all is well, and FALSE on errors.
244: */
1.4 millert 245: int
1.15 vincent 246: linsert(int n, int c)
1.1 deraadt 247: {
1.28 deraadt 248: struct line *lp1;
249: struct mgwin *wp;
1.4 millert 250: RSIZE i;
251: int doto;
1.1 deraadt 252:
1.20 vincent 253: if (!n)
254: return (TRUE);
255:
1.15 vincent 256: if (curbp->b_flag & BFREADONLY) {
257: ewprintf("Buffer is read only");
1.22 db 258: return (FALSE);
1.15 vincent 259: }
260:
1.1 deraadt 261: lchange(WFEDIT);
1.4 millert 262:
263: /* current line */
264: lp1 = curwp->w_dotp;
1.15 vincent 265:
1.4 millert 266: /* special case for the end */
267: if (lp1 == curbp->b_linep) {
1.28 deraadt 268: struct line *lp2, *lp3;
1.11 deraadt 269:
1.4 millert 270: /* now should only happen in empty buffer */
1.1 deraadt 271: if (curwp->w_doto != 0) {
272: ewprintf("bug: linsert");
1.22 db 273: return (FALSE);
1.1 deraadt 274: }
1.4 millert 275: /* allocate a new line */
1.9 vincent 276: if ((lp2 = lalloc(n)) == NULL)
1.22 db 277: return (FALSE);
1.4 millert 278: /* previous line */
279: lp3 = lp1->l_bp;
280: /* link in */
281: lp3->l_fp = lp2;
1.1 deraadt 282: lp2->l_fp = lp1;
283: lp1->l_bp = lp2;
284: lp2->l_bp = lp3;
1.3 millert 285: for (i = 0; i < n; ++i)
1.1 deraadt 286: lp2->l_text[i] = c;
1.3 millert 287: for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
1.1 deraadt 288: if (wp->w_linep == lp1)
289: wp->w_linep = lp2;
290: if (wp->w_dotp == lp1)
291: wp->w_dotp = lp2;
292: if (wp->w_markp == lp1)
293: wp->w_markp = lp2;
294: }
1.16 vincent 295: undo_add_insert(lp2, 0, n);
1.1 deraadt 296: curwp->w_doto = n;
1.22 db 297: return (TRUE);
1.1 deraadt 298: }
1.4 millert 299: /* save for later */
300: doto = curwp->w_doto;
1.9 vincent 301:
302: if ((lp1->l_used + n) > lp1->l_size) {
303: if (lrealloc(lp1, lp1->l_used + n) == FALSE)
1.22 db 304: return (FALSE);
1.11 deraadt 305: }
1.9 vincent 306: lp1->l_used += n;
1.11 deraadt 307: if (lp1->l_used != n)
1.9 vincent 308: memmove(&lp1->l_text[doto + n], &lp1->l_text[doto],
309: lp1->l_used - n - doto);
310:
1.4 millert 311: /* Add the characters */
312: for (i = 0; i < n; ++i)
1.9 vincent 313: lp1->l_text[doto + i] = c;
1.3 millert 314: for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
1.1 deraadt 315: if (wp->w_dotp == lp1) {
1.3 millert 316: if (wp == curwp || wp->w_doto > doto)
1.1 deraadt 317: wp->w_doto += n;
318: }
319: if (wp->w_markp == lp1) {
320: if (wp->w_marko > doto)
321: wp->w_marko += n;
322: }
323: }
1.16 vincent 324: undo_add_insert(curwp->w_dotp, doto, n);
1.22 db 325: return (TRUE);
1.1 deraadt 326: }
327:
1.4 millert 328: int
1.28 deraadt 329: lnewline_at(struct line *lp1, int doto)
1.1 deraadt 330: {
1.28 deraadt 331: struct line *lp2;
1.21 vincent 332: int nlen;
1.28 deraadt 333: struct mgwin *wp;
1.24 kjell 334: int retval = TRUE;
1.1 deraadt 335:
336: lchange(WFHARD);
1.14 vincent 337:
1.4 millert 338: /* avoid unnecessary copying */
339: if (doto == 0) {
340: /* new first part */
1.24 kjell 341: if ((lp2 = lalloc(0)) == NULL) {
342: retval = FALSE;
343: goto lnl_done;
344: }
1.1 deraadt 345: lp2->l_bp = lp1->l_bp;
346: lp1->l_bp->l_fp = lp2;
347: lp2->l_fp = lp1;
348: lp1->l_bp = lp2;
1.3 millert 349: for (wp = wheadp; wp != NULL; wp = wp->w_wndp)
350: if (wp->w_linep == lp1)
351: wp->w_linep = lp2;
1.24 kjell 352: goto lnl_done;
1.1 deraadt 353: }
1.4 millert 354:
355: /* length of new part */
356: nlen = llength(lp1) - doto;
357:
358: /* new second half line */
1.24 kjell 359: if ((lp2 = lalloc(nlen)) == NULL) {
360: retval = FALSE;
361: goto lnl_done;
362: }
1.3 millert 363: if (nlen != 0)
364: bcopy(&lp1->l_text[doto], &lp2->l_text[0], nlen);
1.1 deraadt 365: lp1->l_used = doto;
366: lp2->l_bp = lp1;
367: lp2->l_fp = lp1->l_fp;
368: lp1->l_fp = lp2;
369: lp2->l_fp->l_bp = lp2;
1.4 millert 370: /* Windows */
371: for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
1.1 deraadt 372: if (wp->w_dotp == lp1 && wp->w_doto >= doto) {
373: wp->w_dotp = lp2;
374: wp->w_doto -= doto;
375: }
376: if (wp->w_markp == lp1 && wp->w_marko >= doto) {
377: wp->w_markp = lp2;
378: wp->w_marko -= doto;
379: }
380: }
1.24 kjell 381: lnl_done:
382: undo_add_boundary();
383: undo_add_insert(lp1, llength(lp1), 1);
384: undo_add_boundary();
385: return (retval);
1.1 deraadt 386: }
387:
388: /*
1.21 vincent 389: * Insert a newline into the buffer at the current location of dot in the
390: * current window.
391: */
392: int
393: lnewline(void)
394: {
395: if (curbp->b_flag & BFREADONLY) {
396: ewprintf("Buffer is read only");
1.22 db 397: return (FALSE);
1.21 vincent 398: }
1.22 db 399: return (lnewline_at(curwp->w_dotp, curwp->w_doto));
1.21 vincent 400: }
401:
402: /*
1.8 mickey 403: * This function deletes "n" bytes, starting at dot. It understands how to
404: * deal with end of lines, etc. It returns TRUE if all of the characters
405: * were deleted, and FALSE if they were not (because dot ran into the end
406: * of the buffer. The "kflag" indicates either no insertion, or direction
1.4 millert 407: * of insertion into the kill buffer.
1.1 deraadt 408: */
1.4 millert 409: int
1.15 vincent 410: ldelete(RSIZE n, int kflag)
1.3 millert 411: {
1.28 deraadt 412: struct line *dotp;
1.4 millert 413: RSIZE chunk;
1.28 deraadt 414: struct mgwin *wp;
1.4 millert 415: int doto;
416: char *cp1, *cp2;
1.32 ! kjell 417: size_t len;
! 418: char *sv;
! 419: int end;
1.1 deraadt 420:
1.15 vincent 421: if (curbp->b_flag & BFREADONLY) {
422: ewprintf("Buffer is read only");
1.22 db 423: return (FALSE);
1.15 vincent 424: }
1.32 ! kjell 425: len = n;
! 426: if ((sv = calloc(1, len + 1)) == NULL)
! 427: return (FALSE);
! 428: end = 0;
1.15 vincent 429:
1.16 vincent 430: undo_add_delete(curwp->w_dotp, curwp->w_doto, n);
1.15 vincent 431:
1.1 deraadt 432: while (n != 0) {
433: dotp = curwp->w_dotp;
434: doto = curwp->w_doto;
1.4 millert 435: /* Hit the end of the buffer */
436: if (dotp == curbp->b_linep)
1.22 db 437: return (FALSE);
1.4 millert 438: /* Size of the chunk */
439: chunk = dotp->l_used - doto;
1.20 vincent 440:
1.1 deraadt 441: if (chunk > n)
442: chunk = n;
1.4 millert 443: /* End of line, merge */
444: if (chunk == 0) {
1.3 millert 445: if (dotp == lback(curbp->b_linep))
1.4 millert 446: /* End of buffer */
1.22 db 447: return (FALSE);
1.1 deraadt 448: lchange(WFHARD);
1.32 ! kjell 449: if (ldelnewline() == FALSE)
1.22 db 450: return (FALSE);
1.32 ! kjell 451: end = strlcat(sv, "\n", len + 1);
1.1 deraadt 452: --n;
453: continue;
454: }
455: lchange(WFEDIT);
1.4 millert 456: /* Scrunch text */
457: cp1 = &dotp->l_text[doto];
1.32 ! kjell 458: memcpy(&sv[end], cp1, chunk);
! 459: end += chunk;
! 460: sv[end] = '\0';
1.20 vincent 461: for (cp2 = cp1 + chunk; cp2 < &dotp->l_text[dotp->l_used];
462: cp2++)
463: *cp1++ = *cp2;
1.4 millert 464: dotp->l_used -= (int)chunk;
1.3 millert 465: for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
466: if (wp->w_dotp == dotp && wp->w_doto >= doto) {
467: /* NOSTRICT */
1.1 deraadt 468: wp->w_doto -= chunk;
469: if (wp->w_doto < doto)
470: wp->w_doto = doto;
471: }
1.3 millert 472: if (wp->w_markp == dotp && wp->w_marko >= doto) {
473: /* NOSTRICT */
1.1 deraadt 474: wp->w_marko -= chunk;
475: if (wp->w_marko < doto)
476: wp->w_marko = doto;
477: }
478: }
479: n -= chunk;
480: }
1.32 ! kjell 481: if (kchunk(sv, len, kflag) != TRUE)
! 482: return (FALSE);
! 483: free(sv);
1.22 db 484: return (TRUE);
1.1 deraadt 485: }
486:
487: /*
1.8 mickey 488: * Delete a newline and join the current line with the next line. If the next
1.4 millert 489: * line is the magic header line always return TRUE; merging the last line
1.8 mickey 490: * with the header line can be thought of as always being a successful
491: * operation. Even if nothing is done, this makes the kill buffer work
492: * "right". Easy cases can be done by shuffling data around. Hard cases
493: * require that lines be moved about in memory. Return FALSE on error and
1.4 millert 494: * TRUE if all looks ok.
1.1 deraadt 495: */
1.4 millert 496: int
1.15 vincent 497: ldelnewline(void)
1.3 millert 498: {
1.28 deraadt 499: struct line *lp1, *lp2, *lp3;
500: struct mgwin *wp;
1.1 deraadt 501:
1.15 vincent 502: if (curbp->b_flag & BFREADONLY) {
503: ewprintf("Buffer is read only");
1.22 db 504: return (FALSE);
1.15 vincent 505: }
506:
1.1 deraadt 507: lp1 = curwp->w_dotp;
508: lp2 = lp1->l_fp;
1.4 millert 509: /* at the end of the buffer */
510: if (lp2 == curbp->b_linep)
1.22 db 511: return (TRUE);
1.1 deraadt 512: if (lp2->l_used <= lp1->l_size - lp1->l_used) {
513: bcopy(&lp2->l_text[0], &lp1->l_text[lp1->l_used], lp2->l_used);
1.3 millert 514: for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
1.1 deraadt 515: if (wp->w_linep == lp2)
516: wp->w_linep = lp1;
517: if (wp->w_dotp == lp2) {
1.3 millert 518: wp->w_dotp = lp1;
1.1 deraadt 519: wp->w_doto += lp1->l_used;
520: }
521: if (wp->w_markp == lp2) {
1.3 millert 522: wp->w_markp = lp1;
1.1 deraadt 523: wp->w_marko += lp1->l_used;
524: }
525: }
526: lp1->l_used += lp2->l_used;
527: lp1->l_fp = lp2->l_fp;
528: lp2->l_fp->l_bp = lp1;
1.4 millert 529: free((char *)lp2);
1.22 db 530: return (TRUE);
1.1 deraadt 531: }
1.3 millert 532: if ((lp3 = lalloc(lp1->l_used + lp2->l_used)) == NULL)
1.22 db 533: return (FALSE);
1.1 deraadt 534: bcopy(&lp1->l_text[0], &lp3->l_text[0], lp1->l_used);
535: bcopy(&lp2->l_text[0], &lp3->l_text[lp1->l_used], lp2->l_used);
536: lp1->l_bp->l_fp = lp3;
537: lp3->l_fp = lp2->l_fp;
538: lp2->l_fp->l_bp = lp3;
539: lp3->l_bp = lp1->l_bp;
1.3 millert 540: for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
541: if (wp->w_linep == lp1 || wp->w_linep == lp2)
1.1 deraadt 542: wp->w_linep = lp3;
543: if (wp->w_dotp == lp1)
1.3 millert 544: wp->w_dotp = lp3;
1.1 deraadt 545: else if (wp->w_dotp == lp2) {
1.3 millert 546: wp->w_dotp = lp3;
1.1 deraadt 547: wp->w_doto += lp1->l_used;
548: }
549: if (wp->w_markp == lp1)
1.3 millert 550: wp->w_markp = lp3;
1.1 deraadt 551: else if (wp->w_markp == lp2) {
1.3 millert 552: wp->w_markp = lp3;
1.1 deraadt 553: wp->w_marko += lp1->l_used;
554: }
555: }
1.4 millert 556: free((char *)lp1);
557: free((char *)lp2);
1.22 db 558: return (TRUE);
1.1 deraadt 559: }
1.9 vincent 560:
1.1 deraadt 561: /*
1.8 mickey 562: * Replace plen characters before dot with argument string. Control-J
563: * characters in st are interpreted as newlines. There is a casehack
564: * disable flag (normally it likes to match case of replacement to what
1.4 millert 565: * was there).
1.1 deraadt 566: */
1.4 millert 567: int
1.27 kjell 568: lreplace(RSIZE plen, char *st)
1.4 millert 569: {
570: RSIZE rlen; /* replacement length */
1.15 vincent 571:
572: if (curbp->b_flag & BFREADONLY) {
573: ewprintf("Buffer is read only");
1.22 db 574: return (FALSE);
1.15 vincent 575: }
1.24 kjell 576: undo_add_boundary();
577: undo_no_boundary(TRUE);
1.25 deraadt 578:
1.6 art 579: (void)backchar(FFARG | FFRAND, (int)plen);
1.24 kjell 580: (void)ldelete(plen, KNONE);
1.15 vincent 581:
1.1 deraadt 582: rlen = strlen(st);
1.24 kjell 583: region_put_data(st, rlen);
584: lchange(WFHARD);
1.1 deraadt 585:
1.24 kjell 586: undo_no_boundary(FALSE);
587: undo_add_boundary();
1.1 deraadt 588: return (TRUE);
589: }
1.13 vincent 590:
1.1 deraadt 591: /*
1.8 mickey 592: * Delete all of the text saved in the kill buffer. Called by commands when
593: * a new kill context is created. The kill buffer array is released, just in
1.4 millert 594: * case the buffer has grown to an immense size. No errors.
1.1 deraadt 595: */
1.6 art 596: void
1.17 vincent 597: kdelete(void)
1.3 millert 598: {
1.1 deraadt 599: if (kbufp != NULL) {
1.4 millert 600: free((char *)kbufp);
1.1 deraadt 601: kbufp = NULL;
602: kstart = kused = ksize = 0;
603: }
604: }
605:
606: /*
1.8 mickey 607: * Insert a character to the kill buffer, enlarging the buffer if there
608: * isn't any room. Always grow the buffer in chunks, on the assumption
609: * that if you put something in the kill buffer you are going to put more
610: * stuff there too later. Return TRUE if all is well, and FALSE on errors.
1.4 millert 611: * Print a message on errors. Dir says whether to put it at back or front.
1.32 ! kjell 612: * This call is ignored if KNONE is set.
1.1 deraadt 613: */
1.4 millert 614: int
1.17 vincent 615: kinsert(int c, int dir)
1.3 millert 616: {
1.32 ! kjell 617: if (dir == KNONE)
! 618: return (TRUE);
1.26 kjell 619: if (kused == ksize && dir == KFORW && kgrow(dir) == FALSE)
1.22 db 620: return (FALSE);
1.26 kjell 621: if (kstart == 0 && dir == KBACK && kgrow(dir) == FALSE)
1.22 db 622: return (FALSE);
1.3 millert 623: if (dir == KFORW)
624: kbufp[kused++] = c;
625: else if (dir == KBACK)
626: kbufp[--kstart] = c;
627: else
628: panic("broken kinsert call"); /* Oh shit! */
1.1 deraadt 629: return (TRUE);
630: }
631:
632: /*
1.26 kjell 633: * kgrow - just get more kill buffer for the callee. If dir = KBACK
1.1 deraadt 634: * we are trying to get space at the beginning of the kill buffer.
635: */
1.4 millert 636: static int
1.26 kjell 637: kgrow(int dir)
1.3 millert 638: {
1.4 millert 639: int nstart;
640: char *nbufp;
1.1 deraadt 641:
1.4 millert 642: if ((unsigned)(ksize + KBLOCK) <= (unsigned)ksize) {
1.1 deraadt 643: /* probably 16 bit unsigned */
644: ewprintf("Kill buffer size at maximum");
1.22 db 645: return (FALSE);
1.1 deraadt 646: }
1.4 millert 647: if ((nbufp = malloc((unsigned)(ksize + KBLOCK))) == NULL) {
648: ewprintf("Can't get %ld bytes", (long)(ksize + KBLOCK));
1.22 db 649: return (FALSE);
1.1 deraadt 650: }
1.26 kjell 651: nstart = (dir == KBACK) ? (kstart + KBLOCK) : (KBLOCK / 4);
1.4 millert 652: bcopy(&(kbufp[kstart]), &(nbufp[nstart]), (int)(kused - kstart));
1.1 deraadt 653: if (kbufp != NULL)
1.4 millert 654: free((char *)kbufp);
1.3 millert 655: kbufp = nbufp;
1.1 deraadt 656: ksize += KBLOCK;
657: kused = kused - kstart + nstart;
658: kstart = nstart;
1.22 db 659: return (TRUE);
1.1 deraadt 660: }
661:
662: /*
1.8 mickey 663: * This function gets characters from the kill buffer. If the character
664: * index "n" is off the end, it returns "-1". This lets the caller just
1.4 millert 665: * scan along until it gets a "-1" back.
1.1 deraadt 666: */
1.4 millert 667: int
1.21 vincent 668: kremove(int n)
1.3 millert 669: {
1.1 deraadt 670: if (n < 0 || n + kstart >= kused)
1.22 db 671: return (-1);
672: return (CHARMASK(kbufp[n + kstart]));
1.29 kjell 673: }
674:
675: /*
676: * Copy a string into the kill buffer. kflag gives direction.
677: * if KNONE, do nothing.
678: */
679: int
680: kchunk(char *cp1, RSIZE chunk, int kflag)
681: {
682: /*
683: * HACK - doesn't matter, and fixes back-over-nl bug for empty
684: * kill buffers.
685: */
686: if (kused == kstart)
687: kflag = KFORW;
688:
689: if (kflag == KFORW) {
690: while (ksize - kused < chunk)
691: if (kgrow(kflag) == FALSE)
692: return (FALSE);
693: bcopy(cp1, &(kbufp[kused]), (int)chunk);
694: kused += chunk;
695: } else if (kflag == KBACK) {
696: while (kstart < chunk)
697: if (kgrow(kflag) == FALSE)
698: return (FALSE);
699: bcopy(cp1, &(kbufp[kstart - chunk]), (int)chunk);
700: kstart -= chunk;
701: } else if (kflag != KNONE)
702: panic("broken ldelete call");
703:
704: return (TRUE);
1.1 deraadt 705: }