summaryrefslogtreecommitdiff
path: root/sys/src/ape/lib/ap/stdio/rdline.c
blob: 6281a97e83fd58eb5f24c13a8c2abcd8f86a2a7e (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
/*
 * pANS stdio -- rdline
 * This is not a pANS routine.
 */
#include "iolib.h"
#include <string.h>

char *rdline(FILE *f, char **ep){
	int cnt;
	char *nlp, *vp;
	switch(f->state){
	default:	/* CLOSED, WR, ERR, EOF */
		return NULL;
	case OPEN:
		_IO_setvbuf(f);
	case RDWR:
		f->state=RD;
	case RD:
		if(f->bufl==0){		/* Called by a comedian! */
			f->state=ERR;
			return NULL;
		}
		vp=f->rp;
		for(;;){
			/*
			 * Look for a newline.
			 * If none found, slide the partial line to the beginning
			 * of the buffer, read some more and keep looking.
			 */
			nlp=memchr(f->rp, '\n', f->wp-f->rp);
			if(nlp!=0) break;
			if(f->flags&STRING){
				f->rp=f->wp;
				if(ep) *ep=f->wp;
				return vp;
			}
			if(f->rp!=f->buf){
				memmove(f->buf, f->rp, f->wp-f->rp);
				f->wp-=f->rp-f->buf;
				f->rp=f->buf;
				vp=f->rp;
			}
			cnt=f->bufl-(f->wp-f->buf);
			if(cnt==0){	/* no room left */
				nlp=f->wp-1;
				break;
			}
			cnt=read(f->fd, f->wp, cnt);
			if(cnt==-1){
				f->state=ERR;
				return NULL;
			}
			if(cnt==0){	/* is this ok? */
				f->state=EOF;
				return NULL;
			}
			f->rp=f->wp;
			f->wp+=cnt;
		}
		*nlp='\0';
		f->rp=nlp+1;
		if(ep) *ep=nlp;
		return vp;
	}
}