Annotation of src/usr.bin/mg/line.c, Revision 1.21
1.21 ! vincent 1: /* $OpenBSD: line.c,v 1.20 2004/01/27 23:43:37 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.3 millert 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.9 vincent 54: if ((lp = malloc(sizeof *lp)) == NULL)
1.18 millert 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.7 art 61: return NULL;
1.1 deraadt 62: }
63: return lp;
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)
73: return FALSE;
74: lp->l_text = tmp;
75: lp->l_size = newsize;
76: }
1.11 deraadt 77:
1.9 vincent 78: return TRUE;
1.1 deraadt 79: }
80:
81: /*
1.4 millert 82: * Delete line "lp". Fix all of the links that might point to it (they are
1.8 mickey 83: * moved to offset 0 of the next line. Unlink the line from whatever buffer
84: * it might be in, and release the memory. The buffers are updated too; the
1.4 millert 85: * magic conditions described in the above comments don't hold here.
1.1 deraadt 86: */
1.6 art 87: void
1.15 vincent 88: lfree(LINE *lp)
1.3 millert 89: {
1.4 millert 90: BUFFER *bp;
91: MGWIN *wp;
1.1 deraadt 92:
1.3 millert 93: for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
1.1 deraadt 94: if (wp->w_linep == lp)
95: wp->w_linep = lp->l_fp;
1.3 millert 96: if (wp->w_dotp == lp) {
97: wp->w_dotp = lp->l_fp;
98: wp->w_doto = 0;
1.1 deraadt 99: }
100: if (wp->w_markp == lp) {
101: wp->w_markp = lp->l_fp;
102: wp->w_marko = 0;
103: }
104: }
1.3 millert 105: for (bp = bheadp; bp != NULL; bp = bp->b_bufp) {
1.1 deraadt 106: if (bp->b_nwnd == 0) {
1.3 millert 107: if (bp->b_dotp == lp) {
1.1 deraadt 108: bp->b_dotp = lp->l_fp;
109: bp->b_doto = 0;
110: }
111: if (bp->b_markp == lp) {
112: bp->b_markp = lp->l_fp;
113: bp->b_marko = 0;
114: }
115: }
116: }
117: lp->l_bp->l_fp = lp->l_fp;
118: lp->l_fp->l_bp = lp->l_bp;
1.9 vincent 119: if (lp->l_text != NULL)
120: free(lp->l_text);
121: free(lp);
1.1 deraadt 122: }
123:
124: /*
1.8 mickey 125: * This routine is called when a character changes in place in the current
126: * buffer. It updates all of the required flags in the buffer and window
127: * system. The flag used is passed as an argument; if the buffer is being
128: * displayed in more than 1 window we change EDIT to HARD. Set MODE if the
1.4 millert 129: * mode line needs to be updated (the "*" has to be set).
1.1 deraadt 130: */
1.6 art 131: void
1.15 vincent 132: lchange(int flag)
1.3 millert 133: {
1.4 millert 134: MGWIN *wp;
1.1 deraadt 135:
1.4 millert 136: /* update mode lines if this is the first change. */
137: if ((curbp->b_flag & BFCHG) == 0) {
138: flag |= WFMODE;
1.1 deraadt 139: curbp->b_flag |= BFCHG;
140: }
1.3 millert 141: for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
1.1 deraadt 142: if (wp->w_bufp == curbp) {
143: wp->w_flag |= flag;
1.3 millert 144: if (wp != curwp)
145: wp->w_flag |= WFHARD;
1.1 deraadt 146: }
147: }
148: }
149:
150: /*
1.20 vincent 151: * Insert "n" bytes from "s" at the current location of dot.
152: * In the easy case all that happens is the text is stored in the line.
153: * In the hard case, the line has to be reallocated. When the window list
154: * is updated, take special care; I screwed it up once. You always update
155: * dot in the current window. You update mark and a dot in another window
156: * if it is greater than the place where you did the insert. Return TRUE
157: * if all is well, and FALSE on errors.
158: */
159: int
160: linsert_str(const char *s, int n)
161: {
162: LINE *lp1;
163: MGWIN *wp;
164: RSIZE i;
165: int doto;
166:
167: if (curbp->b_flag & BFREADONLY) {
168: ewprintf("Buffer is read only");
169: return FALSE;
170: }
171:
172: if (!n)
173: return (TRUE);
174:
175: lchange(WFHARD);
176:
177: /* current line */
178: lp1 = curwp->w_dotp;
179:
180: /* special case for the end */
181: if (lp1 == curbp->b_linep) {
182: LINE *lp2, *lp3;
183:
184: /* now should only happen in empty buffer */
185: if (curwp->w_doto != 0)
186: panic("bug: linsert_str");
187: /* allocate a new line */
188: if ((lp2 = lalloc(n)) == NULL)
189: return FALSE;
190: /* previous line */
191: lp3 = lp1->l_bp;
192: /* link in */
193: lp3->l_fp = lp2;
194: lp2->l_fp = lp1;
195: lp1->l_bp = lp2;
196: lp2->l_bp = lp3;
197: for (i = 0; i < n; ++i)
198: lp2->l_text[i] = s[i];
199: for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
200: if (wp->w_linep == lp1)
201: wp->w_linep = lp2;
202: if (wp->w_dotp == lp1)
203: wp->w_dotp = lp2;
204: if (wp->w_markp == lp1)
205: wp->w_markp = lp2;
206: }
207: undo_add_insert(lp2, 0, n);
208: curwp->w_doto = n;
209: return TRUE;
210: }
211: /* save for later */
212: doto = curwp->w_doto;
213:
214: if ((lp1->l_used + n) > lp1->l_size) {
215: if (lrealloc(lp1, lp1->l_used + n) == FALSE)
216: return FALSE;
217: }
218: lp1->l_used += n;
219: if (lp1->l_used != n)
220: memmove(&lp1->l_text[doto + n], &lp1->l_text[doto],
221: lp1->l_used - n - doto);
222:
223: /* Add the characters */
224: for (i = 0; i < n; ++i)
225: lp1->l_text[doto + i] = s[i];
226: for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
227: if (wp->w_dotp == lp1) {
228: if (wp == curwp || wp->w_doto > doto)
229: wp->w_doto += n;
230: }
231: if (wp->w_markp == lp1) {
232: if (wp->w_marko > doto)
233: wp->w_marko += n;
234: }
235: }
236: undo_add_insert(curwp->w_dotp, doto, n);
237: return TRUE;
238: }
239:
240: /*
1.8 mickey 241: * Insert "n" copies of the character "c" at the current location of dot.
242: * In the easy case all that happens is the text is stored in the line.
243: * In the hard case, the line has to be reallocated. When the window list
244: * is updated, take special care; I screwed it up once. You always update
1.4 millert 245: * dot in the current window. You update mark and a dot in another window
246: * if it is greater than the place where you did the insert. Return TRUE
1.1 deraadt 247: * if all is well, and FALSE on errors.
248: */
1.4 millert 249: int
1.15 vincent 250: linsert(int n, int c)
1.1 deraadt 251: {
1.9 vincent 252: LINE *lp1;
1.4 millert 253: MGWIN *wp;
254: RSIZE i;
255: int doto;
1.1 deraadt 256:
1.20 vincent 257: if (!n)
258: return (TRUE);
259:
1.15 vincent 260: if (curbp->b_flag & BFREADONLY) {
261: ewprintf("Buffer is read only");
262: return FALSE;
263: }
264:
1.1 deraadt 265: lchange(WFEDIT);
1.4 millert 266:
267: /* current line */
268: lp1 = curwp->w_dotp;
1.15 vincent 269:
1.4 millert 270: /* special case for the end */
271: if (lp1 == curbp->b_linep) {
1.9 vincent 272: LINE *lp2, *lp3;
1.11 deraadt 273:
1.4 millert 274: /* now should only happen in empty buffer */
1.1 deraadt 275: if (curwp->w_doto != 0) {
276: ewprintf("bug: linsert");
277: return FALSE;
278: }
1.4 millert 279: /* allocate a new line */
1.9 vincent 280: if ((lp2 = lalloc(n)) == NULL)
1.1 deraadt 281: return FALSE;
1.4 millert 282: /* previous line */
283: lp3 = lp1->l_bp;
284: /* link in */
285: lp3->l_fp = lp2;
1.1 deraadt 286: lp2->l_fp = lp1;
287: lp1->l_bp = lp2;
288: lp2->l_bp = lp3;
1.3 millert 289: for (i = 0; i < n; ++i)
1.1 deraadt 290: lp2->l_text[i] = c;
1.3 millert 291: for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
1.1 deraadt 292: if (wp->w_linep == lp1)
293: wp->w_linep = lp2;
294: if (wp->w_dotp == lp1)
295: wp->w_dotp = lp2;
296: if (wp->w_markp == lp1)
297: wp->w_markp = lp2;
298: }
1.16 vincent 299: undo_add_insert(lp2, 0, n);
1.1 deraadt 300: curwp->w_doto = n;
301: return TRUE;
302: }
1.4 millert 303: /* save for later */
304: doto = curwp->w_doto;
1.9 vincent 305:
306:
307: if ((lp1->l_used + n) > lp1->l_size) {
308: if (lrealloc(lp1, lp1->l_used + n) == FALSE)
1.1 deraadt 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.1 deraadt 330: return TRUE;
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.1 deraadt 350: return FALSE;
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;
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.1 deraadt 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: }
385: return TRUE;
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");
! 397: return FALSE;
! 398: }
! 399: return lnewline_at(curwp->w_dotp, curwp->w_doto);
! 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");
420: return FALSE;
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.1 deraadt 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 */
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.1 deraadt 451: return FALSE;
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)
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)
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: }
492: return TRUE;
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");
512: return FALSE;
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.1 deraadt 519: return TRUE;
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.1 deraadt 538: return TRUE;
539: }
1.3 millert 540: if ((lp3 = lalloc(lp1->l_used + lp2->l_used)) == NULL)
1.1 deraadt 541: return FALSE;
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.1 deraadt 566: return TRUE;
567: }
1.9 vincent 568:
1.1 deraadt 569:
570: /*
1.8 mickey 571: * Replace plen characters before dot with argument string. Control-J
572: * characters in st are interpreted as newlines. There is a casehack
573: * disable flag (normally it likes to match case of replacement to what
1.4 millert 574: * was there).
1.1 deraadt 575: */
1.4 millert 576: int
1.15 vincent 577: lreplace(RSIZE plen, char *st, int f)
1.4 millert 578: {
579: RSIZE rlen; /* replacement length */
580: int rtype; /* capitalization */
581: int c; /* used for random characters */
582: int doto; /* offset into line */
1.15 vincent 583:
584: if (curbp->b_flag & BFREADONLY) {
585: ewprintf("Buffer is read only");
586: return FALSE;
587: }
1.16 vincent 588:
589: undo_add_change(curwp->w_dotp, curwp->w_doto, plen);
1.15 vincent 590:
1.1 deraadt 591: /*
1.8 mickey 592: * Find the capitalization of the word that was found. f says use
593: * exact case of replacement string (same thing that happens with
1.4 millert 594: * lowercase found), so bypass check.
1.1 deraadt 595: */
1.3 millert 596: /* NOSTRICT */
1.6 art 597: (void)backchar(FFARG | FFRAND, (int)plen);
1.10 vincent 598: rtype = _MG_L;
1.1 deraadt 599: c = lgetc(curwp->w_dotp, curwp->w_doto);
1.3 millert 600: if (ISUPPER(c) != FALSE && f == FALSE) {
1.10 vincent 601: rtype = _MG_U | _MG_L;
1.3 millert 602: if (curwp->w_doto + 1 < llength(curwp->w_dotp)) {
603: c = lgetc(curwp->w_dotp, curwp->w_doto + 1);
1.1 deraadt 604: if (ISUPPER(c) != FALSE) {
1.10 vincent 605: rtype = _MG_U;
1.1 deraadt 606: }
607: }
608: }
1.15 vincent 609:
1.1 deraadt 610: /*
611: * make the string lengths match (either pad the line
612: * so that it will fit, or scrunch out the excess).
613: * be careful with dot's offset.
614: */
615: rlen = strlen(st);
616: doto = curwp->w_doto;
617: if (plen > rlen)
1.6 art 618: (void)ldelete((RSIZE) (plen - rlen), KNONE);
1.1 deraadt 619: else if (plen < rlen) {
1.4 millert 620: if (linsert((int)(rlen - plen), ' ') == FALSE)
1.1 deraadt 621: return FALSE;
622: }
623: curwp->w_doto = doto;
624:
625: /*
626: * do the replacement: If was capital, then place first
627: * char as if upper, and subsequent chars as if lower.
628: * If inserting upper, check replacement for case.
629: */
630: while ((c = CHARMASK(*st++)) != '\0') {
1.10 vincent 631: if ((rtype & _MG_U) != 0 && ISLOWER(c) != 0)
1.1 deraadt 632: c = TOUPPER(c);
1.10 vincent 633: if (rtype == (_MG_U | _MG_L))
634: rtype = _MG_L;
1.1 deraadt 635: if (c == CCHR('J')) {
636: if (curwp->w_doto == llength(curwp->w_dotp))
1.6 art 637: (void)forwchar(FFRAND, 1);
1.1 deraadt 638: else {
639: if (ldelete((RSIZE) 1, KNONE) != FALSE)
1.6 art 640: (void)lnewline();
1.1 deraadt 641: }
642: } else if (curwp->w_dotp == curbp->b_linep) {
1.6 art 643: (void)linsert(1, c);
1.1 deraadt 644: } else if (curwp->w_doto == llength(curwp->w_dotp)) {
645: if (ldelete((RSIZE) 1, KNONE) != FALSE)
1.6 art 646: (void)linsert(1, c);
1.1 deraadt 647: } else
648: lputc(curwp->w_dotp, curwp->w_doto++, c);
649: }
650: lchange(WFHARD);
651: return (TRUE);
652: }
1.13 vincent 653:
1.1 deraadt 654:
655: /*
1.8 mickey 656: * Delete all of the text saved in the kill buffer. Called by commands when
657: * a new kill context is created. The kill buffer array is released, just in
1.4 millert 658: * case the buffer has grown to an immense size. No errors.
1.1 deraadt 659: */
1.6 art 660: void
1.17 vincent 661: kdelete(void)
1.3 millert 662: {
1.1 deraadt 663: if (kbufp != NULL) {
1.4 millert 664: free((char *)kbufp);
1.1 deraadt 665: kbufp = NULL;
666: kstart = kused = ksize = 0;
667: }
668: }
669:
670: /*
1.8 mickey 671: * Insert a character to the kill buffer, enlarging the buffer if there
672: * isn't any room. Always grow the buffer in chunks, on the assumption
673: * that if you put something in the kill buffer you are going to put more
674: * stuff there too later. Return TRUE if all is well, and FALSE on errors.
1.4 millert 675: * Print a message on errors. Dir says whether to put it at back or front.
1.1 deraadt 676: */
1.4 millert 677: int
1.17 vincent 678: kinsert(int c, int dir)
1.3 millert 679: {
1.1 deraadt 680: if (kused == ksize && dir == KFORW && kgrow(FALSE) == FALSE)
681: return FALSE;
682: if (kstart == 0 && dir == KBACK && kgrow(TRUE) == FALSE)
683: return FALSE;
1.3 millert 684: if (dir == KFORW)
685: kbufp[kused++] = c;
686: else if (dir == KBACK)
687: kbufp[--kstart] = c;
688: else
689: panic("broken kinsert call"); /* Oh shit! */
1.1 deraadt 690: return (TRUE);
691: }
692:
693: /*
694: * kgrow - just get more kill buffer for the callee. back is true if
695: * we are trying to get space at the beginning of the kill buffer.
696: */
1.4 millert 697: static int
1.21 ! vincent 698: kgrow(int back)
1.3 millert 699: {
1.4 millert 700: int nstart;
701: char *nbufp;
1.1 deraadt 702:
1.4 millert 703: if ((unsigned)(ksize + KBLOCK) <= (unsigned)ksize) {
1.1 deraadt 704: /* probably 16 bit unsigned */
705: ewprintf("Kill buffer size at maximum");
706: return FALSE;
707: }
1.4 millert 708: if ((nbufp = malloc((unsigned)(ksize + KBLOCK))) == NULL) {
709: ewprintf("Can't get %ld bytes", (long)(ksize + KBLOCK));
1.1 deraadt 710: return FALSE;
711: }
1.3 millert 712: nstart = (back == TRUE) ? (kstart + KBLOCK) : (KBLOCK / 4);
1.4 millert 713: bcopy(&(kbufp[kstart]), &(nbufp[nstart]), (int)(kused - kstart));
1.1 deraadt 714: if (kbufp != NULL)
1.4 millert 715: free((char *)kbufp);
1.3 millert 716: kbufp = nbufp;
1.1 deraadt 717: ksize += KBLOCK;
718: kused = kused - kstart + nstart;
719: kstart = nstart;
720: return TRUE;
721: }
722:
723: /*
1.8 mickey 724: * This function gets characters from the kill buffer. If the character
725: * index "n" is off the end, it returns "-1". This lets the caller just
1.4 millert 726: * scan along until it gets a "-1" back.
1.1 deraadt 727: */
1.4 millert 728: int
1.21 ! vincent 729: kremove(int n)
1.3 millert 730: {
1.1 deraadt 731: if (n < 0 || n + kstart >= kused)
732: return -1;
733: return CHARMASK(kbufp[n + kstart]);
734: }