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
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
33 typedef struct _file_s
34 { Sfio_t* f; /* the stream */
35 Sfoff_t lower; /* its lowest end */
36 } File_t;
37
38 typedef 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
unwrite(Sfio_t * f,const Void_t * buf,size_t n,Sfdisc_t * disc)49 static ssize_t unwrite(Sfio_t* f, const Void_t* buf, size_t n, Sfdisc_t* disc)
50 #else
51 static ssize_t unwrite(f, buf, n, disc)
52 Sfio_t* f; /* stream involved */
53 Void_t* buf; /* buffer to read into */
54 size_t n; /* number of bytes to read */
55 Sfdisc_t* disc; /* discipline */
56 #endif
57 {
58 return -1;
59 }
60
61 #if __STD_C
unread(Sfio_t * f,Void_t * buf,size_t n,Sfdisc_t * disc)62 static ssize_t unread(Sfio_t* f, Void_t* buf, size_t n, Sfdisc_t* disc)
63 #else
64 static ssize_t unread(f, buf, n, disc)
65 Sfio_t* f; /* stream involved */
66 Void_t* buf; /* buffer to read into */
67 size_t n; /* number of bytes to read */
68 Sfdisc_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
unseek(Sfio_t * f,Sfoff_t addr,int type,Sfdisc_t * disc)95 static Sfoff_t unseek(Sfio_t* f, Sfoff_t addr, int type, Sfdisc_t* disc)
96 #else
97 static Sfoff_t unseek(f, addr, type, disc)
98 Sfio_t* f;
99 Sfoff_t addr;
100 int type;
101 Sfdisc_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
unexcept(Sfio_t * f,int type,Void_t * data,Sfdisc_t * disc)148 static int unexcept(Sfio_t* f, int type, Void_t* data, Sfdisc_t* disc)
149 #else
150 static int unexcept(f,type,data,disc)
151 Sfio_t* f;
152 int type;
153 Void_t* data;
154 Sfdisc_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
sfdcunion(Sfio_t * f,Sfio_t ** array,int n)164 int sfdcunion(Sfio_t* f, Sfio_t** array, int n)
165 #else
166 int sfdcunion(f, array, n)
167 Sfio_t* f;
168 Sfio_t** array;
169 int 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