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 /*	Make a sequence of streams act like a single stream.
26da2e3ebdSchin **	This is for reading only.
27da2e3ebdSchin **
28da2e3ebdSchin **	Written by Kiem-Phong Vo, kpv@research.att.com, 03/18/1998.
29da2e3ebdSchin */
30da2e3ebdSchin 
31da2e3ebdSchin #define	UNSEEKABLE	1
32da2e3ebdSchin 
33da2e3ebdSchin typedef struct _file_s
34da2e3ebdSchin {	Sfio_t*	f;	/* the stream		*/
35da2e3ebdSchin 	Sfoff_t	lower;	/* its lowest end	*/
36da2e3ebdSchin } File_t;
37da2e3ebdSchin 
38da2e3ebdSchin typedef struct _union_s
39da2e3ebdSchin {
40da2e3ebdSchin 	Sfdisc_t	disc;	/* discipline structure */
41da2e3ebdSchin 	short		type;	/* type of streams	*/
42da2e3ebdSchin 	short		c;	/* current stream	*/
43da2e3ebdSchin 	short		n;	/* number of streams	*/
44da2e3ebdSchin 	Sfoff_t		here;	/* current location	*/
45da2e3ebdSchin 	File_t		f[1];	/* array of streams	*/
46da2e3ebdSchin } Union_t;
47da2e3ebdSchin 
48da2e3ebdSchin #if __STD_C
unwrite(Sfio_t * f,const Void_t * buf,size_t n,Sfdisc_t * disc)49da2e3ebdSchin static ssize_t unwrite(Sfio_t* f, const Void_t* buf, size_t n, Sfdisc_t* disc)
50da2e3ebdSchin #else
51da2e3ebdSchin static ssize_t unwrite(f, buf, n, disc)
52da2e3ebdSchin Sfio_t*        f;      /* stream involved */
53da2e3ebdSchin Void_t*        buf;    /* buffer to read into */
54da2e3ebdSchin size_t         n;      /* number of bytes to read */
55da2e3ebdSchin Sfdisc_t*      disc;   /* discipline */
56da2e3ebdSchin #endif
57da2e3ebdSchin {
58da2e3ebdSchin 	return -1;
59da2e3ebdSchin }
60da2e3ebdSchin 
61da2e3ebdSchin #if __STD_C
unread(Sfio_t * f,Void_t * buf,size_t n,Sfdisc_t * disc)62da2e3ebdSchin static ssize_t unread(Sfio_t* f, Void_t* buf, size_t n, Sfdisc_t* disc)
63da2e3ebdSchin #else
64da2e3ebdSchin static ssize_t unread(f, buf, n, disc)
65da2e3ebdSchin Sfio_t*        f;      /* stream involved */
66da2e3ebdSchin Void_t*        buf;    /* buffer to read into */
67da2e3ebdSchin size_t         n;      /* number of bytes to read */
68da2e3ebdSchin Sfdisc_t*      disc;   /* discipline */
69da2e3ebdSchin #endif
70da2e3ebdSchin {
71da2e3ebdSchin 	reg Union_t*	un;
72da2e3ebdSchin 	reg ssize_t	r, m;
73da2e3ebdSchin 
74da2e3ebdSchin 	un = (Union_t*)disc;
75da2e3ebdSchin 	m = n;
76da2e3ebdSchin 	f = un->f[un->c].f;
77da2e3ebdSchin 	while(1)
78da2e3ebdSchin 	{	if((r = sfread(f,buf,m)) < 0 || (r == 0 && un->c == un->n-1) )
79da2e3ebdSchin 			break;
80da2e3ebdSchin 
81da2e3ebdSchin 		m -= r;
82da2e3ebdSchin 		un->here += r;
83da2e3ebdSchin 
84da2e3ebdSchin 		if(m == 0)
85da2e3ebdSchin 			break;
86da2e3ebdSchin 
87da2e3ebdSchin 		buf = (char*)buf + r;
88da2e3ebdSchin 		if(sfeof(f) && un->c < un->n-1)
89da2e3ebdSchin 			f = un->f[un->c += 1].f;
90da2e3ebdSchin 	}
91da2e3ebdSchin 	return n-m;
92da2e3ebdSchin }
93da2e3ebdSchin 
94da2e3ebdSchin #if __STD_C
unseek(Sfio_t * f,Sfoff_t addr,int type,Sfdisc_t * disc)95da2e3ebdSchin static Sfoff_t unseek(Sfio_t* f, Sfoff_t addr, int type, Sfdisc_t* disc)
96da2e3ebdSchin #else
97da2e3ebdSchin static Sfoff_t unseek(f, addr, type, disc)
98da2e3ebdSchin Sfio_t*        f;
99da2e3ebdSchin Sfoff_t        addr;
100da2e3ebdSchin int            type;
101da2e3ebdSchin Sfdisc_t*      disc;
102da2e3ebdSchin #endif
103da2e3ebdSchin {
104da2e3ebdSchin 	reg Union_t*	un;
105da2e3ebdSchin 	reg int		i;
106da2e3ebdSchin 	reg Sfoff_t	extent, s;
107da2e3ebdSchin 
108da2e3ebdSchin 	un = (Union_t*)disc;
109da2e3ebdSchin 	if(un->type&UNSEEKABLE)
110da2e3ebdSchin 		return -1L;
111da2e3ebdSchin 
112da2e3ebdSchin 	if(type == 2)
113da2e3ebdSchin 	{	extent = 0;
114da2e3ebdSchin 		for(i = 0; i < un->n; ++i)
115da2e3ebdSchin 			extent += (sfsize(un->f[i].f) - un->f[i].lower);
116da2e3ebdSchin 		addr += extent;
117da2e3ebdSchin 	}
118da2e3ebdSchin 	else if(type == 1)
119da2e3ebdSchin 		addr += un->here;
120da2e3ebdSchin 
121da2e3ebdSchin 	if(addr < 0)
122da2e3ebdSchin 		return -1;
123da2e3ebdSchin 
124da2e3ebdSchin 	/* find the stream where the addr could be in */
125da2e3ebdSchin 	extent = 0;
126da2e3ebdSchin 	for(i = 0; i < un->n-1; ++i)
127da2e3ebdSchin 	{	s = sfsize(un->f[i].f) - un->f[i].lower;
128da2e3ebdSchin 		if(addr < extent + s)
129da2e3ebdSchin 			break;
130da2e3ebdSchin 		extent += s;
131da2e3ebdSchin 	}
132da2e3ebdSchin 
133da2e3ebdSchin 	s = (addr-extent) + un->f[i].lower;
134da2e3ebdSchin 	if(sfseek(un->f[i].f,s,0) != s)
135da2e3ebdSchin 		return -1;
136da2e3ebdSchin 
137da2e3ebdSchin 	un->c = i;
138da2e3ebdSchin 	un->here = addr;
139da2e3ebdSchin 
140da2e3ebdSchin 	for(i += 1; i < un->n; ++i)
141da2e3ebdSchin 		sfseek(un->f[i].f,un->f[i].lower,0);
142da2e3ebdSchin 
143da2e3ebdSchin 	return addr;
144da2e3ebdSchin }
145da2e3ebdSchin 
146da2e3ebdSchin /* on close, remove the discipline */
147da2e3ebdSchin #if __STD_C
unexcept(Sfio_t * f,int type,Void_t * data,Sfdisc_t * disc)148da2e3ebdSchin static int unexcept(Sfio_t* f, int type, Void_t* data, Sfdisc_t* disc)
149da2e3ebdSchin #else
150da2e3ebdSchin static int unexcept(f,type,data,disc)
151da2e3ebdSchin Sfio_t*		f;
152da2e3ebdSchin int		type;
153da2e3ebdSchin Void_t*		data;
154da2e3ebdSchin Sfdisc_t*	disc;
155da2e3ebdSchin #endif
156da2e3ebdSchin {
157da2e3ebdSchin 	if(type == SF_FINAL || type == SF_DPOP)
158da2e3ebdSchin 		free(disc);
159da2e3ebdSchin 
160da2e3ebdSchin 	return 0;
161da2e3ebdSchin }
162da2e3ebdSchin 
163da2e3ebdSchin #if __STD_C
sfdcunion(Sfio_t * f,Sfio_t ** array,int n)164da2e3ebdSchin int sfdcunion(Sfio_t* f, Sfio_t** array, int n)
165da2e3ebdSchin #else
166da2e3ebdSchin int sfdcunion(f, array, n)
167da2e3ebdSchin Sfio_t*		f;
168da2e3ebdSchin Sfio_t**	array;
169da2e3ebdSchin int		n;
170da2e3ebdSchin #endif
171da2e3ebdSchin {
172da2e3ebdSchin 	reg Union_t*	un;
173da2e3ebdSchin 	reg int		i;
174da2e3ebdSchin 
175da2e3ebdSchin 	if(n <= 0)
176da2e3ebdSchin 		return -1;
177da2e3ebdSchin 
178da2e3ebdSchin 	if(!(un = (Union_t*)malloc(sizeof(Union_t)+(n-1)*sizeof(File_t))) )
179da2e3ebdSchin 		return -1;
180da2e3ebdSchin 	memset(un, 0, sizeof(*un));
181da2e3ebdSchin 
182da2e3ebdSchin 	un->disc.readf = unread;
183da2e3ebdSchin 	un->disc.writef = unwrite;
184da2e3ebdSchin 	un->disc.seekf = unseek;
185da2e3ebdSchin 	un->disc.exceptf = unexcept;
186da2e3ebdSchin 	un->n = n;
187da2e3ebdSchin 
188da2e3ebdSchin 	for(i = 0; i < n; ++i)
189da2e3ebdSchin 	{	un->f[i].f = array[i];
190da2e3ebdSchin 		if(!(un->type&UNSEEKABLE))
191da2e3ebdSchin 		{	un->f[i].lower = sfseek(array[i],(Sfoff_t)0,1);
192da2e3ebdSchin 			if(un->f[i].lower < 0)
193da2e3ebdSchin 				un->type |= UNSEEKABLE;
194da2e3ebdSchin 		}
195da2e3ebdSchin 	}
196da2e3ebdSchin 
197da2e3ebdSchin 	if(sfdisc(f,(Sfdisc_t*)un) != (Sfdisc_t*)un)
198da2e3ebdSchin 	{	free(un);
199da2e3ebdSchin 		return -1;
200da2e3ebdSchin 	}
201da2e3ebdSchin 
202da2e3ebdSchin 	return 0;
203da2e3ebdSchin }
204