1/***********************************************************************
2*                                                                      *
3*               This software is part of the ast package               *
4*          Copyright (c) 1985-2011 AT&T Intellectual Property          *
5*                      and is licensed under the                       *
6*                  Common Public License, Version 1.0                  *
7*                    by AT&T Intellectual Property                     *
8*                                                                      *
9*                A copy of the License is available at                 *
10*            http://www.opensource.org/licenses/cpl1.0.txt             *
11*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12*                                                                      *
13*              Information and Software Systems Research               *
14*                            AT&T Research                             *
15*                           Florham Park NJ                            *
16*                                                                      *
17*                 Glenn Fowler <gsf@research.att.com>                  *
18*                  David Korn <dgk@research.att.com>                   *
19*                   Phong Vo <kpv@research.att.com>                    *
20*                                                                      *
21***********************************************************************/
22#include	"sfhdr.h"
23
24/*	Read a record delineated by a character.
25**	The record length can be accessed via sfvalue(f).
26**
27**	Written by Kiem-Phong Vo
28*/
29
30#if __STD_C
31char* sfgetr(Sfio_t *f, int rc, int type)
32#else
33char* sfgetr(f,rc,type)
34Sfio_t*		f;	/* stream to read from	*/
35int		rc;	/* record separator	*/
36int		type;
37#endif
38{
39	ssize_t		n, un;
40	uchar		*s, *ends, *us;
41	int		found;
42	Sfrsrv_t*	rsrv;
43	SFMTXDECL(f);
44
45	SFMTXENTER(f, NIL(char*));
46
47	if(rc < 0 || (f->mode != SF_READ && _sfmode(f,SF_READ,0) < 0) )
48		SFMTXRETURN(f, NIL(char*));
49	SFLOCK(f,0);
50
51	/* buffer to be returned */
52	rsrv = NIL(Sfrsrv_t*);
53	us = NIL(uchar*);
54	un = 0;
55	found = 0;
56
57	/* compatibility mode */
58	type = type < 0 ? SF_LASTR : type == 1 ? SF_STRING : type;
59
60	if(type&SF_LASTR) /* return the broken record */
61	{	if((f->flags&SF_STRING) && (un = f->endb - f->next))
62		{	us = f->next;
63			f->next = f->endb;
64			found = 1;
65		}
66		else if((rsrv = f->rsrv) && (un = -rsrv->slen) > 0)
67		{	us = rsrv->data;
68			found = 1;
69		}
70		goto done;
71	}
72
73	while(!found)
74	{	/* fill buffer if necessary */
75		if((n = (ends = f->endb) - (s = f->next)) <= 0)
76		{	/* for unseekable devices, peek-read 1 record */
77			f->getr = rc;
78			f->mode |= SF_RC;
79
80			/* fill buffer the conventional way */
81			if(SFRPEEK(f,s,n) <= 0)
82			{	us = NIL(uchar*);
83				goto done;
84			}
85			else
86			{	ends = s+n;
87				if(f->mode&SF_RC)
88				{	s = ends[-1] == rc ? ends-1 : ends;
89					goto do_copy;
90				}
91			}
92		}
93
94#if _lib_memchr
95		if(!(s = (uchar*)memchr((char*)s,rc,n)))
96			s = ends;
97#else
98		while(*s != rc)
99			if((s += 1) == ends)
100				break;
101#endif
102	do_copy:
103		if(s < ends) /* found separator */
104		{	s += 1;		/* include the separator */
105			found = 1;
106
107			if(!us &&
108			   (!(type&SF_STRING) || !(f->flags&SF_STRING) ||
109			    ((f->flags&SF_STRING) && (f->bits&SF_BOTH) ) ) )
110			{	/* returning data in buffer */
111				us = f->next;
112				un = s - f->next;
113				f->next = s;
114				goto done;
115			}
116		}
117
118		/* amount to be read */
119		n = s - f->next;
120
121		if(!found && (_Sfmaxr > 0 && un+n+1 >= _Sfmaxr || (f->flags&SF_STRING))) /* already exceed limit */
122		{	us = NIL(uchar*);
123			goto done;
124		}
125
126		/* get internal buffer */
127		if(!rsrv || rsrv->size < un+n+1)
128		{	if(rsrv)
129				rsrv->slen = un;
130			if((rsrv = _sfrsrv(f,un+n+1)) != NIL(Sfrsrv_t*))
131				us = rsrv->data;
132			else
133			{	us = NIL(uchar*);
134				goto done;
135			}
136		}
137
138		/* now copy data */
139		s = us+un;
140		un += n;
141		ends = f->next;
142		f->next += n;
143		MEMCPY(s,ends,n);
144	}
145
146done:
147	_Sfi = f->val = un;
148	f->getr = 0;
149	if(found && rc != 0 && (type&SF_STRING) )
150	{	us[un-1] = '\0';
151		if(us >= f->data && us < f->endb)
152		{	f->getr = rc;
153			f->mode |= SF_GETR;
154		}
155	}
156
157	/* prepare for a call to get the broken record */
158	if(rsrv)
159		rsrv->slen = found ? 0 : -un;
160
161	SFOPEN(f,0);
162
163	if(us && (type&SF_LOCKR) )
164	{	f->mode |= SF_PEEK|SF_GETR;
165		f->endr = f->data;
166	}
167
168	SFMTXRETURN(f, (char*)us);
169}
170