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