Subversion Repositories planix.SVN

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

#include        <u.h>
#include        <libc.h>
#include        <bio.h>

static char*
badd(char *p, int *np, char *data, int ndata, int delim, int nulldelim)
{
        int n;

        n = *np;
        p = realloc(p, n+ndata+1);
        if(p){
                memmove(p+n, data, ndata);
                n += ndata;
                if(n>0 && nulldelim && p[n-1]==delim)
                        p[--n] = '\0';
                else
                        p[n] = '\0';
                *np = n;
        }
        return p;
}

char*
Brdstr(Biobufhdr *bp, int delim, int nulldelim)
{
        char *ip, *ep, *p;
        int i, j;

        i = -bp->icount;
        bp->rdline = 0;
        if(i == 0) {
                /*
                 * eof or other error
                 */
                if(bp->state != Bractive) {
                        if(bp->state == Bracteof)
                                bp->state = Bractive;
                        bp->gbuf = bp->ebuf;
                        return nil;
                }
        }

        /*
         * first try in remainder of buffer (gbuf doesn't change)
         */
        ip = (char*)bp->ebuf - i;
        ep = memchr(ip, delim, i);
        if(ep) {
                j = (ep - ip) + 1;
                bp->icount += j;
                return badd(nil, &bp->rdline, ip, j, delim, nulldelim);
        }

        /*
         * copy data to beginning of buffer
         */
        if(i < bp->bsize)
                memmove(bp->bbuf, ip, i);
        bp->gbuf = bp->bbuf;

        /*
         * append to buffer looking for the delim
         */
        p = nil;
        for(;;){
                ip = (char*)bp->bbuf + i;
                while(i < bp->bsize) {
                        j = read(bp->fid, ip, bp->bsize-i);
                        if(j <= 0 && i == 0)
                                return p;
                        if(j <= 0 && i > 0){
                                /*
                                 * end of file but no delim. pretend we got a delim
                                 * by making the delim \0 and smashing it with nulldelim.
                                 */
                                j = 1;
                                ep = ip;
                                delim = '\0';
                                nulldelim = 1;
                                *ep = delim;    /* there will be room for this */
                        }else{
                                bp->offset += j;
                                ep = memchr(ip, delim, j);
                        }
                        i += j;
                        if(ep) {
                                /*
                                 * found in new piece
                                 * copy back up and reset everything
                                 */
                                ip = (char*)bp->ebuf - i;
                                if(i < bp->bsize){
                                        memmove(ip, bp->bbuf, i);
                                        bp->gbuf = (uchar*)ip;
                                }
                                j = (ep - (char*)bp->bbuf) + 1;
                                bp->icount = j - i;
                                return badd(p, &bp->rdline, ip, j, delim, nulldelim);
                        }
                        ip += j;
                }
        
                /*
                 * full buffer without finding; add to user string and continue
                 */
                p = badd(p, &bp->rdline, (char*)bp->bbuf, bp->bsize, 0, 0);
                i = 0;
                bp->icount = 0;
                bp->gbuf = bp->ebuf;
        }
}