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