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