/*********************************************************************** * * * This software is part of the ast package * * Copyright (c) 1985-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * * * * Information and Software Systems Research * * AT&T Research * * Florham Park NJ * * * * Glenn Fowler * * David Korn * * Phong Vo * * * ***********************************************************************/ #include "sfdchdr.h" /* Make a sequence of streams act like a single stream. ** This is for reading only. ** ** Written by Kiem-Phong Vo, kpv@research.att.com, 03/18/1998. */ #define UNSEEKABLE 1 typedef struct _file_s { Sfio_t* f; /* the stream */ Sfoff_t lower; /* its lowest end */ } File_t; typedef struct _union_s { Sfdisc_t disc; /* discipline structure */ short type; /* type of streams */ short c; /* current stream */ short n; /* number of streams */ Sfoff_t here; /* current location */ File_t f[1]; /* array of streams */ } Union_t; #if __STD_C static ssize_t unwrite(Sfio_t* f, const Void_t* buf, size_t n, Sfdisc_t* disc) #else static ssize_t unwrite(f, buf, n, disc) Sfio_t* f; /* stream involved */ Void_t* buf; /* buffer to read into */ size_t n; /* number of bytes to read */ Sfdisc_t* disc; /* discipline */ #endif { return -1; } #if __STD_C static ssize_t unread(Sfio_t* f, Void_t* buf, size_t n, Sfdisc_t* disc) #else static ssize_t unread(f, buf, n, disc) Sfio_t* f; /* stream involved */ Void_t* buf; /* buffer to read into */ size_t n; /* number of bytes to read */ Sfdisc_t* disc; /* discipline */ #endif { reg Union_t* un; reg ssize_t r, m; un = (Union_t*)disc; m = n; f = un->f[un->c].f; while(1) { if((r = sfread(f,buf,m)) < 0 || (r == 0 && un->c == un->n-1) ) break; m -= r; un->here += r; if(m == 0) break; buf = (char*)buf + r; if(sfeof(f) && un->c < un->n-1) f = un->f[un->c += 1].f; } return n-m; } #if __STD_C static Sfoff_t unseek(Sfio_t* f, Sfoff_t addr, int type, Sfdisc_t* disc) #else static Sfoff_t unseek(f, addr, type, disc) Sfio_t* f; Sfoff_t addr; int type; Sfdisc_t* disc; #endif { reg Union_t* un; reg int i; reg Sfoff_t extent, s; un = (Union_t*)disc; if(un->type&UNSEEKABLE) return -1L; if(type == 2) { extent = 0; for(i = 0; i < un->n; ++i) extent += (sfsize(un->f[i].f) - un->f[i].lower); addr += extent; } else if(type == 1) addr += un->here; if(addr < 0) return -1; /* find the stream where the addr could be in */ extent = 0; for(i = 0; i < un->n-1; ++i) { s = sfsize(un->f[i].f) - un->f[i].lower; if(addr < extent + s) break; extent += s; } s = (addr-extent) + un->f[i].lower; if(sfseek(un->f[i].f,s,0) != s) return -1; un->c = i; un->here = addr; for(i += 1; i < un->n; ++i) sfseek(un->f[i].f,un->f[i].lower,0); return addr; } /* on close, remove the discipline */ #if __STD_C static int unexcept(Sfio_t* f, int type, Void_t* data, Sfdisc_t* disc) #else static int unexcept(f,type,data,disc) Sfio_t* f; int type; Void_t* data; Sfdisc_t* disc; #endif { if(type == SF_FINAL || type == SF_DPOP) free(disc); return 0; } #if __STD_C int sfdcunion(Sfio_t* f, Sfio_t** array, int n) #else int sfdcunion(f, array, n) Sfio_t* f; Sfio_t** array; int n; #endif { reg Union_t* un; reg int i; if(n <= 0) return -1; if(!(un = (Union_t*)malloc(sizeof(Union_t)+(n-1)*sizeof(File_t))) ) return -1; memset(un, 0, sizeof(*un)); un->disc.readf = unread; un->disc.writef = unwrite; un->disc.seekf = unseek; un->disc.exceptf = unexcept; un->n = n; for(i = 0; i < n; ++i) { un->f[i].f = array[i]; if(!(un->type&UNSEEKABLE)) { un->f[i].lower = sfseek(array[i],(Sfoff_t)0,1); if(un->f[i].lower < 0) un->type |= UNSEEKABLE; } } if(sfdisc(f,(Sfdisc_t*)un) != (Sfdisc_t*)un) { free(un); return -1; } return 0; }