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