Annotation of src/usr.bin/mg/line.c, Revision 1.23
1.23 ! kjell 1: /* $OpenBSD: line.c,v 1.22 2005/04/03 02:09:28 db Exp $ */
! 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: */
51: LINE *
1.9 vincent 52: lalloc(int used)
1.3 millert 53: {
1.9 vincent 54: 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
69: lrealloc(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.15 vincent 89: lfree(LINE *lp)
1.3 millert 90: {
1.4 millert 91: BUFFER *bp;
92: 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.4 millert 135: 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.22 db 163: LINE *lp1;
1.20 vincent 164: MGWIN *wp;
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) {
183: LINE *lp2, *lp3;
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.22 db 253: LINE *lp1;
1.4 millert 254: MGWIN *wp;
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.9 vincent 273: 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.21 vincent 334: lnewline_at(LINE *lp1, int doto)
1.1 deraadt 335: {
1.21 vincent 336: LINE *lp2;
337: int nlen;
1.4 millert 338: MGWIN *wp;
1.1 deraadt 339:
340: lchange(WFHARD);
1.14 vincent 341:
1.19 vincent 342: undo_add_boundary();
1.21 vincent 343: undo_add_insert(lp1, llength(lp1), 1);
1.19 vincent 344: undo_add_boundary();
1.14 vincent 345:
1.4 millert 346: /* avoid unnecessary copying */
347: if (doto == 0) {
348: /* new first part */
1.9 vincent 349: if ((lp2 = lalloc(0)) == NULL)
1.22 db 350: return (FALSE);
1.1 deraadt 351: lp2->l_bp = lp1->l_bp;
352: lp1->l_bp->l_fp = lp2;
353: lp2->l_fp = lp1;
354: lp1->l_bp = lp2;
1.3 millert 355: for (wp = wheadp; wp != NULL; wp = wp->w_wndp)
356: if (wp->w_linep == lp1)
357: wp->w_linep = lp2;
1.22 db 358: return (TRUE);
1.1 deraadt 359: }
1.4 millert 360:
361: /* length of new part */
362: nlen = llength(lp1) - doto;
363:
364: /* new second half line */
1.9 vincent 365: if ((lp2 = lalloc(nlen)) == NULL)
1.22 db 366: return (FALSE);
1.3 millert 367: if (nlen != 0)
368: bcopy(&lp1->l_text[doto], &lp2->l_text[0], nlen);
1.1 deraadt 369: lp1->l_used = doto;
370: lp2->l_bp = lp1;
371: lp2->l_fp = lp1->l_fp;
372: lp1->l_fp = lp2;
373: lp2->l_fp->l_bp = lp2;
1.4 millert 374: /* Windows */
375: for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
1.1 deraadt 376: if (wp->w_dotp == lp1 && wp->w_doto >= doto) {
377: wp->w_dotp = lp2;
378: wp->w_doto -= doto;
379: }
380: if (wp->w_markp == lp1 && wp->w_marko >= doto) {
381: wp->w_markp = lp2;
382: wp->w_marko -= doto;
383: }
384: }
1.22 db 385: return (TRUE);
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.4 millert 412: LINE *dotp;
413: RSIZE chunk;
414: MGWIN *wp;
415: int doto;
416: char *cp1, *cp2;
1.1 deraadt 417:
1.15 vincent 418: if (curbp->b_flag & BFREADONLY) {
419: ewprintf("Buffer is read only");
1.22 db 420: return (FALSE);
1.15 vincent 421: }
422:
1.16 vincent 423: undo_add_delete(curwp->w_dotp, curwp->w_doto, n);
1.15 vincent 424:
1.1 deraadt 425: /*
426: * HACK - doesn't matter, and fixes back-over-nl bug for empty
427: * kill buffers.
428: */
1.3 millert 429: if (kused == kstart)
430: kflag = KFORW;
1.1 deraadt 431:
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.8 mickey 449: if (ldelnewline() == FALSE ||
1.4 millert 450: (kflag != KNONE && kinsert('\n', kflag) == FALSE))
1.22 db 451: return (FALSE);
1.1 deraadt 452: --n;
453: continue;
454: }
455: lchange(WFEDIT);
1.4 millert 456: /* Scrunch text */
457: cp1 = &dotp->l_text[doto];
1.1 deraadt 458: if (kflag == KFORW) {
459: while (ksize - kused < chunk)
1.3 millert 460: if (kgrow(FALSE) == FALSE)
1.22 db 461: return (FALSE);
1.4 millert 462: bcopy(cp1, &(kbufp[kused]), (int)chunk);
1.1 deraadt 463: kused += chunk;
464: } else if (kflag == KBACK) {
465: while (kstart < chunk)
1.3 millert 466: if (kgrow(TRUE) == FALSE)
1.22 db 467: return (FALSE);
1.4 millert 468: bcopy(cp1, &(kbufp[kstart - chunk]), (int)chunk);
1.1 deraadt 469: kstart -= chunk;
1.3 millert 470: } else if (kflag != KNONE)
471: panic("broken ldelete call");
1.20 vincent 472: for (cp2 = cp1 + chunk; cp2 < &dotp->l_text[dotp->l_used];
473: cp2++)
474: *cp1++ = *cp2;
1.4 millert 475: dotp->l_used -= (int)chunk;
1.3 millert 476: for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
477: if (wp->w_dotp == dotp && wp->w_doto >= doto) {
478: /* NOSTRICT */
1.1 deraadt 479: wp->w_doto -= chunk;
480: if (wp->w_doto < doto)
481: wp->w_doto = doto;
482: }
1.3 millert 483: if (wp->w_markp == dotp && wp->w_marko >= doto) {
484: /* NOSTRICT */
1.1 deraadt 485: wp->w_marko -= chunk;
486: if (wp->w_marko < doto)
487: wp->w_marko = doto;
488: }
489: }
490: n -= chunk;
491: }
1.22 db 492: return (TRUE);
1.1 deraadt 493: }
494:
495: /*
1.8 mickey 496: * Delete a newline and join the current line with the next line. If the next
1.4 millert 497: * line is the magic header line always return TRUE; merging the last line
1.8 mickey 498: * with the header line can be thought of as always being a successful
499: * operation. Even if nothing is done, this makes the kill buffer work
500: * "right". Easy cases can be done by shuffling data around. Hard cases
501: * require that lines be moved about in memory. Return FALSE on error and
1.4 millert 502: * TRUE if all looks ok.
1.1 deraadt 503: */
1.4 millert 504: int
1.15 vincent 505: ldelnewline(void)
1.3 millert 506: {
1.4 millert 507: LINE *lp1, *lp2, *lp3;
508: MGWIN *wp;
1.1 deraadt 509:
1.15 vincent 510: if (curbp->b_flag & BFREADONLY) {
511: ewprintf("Buffer is read only");
1.22 db 512: return (FALSE);
1.15 vincent 513: }
514:
1.1 deraadt 515: lp1 = curwp->w_dotp;
516: lp2 = lp1->l_fp;
1.4 millert 517: /* at the end of the buffer */
518: if (lp2 == curbp->b_linep)
1.22 db 519: return (TRUE);
1.1 deraadt 520: if (lp2->l_used <= lp1->l_size - lp1->l_used) {
521: bcopy(&lp2->l_text[0], &lp1->l_text[lp1->l_used], lp2->l_used);
1.3 millert 522: for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
1.1 deraadt 523: if (wp->w_linep == lp2)
524: wp->w_linep = lp1;
525: if (wp->w_dotp == lp2) {
1.3 millert 526: wp->w_dotp = lp1;
1.1 deraadt 527: wp->w_doto += lp1->l_used;
528: }
529: if (wp->w_markp == lp2) {
1.3 millert 530: wp->w_markp = lp1;
1.1 deraadt 531: wp->w_marko += lp1->l_used;
532: }
533: }
534: lp1->l_used += lp2->l_used;
535: lp1->l_fp = lp2->l_fp;
536: lp2->l_fp->l_bp = lp1;
1.4 millert 537: free((char *)lp2);
1.22 db 538: return (TRUE);
1.1 deraadt 539: }
1.3 millert 540: if ((lp3 = lalloc(lp1->l_used + lp2->l_used)) == NULL)
1.22 db 541: return (FALSE);
1.1 deraadt 542: bcopy(&lp1->l_text[0], &lp3->l_text[0], lp1->l_used);
543: bcopy(&lp2->l_text[0], &lp3->l_text[lp1->l_used], lp2->l_used);
544: lp1->l_bp->l_fp = lp3;
545: lp3->l_fp = lp2->l_fp;
546: lp2->l_fp->l_bp = lp3;
547: lp3->l_bp = lp1->l_bp;
1.3 millert 548: for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
549: if (wp->w_linep == lp1 || wp->w_linep == lp2)
1.1 deraadt 550: wp->w_linep = lp3;
551: if (wp->w_dotp == lp1)
1.3 millert 552: wp->w_dotp = lp3;
1.1 deraadt 553: else if (wp->w_dotp == lp2) {
1.3 millert 554: wp->w_dotp = lp3;
1.1 deraadt 555: wp->w_doto += lp1->l_used;
556: }
557: if (wp->w_markp == lp1)
1.3 millert 558: wp->w_markp = lp3;
1.1 deraadt 559: else if (wp->w_markp == lp2) {
1.3 millert 560: wp->w_markp = lp3;
1.1 deraadt 561: wp->w_marko += lp1->l_used;
562: }
563: }
1.4 millert 564: free((char *)lp1);
565: free((char *)lp2);
1.22 db 566: return (TRUE);
1.1 deraadt 567: }
1.9 vincent 568:
1.1 deraadt 569: /*
1.8 mickey 570: * Replace plen characters before dot with argument string. Control-J
571: * characters in st are interpreted as newlines. There is a casehack
572: * disable flag (normally it likes to match case of replacement to what
1.4 millert 573: * was there).
1.1 deraadt 574: */
1.4 millert 575: int
1.15 vincent 576: lreplace(RSIZE plen, char *st, int f)
1.4 millert 577: {
578: RSIZE rlen; /* replacement length */
579: int rtype; /* capitalization */
580: int c; /* used for random characters */
581: int doto; /* offset into line */
1.15 vincent 582:
583: if (curbp->b_flag & BFREADONLY) {
584: ewprintf("Buffer is read only");
1.22 db 585: return (FALSE);
1.15 vincent 586: }
1.16 vincent 587:
588: undo_add_change(curwp->w_dotp, curwp->w_doto, plen);
1.15 vincent 589:
1.1 deraadt 590: /*
1.8 mickey 591: * Find the capitalization of the word that was found. f says use
592: * exact case of replacement string (same thing that happens with
1.4 millert 593: * lowercase found), so bypass check.
1.1 deraadt 594: */
1.3 millert 595: /* NOSTRICT */
1.6 art 596: (void)backchar(FFARG | FFRAND, (int)plen);
1.10 vincent 597: rtype = _MG_L;
1.1 deraadt 598: c = lgetc(curwp->w_dotp, curwp->w_doto);
1.3 millert 599: if (ISUPPER(c) != FALSE && f == FALSE) {
1.10 vincent 600: rtype = _MG_U | _MG_L;
1.3 millert 601: if (curwp->w_doto + 1 < llength(curwp->w_dotp)) {
602: c = lgetc(curwp->w_dotp, curwp->w_doto + 1);
1.1 deraadt 603: if (ISUPPER(c) != FALSE) {
1.10 vincent 604: rtype = _MG_U;
1.1 deraadt 605: }
606: }
607: }
1.15 vincent 608:
1.1 deraadt 609: /*
610: * make the string lengths match (either pad the line
611: * so that it will fit, or scrunch out the excess).
612: * be careful with dot's offset.
613: */
614: rlen = strlen(st);
615: doto = curwp->w_doto;
616: if (plen > rlen)
1.6 art 617: (void)ldelete((RSIZE) (plen - rlen), KNONE);
1.1 deraadt 618: else if (plen < rlen) {
1.4 millert 619: if (linsert((int)(rlen - plen), ' ') == FALSE)
1.22 db 620: return (FALSE);
1.1 deraadt 621: }
622: curwp->w_doto = doto;
623:
624: /*
625: * do the replacement: If was capital, then place first
626: * char as if upper, and subsequent chars as if lower.
627: * If inserting upper, check replacement for case.
628: */
629: while ((c = CHARMASK(*st++)) != '\0') {
1.10 vincent 630: if ((rtype & _MG_U) != 0 && ISLOWER(c) != 0)
1.1 deraadt 631: c = TOUPPER(c);
1.10 vincent 632: if (rtype == (_MG_U | _MG_L))
633: rtype = _MG_L;
1.1 deraadt 634: if (c == CCHR('J')) {
635: if (curwp->w_doto == llength(curwp->w_dotp))
1.6 art 636: (void)forwchar(FFRAND, 1);
1.1 deraadt 637: else {
638: if (ldelete((RSIZE) 1, KNONE) != FALSE)
1.6 art 639: (void)lnewline();
1.1 deraadt 640: }
641: } else if (curwp->w_dotp == curbp->b_linep) {
1.6 art 642: (void)linsert(1, c);
1.1 deraadt 643: } else if (curwp->w_doto == llength(curwp->w_dotp)) {
644: if (ldelete((RSIZE) 1, KNONE) != FALSE)
1.6 art 645: (void)linsert(1, c);
1.1 deraadt 646: } else
647: lputc(curwp->w_dotp, curwp->w_doto++, c);
648: }
649: lchange(WFHARD);
650: return (TRUE);
651: }
1.13 vincent 652:
1.1 deraadt 653: /*
1.8 mickey 654: * Delete all of the text saved in the kill buffer. Called by commands when
655: * a new kill context is created. The kill buffer array is released, just in
1.4 millert 656: * case the buffer has grown to an immense size. No errors.
1.1 deraadt 657: */
1.6 art 658: void
1.17 vincent 659: kdelete(void)
1.3 millert 660: {
1.1 deraadt 661: if (kbufp != NULL) {
1.4 millert 662: free((char *)kbufp);
1.1 deraadt 663: kbufp = NULL;
664: kstart = kused = ksize = 0;
665: }
666: }
667:
668: /*
1.8 mickey 669: * Insert a character to the kill buffer, enlarging the buffer if there
670: * isn't any room. Always grow the buffer in chunks, on the assumption
671: * that if you put something in the kill buffer you are going to put more
672: * stuff there too later. Return TRUE if all is well, and FALSE on errors.
1.4 millert 673: * Print a message on errors. Dir says whether to put it at back or front.
1.1 deraadt 674: */
1.4 millert 675: int
1.17 vincent 676: kinsert(int c, int dir)
1.3 millert 677: {
1.1 deraadt 678: if (kused == ksize && dir == KFORW && kgrow(FALSE) == FALSE)
1.22 db 679: return (FALSE);
1.1 deraadt 680: if (kstart == 0 && dir == KBACK && kgrow(TRUE) == FALSE)
1.22 db 681: return (FALSE);
1.3 millert 682: if (dir == KFORW)
683: kbufp[kused++] = c;
684: else if (dir == KBACK)
685: kbufp[--kstart] = c;
686: else
687: panic("broken kinsert call"); /* Oh shit! */
1.1 deraadt 688: return (TRUE);
689: }
690:
691: /*
692: * kgrow - just get more kill buffer for the callee. back is true if
693: * we are trying to get space at the beginning of the kill buffer.
694: */
1.4 millert 695: static int
1.21 vincent 696: kgrow(int back)
1.3 millert 697: {
1.4 millert 698: int nstart;
699: char *nbufp;
1.1 deraadt 700:
1.4 millert 701: if ((unsigned)(ksize + KBLOCK) <= (unsigned)ksize) {
1.1 deraadt 702: /* probably 16 bit unsigned */
703: ewprintf("Kill buffer size at maximum");
1.22 db 704: return (FALSE);
1.1 deraadt 705: }
1.4 millert 706: if ((nbufp = malloc((unsigned)(ksize + KBLOCK))) == NULL) {
707: ewprintf("Can't get %ld bytes", (long)(ksize + KBLOCK));
1.22 db 708: return (FALSE);
1.1 deraadt 709: }
1.3 millert 710: nstart = (back == TRUE) ? (kstart + KBLOCK) : (KBLOCK / 4);
1.4 millert 711: bcopy(&(kbufp[kstart]), &(nbufp[nstart]), (int)(kused - kstart));
1.1 deraadt 712: if (kbufp != NULL)
1.4 millert 713: free((char *)kbufp);
1.3 millert 714: kbufp = nbufp;
1.1 deraadt 715: ksize += KBLOCK;
716: kused = kused - kstart + nstart;
717: kstart = nstart;
1.22 db 718: return (TRUE);
1.1 deraadt 719: }
720:
721: /*
1.8 mickey 722: * This function gets characters from the kill buffer. If the character
723: * index "n" is off the end, it returns "-1". This lets the caller just
1.4 millert 724: * scan along until it gets a "-1" back.
1.1 deraadt 725: */
1.4 millert 726: int
1.21 vincent 727: kremove(int n)
1.3 millert 728: {
1.1 deraadt 729: if (n < 0 || n + kstart >= kused)
1.22 db 730: return (-1);
731: return (CHARMASK(kbufp[n + kstart]));
1.1 deraadt 732: }