aboutsummaryrefslogtreecommitdiff
path: root/src/libbio/brdstr.c
blob: 52baf517178584aa36f24c7b397f00f420b53fc8 (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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#include	"lib9.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(Biobuf *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 = (unsigned char*)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;
	}
}