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