home *** CD-ROM | disk | FTP | other *** search
- /*
- * Text line handling. The functions in this file are a general set of line
- * management utilities. They are the only routines that touch the text. They
- * also touch the buffer and window structures, to make sure that the
- * necessary updating gets done. There are routines in this file that handle
- * the kill buffer too. It isn't here for any good reason.
- *
- * Note that this code only updates the dot and mark values in the window list.
- * Since all the code acts on the current window, the buffer that we are
- * editing must be being displayed, which means that "b_nwnd" is non zero,
- * which means that the dot and mark values in the buffer headers are
- * nonsense.
- */
- #include "def.h"
- #include "line.h"
- #include "buffer.h"
- #include "window.h"
-
- #ifdef ANSI
- #include <stdlib.h>
- #include <stddef.h>
- #include <string.h>
- /* Use the ANSI offsetof if we can */
- #define OFFSET(t, m) offsetof(t, m)
- #else
- /* Otherwise, if we don't know yet, use the default */
- #ifndef OFFSET
- #define OFFSET(type,member) ((char *)&(((type *)0)->member)-(char *)((type *)0))
- #endif
- #endif
-
- /*
- * define/prototype static functions here.
- */
- static VOID kcopy
- PROTO((char *, RSIZE, int));
- static kgrow
- PROTO((int));
-
-
- #ifndef NBLOCK
- #define NBLOCK 16 /* Line block chunk size */
- #endif
-
- #define KBLOCK 256
- #define KBSHIFT 8 /* = log[2](KBLOCK) */
- #define KBSIZE 2048 /* maximal size of kbbuf array */
-
- static char **kbufp = NULL; /* now addressed as an array of arrays */
- static RSIZE kallst = 0; /* # of first allocated byte */
-
- static RSIZE kused = 0; /* # of bytes used in KB. */
- static RSIZE ksize = 0; /* # of bytes allocated in KB. */
- static RSIZE kstart = 0; /* # of first used byte in KB. */
-
- /*
- * This routine allocates a block of memory large enough to hold a LINE
- * containing "used" characters. The block is rounded up to whatever needs to
- * be allocated. (use lallocx for lines likely to grow.) Return a pointer to
- * the new block, or NULL if there isn't any memory left. Print a message in
- * the message line if no space.
- */
- struct line *
- lalloc(used)
- register int used;
- {
- register struct line *lp;
- register int size;
-
- /* any padding at the end of the structure is used */
- if ((size = used + OFFSET(struct line, l_text[0])) < sizeof(struct line))
- size = sizeof(struct line);
- #ifdef MALLOCROUND
- MALLOCROUND(size); /* round up to a size optimal to malloc */
- #endif
- if ((lp = (struct line *) malloc((unsigned) size)) == NULL) {
- ewprintf("Can't get %d bytes", size);
- return (struct line *) NULL;
- }
- lp->l_size = size - OFFSET(struct line, l_text[0]);
- lp->l_used = used;
- return lp;
- }
-
- /*
- * Like lalloc, only round amount desired up because this line will probably
- * grow. We always make room for at least one more char. (thus making 0 not
- * a special case anymore.)
- */
- struct line *
- lallocx(used)
- int used;
- {
- register int size;
- register struct line *lp;
-
- size = (NBLOCK + used) & ~(NBLOCK - 1);
- if ((lp = lalloc(size)) != NULL)
- lp->l_used = used;
- return lp;
- }
-
- /*
- * Delete line "lp". Fix all of the links that might point at it (they are
- * moved to offset 0 of the next line. Unlink the line from whatever buffer
- * it might be in. Release the memory. The buffers are updated too; the magic
- * conditions described in the above comments don't hold here.
- */
- VOID
- lfree(lp)
- register struct line *lp;
- {
- register struct buffer *bp;
- register struct window *wp;
-
- for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
- if (wp->w_linep == lp)
- wp->w_linep = lp->l_fp;
- if (wp->w_dotp == lp) {
- wp->w_dotp = lp->l_fp;
- wp->w_doto = 0;
- }
- if (wp->w_markp == lp) {
- wp->w_markp = lp->l_fp;
- wp->w_marko = 0;
- }
- }
- for (bp = bheadp; bp != NULL; bp = bp->b_bufp) {
- if (bp->b_nwnd == 0) {
- if (bp->b_dotp == lp) {
- bp->b_dotp = lp->l_fp;
- bp->b_doto = 0;
- }
- if (bp->b_markp == lp) {
- bp->b_markp = lp->l_fp;
- bp->b_marko = 0;
- }
- }
- }
- lp->l_bp->l_fp = lp->l_fp;
- lp->l_fp->l_bp = lp->l_bp;
- free((char *) lp);
- }
-
- /*
- * This routine gets called when a character is changed in place in the
- * current buffer. It updates all of the required flags in the buffer and
- * window system. The flag used is passed as an argument; if the buffer is
- * being displayed in more than 1 window we change EDIT to HARD. Set MODE if
- * the mode line needs to be updated (the "*" has to be set).
- */
- VOID
- lchange(flag)
- register int flag;
- {
- register struct window *wp;
-
- if ((curbp->b_flag & BFCHG) == 0) { /* First change, so */
- flag |= WFMODE; /* update mode lines. */
- curbp->b_flag |= BFCHG;
- }
- for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
- if (wp->w_bufp == curbp) {
- wp->w_flag |= flag;
- if (wp != curwp)
- wp->w_flag |= WFHARD;
- }
- }
- }
-
- /*
- * Insert "n" copies of the character "c" at the current location of dot. In
- * the easy case all that happens is the text is stored in the line. In the
- * hard case, the line has to be reallocated. When the window list is
- * updated, take special care; I screwed it up once. You always update dot in
- * the current window. You update mark, and a dot in another window, if it is
- * greater than the place where you did the insert. Return TRUE if all is
- * well, and FALSE on errors.
- */
- linsert(n, c)
- int n;
- {
- register char *cp1;
- register char *cp2;
- register struct line *lp1;
- struct line *lp2;
- struct line *lp3;
- register int doto;
- register RSIZE i;
- struct window *wp;
-
- lchange(WFEDIT);
- lp1 = curwp->w_dotp; /* Current line */
- if (lp1 == curbp->b_linep) { /* At the end: special */
- /* (now should only happen in empty buffer */
- if (curwp->w_doto != 0) {
- ewprintf("bug: linsert");
- return FALSE;
- }
- if ((lp2 = lallocx(n)) == NULL) /* Allocate new line */
- return FALSE;
- lp3 = lp1->l_bp;/* Previous line */
- lp3->l_fp = lp2;/* Link in */
- lp2->l_fp = lp1;
- lp1->l_bp = lp2;
- lp2->l_bp = lp3;
- for (i = 0; i < n; ++i)
- lp2->l_text[i] = c;
- for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
- if (wp->w_linep == lp1)
- wp->w_linep = lp2;
- if (wp->w_dotp == lp1)
- wp->w_dotp = lp2;
- if (wp->w_markp == lp1)
- wp->w_markp = lp2;
- }
- /* NOSTRICT */
- curwp->w_doto = n;
- return TRUE;
- }
- doto = curwp->w_doto; /* Save for later. */
- /* NOSTRICT (2) */
- if (lp1->l_used + n > lp1->l_size) { /* Hard: reallocate */
- if ((lp2 = lallocx(lp1->l_used + n)) == NULL)
- return FALSE;
- cp1 = &lp1->l_text[0];
- cp2 = &lp2->l_text[0];
- while (cp1 != &lp1->l_text[doto])
- *cp2++ = *cp1++;
- /* NOSTRICT */
- cp2 += n;
- while (cp1 != &lp1->l_text[lp1->l_used])
- *cp2++ = *cp1++;
- lp1->l_bp->l_fp = lp2;
- lp2->l_fp = lp1->l_fp;
- lp1->l_fp->l_bp = lp2;
- lp2->l_bp = lp1->l_bp;
- free((char *) lp1);
- } else { /* Easy: in place */
- lp2 = lp1; /* Pretend new line */
- /* NOSTRICT */
- lp2->l_used += n;
- cp2 = &lp1->l_text[lp1->l_used];
-
- cp1 = cp2 - n;
- while (cp1 != &lp1->l_text[doto])
- *--cp2 = *--cp1;
- }
- for (i = 0; i < n; ++i) /* Add the characters */
- lp2->l_text[doto + i] = c;
-
- for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
- if (wp->w_linep == lp1)
- wp->w_linep = lp2;
- if (wp->w_dotp == lp1) {
- wp->w_dotp = lp2;
- if (wp == curwp || wp->w_doto > doto)
- /* NOSTRICT */
- wp->w_doto += n;
- }
- if (wp->w_markp == lp1) {
- wp->w_markp = lp2;
- if (wp->w_marko > doto)
- /* NOSTRICT */
- wp->w_marko += n;
- }
- }
- return TRUE;
- }
-
- /*
- * Insert a newline into the buffer at the current location of dot in the
- * current window. The funny ass-backwards way is no longer used.
- */
- lnewline()
- {
- register struct line *lp1;
- register struct line *lp2;
- register int doto;
- register int nlen;
- struct window *wp;
-
- lchange(WFHARD);
- lp1 = curwp->w_dotp; /* Get the address and */
- doto = curwp->w_doto; /* offset of "." */
- if (doto == 0) { /* avoid unnessisary copying */
- if ((lp2 = lallocx(0)) == NULL) /* new first part */
- return FALSE;
- lp2->l_bp = lp1->l_bp;
- lp1->l_bp->l_fp = lp2;
- lp2->l_fp = lp1;
- lp1->l_bp = lp2;
- if (lp1->l_bp == lp1->l_fp) /* Screwy case */
- for (wp = wheadp; wp != NULL; wp = wp->w_wndp)
- if (wp->w_linep == lp1)
- wp->w_linep = lp2;
- return TRUE;
- }
- nlen = llength(lp1) - doto; /* length of new part */
- if ((lp2 = lallocx(nlen)) == NULL) /* New second half line */
- return FALSE;
- if (nlen != 0)
- bcopy(&lp1->l_text[doto], &lp2->l_text[0], nlen);
- lp1->l_used = doto;
- lp2->l_bp = lp1;
- lp2->l_fp = lp1->l_fp;
- lp1->l_fp = lp2;
- lp2->l_fp->l_bp = lp2;
- for (wp = wheadp; wp != NULL; wp = wp->w_wndp) { /* Windows */
- if (wp->w_dotp == lp1 && wp->w_doto >= doto) {
- wp->w_dotp = lp2;
- wp->w_doto -= doto;
- }
- if (wp->w_markp == lp1 && wp->w_marko >= doto) {
- wp->w_markp = lp2;
- wp->w_marko -= doto;
- }
- }
- return TRUE;
- }
-
- /*
- * This function copies a string of length N into the kill buffer starting at
- * index X.
- */
- static VOID
- kcopy(str, x, n)
- register char *str;
- register RSIZE x;
- register int n;
- {
- register int i;
-
- for (i = 0; i < n; i++) {
- kbufp[x >> KBSHIFT][x & (KBLOCK - 1)] = *str;
- str++;
- x++;
- }
- }
-
-
- /*
- * This function deletes "n" bytes forward from dot. It understands how do
- * deal with end of lines, etc. It returns TRUE if all of the characters were
- * deleted, and FALSE if they were not (because dot ran into the end of the
- * buffer. Kflag is true if we instert the deleted character into the kill
- * buffer.
- */
- fdelete(n, kflag)
- RSIZE n;
- {
- register char *cp1;
- register char *cp2;
- register struct line *dotp;
- register int doto;
- register RSIZE chunk;
- struct window *wp;
-
- while (n != 0) {
- dotp = curwp->w_dotp;
- doto = curwp->w_doto;
- if (dotp == curbp->b_linep) /* Hit end of buffer. */
- return FALSE;
- chunk = dotp->l_used - doto; /* Size of chunk. */
- if (chunk > n)
- chunk = n;
- if (chunk == 0) { /* End of line, merge. */
- if (dotp == lback(curbp->b_linep))
- return FALSE; /* End of buffer. */
- lchange(WFHARD);
- if (ldelnewline() == FALSE
- || (kflag && kinsert('\n', KFORW) == FALSE))
- return FALSE;
- --n;
- continue;
- }
- lchange(WFEDIT);
- cp1 = &dotp->l_text[doto]; /* Scrunch text. */
- cp2 = cp1 + chunk;
- if (kflag) {
- while (ksize - kused < chunk)
- if (kgrow(FALSE) == FALSE)
- return FALSE;
- kcopy(cp1, kallst + kused, (int) chunk);
- kused += chunk;
- }
- while (cp2 != &dotp->l_text[dotp->l_used])
- *cp1++ = *cp2++;
- dotp->l_used -= (int) chunk;
- for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
- if (wp->w_dotp == dotp && wp->w_doto >= doto) {
- /* NOSTRICT */
- wp->w_doto -= chunk;
- if (wp->w_doto < doto)
- wp->w_doto = doto;
- }
- if (wp->w_markp == dotp && wp->w_marko >= doto) {
- /* NOSTRICT */
- wp->w_marko -= chunk;
- if (wp->w_marko < doto)
- wp->w_marko = doto;
- }
- }
- n -= chunk;
- }
- return TRUE;
- }
- /*
- * This function deletes "n" bytes backwards from dot. It understands how do
- * deal with end of lines, etc. It returns TRUE if all of the characters were
- * deleted, and FALSE if they were not (because dot ran into the end of the
- * buffer. Kflag is true if we instert the deleted character into the kill
- * buffer.
- */
- bdelete(n, kflag)
- RSIZE n;
- {
- register char *cp1;
- register char *cp2;
- register struct line *dotp;
- register int doto;
- register RSIZE chunk;
- struct window *wp;
-
- while (n != 0) {
- dotp = curwp->w_dotp;
- doto = curwp->w_doto;
- if (dotp == curbp->b_linep) /* Hit end of buffer. */
- return FALSE;
- chunk = doto; /* Size of chunk. */
- if (chunk > n)
- chunk = n;
- if (chunk == 0) { /* End of line, merge. */
- if (backchar(FFRAND, 1) == FALSE)
- return FALSE; /* End of buffer. */
- lchange(WFHARD);
- if (ldelnewline() == FALSE
- || (kflag && kinsert('\n', KBACK) == FALSE))
- return FALSE;
- --n;
- continue;
- }
- lchange(WFEDIT);
- cp2 = &dotp->l_text[doto]; /* Scrunch text. */
- cp1 = cp2 - chunk;
- if (kflag) {
- while (kstart - kallst < chunk)
- if (kgrow(TRUE) == FALSE)
- return FALSE;
- kcopy(cp1, kstart - chunk, (int) chunk);
- kstart -= chunk;
- }
- while (cp2 != &dotp->l_text[dotp->l_used])
- *cp1++ = *cp2++;
- dotp->l_used -= (int) chunk;
- doto -= chunk;
- for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
- if (wp->w_dotp == dotp && wp->w_doto >= doto) {
- /* NOSTRICT */
- wp->w_doto -= chunk;
- if (wp->w_doto < doto)
- wp->w_doto = doto;
- }
- if (wp->w_markp == dotp && wp->w_marko >= doto) {
- /* NOSTRICT */
- wp->w_marko -= chunk;
- if (wp->w_marko < doto)
- wp->w_marko = doto;
- }
- }
- n -= chunk;
- }
- return TRUE;
- }
-
- /*
- * Delete a newline. Join the current line with the next line. If the next
- * line is the magic header line always return TRUE; merging the last line
- * with the header line can be thought of as always being a successful
- * operation, even if nothing is done, and this makes the kill buffer work
- * "right". Easy cases can be done by shuffling data around. Hard cases
- * require that lines be moved about in memory. Return FALSE on error and
- * TRUE if all looks ok.
- */
- ldelnewline()
- {
- register struct line *lp1;
- register struct line *lp2;
- register struct window *wp;
- struct line *lp3;
-
- lp1 = curwp->w_dotp;
- lp2 = lp1->l_fp;
- if (lp2 == curbp->b_linep) /* At the buffer end. */
- return TRUE;
- if (lp2->l_used <= lp1->l_size - lp1->l_used) {
- bcopy(&lp2->l_text[0], &lp1->l_text[lp1->l_used], lp2->l_used);
- for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
- if (wp->w_linep == lp2)
- wp->w_linep = lp1;
- if (wp->w_dotp == lp2) {
- wp->w_dotp = lp1;
- wp->w_doto += lp1->l_used;
- }
- if (wp->w_markp == lp2) {
- wp->w_markp = lp1;
- wp->w_marko += lp1->l_used;
- }
- }
- lp1->l_used += lp2->l_used;
- lp1->l_fp = lp2->l_fp;
- lp2->l_fp->l_bp = lp1;
- free((char *) lp2);
- return TRUE;
- }
- if ((lp3 = lalloc(lp1->l_used + lp2->l_used)) == NULL)
- return FALSE;
- bcopy(&lp1->l_text[0], &lp3->l_text[0], lp1->l_used);
- bcopy(&lp2->l_text[0], &lp3->l_text[lp1->l_used], lp2->l_used);
- lp1->l_bp->l_fp = lp3;
- lp3->l_fp = lp2->l_fp;
- lp2->l_fp->l_bp = lp3;
- lp3->l_bp = lp1->l_bp;
- for (wp = wheadp; wp != NULL; wp = wp->w_wndp) {
- if (wp->w_linep == lp1 || wp->w_linep == lp2)
- wp->w_linep = lp3;
- if (wp->w_dotp == lp1)
- wp->w_dotp = lp3;
- else if (wp->w_dotp == lp2) {
- wp->w_dotp = lp3;
- wp->w_doto += lp1->l_used;
- }
- if (wp->w_markp == lp1)
- wp->w_markp = lp3;
- else if (wp->w_markp == lp2) {
- wp->w_markp = lp3;
- wp->w_marko += lp1->l_used;
- }
- }
- free((char *) lp1);
- free((char *) lp2);
- return TRUE;
- }
-
- /*
- * Replace plen characters before dot with argument string. Control-J
- * characters in st are interpreted as newlines. There is a casehack disable
- * flag (normally it likes to match case of replacement to what was there).
- */
- lreplace(plen, st, f)
- register RSIZE plen; /* length to remove */
- char *st; /* replacement string */
- int f; /* case hack disable */
- {
- register RSIZE rlen; /* replacement length */
- register int rtype; /* capitalization */
- register int c; /* used for random characters */
- register int doto; /* offset into line */
-
- /*
- * Find the capitalization of the word that was found. f says use
- * exact case of replacement string (same thing that happens with
- * lowercase found), so bypass check.
- */
- /* NOSTRICT */
- (VOID) backchar(FFARG | FFRAND, (int) plen);
- rtype = _L;
- c = lgetc(curwp->w_dotp, curwp->w_doto);
- if (ISUPPER(c) != FALSE && f == FALSE) {
- rtype = _U | _L;
- if (curwp->w_doto + 1 < llength(curwp->w_dotp)) {
- c = lgetc(curwp->w_dotp, curwp->w_doto + 1);
- if (ISUPPER(c) != FALSE) {
- rtype = _U;
- }
- }
- }
- /*
- * make the string lengths match (either pad the line so that it will
- * fit, or scrunch out the excess). be careful with dot's offset.
- */
- rlen = st ? strlen(st) : 0;
- doto = curwp->w_doto;
- if (plen > rlen)
- (VOID) fdelete((RSIZE) (plen - rlen), FALSE);
- else if (plen < rlen) {
- if (linsert((int) (rlen - plen), ' ') == FALSE)
- return FALSE;
- }
- curwp->w_doto = doto;
-
- /*
- * do the replacement: If was capital, then place first char as if
- * upper, and subsequent chars as if lower. If inserting upper, check
- * replacement for case.
- */
- while ((c = CHARMASK(*st++)) != '\0') {
- if ((rtype & _U) != 0 && ISLOWER(c) != 0)
- c = TOUPPER(c);
- if (rtype == (_U | _L))
- rtype = _L;
- if (c == CCHR('J')) {
- if (curwp->w_doto == llength(curwp->w_dotp))
- (VOID) forwchar(FFRAND, 1);
- else {
- if (fdelete((RSIZE) 1, FALSE) != FALSE)
- (VOID) lnewline();
- }
- } else if (curwp->w_dotp == curbp->b_linep) {
- (VOID) linsert(1, c);
- } else if (curwp->w_doto == llength(curwp->w_dotp)) {
- if (fdelete((RSIZE) 1, FALSE) != FALSE)
- (VOID) linsert(1, c);
- } else
- lputc(curwp->w_dotp, curwp->w_doto++, c);
- }
- lchange(WFHARD);
- return (TRUE);
- }
-
- /*
- * Delete all of the text saved in the kill buffer. Called by commands when a
- * new kill context is being created. The kill buffer array is released, just
- * in case the buffer has grown to immense size. No errors.
- */
- VOID
- kdelete()
- {
- int i;
- if (kbufp != NULL)
- for (i = 0; i < KBSIZE; i++)
- if (kbufp[i] != NULL) {
- free((char *) kbufp[i]);
- kbufp[i] = NULL;
- }
- kstart = kused = ksize = kallst = 0;
- }
-
- /*
- * Insert a character to the kill buffer, enlarging the buffer if there isn't
- * any room. Always grow the buffer in chunks, on the assumption that if you
- * put something in the kill buffer you are going to put more stuff there too
- * later. Return TRUE if all is well, and FALSE on errors. Print a message on
- * errors. Dir says whether to put it at back or front.
- */
- kinsert(c, dir)
- {
-
- if (kused == ksize && dir == KFORW && kgrow(FALSE) == FALSE)
- return FALSE;
- if (kstart == kallst && dir == KBACK && kgrow(TRUE) == FALSE)
- return FALSE;
- if (dir == KFORW) {
- kbufp[(kallst + kused) >> KBSHIFT][(kallst + kused) & (KBLOCK - 1)] = c;
- kused++;
- } else if (dir == KBACK) {
- kstart--;
- kbufp[kstart >> KBSHIFT][kstart & (KBLOCK - 1)] = c;
- } else
- panic("broken kinsert call"); /* Oh shit! */
- return (TRUE);
- }
-
- /*
- * kgrow - just get more kill buffer for the callee. back is true if we are
- * trying to get space at the beginning of the kill buffer.
- */
- static
- kgrow(back)
- {
- register char *nbufp;
- register int i;
- if (kbufp == NULL)
- if ((kbufp = (char **) malloc(KBSIZE * sizeof(nbufp))) == NULL) {
- ewprintf("Can't get %d bytes", KBSIZE * sizeof(nbufp));
- return (FALSE);
- } else
- for (i = 0; i < KBSIZE; i++)
- kbufp[i] = NULL;
- if ((kallst == 0) && (kused == 0))
- kallst = kstart = ((long) KBSIZE / 2) * KBLOCK;
- if ((back && (kallst == 0)) ||
- (!back && ((kallst + kused) == ((long) KBSIZE - 1) * KBLOCK))) {
- ewprintf("Kill buffer overflow!");
- return (FALSE);
- }
- if ((nbufp = (char *) malloc(KBLOCK)) == NULL) {
- ewprintf("Can't get %d bytes", KBLOCK);
- return (FALSE);
- }
- if (back) {
- kallst -= KBLOCK;
- kused += KBLOCK;
- kbufp[kallst >> KBSHIFT] = nbufp;
- } else
- kbufp[(kallst + ksize) >> KBSHIFT] = nbufp;
- ksize += KBLOCK;
- return TRUE;
- }
-
- /*
- * This function gets characters from the kill buffer. If the character index
- * "n" is off the end, it returns "-1". This lets the caller just scan along
- * until it gets a "-1" back.
- */
- char
- kremove(n)
- register RSIZE n;
- {
- register RSIZE addr;
- addr = (n + kstart);
- if ((n < 0) || (addr >= (kused + kallst)))
- return -1;
- return CHARMASK(kbufp[addr >> KBSHIFT][addr & (KBLOCK - 1)]);
- }
-
- /*
- * This function gets entire lines from the kill buffer. If there is no line,
- * a "-1" is returned, otherwise n is advanced, the characters are copied to
- * str and the length is returned.
- */
- int
- klremove(str, n)
- char *str;
- RSIZE *n;
- {
- register int size;
- register RSIZE addr;
-
- size = 0;
- addr = kstart + *n;
- while ((addr >= kstart) && (addr < (kallst + kused)) &&
- ((*str++ = kbufp[addr >> KBSHIFT][addr & (KBLOCK - 1)]) != '\n')) {
- addr++;
- size++;
- }
- if ((addr >= kstart) && (addr < (kallst + kused))) {
- *n = addr - kstart;
- return (size);
- } else
- return -1;
- }
-