xref: /titanic_44/usr/src/lib/libast/common/disc/sfdcdos.c (revision edcc07547a39d6570197493a9836083bd6b2a197)
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	"sfdchdr.h"
23 
24 /*	Discipline to turn \r\n into \n.
25 **	This is useful to deal with DOS text files.
26 **
27 **	Written by David Korn (03/18/1998).
28 */
29 
30 #define MINMAP	8
31 #define CHUNK	1024
32 
33 struct map
34 {
35 	Sfoff_t	logical;
36 	Sfoff_t	physical;
37 };
38 
39 typedef struct _dosdisc
40 {
41 	Sfdisc_t	disc;
42 	struct map	*maptable;
43 	int		mapsize;
44 	int		maptop;
45 	Sfoff_t		lhere;
46 	Sfoff_t		llast;
47 	Sfoff_t		lmax;
48 	Sfoff_t		pmax;
49 	Sfoff_t		phere;
50 	Sfoff_t		plast;
51 	Sfoff_t		begin;
52 	int		skip;
53 	void		*buff;
54 	char		last;
55 	char		extra;
56 	int		bsize;
57 } Dosdisc_t;
58 
59 #if __STD_C
60 static void addmapping(register Dosdisc_t *dp)
61 #else
62 static void addmapping(dp)
63 register Dosdisc_t *dp;
64 #endif
65 {
66 	register int n;
67 	if((n=dp->maptop++)>=dp->mapsize)
68 	{
69 		dp->mapsize *= 2;
70 		if(!(dp->maptable=(struct map*)realloc((void*)dp->maptable,(dp->mapsize+1)*sizeof(struct map))))
71 		{
72 			dp->maptop--;
73 			dp->mapsize *= 2;
74 			return;
75 		}
76 	}
77 	dp->maptable[n].physical = dp->phere;
78 	dp->maptable[n].logical = dp->lhere;
79 	dp->maptable[dp->maptop].logical=0;
80 }
81 
82 #if __STD_C
83 static struct map *getmapping(Dosdisc_t *dp, Sfoff_t offset, register int whence)
84 #else
85 static struct map *getmapping(dp, offset, whence)
86 Dosdisc_t *dp;
87 Sfoff_t offset;
88 register int whence;
89 #endif
90 {
91 	register struct map *mp;
92 	static struct map dummy;
93 	if(offset <= dp->begin)
94 	{
95 		dummy.logical = dummy.physical = offset;
96 		return(&dummy);
97 	}
98 	if(!(mp=dp->maptable))
99 	{
100 		dummy.logical = dp->begin;
101 		dummy.physical = dummy.logical+1;
102 		return(&dummy);
103 	}
104 	while((++mp)->logical && (whence==SEEK_CUR?mp->physical:mp->logical) <= offset);
105 	return(mp-1);
106 }
107 
108 #if __STD_C
109 static ssize_t dos_read(Sfio_t *iop, void *buff, size_t size, Sfdisc_t* disc)
110 #else
111 static ssize_t dos_read(iop, buff, size, disc)
112 Sfio_t *iop;
113 void *buff;
114 size_t size;
115 Sfdisc_t* disc;
116 #endif
117 {
118 	register Dosdisc_t *dp = (Dosdisc_t*)disc;
119 	register char *cp = (char*)buff, *first, *cpmax;
120 	register int n, count, m;
121 	if(dp->extra)
122 	{
123 		dp->extra=0;
124 		*cp = dp->last;
125 		return(1);
126 	}
127 	while(1)
128 	{
129 		if((n = sfrd(iop,buff,size,disc)) <= 0)
130 			return(n);
131 		dp->plast=dp->phere;
132 		dp->phere +=n;
133 		dp->llast = dp->lhere;
134 		cpmax = cp+n-1;
135 		if(dp->last=='\r' && *cp!='\n')
136 		{
137 			/* should insert a '\r' */ ;
138 		}
139 		dp->last = *cpmax;
140 		if(n>1)
141 			break;
142 		if(dp->last!='\r')
143 		{
144 			dp->lhere++;
145 			return(1);
146 		}
147 	}
148 	if(dp->last=='\r')
149 		n--;
150 	else if(dp->last!='\n' || cpmax[-1]!='\r')
151 		*cpmax = '\r';
152 	dp->lhere += n;
153 	while(1)
154 	{
155 		while(*cp++ != '\r');
156 		if(cp > cpmax || *cp=='\n')
157 			break;
158 	}
159 	dp->skip = cp-1 - (char*)buff;
160 	/* if not \r\n in buffer, just return */
161 	if((count = cpmax+1-cp) <=0)
162 	{
163 		*cpmax = dp->last;
164 		if(!dp->maptable)
165 			dp->begin +=n;
166 		dp->skip++;
167 		count=0;
168 		goto done;
169 	}
170 	if(!dp->maptable)
171 	{
172 		dp->begin += cp - (char*)buff-1;
173 		if(dp->maptable=(struct map*)malloc((MINMAP+1)*sizeof(struct map)))
174 		{
175 			dp->mapsize = MINMAP;
176 			dp->maptable[0].logical=  dp->begin;
177 			dp->maptable[0].physical = dp->maptable[0].logical+1;
178 			dp->maptable[1].logical=0;
179 			dp->maptop = 1;
180 		}
181 	}
182 	/* save original discipline inside buffer */
183 	if(count>dp->bsize)
184 	{
185 		if(dp->bsize==0)
186 			dp->buff = malloc(count);
187 		else
188 			dp->buff = realloc(dp->buff,count);
189 		dp->bsize = count;
190 		if(!dp->buff)
191 			return(-1);
192 	}
193 	memcpy(dp->buff, cp, count);
194 	count=1;
195 	while(1)
196 	{
197 		first=cp;
198 		if(cp==cpmax)
199 			cp++;
200 		else
201 			while(*cp++ != '\r');
202 		if(cp<=cpmax && *cp!='\n')
203 			continue;
204 		if((m=(cp-first)-1) >0)
205 			memcpy(first-count, first, m);
206 		if(cp > cpmax)
207 			break;
208 		count++;
209 	}
210 	cpmax[-count] = dp->last;
211 	dp->lhere -= count;
212 done:
213 	if(dp->lhere>dp->lmax)
214 	{
215 		dp->lmax = dp->lhere;
216 		dp->pmax = dp->phere;
217 		if(dp->maptable && dp->lmax > dp->maptable[dp->maptop-1].logical+CHUNK)
218 			addmapping(dp);
219 	}
220 	return(n-count);
221 }
222 
223 /*
224  * returns the current offset
225  * <offset> must be in the current buffer
226  * if <whence> is SEEK_CUR, physical offset converted to logical offset
227  *  otherwise, logical offset is converted to physical offset
228  */
229 #if __STD_C
230 static Sfoff_t cur_offset(Dosdisc_t *dp, Sfoff_t offset,Sfio_t *iop,register int whence)
231 #else
232 static Sfoff_t cur_offset(dp, offset, iop, whence)
233 Dosdisc_t *dp;
234 Sfoff_t offset;
235 Sfio_t *iop;
236 register int whence;
237 #endif
238 {
239 	register Sfoff_t n,m=0;
240 	register char *cp;
241 
242 	if(whence==SEEK_CUR)
243 	{
244 		whence= -1;
245 		n = offset - dp->plast;
246 		iop->next = iop->data + n;
247 		offset =  dp->llast;
248 	}
249 	else
250 	{
251 		whence = 1;
252 		n = offset - dp->llast;
253 		offset = dp->plast;
254 	}
255 	offset +=n;
256 	if((n -= dp->skip) > 0)
257 	{
258 		m=whence;
259 		cp = (char*)dp->buff;
260 		while(n--)
261 		{
262 			if(*cp++=='\r' && *cp=='\n')
263 			{
264 				m += whence;
265 				if(whence>0)
266 					n++;
267 			}
268 		}
269 	}
270 	if(whence<0)
271 		iop->next += m;
272 	return(offset+m);
273 }
274 
275 #if __STD_C
276 static Sfoff_t dos_seek(Sfio_t *iop, Sfoff_t offset, register int whence, Sfdisc_t* disc)
277 #else
278 static Sfoff_t dos_seek(iop, offset, whence, disc)
279 Sfio_t *iop;
280 Sfoff_t offset;
281 register int whence;
282 Sfdisc_t* disc;
283 #endif
284 {
285 	register Dosdisc_t *dp = (Dosdisc_t*)disc;
286 	struct map dummy, *mp=0;
287 	Sfoff_t physical;
288 	register int n,size;
289 retry:
290 	switch(whence)
291 	{
292 	    case SEEK_CUR:
293 		offset = sfsk(iop, (Sfoff_t)0,SEEK_CUR,disc);
294 		if(offset<=dp->begin)
295 			return(offset);
296 		/* check for seek outside buffer */
297 		if(offset==dp->phere)
298 			return(dp->lhere);
299 		else if(offset==dp->plast)
300 			return(dp->llast);
301 		else if(offset<dp->plast || offset>dp->phere)
302 			mp = getmapping(dp,offset,whence);
303 		break;
304 	    case SEEK_SET:
305 		/* check for seek outside buffer */
306 		if(offset<dp->llast || offset > dp->lhere)
307 			mp = getmapping(dp,offset,whence);
308 		break;
309 	    case SEEK_END:
310 		if(!dp->maptable)
311 			return(sfsk(iop,offset,SEEK_END,disc));
312 		mp = &dummy;
313 		mp->physical = dp->plast;
314 		mp->logical = dp->llast;
315 		break;
316 	}
317 	if(sfsetbuf(iop,(char*)iop,0))
318 		size = sfvalue(iop);
319 	else
320 		size = iop->endb-iop->data;
321 	if(mp)
322 	{
323 		sfsk(iop,mp->physical,SEEK_SET,disc);
324 		dp->phere = mp->physical;
325 		dp->lhere = mp->logical;
326 		if((*disc->readf)(iop,iop->data,size,disc)<0)
327 			return(-1);
328 	}
329 	while(1)
330 	{
331 		if(whence==SEEK_CUR && dp->phere>=offset)
332 			break;
333 		if(whence==SEEK_SET && dp->lhere>=offset)
334 			break;
335 		n=(*disc->readf)(iop,iop->data,size,disc);
336 		if(n < 0)
337 			return(-1);
338 		if(n==0)
339 		{
340 			if(whence==SEEK_END && offset<0)
341 			{
342 				offset = dp->lhere;
343 				whence=SEEK_SET;
344 				goto retry;
345 			}
346 			break;
347 		}
348 	}
349 	if(whence==SEEK_END)
350 		offset += dp->lhere;
351 	else
352 	{
353 		physical = cur_offset(dp,offset,iop,whence);
354 		if(whence==SEEK_SET)
355 		{
356 			sfsk(iop, physical ,SEEK_SET,disc);
357 			dp->phere = physical;
358 			dp->lhere = offset;
359 		}
360 		else
361 			offset = physical;
362 	}
363 	return(offset);
364 }
365 
366 #if __STD_C
367 static int dos_except(Sfio_t *iop, int type, void *arg, Sfdisc_t *disc)
368 #else
369 static int dos_except(iop, type, arg, disc)
370 Sfio_t *iop;
371 int type;
372 void *arg;
373 Sfdisc_t *disc;
374 #endif
375 {
376 	register Dosdisc_t *dp = (Dosdisc_t*)disc;
377 	if(type==SF_DPOP || type==SF_FINAL)
378 	{
379 		if(dp->bsize>0)
380 			free((void*)dp->buff);
381 		if(dp->mapsize)
382 			free((void*)dp->maptable);
383 		free((void*)disc);
384 	}
385 	return(0);
386 }
387 
388 #if __STD_C
389 int sfdcdos(Sfio_t *f)
390 #else
391 int sfdcdos(f)
392 Sfio_t *f;
393 #endif
394 {
395 	Dosdisc_t *dos;
396 
397 	/* this is a readonly discipline */
398 	if(sfset(f,0,0)&SF_WRITE)
399 		return(-1);
400 
401 	if(!(dos = (Dosdisc_t*)malloc(sizeof(Dosdisc_t))) )
402 		return -1;
403 	memset(dos,'\0',sizeof(Dosdisc_t));
404 
405 	dos->disc.readf = dos_read;
406 	dos->disc.writef = NIL(Sfwrite_f);
407 	dos->disc.seekf = dos_seek;
408 	dos->disc.exceptf = dos_except;
409 
410 	if(sfdisc(f,(Sfdisc_t*)dos) != (Sfdisc_t*)dos)
411 	{	free(dos);
412 		return -1;
413 	}
414 
415 	return(0);
416 }
417