1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin *                                                                      *
3da2e3ebdSchin *               This software is part of the ast package               *
4*b30d1939SAndy Fiddaman *          Copyright (c) 1985-2011 AT&T Intellectual Property          *
5da2e3ebdSchin *                      and is licensed under the                       *
6*b30d1939SAndy Fiddaman *                 Eclipse Public License, Version 1.0                  *
77c2fbfb3SApril Chin *                    by AT&T Intellectual Property                     *
8da2e3ebdSchin *                                                                      *
9da2e3ebdSchin *                A copy of the License is available at                 *
10*b30d1939SAndy Fiddaman *          http://www.eclipse.org/org/documents/epl-v10.html           *
11*b30d1939SAndy Fiddaman *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12da2e3ebdSchin *                                                                      *
13da2e3ebdSchin *              Information and Software Systems Research               *
14da2e3ebdSchin *                            AT&T Research                             *
15da2e3ebdSchin *                           Florham Park NJ                            *
16da2e3ebdSchin *                                                                      *
17da2e3ebdSchin *                 Glenn Fowler <gsf@research.att.com>                  *
18da2e3ebdSchin *                  David Korn <dgk@research.att.com>                   *
19da2e3ebdSchin *                   Phong Vo <kpv@research.att.com>                    *
20da2e3ebdSchin *                                                                      *
21da2e3ebdSchin ***********************************************************************/
22da2e3ebdSchin #include	"sfdchdr.h"
23da2e3ebdSchin 
24da2e3ebdSchin 
25da2e3ebdSchin /*	Discipline to treat a contiguous segment of a stream as a stream
26da2e3ebdSchin **	in its own right. The hard part in all this is to allow multiple
27da2e3ebdSchin **	segments of the stream to be used as substreams at the same time.
28da2e3ebdSchin **
29da2e3ebdSchin **	Written by David G. Korn and Kiem-Phong Vo (03/18/1998)
30da2e3ebdSchin */
31da2e3ebdSchin 
32da2e3ebdSchin typedef struct _subfile_s
33da2e3ebdSchin {
34da2e3ebdSchin 	Sfdisc_t	disc;	/* sfio discipline */
35da2e3ebdSchin 	Sfio_t*		parent;	/* parent stream */
36da2e3ebdSchin 	Sfoff_t		offset;	/* starting offset */
37da2e3ebdSchin 	Sfoff_t		extent;	/* size wanted */
38da2e3ebdSchin 	Sfoff_t		here;	/* current seek location */
39da2e3ebdSchin } Subfile_t;
40da2e3ebdSchin 
41da2e3ebdSchin #if __STD_C
streamio(Sfio_t * f,Void_t * buf,size_t n,Sfdisc_t * disc,int type)42da2e3ebdSchin static ssize_t streamio(Sfio_t* f, Void_t* buf, size_t n, Sfdisc_t* disc, int type)
43da2e3ebdSchin #else
44da2e3ebdSchin static ssize_t streamio(f, buf, n, disc, type)
45da2e3ebdSchin Sfio_t*		f;
46da2e3ebdSchin Void_t*		buf;
47da2e3ebdSchin size_t		n;
48da2e3ebdSchin Sfdisc_t*	disc;
49da2e3ebdSchin int		type;
50da2e3ebdSchin #endif
51da2e3ebdSchin {
52da2e3ebdSchin 	reg Subfile_t	*su;
53da2e3ebdSchin 	reg Sfoff_t	here, parent;
54da2e3ebdSchin 	reg ssize_t	io;
55da2e3ebdSchin 
56da2e3ebdSchin 	su = (Subfile_t*)disc;
57da2e3ebdSchin 
58da2e3ebdSchin 	/* read just what we need */
59da2e3ebdSchin 	if(su->extent >= 0 && (ssize_t)n > (io = (ssize_t)(su->extent - su->here)) )
60da2e3ebdSchin 		n = io;
61da2e3ebdSchin 	if(n <= 0)
62da2e3ebdSchin 		return n;
63da2e3ebdSchin 
64da2e3ebdSchin 	/* save current location in parent stream */
65da2e3ebdSchin 	parent = sfsk(f,(Sfoff_t)0,SEEK_CUR,disc);
66da2e3ebdSchin 
67da2e3ebdSchin 	/* read data */
68da2e3ebdSchin 	here = su->here + su->offset;
69da2e3ebdSchin 	if(sfsk(f,here,SEEK_SET,disc) != here)
70da2e3ebdSchin 		io = 0;
71da2e3ebdSchin 	else
72da2e3ebdSchin 	{	if(type == SF_WRITE)
73da2e3ebdSchin 			io = sfwr(f,buf,n,disc);
74da2e3ebdSchin 		else	io = sfrd(f,buf,n,disc);
75da2e3ebdSchin 		if(io > 0)
76da2e3ebdSchin 			su->here += io;
77da2e3ebdSchin 	}
78da2e3ebdSchin 
79da2e3ebdSchin 	/* restore parent current position */
80da2e3ebdSchin 	sfsk(f,parent,SEEK_SET,disc);
81da2e3ebdSchin 
82da2e3ebdSchin 	return io;
83da2e3ebdSchin }
84da2e3ebdSchin 
85da2e3ebdSchin #if __STD_C
streamwrite(Sfio_t * f,const Void_t * buf,size_t n,Sfdisc_t * disc)86da2e3ebdSchin static ssize_t streamwrite(Sfio_t* f, const Void_t* buf, size_t n, Sfdisc_t* disc)
87da2e3ebdSchin #else
88da2e3ebdSchin static ssize_t streamwrite(f, buf, n, disc)
89da2e3ebdSchin Sfio_t*		f;
90da2e3ebdSchin Void_t*		buf;
91da2e3ebdSchin size_t		n;
92da2e3ebdSchin Sfdisc_t*	disc;
93da2e3ebdSchin #endif
94da2e3ebdSchin {
95da2e3ebdSchin 	return streamio(f,(Void_t*)buf,n,disc,SF_WRITE);
96da2e3ebdSchin }
97da2e3ebdSchin 
98da2e3ebdSchin #if __STD_C
streamread(Sfio_t * f,Void_t * buf,size_t n,Sfdisc_t * disc)99da2e3ebdSchin static ssize_t streamread(Sfio_t* f, Void_t* buf, size_t n, Sfdisc_t* disc)
100da2e3ebdSchin #else
101da2e3ebdSchin static ssize_t streamread(f, buf, n, disc)
102da2e3ebdSchin Sfio_t*		f;
103da2e3ebdSchin Void_t*		buf;
104da2e3ebdSchin size_t		n;
105da2e3ebdSchin Sfdisc_t*	disc;
106da2e3ebdSchin #endif
107da2e3ebdSchin {
108da2e3ebdSchin 	return streamio(f,buf,n,disc,SF_READ);
109da2e3ebdSchin }
110da2e3ebdSchin 
111da2e3ebdSchin #if __STD_C
streamseek(Sfio_t * f,Sfoff_t pos,int type,Sfdisc_t * disc)112da2e3ebdSchin static Sfoff_t streamseek(Sfio_t* f, Sfoff_t pos, int type, Sfdisc_t* disc)
113da2e3ebdSchin #else
114da2e3ebdSchin static Sfoff_t streamseek(f, pos, type, disc)
115da2e3ebdSchin Sfio_t*		f;
116da2e3ebdSchin Sfoff_t		pos;
117da2e3ebdSchin int		type;
118da2e3ebdSchin Sfdisc_t*	disc;
119da2e3ebdSchin #endif
120da2e3ebdSchin {
121da2e3ebdSchin 	reg Subfile_t*	su;
122da2e3ebdSchin 	reg Sfoff_t	here, parent;
123da2e3ebdSchin 
124da2e3ebdSchin 	su = (Subfile_t*)disc;
125da2e3ebdSchin 
126da2e3ebdSchin 	switch(type)
127da2e3ebdSchin 	{
128da2e3ebdSchin 	case SEEK_SET:
129da2e3ebdSchin 		here = 0;
130da2e3ebdSchin 		break;
131da2e3ebdSchin 	case SEEK_CUR:
132da2e3ebdSchin 		here = su->here;
133da2e3ebdSchin 		break;
134da2e3ebdSchin 	case SEEK_END:
135da2e3ebdSchin 		if(su->extent >= 0)
136da2e3ebdSchin 			here = su->extent;
137da2e3ebdSchin 		else
138da2e3ebdSchin 		{	parent = sfsk(f,(Sfoff_t)0,SEEK_CUR,disc);
139da2e3ebdSchin 			if((here = sfsk(f,(Sfoff_t)0,SEEK_END,disc)) < 0)
140da2e3ebdSchin 				return -1;
141da2e3ebdSchin 			else	here -= su->offset;
142da2e3ebdSchin 			sfsk(f,parent,SEEK_SET,disc);
143da2e3ebdSchin 		}
144da2e3ebdSchin 		break;
145da2e3ebdSchin 	default:
146da2e3ebdSchin 		return -1;
147da2e3ebdSchin 	}
148da2e3ebdSchin 
149da2e3ebdSchin 	pos += here;
150da2e3ebdSchin 	if(pos < 0 || (su->extent >= 0 && pos >= su->extent))
151da2e3ebdSchin 		return -1;
152da2e3ebdSchin 
153da2e3ebdSchin 	return (su->here = pos);
154da2e3ebdSchin }
155da2e3ebdSchin 
156da2e3ebdSchin #if __STD_C
streamexcept(Sfio_t * f,int type,Void_t * data,Sfdisc_t * disc)157da2e3ebdSchin static int streamexcept(Sfio_t* f, int type, Void_t* data, Sfdisc_t* disc)
158da2e3ebdSchin #else
159da2e3ebdSchin static int streamexcept(f, type, data, disc)
160da2e3ebdSchin Sfio_t*		f;
161da2e3ebdSchin int		type;
162da2e3ebdSchin Void_t*		data;
163da2e3ebdSchin Sfdisc_t*	disc;
164da2e3ebdSchin #endif
165da2e3ebdSchin {
166da2e3ebdSchin 	if(type == SF_FINAL || type == SF_DPOP)
167da2e3ebdSchin 		free(disc);
168da2e3ebdSchin 	return 0;
169da2e3ebdSchin }
170da2e3ebdSchin 
171da2e3ebdSchin #if __STD_C
sfdcsubstream(Sfio_t * f,Sfio_t * parent,Sfoff_t offset,Sfoff_t extent)172da2e3ebdSchin Sfio_t* sfdcsubstream(Sfio_t* f, Sfio_t* parent, Sfoff_t offset, Sfoff_t extent)
173da2e3ebdSchin #else
174da2e3ebdSchin Sfio_t* sfdcsubstream(f, parent, offset, extent)
175da2e3ebdSchin Sfio_t*	f;	/* stream */
176da2e3ebdSchin Sfio_t*	parent;	/* parent stream */
177da2e3ebdSchin Sfoff_t	offset;	/* offset in f */
178da2e3ebdSchin Sfoff_t	extent;	/* desired size */
179da2e3ebdSchin #endif
180da2e3ebdSchin {
181da2e3ebdSchin 	reg Sfio_t*	sp;
182da2e3ebdSchin 	reg Subfile_t*	su;
183da2e3ebdSchin 	reg Sfoff_t	here;
184da2e3ebdSchin 
185da2e3ebdSchin 	/* establish that we can seek to offset */
186da2e3ebdSchin 	if((here = sfseek(parent,(Sfoff_t)0,SEEK_CUR)) < 0 || sfseek(parent,offset,SEEK_SET) < 0)
187da2e3ebdSchin 		return 0;
188da2e3ebdSchin 	else	sfseek(parent,here,SEEK_SET);
189da2e3ebdSchin 	sfpurge(parent);
190da2e3ebdSchin 
191da2e3ebdSchin 	if (!(sp = f) && !(sp = sfnew(NIL(Sfio_t*), NIL(Void_t*), (size_t)SF_UNBOUND, dup(sffileno(parent)), parent->flags)))
192da2e3ebdSchin 		return 0;
193da2e3ebdSchin 
194da2e3ebdSchin 	if(!(su = (Subfile_t*)malloc(sizeof(Subfile_t))))
195da2e3ebdSchin 	{	if(sp != f)
196da2e3ebdSchin 			sfclose(sp);
197da2e3ebdSchin 		return 0;
198da2e3ebdSchin 	}
199da2e3ebdSchin 	memset(su, 0, sizeof(*su));
200da2e3ebdSchin 
201da2e3ebdSchin 	su->disc.readf = streamread;
202da2e3ebdSchin 	su->disc.writef = streamwrite;
203da2e3ebdSchin 	su->disc.seekf = streamseek;
204da2e3ebdSchin 	su->disc.exceptf = streamexcept;
205da2e3ebdSchin 	su->parent = parent;
206da2e3ebdSchin 	su->offset = offset;
207da2e3ebdSchin 	su->extent = extent;
208da2e3ebdSchin 
209da2e3ebdSchin 	if(sfdisc(sp, (Sfdisc_t*)su) != (Sfdisc_t*)su)
210da2e3ebdSchin 	{	free(su);
211da2e3ebdSchin 		if(sp != f)
212da2e3ebdSchin 			sfclose(sp);
213da2e3ebdSchin 		return 0;
214da2e3ebdSchin 	}
215da2e3ebdSchin 
216da2e3ebdSchin 	return sp;
217da2e3ebdSchin }
218