xref: /plan9-contrib/sys/src/libbio/brdstr.c (revision b85a83648eec38fe82b6f00adfd7828ceec5ee8d)
1 #include	<u.h>
2 #include	<libc.h>
3 #include	<bio.h>
4 
5 static char*
badd(char * p,int * np,char * data,int ndata,int delim,int nulldelim)6 badd(char *p, int *np, char *data, int ndata, int delim, int nulldelim)
7 {
8 	int n;
9 
10 	n = *np;
11 	p = realloc(p, n+ndata+1);
12 	if(p){
13 		memmove(p+n, data, ndata);
14 		n += ndata;
15 		if(n>0 && nulldelim && p[n-1]==delim)
16 			p[--n] = '\0';
17 		else
18 			p[n] = '\0';
19 		*np = n;
20 	}
21 	return p;
22 }
23 
24 char*
Brdstr(Biobufhdr * bp,int delim,int nulldelim)25 Brdstr(Biobufhdr *bp, int delim, int nulldelim)
26 {
27 	char *ip, *ep, *p;
28 	int i, j;
29 
30 	i = -bp->icount;
31 	bp->rdline = 0;
32 	if(i == 0) {
33 		/*
34 		 * eof or other error
35 		 */
36 		if(bp->state != Bractive) {
37 			if(bp->state == Bracteof)
38 				bp->state = Bractive;
39 			bp->gbuf = bp->ebuf;
40 			return nil;
41 		}
42 	}
43 
44 	/*
45 	 * first try in remainder of buffer (gbuf doesn't change)
46 	 */
47 	ip = (char*)bp->ebuf - i;
48 	ep = memchr(ip, delim, i);
49 	if(ep) {
50 		j = (ep - ip) + 1;
51 		bp->icount += j;
52 		return badd(nil, &bp->rdline, ip, j, delim, nulldelim);
53 	}
54 
55 	/*
56 	 * copy data to beginning of buffer
57 	 */
58 	if(i < bp->bsize)
59 		memmove(bp->bbuf, ip, i);
60 	bp->gbuf = bp->bbuf;
61 
62 	/*
63 	 * append to buffer looking for the delim
64 	 */
65 	p = nil;
66 	for(;;){
67 		ip = (char*)bp->bbuf + i;
68 		while(i < bp->bsize) {
69 			j = read(bp->fid, ip, bp->bsize-i);
70 			if(j <= 0 && i == 0)
71 				return p;
72 			if(j <= 0 && i > 0){
73 				/*
74 				 * end of file but no delim. pretend we got a delim
75 				 * by making the delim \0 and smashing it with nulldelim.
76 				 */
77 				j = 1;
78 				ep = ip;
79 				delim = '\0';
80 				nulldelim = 1;
81 				*ep = delim;	/* there will be room for this */
82 			}else{
83 				bp->offset += j;
84 				ep = memchr(ip, delim, j);
85 			}
86 			i += j;
87 			if(ep) {
88 				/*
89 				 * found in new piece
90 				 * copy back up and reset everything
91 				 */
92 				ip = (char*)bp->ebuf - i;
93 				if(i < bp->bsize){
94 					memmove(ip, bp->bbuf, i);
95 					bp->gbuf = (uchar*)ip;
96 				}
97 				j = (ep - (char*)bp->bbuf) + 1;
98 				bp->icount = j - i;
99 				return badd(p, &bp->rdline, ip, j, delim, nulldelim);
100 			}
101 			ip += j;
102 		}
103 
104 		/*
105 		 * full buffer without finding; add to user string and continue
106 		 */
107 		p = badd(p, &bp->rdline, (char*)bp->bbuf, bp->bsize, 0, 0);
108 		i = 0;
109 		bp->icount = 0;
110 		bp->gbuf = bp->ebuf;
111 	}
112 }
113