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 *                 Eclipse Public License, Version 1.0                  *
7 *                    by AT&T Intellectual Property                     *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *          http://www.eclipse.org/org/documents/epl-v10.html           *
11 *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
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
sfgetr(Sfio_t * f,int rc,int type)31 char* sfgetr(Sfio_t *f, int rc, int type)
32 #else
33 char* sfgetr(f,rc,type)
34 Sfio_t*		f;	/* stream to read from	*/
35 int		rc;	/* record separator	*/
36 int		type;
37 #endif
38 {
39 	ssize_t		n, un;
40 	uchar		*s, *ends, *us;
41 	int		found;
42 	Sfrsrv_t*	rsrv;
43 	SFMTXDECL(f); /* declare a local stream variable for multithreading */
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 
146 done:
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