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