14887Schin /***********************************************************************
24887Schin * *
34887Schin * This software is part of the ast package *
4*12068SRoger.Faulkner@Oracle.COM * Copyright (c) 1985-2010 AT&T Intellectual Property *
54887Schin * and is licensed under the *
64887Schin * Common Public License, Version 1.0 *
78462SApril.Chin@Sun.COM * by AT&T Intellectual Property *
84887Schin * *
94887Schin * A copy of the License is available at *
104887Schin * http://www.opensource.org/licenses/cpl1.0.txt *
114887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
124887Schin * *
134887Schin * Information and Software Systems Research *
144887Schin * AT&T Research *
154887Schin * Florham Park NJ *
164887Schin * *
174887Schin * Glenn Fowler <gsf@research.att.com> *
184887Schin * David Korn <dgk@research.att.com> *
194887Schin * Phong Vo <kpv@research.att.com> *
204887Schin * *
214887Schin ***********************************************************************/
224887Schin #include "sfdchdr.h"
234887Schin
244887Schin
254887Schin /* Make a sequence of streams act like a single stream.
264887Schin ** This is for reading only.
274887Schin **
284887Schin ** Written by Kiem-Phong Vo, kpv@research.att.com, 03/18/1998.
294887Schin */
304887Schin
314887Schin #define UNSEEKABLE 1
324887Schin
334887Schin typedef struct _file_s
344887Schin { Sfio_t* f; /* the stream */
354887Schin Sfoff_t lower; /* its lowest end */
364887Schin } File_t;
374887Schin
384887Schin typedef struct _union_s
394887Schin {
404887Schin Sfdisc_t disc; /* discipline structure */
414887Schin short type; /* type of streams */
424887Schin short c; /* current stream */
434887Schin short n; /* number of streams */
444887Schin Sfoff_t here; /* current location */
454887Schin File_t f[1]; /* array of streams */
464887Schin } Union_t;
474887Schin
484887Schin #if __STD_C
unwrite(Sfio_t * f,const Void_t * buf,size_t n,Sfdisc_t * disc)494887Schin static ssize_t unwrite(Sfio_t* f, const Void_t* buf, size_t n, Sfdisc_t* disc)
504887Schin #else
514887Schin static ssize_t unwrite(f, buf, n, disc)
524887Schin Sfio_t* f; /* stream involved */
534887Schin Void_t* buf; /* buffer to read into */
544887Schin size_t n; /* number of bytes to read */
554887Schin Sfdisc_t* disc; /* discipline */
564887Schin #endif
574887Schin {
584887Schin return -1;
594887Schin }
604887Schin
614887Schin #if __STD_C
unread(Sfio_t * f,Void_t * buf,size_t n,Sfdisc_t * disc)624887Schin static ssize_t unread(Sfio_t* f, Void_t* buf, size_t n, Sfdisc_t* disc)
634887Schin #else
644887Schin static ssize_t unread(f, buf, n, disc)
654887Schin Sfio_t* f; /* stream involved */
664887Schin Void_t* buf; /* buffer to read into */
674887Schin size_t n; /* number of bytes to read */
684887Schin Sfdisc_t* disc; /* discipline */
694887Schin #endif
704887Schin {
714887Schin reg Union_t* un;
724887Schin reg ssize_t r, m;
734887Schin
744887Schin un = (Union_t*)disc;
754887Schin m = n;
764887Schin f = un->f[un->c].f;
774887Schin while(1)
784887Schin { if((r = sfread(f,buf,m)) < 0 || (r == 0 && un->c == un->n-1) )
794887Schin break;
804887Schin
814887Schin m -= r;
824887Schin un->here += r;
834887Schin
844887Schin if(m == 0)
854887Schin break;
864887Schin
874887Schin buf = (char*)buf + r;
884887Schin if(sfeof(f) && un->c < un->n-1)
894887Schin f = un->f[un->c += 1].f;
904887Schin }
914887Schin return n-m;
924887Schin }
934887Schin
944887Schin #if __STD_C
unseek(Sfio_t * f,Sfoff_t addr,int type,Sfdisc_t * disc)954887Schin static Sfoff_t unseek(Sfio_t* f, Sfoff_t addr, int type, Sfdisc_t* disc)
964887Schin #else
974887Schin static Sfoff_t unseek(f, addr, type, disc)
984887Schin Sfio_t* f;
994887Schin Sfoff_t addr;
1004887Schin int type;
1014887Schin Sfdisc_t* disc;
1024887Schin #endif
1034887Schin {
1044887Schin reg Union_t* un;
1054887Schin reg int i;
1064887Schin reg Sfoff_t extent, s;
1074887Schin
1084887Schin un = (Union_t*)disc;
1094887Schin if(un->type&UNSEEKABLE)
1104887Schin return -1L;
1114887Schin
1124887Schin if(type == 2)
1134887Schin { extent = 0;
1144887Schin for(i = 0; i < un->n; ++i)
1154887Schin extent += (sfsize(un->f[i].f) - un->f[i].lower);
1164887Schin addr += extent;
1174887Schin }
1184887Schin else if(type == 1)
1194887Schin addr += un->here;
1204887Schin
1214887Schin if(addr < 0)
1224887Schin return -1;
1234887Schin
1244887Schin /* find the stream where the addr could be in */
1254887Schin extent = 0;
1264887Schin for(i = 0; i < un->n-1; ++i)
1274887Schin { s = sfsize(un->f[i].f) - un->f[i].lower;
1284887Schin if(addr < extent + s)
1294887Schin break;
1304887Schin extent += s;
1314887Schin }
1324887Schin
1334887Schin s = (addr-extent) + un->f[i].lower;
1344887Schin if(sfseek(un->f[i].f,s,0) != s)
1354887Schin return -1;
1364887Schin
1374887Schin un->c = i;
1384887Schin un->here = addr;
1394887Schin
1404887Schin for(i += 1; i < un->n; ++i)
1414887Schin sfseek(un->f[i].f,un->f[i].lower,0);
1424887Schin
1434887Schin return addr;
1444887Schin }
1454887Schin
1464887Schin /* on close, remove the discipline */
1474887Schin #if __STD_C
unexcept(Sfio_t * f,int type,Void_t * data,Sfdisc_t * disc)1484887Schin static int unexcept(Sfio_t* f, int type, Void_t* data, Sfdisc_t* disc)
1494887Schin #else
1504887Schin static int unexcept(f,type,data,disc)
1514887Schin Sfio_t* f;
1524887Schin int type;
1534887Schin Void_t* data;
1544887Schin Sfdisc_t* disc;
1554887Schin #endif
1564887Schin {
1574887Schin if(type == SF_FINAL || type == SF_DPOP)
1584887Schin free(disc);
1594887Schin
1604887Schin return 0;
1614887Schin }
1624887Schin
1634887Schin #if __STD_C
sfdcunion(Sfio_t * f,Sfio_t ** array,int n)1644887Schin int sfdcunion(Sfio_t* f, Sfio_t** array, int n)
1654887Schin #else
1664887Schin int sfdcunion(f, array, n)
1674887Schin Sfio_t* f;
1684887Schin Sfio_t** array;
1694887Schin int n;
1704887Schin #endif
1714887Schin {
1724887Schin reg Union_t* un;
1734887Schin reg int i;
1744887Schin
1754887Schin if(n <= 0)
1764887Schin return -1;
1774887Schin
1784887Schin if(!(un = (Union_t*)malloc(sizeof(Union_t)+(n-1)*sizeof(File_t))) )
1794887Schin return -1;
1804887Schin memset(un, 0, sizeof(*un));
1814887Schin
1824887Schin un->disc.readf = unread;
1834887Schin un->disc.writef = unwrite;
1844887Schin un->disc.seekf = unseek;
1854887Schin un->disc.exceptf = unexcept;
1864887Schin un->n = n;
1874887Schin
1884887Schin for(i = 0; i < n; ++i)
1894887Schin { un->f[i].f = array[i];
1904887Schin if(!(un->type&UNSEEKABLE))
1914887Schin { un->f[i].lower = sfseek(array[i],(Sfoff_t)0,1);
1924887Schin if(un->f[i].lower < 0)
1934887Schin un->type |= UNSEEKABLE;
1944887Schin }
1954887Schin }
1964887Schin
1974887Schin if(sfdisc(f,(Sfdisc_t*)un) != (Sfdisc_t*)un)
1984887Schin { free(un);
1994887Schin return -1;
2004887Schin }
2014887Schin
2024887Schin return 0;
2034887Schin }
204