1/***********************************************************************
2*                                                                      *
3*               This software is part of the ast package               *
4*          Copyright (c) 1985-2010 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	"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
33struct map
34{
35	Sfoff_t	logical;
36	Sfoff_t	physical;
37};
38
39typedef 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
60static void addmapping(register Dosdisc_t *dp)
61#else
62static void addmapping(dp)
63register 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
83static struct map *getmapping(Dosdisc_t *dp, Sfoff_t offset, register int whence)
84#else
85static struct map *getmapping(dp, offset, whence)
86Dosdisc_t *dp;
87Sfoff_t offset;
88register 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
109static ssize_t dos_read(Sfio_t *iop, void *buff, size_t size, Sfdisc_t* disc)
110#else
111static ssize_t dos_read(iop, buff, size, disc)
112Sfio_t *iop;
113void *buff;
114size_t size;
115Sfdisc_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;
212done:
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
230static Sfoff_t cur_offset(Dosdisc_t *dp, Sfoff_t offset,Sfio_t *iop,register int whence)
231#else
232static Sfoff_t cur_offset(dp, offset, iop, whence)
233Dosdisc_t *dp;
234Sfoff_t offset;
235Sfio_t *iop;
236register 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
276static Sfoff_t dos_seek(Sfio_t *iop, Sfoff_t offset, register int whence, Sfdisc_t* disc)
277#else
278static Sfoff_t dos_seek(iop, offset, whence, disc)
279Sfio_t *iop;
280Sfoff_t offset;
281register int whence;
282Sfdisc_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;
289retry:
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
367static int dos_except(Sfio_t *iop, int type, void *arg, Sfdisc_t *disc)
368#else
369static int dos_except(iop, type, arg, disc)
370Sfio_t *iop;
371int type;
372void *arg;
373Sfdisc_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
389int sfdcdos(Sfio_t *f)
390#else
391int sfdcdos(f)
392Sfio_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