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