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 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 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 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 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 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