Annotation of src/usr.bin/mg/line.c, Revision 1.28
1.28 ! deraadt 1: /* $OpenBSD: line.c,v 1.27 2005/11/18 17:35:17 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: /*
431: * HACK - doesn't matter, and fixes back-over-nl bug for empty
432: * kill buffers.
433: */
1.3 millert 434: if (kused == kstart)
435: kflag = KFORW;
1.1 deraadt 436:
437: while (n != 0) {
438: dotp = curwp->w_dotp;
439: doto = curwp->w_doto;
1.4 millert 440: /* Hit the end of the buffer */
441: if (dotp == curbp->b_linep)
1.22 db 442: return (FALSE);
1.4 millert 443: /* Size of the chunk */
444: chunk = dotp->l_used - doto;
1.20 vincent 445:
1.1 deraadt 446: if (chunk > n)
447: chunk = n;
1.4 millert 448: /* End of line, merge */
449: if (chunk == 0) {
1.3 millert 450: if (dotp == lback(curbp->b_linep))
1.4 millert 451: /* End of buffer */
1.22 db 452: return (FALSE);
1.1 deraadt 453: lchange(WFHARD);
1.8 mickey 454: if (ldelnewline() == FALSE ||
1.4 millert 455: (kflag != KNONE && kinsert('\n', kflag) == FALSE))
1.22 db 456: return (FALSE);
1.1 deraadt 457: --n;
458: continue;
459: }
460: lchange(WFEDIT);
1.4 millert 461: /* Scrunch text */
462: cp1 = &dotp->l_text[doto];
1.1 deraadt 463: if (kflag == KFORW) {
464: while (ksize - kused < chunk)
1.26 kjell 465: if (kgrow(kflag) == FALSE)
1.22 db 466: return (FALSE);
1.4 millert 467: bcopy(cp1, &(kbufp[kused]), (int)chunk);
1.1 deraadt 468: kused += chunk;
469: } else if (kflag == KBACK) {
470: while (kstart < chunk)
1.26 kjell 471: if (kgrow(kflag) == FALSE)
1.22 db 472: return (FALSE);
1.4 millert 473: bcopy(cp1, &(kbufp[kstart - chunk]), (int)chunk);
1.1 deraadt 474: kstart -= chunk;
1.3 millert 475: } else if (kflag != KNONE)
476: panic("broken ldelete call");
1.20 vincent 477: for (cp2 = cp1 + chunk; cp2 < &dotp->l_text[dotp->l_used];
478: cp2++)
479: *cp1++ = *cp2;
1.4 millert 480: dotp->l_used -= (int)chunk;
1.3 millert 481: for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
482: if (wp->w_dotp == dotp && wp->w_doto >= doto) {
483: /* NOSTRICT */
1.1 deraadt 484: wp->w_doto -= chunk;
485: if (wp->w_doto < doto)
486: wp->w_doto = doto;
487: }
1.3 millert 488: if (wp->w_markp == dotp && wp->w_marko >= doto) {
489: /* NOSTRICT */
1.1 deraadt 490: wp->w_marko -= chunk;
491: if (wp->w_marko < doto)
492: wp->w_marko = doto;
493: }
494: }
495: n -= chunk;
496: }
1.22 db 497: return (TRUE);
1.1 deraadt 498: }
499:
500: /*
1.8 mickey 501: * Delete a newline and join the current line with the next line. If the next
1.4 millert 502: * line is the magic header line always return TRUE; merging the last line
1.8 mickey 503: * with the header line can be thought of as always being a successful
504: * operation. Even if nothing is done, this makes the kill buffer work
505: * "right". Easy cases can be done by shuffling data around. Hard cases
506: * require that lines be moved about in memory. Return FALSE on error and
1.4 millert 507: * TRUE if all looks ok.
1.1 deraadt 508: */
1.4 millert 509: int
1.15 vincent 510: ldelnewline(void)
1.3 millert 511: {
1.28 ! deraadt 512: struct line *lp1, *lp2, *lp3;
! 513: struct mgwin *wp;
1.1 deraadt 514:
1.15 vincent 515: if (curbp->b_flag & BFREADONLY) {
516: ewprintf("Buffer is read only");
1.22 db 517: return (FALSE);
1.15 vincent 518: }
519:
1.1 deraadt 520: lp1 = curwp->w_dotp;
521: lp2 = lp1->l_fp;
1.4 millert 522: /* at the end of the buffer */
523: if (lp2 == curbp->b_linep)
1.22 db 524: return (TRUE);
1.1 deraadt 525: if (lp2->l_used <= lp1->l_size - lp1->l_used) {
526: bcopy(&lp2->l_text[0], &lp1->l_text[lp1->l_used], lp2->l_used);
1.3 millert 527: for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
1.1 deraadt 528: if (wp->w_linep == lp2)
529: wp->w_linep = lp1;
530: if (wp->w_dotp == lp2) {
1.3 millert 531: wp->w_dotp = lp1;
1.1 deraadt 532: wp->w_doto += lp1->l_used;
533: }
534: if (wp->w_markp == lp2) {
1.3 millert 535: wp->w_markp = lp1;
1.1 deraadt 536: wp->w_marko += lp1->l_used;
537: }
538: }
539: lp1->l_used += lp2->l_used;
540: lp1->l_fp = lp2->l_fp;
541: lp2->l_fp->l_bp = lp1;
1.4 millert 542: free((char *)lp2);
1.22 db 543: return (TRUE);
1.1 deraadt 544: }
1.3 millert 545: if ((lp3 = lalloc(lp1->l_used + lp2->l_used)) == NULL)
1.22 db 546: return (FALSE);
1.1 deraadt 547: bcopy(&lp1->l_text[0], &lp3->l_text[0], lp1->l_used);
548: bcopy(&lp2->l_text[0], &lp3->l_text[lp1->l_used], lp2->l_used);
549: lp1->l_bp->l_fp = lp3;
550: lp3->l_fp = lp2->l_fp;
551: lp2->l_fp->l_bp = lp3;
552: lp3->l_bp = lp1->l_bp;
1.3 millert 553: for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
554: if (wp->w_linep == lp1 || wp->w_linep == lp2)
1.1 deraadt 555: wp->w_linep = lp3;
556: if (wp->w_dotp == lp1)
1.3 millert 557: wp->w_dotp = lp3;
1.1 deraadt 558: else if (wp->w_dotp == lp2) {
1.3 millert 559: wp->w_dotp = lp3;
1.1 deraadt 560: wp->w_doto += lp1->l_used;
561: }
562: if (wp->w_markp == lp1)
1.3 millert 563: wp->w_markp = lp3;
1.1 deraadt 564: else if (wp->w_markp == lp2) {
1.3 millert 565: wp->w_markp = lp3;
1.1 deraadt 566: wp->w_marko += lp1->l_used;
567: }
568: }
1.4 millert 569: free((char *)lp1);
570: free((char *)lp2);
1.22 db 571: return (TRUE);
1.1 deraadt 572: }
1.9 vincent 573:
1.1 deraadt 574: /*
1.8 mickey 575: * Replace plen characters before dot with argument string. Control-J
576: * characters in st are interpreted as newlines. There is a casehack
577: * disable flag (normally it likes to match case of replacement to what
1.4 millert 578: * was there).
1.1 deraadt 579: */
1.4 millert 580: int
1.27 kjell 581: lreplace(RSIZE plen, char *st)
1.4 millert 582: {
583: RSIZE rlen; /* replacement length */
1.15 vincent 584:
585: if (curbp->b_flag & BFREADONLY) {
586: ewprintf("Buffer is read only");
1.22 db 587: return (FALSE);
1.15 vincent 588: }
1.24 kjell 589: undo_add_boundary();
590: undo_no_boundary(TRUE);
1.25 deraadt 591:
1.6 art 592: (void)backchar(FFARG | FFRAND, (int)plen);
1.24 kjell 593: (void)ldelete(plen, KNONE);
1.15 vincent 594:
1.1 deraadt 595: rlen = strlen(st);
1.24 kjell 596: region_put_data(st, rlen);
597: lchange(WFHARD);
1.1 deraadt 598:
1.24 kjell 599: undo_no_boundary(FALSE);
600: undo_add_boundary();
1.1 deraadt 601: return (TRUE);
602: }
1.13 vincent 603:
1.1 deraadt 604: /*
1.8 mickey 605: * Delete all of the text saved in the kill buffer. Called by commands when
606: * a new kill context is created. The kill buffer array is released, just in
1.4 millert 607: * case the buffer has grown to an immense size. No errors.
1.1 deraadt 608: */
1.6 art 609: void
1.17 vincent 610: kdelete(void)
1.3 millert 611: {
1.1 deraadt 612: if (kbufp != NULL) {
1.4 millert 613: free((char *)kbufp);
1.1 deraadt 614: kbufp = NULL;
615: kstart = kused = ksize = 0;
616: }
617: }
618:
619: /*
1.8 mickey 620: * Insert a character to the kill buffer, enlarging the buffer if there
621: * isn't any room. Always grow the buffer in chunks, on the assumption
622: * that if you put something in the kill buffer you are going to put more
623: * stuff there too later. Return TRUE if all is well, and FALSE on errors.
1.4 millert 624: * Print a message on errors. Dir says whether to put it at back or front.
1.1 deraadt 625: */
1.4 millert 626: int
1.17 vincent 627: kinsert(int c, int dir)
1.3 millert 628: {
1.26 kjell 629: if (kused == ksize && dir == KFORW && kgrow(dir) == FALSE)
1.22 db 630: return (FALSE);
1.26 kjell 631: if (kstart == 0 && dir == KBACK && kgrow(dir) == FALSE)
1.22 db 632: return (FALSE);
1.3 millert 633: if (dir == KFORW)
634: kbufp[kused++] = c;
635: else if (dir == KBACK)
636: kbufp[--kstart] = c;
637: else
638: panic("broken kinsert call"); /* Oh shit! */
1.1 deraadt 639: return (TRUE);
640: }
641:
642: /*
1.26 kjell 643: * kgrow - just get more kill buffer for the callee. If dir = KBACK
1.1 deraadt 644: * we are trying to get space at the beginning of the kill buffer.
645: */
1.4 millert 646: static int
1.26 kjell 647: kgrow(int dir)
1.3 millert 648: {
1.4 millert 649: int nstart;
650: char *nbufp;
1.1 deraadt 651:
1.4 millert 652: if ((unsigned)(ksize + KBLOCK) <= (unsigned)ksize) {
1.1 deraadt 653: /* probably 16 bit unsigned */
654: ewprintf("Kill buffer size at maximum");
1.22 db 655: return (FALSE);
1.1 deraadt 656: }
1.4 millert 657: if ((nbufp = malloc((unsigned)(ksize + KBLOCK))) == NULL) {
658: ewprintf("Can't get %ld bytes", (long)(ksize + KBLOCK));
1.22 db 659: return (FALSE);
1.1 deraadt 660: }
1.26 kjell 661: nstart = (dir == KBACK) ? (kstart + KBLOCK) : (KBLOCK / 4);
1.4 millert 662: bcopy(&(kbufp[kstart]), &(nbufp[nstart]), (int)(kused - kstart));
1.1 deraadt 663: if (kbufp != NULL)
1.4 millert 664: free((char *)kbufp);
1.3 millert 665: kbufp = nbufp;
1.1 deraadt 666: ksize += KBLOCK;
667: kused = kused - kstart + nstart;
668: kstart = nstart;
1.22 db 669: return (TRUE);
1.1 deraadt 670: }
671:
672: /*
1.8 mickey 673: * This function gets characters from the kill buffer. If the character
674: * index "n" is off the end, it returns "-1". This lets the caller just
1.4 millert 675: * scan along until it gets a "-1" back.
1.1 deraadt 676: */
1.4 millert 677: int
1.21 vincent 678: kremove(int n)
1.3 millert 679: {
1.1 deraadt 680: if (n < 0 || n + kstart >= kused)
1.22 db 681: return (-1);
682: return (CHARMASK(kbufp[n + kstart]));
1.1 deraadt 683: }