aboutsummaryrefslogtreecommitdiff
path: root/src/base/io/readuntil.c
blob: 58e3d1eba726d1497c238d85ac425b75c2b57a8f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include "internal.h"

void *
io·readuntil(io·Header *io, int delim)
{
    char *b, *e;
    intptr i, j;

    i = -io->ilen;
    if(i==0){
        if(io->state != io·BufRdr){
            if(io->state == io·BufEnd)
                io->state = io·BufRdr;
            io->nread = 0;
            io->g = io->e;
            return nil;
        }
    }

    /* best case, we find it in the remaining bytes */
    b = (char*)io->e - i;
    if((e = mem·findc(b, i, delim)) != nil){
        j = (e - b)+1;
        io->nread = j;
        io->ilen += j;
        return b;
    }
    /* ok no luck, shift over the data and get more */
    if(i < io->cap)
        mem·move(io->b, i, b);
    io->g = io->b;

    /* write to the buffer while we search for delim */
    b = (char *)io->b + i;
    while(i < io->cap){
        if(sys·read(io->fd, b, io->cap-i, &j) || j == 0){
            mem·move(io->e-i, i, io->b);
            io->nread = +i;
            io->ilen = -i;
            io->g = io->e - i;
            return 0;
        }
        io->pos += j;
        i += j;
        e = mem·findc(b, j, delim);
        if(e!=nil){
            /* finally have a hit. reset the world */
            b = (char*)io->e - i;
            if(i < io->cap){
                mem·move(b, i, io->b);
                io->g = (uchar *)b;
            }
            j = (e - (char*)io->b) + 1;
            io->nread = j;
            io->ilen = j - i;
            return b;
        }
        b += j;
    }

    io->nread = +io->cap;
    io->ilen = -io->cap;
    io->g = io->b;
    return nil;
}