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