xref: /titanic_50/usr/src/lib/libast/common/sfio/sfgetr.c (revision 257873cfc1dd3337766407f80397db60a56f2f5a)
1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *           Copyright (c) 1985-2007 AT&T Knowledge Ventures            *
5 *                      and is licensed under the                       *
6 *                  Common Public License, Version 1.0                  *
7 *                      by AT&T Knowledge Ventures                      *
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
31 char* sfgetr(reg Sfio_t *f, reg int rc, int type)
32 #else
33 char* sfgetr(f,rc,type)
34 reg Sfio_t*	f;	/* stream to read from	*/
35 reg int		rc;	/* record separator	*/
36 int		type;
37 #endif
38 {
39 	reg ssize_t	n, un;
40 	reg uchar	*s, *ends, *us;
41 	reg int		found;
42 	reg Sfrsrv_t*	rsrv;
43 
44 	SFMTXSTART(f, NIL(char*));
45 
46 	if(rc < 0 || (f->mode != SF_READ && _sfmode(f,SF_READ,0) < 0) )
47 		SFMTXRETURN(f, NIL(char*));
48 	SFLOCK(f,0);
49 
50 	/* buffer to be returned */
51 	rsrv = NIL(Sfrsrv_t*);
52 	us = NIL(uchar*);
53 	un = 0;
54 	found = 0;
55 
56 	/* compatibility mode */
57 	type = type < 0 ? SF_LASTR : type == 1 ? SF_STRING : type;
58 
59 	if(type&SF_LASTR) /* return the broken record */
60 	{	if((rsrv = f->rsrv) && (un = -rsrv->slen) > 0)
61 		{	us = rsrv->data;
62 			found = 1;
63 		}
64 		goto done;
65 	}
66 
67 	while(!found)
68 	{	/* fill buffer if necessary */
69 		if((n = (ends = f->endb) - (s = f->next)) <= 0)
70 		{	/* for unseekable devices, peek-read 1 record */
71 			f->getr = rc;
72 			f->mode |= SF_RC;
73 
74 			/* fill buffer the conventional way */
75 			if(SFRPEEK(f,s,n) <= 0)
76 			{	us = NIL(uchar*);
77 				goto done;
78 			}
79 			else
80 			{	ends = s+n;
81 				if(f->mode&SF_RC)
82 				{	s = ends[-1] == rc ? ends-1 : ends;
83 					goto do_copy;
84 				}
85 			}
86 		}
87 
88 #if _lib_memchr
89 		if(!(s = (uchar*)memchr((char*)s,rc,n)))
90 			s = ends;
91 #else
92 		while(*s != rc)
93 			if((s += 1) == ends)
94 				break;
95 #endif
96 	do_copy:
97 		if(s < ends) /* found separator */
98 		{	s += 1;		/* include the separator */
99 			found = 1;
100 
101 			if(!us &&
102 			   (!(type&SF_STRING) || !(f->flags&SF_STRING) ||
103 			    ((f->flags&SF_STRING) && (f->bits&SF_BOTH) ) ) )
104 			{	/* returning data in buffer */
105 				us = f->next;
106 				un = s - f->next;
107 				f->next = s;
108 				goto done;
109 			}
110 		}
111 
112 		/* amount to be read */
113 		n = s - f->next;
114 
115 		if(!found && _Sfmaxr > 0 && un+n+1 >= _Sfmaxr) /* already exceed limit */
116 		{	us = NIL(uchar*);
117 			goto done;
118 		}
119 
120 		/* get internal buffer */
121 		if(!rsrv || rsrv->size < un+n+1)
122 		{	if(rsrv)
123 				rsrv->slen = un;
124 			if((rsrv = _sfrsrv(f,un+n+1)) != NIL(Sfrsrv_t*))
125 				us = rsrv->data;
126 			else
127 			{	us = NIL(uchar*);
128 				goto done;
129 			}
130 		}
131 
132 		/* now copy data */
133 		s = us+un;
134 		un += n;
135 		ends = f->next;
136 		f->next += n;
137 		MEMCPY(s,ends,n);
138 	}
139 
140 done:
141 	_Sfi = f->val = un;
142 	f->getr = 0;
143 	if(found && rc != 0 && (type&SF_STRING) )
144 	{	us[un-1] = '\0';
145 		if(us >= f->data && us < f->endb)
146 		{	f->getr = rc;
147 			f->mode |= SF_GETR;
148 		}
149 	}
150 
151 	/* prepare for a call to get the broken record */
152 	if(rsrv)
153 		rsrv->slen = found ? 0 : -un;
154 
155 	SFOPEN(f,0);
156 
157 	if(us && (type&SF_LOCKR) )
158 	{	f->mode |= SF_PEEK|SF_GETR;
159 		f->endr = f->data;
160 	}
161 
162 	SFMTXRETURN(f, (char*)us);
163 }
164