Annotation of src/usr.bin/mg/line.c, Revision 1.18
1.18 ! millert 1: /* $OpenBSD: line.c,v 1.17 2002/07/01 14:33:44 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.8 mickey 151: * Insert "n" copies of the character "c" 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
1.4 millert 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
1.1 deraadt 157: * if all is well, and FALSE on errors.
158: */
1.4 millert 159: int
1.15 vincent 160: linsert(int n, int c)
1.1 deraadt 161: {
1.9 vincent 162: LINE *lp1;
1.4 millert 163: MGWIN *wp;
164: RSIZE i;
165: int doto;
1.1 deraadt 166:
1.15 vincent 167: if (curbp->b_flag & BFREADONLY) {
168: ewprintf("Buffer is read only");
169: return FALSE;
170: }
171:
1.1 deraadt 172: lchange(WFEDIT);
1.4 millert 173:
174: /* current line */
175: lp1 = curwp->w_dotp;
1.15 vincent 176:
1.4 millert 177: /* special case for the end */
178: if (lp1 == curbp->b_linep) {
1.9 vincent 179: LINE *lp2, *lp3;
1.11 deraadt 180:
1.4 millert 181: /* now should only happen in empty buffer */
1.1 deraadt 182: if (curwp->w_doto != 0) {
183: ewprintf("bug: linsert");
184: return FALSE;
185: }
1.4 millert 186: /* allocate a new line */
1.9 vincent 187: if ((lp2 = lalloc(n)) == NULL)
1.1 deraadt 188: return FALSE;
1.4 millert 189: /* previous line */
190: lp3 = lp1->l_bp;
191: /* link in */
192: lp3->l_fp = lp2;
1.1 deraadt 193: lp2->l_fp = lp1;
194: lp1->l_bp = lp2;
195: lp2->l_bp = lp3;
1.3 millert 196: for (i = 0; i < n; ++i)
1.1 deraadt 197: lp2->l_text[i] = c;
1.3 millert 198: for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
1.1 deraadt 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: }
1.16 vincent 206: undo_add_insert(lp2, 0, n);
1.1 deraadt 207: curwp->w_doto = n;
208: return TRUE;
209: }
1.4 millert 210: /* save for later */
211: doto = curwp->w_doto;
1.9 vincent 212:
213:
214: if ((lp1->l_used + n) > lp1->l_size) {
215: if (lrealloc(lp1, lp1->l_used + n) == FALSE)
1.1 deraadt 216: return FALSE;
1.11 deraadt 217: }
1.9 vincent 218: lp1->l_used += n;
1.11 deraadt 219: if (lp1->l_used != n)
1.9 vincent 220: memmove(&lp1->l_text[doto + n], &lp1->l_text[doto],
221: lp1->l_used - n - doto);
222:
1.4 millert 223: /* Add the characters */
224: for (i = 0; i < n; ++i)
1.9 vincent 225: lp1->l_text[doto + i] = c;
1.3 millert 226: for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
1.1 deraadt 227: if (wp->w_dotp == lp1) {
1.3 millert 228: if (wp == curwp || wp->w_doto > doto)
1.1 deraadt 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: }
1.16 vincent 236: undo_add_insert(curwp->w_dotp, doto, n);
1.1 deraadt 237: return TRUE;
238: }
239:
240: /*
1.8 mickey 241: * Insert a newline into the buffer at the current location of dot in the
1.4 millert 242: * current window. The funny ass-backwards way is no longer used.
1.1 deraadt 243: */
1.4 millert 244: int
1.15 vincent 245: lnewline(void)
1.1 deraadt 246: {
1.4 millert 247: LINE *lp1, *lp2;
248: int doto, nlen;
249: MGWIN *wp;
1.1 deraadt 250:
1.15 vincent 251: if (curbp->b_flag & BFREADONLY) {
252: ewprintf("Buffer is read only");
253: return FALSE;
254: }
255:
1.1 deraadt 256: lchange(WFHARD);
1.14 vincent 257:
1.16 vincent 258: /* XXX */
259: undo_add_custom(1,INSERT, curwp->w_dotp, curwp->w_doto,
260: strdup("\n"), 1);
1.14 vincent 261:
1.4 millert 262: /* Get the address and offset of "." */
263: lp1 = curwp->w_dotp;
264: doto = curwp->w_doto;
265:
266: /* avoid unnecessary copying */
267: if (doto == 0) {
268: /* new first part */
1.9 vincent 269: if ((lp2 = lalloc(0)) == NULL)
1.1 deraadt 270: return FALSE;
271: lp2->l_bp = lp1->l_bp;
272: lp1->l_bp->l_fp = lp2;
273: lp2->l_fp = lp1;
274: lp1->l_bp = lp2;
1.3 millert 275: for (wp = wheadp; wp != NULL; wp = wp->w_wndp)
276: if (wp->w_linep == lp1)
277: wp->w_linep = lp2;
278: return TRUE;
1.1 deraadt 279: }
1.4 millert 280:
281: /* length of new part */
282: nlen = llength(lp1) - doto;
283:
284: /* new second half line */
1.9 vincent 285: if ((lp2 = lalloc(nlen)) == NULL)
1.1 deraadt 286: return FALSE;
1.3 millert 287: if (nlen != 0)
288: bcopy(&lp1->l_text[doto], &lp2->l_text[0], nlen);
1.1 deraadt 289: lp1->l_used = doto;
290: lp2->l_bp = lp1;
291: lp2->l_fp = lp1->l_fp;
292: lp1->l_fp = lp2;
293: lp2->l_fp->l_bp = lp2;
1.4 millert 294: /* Windows */
295: for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
1.1 deraadt 296: if (wp->w_dotp == lp1 && wp->w_doto >= doto) {
297: wp->w_dotp = lp2;
298: wp->w_doto -= doto;
299: }
300: if (wp->w_markp == lp1 && wp->w_marko >= doto) {
301: wp->w_markp = lp2;
302: wp->w_marko -= doto;
303: }
304: }
305: return TRUE;
306: }
307:
308: /*
1.8 mickey 309: * This function deletes "n" bytes, starting at dot. It understands how to
310: * deal with end of lines, etc. It returns TRUE if all of the characters
311: * were deleted, and FALSE if they were not (because dot ran into the end
312: * of the buffer. The "kflag" indicates either no insertion, or direction
1.4 millert 313: * of insertion into the kill buffer.
1.1 deraadt 314: */
1.4 millert 315: int
1.15 vincent 316: ldelete(RSIZE n, int kflag)
1.3 millert 317: {
1.4 millert 318: LINE *dotp;
319: RSIZE chunk;
320: MGWIN *wp;
321: int doto;
322: char *cp1, *cp2;
1.1 deraadt 323:
1.15 vincent 324: if (curbp->b_flag & BFREADONLY) {
325: ewprintf("Buffer is read only");
326: return FALSE;
327: }
328:
1.16 vincent 329: undo_add_delete(curwp->w_dotp, curwp->w_doto, n);
1.15 vincent 330:
1.1 deraadt 331: /*
332: * HACK - doesn't matter, and fixes back-over-nl bug for empty
333: * kill buffers.
334: */
1.3 millert 335: if (kused == kstart)
336: kflag = KFORW;
1.1 deraadt 337:
338: while (n != 0) {
339: dotp = curwp->w_dotp;
340: doto = curwp->w_doto;
1.4 millert 341: /* Hit the end of the buffer */
342: if (dotp == curbp->b_linep)
1.1 deraadt 343: return FALSE;
1.4 millert 344: /* Size of the chunk */
345: chunk = dotp->l_used - doto;
1.1 deraadt 346: if (chunk > n)
347: chunk = n;
1.4 millert 348: /* End of line, merge */
349: if (chunk == 0) {
1.3 millert 350: if (dotp == lback(curbp->b_linep))
1.4 millert 351: /* End of buffer */
352: return FALSE;
1.1 deraadt 353: lchange(WFHARD);
1.8 mickey 354: if (ldelnewline() == FALSE ||
1.4 millert 355: (kflag != KNONE && kinsert('\n', kflag) == FALSE))
1.1 deraadt 356: return FALSE;
357: --n;
358: continue;
359: }
360: lchange(WFEDIT);
1.4 millert 361: /* Scrunch text */
362: cp1 = &dotp->l_text[doto];
1.1 deraadt 363: cp2 = cp1 + chunk;
364: if (kflag == KFORW) {
365: while (ksize - kused < chunk)
1.3 millert 366: if (kgrow(FALSE) == FALSE)
367: return FALSE;
1.4 millert 368: bcopy(cp1, &(kbufp[kused]), (int)chunk);
1.1 deraadt 369: kused += chunk;
370: } else if (kflag == KBACK) {
371: while (kstart < chunk)
1.3 millert 372: if (kgrow(TRUE) == FALSE)
373: return FALSE;
1.4 millert 374: bcopy(cp1, &(kbufp[kstart - chunk]), (int)chunk);
1.1 deraadt 375: kstart -= chunk;
1.3 millert 376: } else if (kflag != KNONE)
377: panic("broken ldelete call");
1.1 deraadt 378: while (cp2 != &dotp->l_text[dotp->l_used])
379: *cp1++ = *cp2++;
1.4 millert 380: dotp->l_used -= (int)chunk;
1.3 millert 381: for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
382: if (wp->w_dotp == dotp && wp->w_doto >= doto) {
383: /* NOSTRICT */
1.1 deraadt 384: wp->w_doto -= chunk;
385: if (wp->w_doto < doto)
386: wp->w_doto = doto;
387: }
1.3 millert 388: if (wp->w_markp == dotp && wp->w_marko >= doto) {
389: /* NOSTRICT */
1.1 deraadt 390: wp->w_marko -= chunk;
391: if (wp->w_marko < doto)
392: wp->w_marko = doto;
393: }
394: }
395: n -= chunk;
396: }
397: return TRUE;
398: }
399:
400: /*
1.8 mickey 401: * Delete a newline and join the current line with the next line. If the next
1.4 millert 402: * line is the magic header line always return TRUE; merging the last line
1.8 mickey 403: * with the header line can be thought of as always being a successful
404: * operation. Even if nothing is done, this makes the kill buffer work
405: * "right". Easy cases can be done by shuffling data around. Hard cases
406: * require that lines be moved about in memory. Return FALSE on error and
1.4 millert 407: * TRUE if all looks ok.
1.1 deraadt 408: */
1.4 millert 409: int
1.15 vincent 410: ldelnewline(void)
1.3 millert 411: {
1.4 millert 412: LINE *lp1, *lp2, *lp3;
413: MGWIN *wp;
1.1 deraadt 414:
1.15 vincent 415: if (curbp->b_flag & BFREADONLY) {
416: ewprintf("Buffer is read only");
417: return FALSE;
418: }
419:
1.1 deraadt 420: lp1 = curwp->w_dotp;
421: lp2 = lp1->l_fp;
1.4 millert 422: /* at the end of the buffer */
423: if (lp2 == curbp->b_linep)
1.1 deraadt 424: return TRUE;
425: if (lp2->l_used <= lp1->l_size - lp1->l_used) {
426: bcopy(&lp2->l_text[0], &lp1->l_text[lp1->l_used], lp2->l_used);
1.3 millert 427: for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
1.1 deraadt 428: if (wp->w_linep == lp2)
429: wp->w_linep = lp1;
430: if (wp->w_dotp == lp2) {
1.3 millert 431: wp->w_dotp = lp1;
1.1 deraadt 432: wp->w_doto += lp1->l_used;
433: }
434: if (wp->w_markp == lp2) {
1.3 millert 435: wp->w_markp = lp1;
1.1 deraadt 436: wp->w_marko += lp1->l_used;
437: }
438: }
439: lp1->l_used += lp2->l_used;
440: lp1->l_fp = lp2->l_fp;
441: lp2->l_fp->l_bp = lp1;
1.4 millert 442: free((char *)lp2);
1.1 deraadt 443: return TRUE;
444: }
1.3 millert 445: if ((lp3 = lalloc(lp1->l_used + lp2->l_used)) == NULL)
1.1 deraadt 446: return FALSE;
447: bcopy(&lp1->l_text[0], &lp3->l_text[0], lp1->l_used);
448: bcopy(&lp2->l_text[0], &lp3->l_text[lp1->l_used], lp2->l_used);
449: lp1->l_bp->l_fp = lp3;
450: lp3->l_fp = lp2->l_fp;
451: lp2->l_fp->l_bp = lp3;
452: lp3->l_bp = lp1->l_bp;
1.3 millert 453: for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
454: if (wp->w_linep == lp1 || wp->w_linep == lp2)
1.1 deraadt 455: wp->w_linep = lp3;
456: if (wp->w_dotp == lp1)
1.3 millert 457: wp->w_dotp = lp3;
1.1 deraadt 458: else if (wp->w_dotp == lp2) {
1.3 millert 459: wp->w_dotp = lp3;
1.1 deraadt 460: wp->w_doto += lp1->l_used;
461: }
462: if (wp->w_markp == lp1)
1.3 millert 463: wp->w_markp = lp3;
1.1 deraadt 464: else if (wp->w_markp == lp2) {
1.3 millert 465: wp->w_markp = lp3;
1.1 deraadt 466: wp->w_marko += lp1->l_used;
467: }
468: }
1.4 millert 469: free((char *)lp1);
470: free((char *)lp2);
1.1 deraadt 471: return TRUE;
472: }
1.9 vincent 473:
1.1 deraadt 474:
475: /*
1.8 mickey 476: * Replace plen characters before dot with argument string. Control-J
477: * characters in st are interpreted as newlines. There is a casehack
478: * disable flag (normally it likes to match case of replacement to what
1.4 millert 479: * was there).
1.1 deraadt 480: */
1.4 millert 481: int
1.15 vincent 482: lreplace(RSIZE plen, char *st, int f)
1.4 millert 483: {
484: RSIZE rlen; /* replacement length */
485: int rtype; /* capitalization */
486: int c; /* used for random characters */
487: int doto; /* offset into line */
1.15 vincent 488:
489: if (curbp->b_flag & BFREADONLY) {
490: ewprintf("Buffer is read only");
491: return FALSE;
492: }
1.16 vincent 493:
494: undo_add_change(curwp->w_dotp, curwp->w_doto, plen);
1.15 vincent 495:
1.1 deraadt 496: /*
1.8 mickey 497: * Find the capitalization of the word that was found. f says use
498: * exact case of replacement string (same thing that happens with
1.4 millert 499: * lowercase found), so bypass check.
1.1 deraadt 500: */
1.3 millert 501: /* NOSTRICT */
1.6 art 502: (void)backchar(FFARG | FFRAND, (int)plen);
1.10 vincent 503: rtype = _MG_L;
1.1 deraadt 504: c = lgetc(curwp->w_dotp, curwp->w_doto);
1.3 millert 505: if (ISUPPER(c) != FALSE && f == FALSE) {
1.10 vincent 506: rtype = _MG_U | _MG_L;
1.3 millert 507: if (curwp->w_doto + 1 < llength(curwp->w_dotp)) {
508: c = lgetc(curwp->w_dotp, curwp->w_doto + 1);
1.1 deraadt 509: if (ISUPPER(c) != FALSE) {
1.10 vincent 510: rtype = _MG_U;
1.1 deraadt 511: }
512: }
513: }
1.15 vincent 514:
1.1 deraadt 515: /*
516: * make the string lengths match (either pad the line
517: * so that it will fit, or scrunch out the excess).
518: * be careful with dot's offset.
519: */
520: rlen = strlen(st);
521: doto = curwp->w_doto;
522: if (plen > rlen)
1.6 art 523: (void)ldelete((RSIZE) (plen - rlen), KNONE);
1.1 deraadt 524: else if (plen < rlen) {
1.4 millert 525: if (linsert((int)(rlen - plen), ' ') == FALSE)
1.1 deraadt 526: return FALSE;
527: }
528: curwp->w_doto = doto;
529:
530: /*
531: * do the replacement: If was capital, then place first
532: * char as if upper, and subsequent chars as if lower.
533: * If inserting upper, check replacement for case.
534: */
535: while ((c = CHARMASK(*st++)) != '\0') {
1.10 vincent 536: if ((rtype & _MG_U) != 0 && ISLOWER(c) != 0)
1.1 deraadt 537: c = TOUPPER(c);
1.10 vincent 538: if (rtype == (_MG_U | _MG_L))
539: rtype = _MG_L;
1.1 deraadt 540: if (c == CCHR('J')) {
541: if (curwp->w_doto == llength(curwp->w_dotp))
1.6 art 542: (void)forwchar(FFRAND, 1);
1.1 deraadt 543: else {
544: if (ldelete((RSIZE) 1, KNONE) != FALSE)
1.6 art 545: (void)lnewline();
1.1 deraadt 546: }
547: } else if (curwp->w_dotp == curbp->b_linep) {
1.6 art 548: (void)linsert(1, c);
1.1 deraadt 549: } else if (curwp->w_doto == llength(curwp->w_dotp)) {
550: if (ldelete((RSIZE) 1, KNONE) != FALSE)
1.6 art 551: (void)linsert(1, c);
1.1 deraadt 552: } else
553: lputc(curwp->w_dotp, curwp->w_doto++, c);
554: }
555: lchange(WFHARD);
556: return (TRUE);
557: }
1.13 vincent 558:
1.1 deraadt 559:
560: /*
1.8 mickey 561: * Delete all of the text saved in the kill buffer. Called by commands when
562: * a new kill context is created. The kill buffer array is released, just in
1.4 millert 563: * case the buffer has grown to an immense size. No errors.
1.1 deraadt 564: */
1.6 art 565: void
1.17 vincent 566: kdelete(void)
1.3 millert 567: {
1.1 deraadt 568: if (kbufp != NULL) {
1.4 millert 569: free((char *)kbufp);
1.1 deraadt 570: kbufp = NULL;
571: kstart = kused = ksize = 0;
572: }
573: }
574:
575: /*
1.8 mickey 576: * Insert a character to the kill buffer, enlarging the buffer if there
577: * isn't any room. Always grow the buffer in chunks, on the assumption
578: * that if you put something in the kill buffer you are going to put more
579: * stuff there too later. Return TRUE if all is well, and FALSE on errors.
1.4 millert 580: * Print a message on errors. Dir says whether to put it at back or front.
1.1 deraadt 581: */
1.4 millert 582: int
1.17 vincent 583: kinsert(int c, int dir)
1.3 millert 584: {
1.1 deraadt 585: if (kused == ksize && dir == KFORW && kgrow(FALSE) == FALSE)
586: return FALSE;
587: if (kstart == 0 && dir == KBACK && kgrow(TRUE) == FALSE)
588: return FALSE;
1.3 millert 589: if (dir == KFORW)
590: kbufp[kused++] = c;
591: else if (dir == KBACK)
592: kbufp[--kstart] = c;
593: else
594: panic("broken kinsert call"); /* Oh shit! */
1.1 deraadt 595: return (TRUE);
596: }
597:
598: /*
599: * kgrow - just get more kill buffer for the callee. back is true if
600: * we are trying to get space at the beginning of the kill buffer.
601: */
1.4 millert 602: static int
1.3 millert 603: kgrow(back)
1.4 millert 604: int back;
1.3 millert 605: {
1.4 millert 606: int nstart;
607: char *nbufp;
1.1 deraadt 608:
1.4 millert 609: if ((unsigned)(ksize + KBLOCK) <= (unsigned)ksize) {
1.1 deraadt 610: /* probably 16 bit unsigned */
611: ewprintf("Kill buffer size at maximum");
612: return FALSE;
613: }
1.4 millert 614: if ((nbufp = malloc((unsigned)(ksize + KBLOCK))) == NULL) {
615: ewprintf("Can't get %ld bytes", (long)(ksize + KBLOCK));
1.1 deraadt 616: return FALSE;
617: }
1.3 millert 618: nstart = (back == TRUE) ? (kstart + KBLOCK) : (KBLOCK / 4);
1.4 millert 619: bcopy(&(kbufp[kstart]), &(nbufp[nstart]), (int)(kused - kstart));
1.1 deraadt 620: if (kbufp != NULL)
1.4 millert 621: free((char *)kbufp);
1.3 millert 622: kbufp = nbufp;
1.1 deraadt 623: ksize += KBLOCK;
624: kused = kused - kstart + nstart;
625: kstart = nstart;
626: return TRUE;
627: }
628:
629: /*
1.8 mickey 630: * This function gets characters from the kill buffer. If the character
631: * index "n" is off the end, it returns "-1". This lets the caller just
1.4 millert 632: * scan along until it gets a "-1" back.
1.1 deraadt 633: */
1.4 millert 634: int
1.3 millert 635: kremove(n)
1.4 millert 636: int n;
1.3 millert 637: {
1.1 deraadt 638: if (n < 0 || n + kstart >= kused)
639: return -1;
640: return CHARMASK(kbufp[n + kstart]);
641: }