diff options
Diffstat (limited to 'src/IEEEIO.cc')
-rw-r--r-- | src/IEEEIO.cc | 1443 |
1 files changed, 1443 insertions, 0 deletions
diff --git a/src/IEEEIO.cc b/src/IEEEIO.cc new file mode 100644 index 0000000..c2f653b --- /dev/null +++ b/src/IEEEIO.cc @@ -0,0 +1,1443 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "IEEEIO.hh" + +#ifdef WIN32 +// Are we Microsoft VC++ 5.0 or 6.0? +#if defined(_MSC_VER) && ( (_MSC_VER == 1100) || (_MSC_VER == 1200) ) // yes we are +#include <fcntl.h> +#ifdef O_RDONLY +#undef O_RDONLY +#endif +#define O_RDONLY _O_RDONLY|_O_BINARY +#ifdef O_RDWR +#undef O_RDWR +#endif +#define O_RDWR _O_RDWR|_O_BINARY +#ifdef O_WRONLY +#undef O_WRONLY +#endif +#define O_WRONLY _O_WRONLY|_O_BINARY +#ifdef O_CREAT +#undef O_CREAT +#endif +#define O_CREAT _O_CREAT|_O_BINARY +#ifdef O_TRUNC +#undef O_TRUNC +#endif +#define O_TRUNC _O_TRUNC|_O_BINARY +#ifdef O_APPEND +#undef O_APPEND +#endif +#define O_APPEND _O_APPEND|_O_BINARY +#else // not an MSC compiler (use the old defines) +#define O_RDONLY _O_RDONLY +#define O_RDWR _O_RDWR +#define O_WRONLY _O_WRONLY +#define O_CREAT _O_CREAT +#define O_TRUNC _O_TRUNC +#define O_APPEND _O_APPEND +#endif // not an MSC compiler +#endif // WIN32 + +#ifdef FFIO +#include <ffio.h> +static struct ffsw ffopens_status; +//#define open(x,y,z) ffopens(x,y,z, 0, 0, &ffopens_status, "bufa.bufsize=256.num_buffers=4") +#define LAYERS "" +#ifdef T3E +#define open(x,y,z) ffopens(x,y,S_IWRITE|S_IREAD,0,100,&ffopens_status,LAYERS); +#else // its probably an SGI +#define open(x,y,z) ffopens(x,y,S_IWRITE|S_IREAD,0,0,&ffopens_status,LAYERS); +#endif +#define close(x) ffclose(x) +#endif + +#ifdef T3E +int IEEEIO::ffioIsTrue(){ +#ifdef FFIO + return 1; +#else + return 0; +#endif +} +#endif + + +// int IEEEIO::nextRecord() (stores state in current_record) +// also garauntees integrity of datasetnumber and +// the current_rec and current_dat + +IEEEIO::AttribRef::AttribRef(IEEEIO::AttribRef &src){ + //puts("AttribRef::copy constructor"); + rec=src.rec; + offset=src.offset; + strcpy(name,src.name); +} + +IEEEIO::AttribRef::AttribRef(){ + //puts("empty attribref constructor"); +} +/* +IEEEIO::AttribRef::~AttribRef(){ + //puts("delete an attrib ref"); +} +IEEEIO::RecRef::~RecRef(){ + //puts("delete a recref"); +} +*/ + +IEEEIO::AttribRef &IEEEIO::AttribRef::operator=(IEEEIO::AttribRef &src){ + if(this != &src) { + //puts("\tAttribRef::copy operator"); + rec=src.rec; + offset=src.offset; + //name=src.name; // uses the flexarray copy constructor + strcpy(name,src.name); + } + return *this; +} + +IEEEIO::DataRef::DataRef():end_offset(0){ + //puts("Empty DataRef Constructor!!"); +} + + +IEEEIO::DataRef::DataRef(IEEEIO::DataRef &src){ + //puts("DataRef:: copy constructor"); + rec=src.rec; + offset=src.offset; + end_offset=src.end_offset; + annotations = src.annotations; + attributes = src.attributes; + //puts("DataRef:: copy constructor DONE"); +} +/* +IEEEIO::DataRef::~DataRef(){ + // puts("dataref destructor"); +}*/ + +IEEEIO::DataRef &IEEEIO::DataRef::operator=(IEEEIO::DataRef &src){ + if(this != &src){ + rec=src.rec; + offset=src.offset; + end_offset=src.end_offset; + annotations = src.annotations; + attributes = src.attributes; + } + return *this; +} + +void IEEEIO::initPosition(){ + // init +#ifdef FFIO + actual_position = ::ffseek(fid,0,L_INCR); +#else + actual_position = ::lseek(fid,0,L_INCR); +#endif + virtual_position = actual_position + writebuffercount; + // get actual filesize + +#ifdef FFIO + file_length = ::ffseek(fid,0,L_XTND); + ::ffseek(fid,actual_position,L_SET); // seek back to original pos +#else +#ifdef SGI + file_length = ::lseek64(fid,0,L_XTND); + ::lseek64(fid,actual_position,L_SET); // seek back to original pos +#else + file_length = ::lseek(fid,0,L_XTND); + ::lseek(fid,actual_position,L_SET); // seek back to original pos +#endif +#endif + if(virtual_position > file_length) + file_length = virtual_position; + // printf("Init position: a=%ld v=%ld f=%ld\n", + // actual_position,virtual_position,file_length); +} + + +//long IEEEIO::getPosition(int immediate) { +//#ifdef FFIO +// if(!writebuffer || immediate) +// return ::ffseek(fid,0,L_INCR); +// else +// return ::ffseek(fid,0,L_INCR)+writebuffercount; +//#else +// if(!writebuffer || immediate) +// return ::lseek(fid,0,L_INCR); +// else +// return ::lseek(fid,0,L_INCR)+writebuffercount; +//#endif +//} + +void IEEEIO::restart(){ + // this->initPosition(); + //puts("restart seek"); + IEEEIO::lseek(FileHdrSize,L_SET); // T3E Kludge + //puts("restart"); + current_rec_offset=current_dat_offset=FileHdrSize; // T3E Kludge + current_rec.recordsize=0; + current_dat.datasize=0; + current_dat.rank=0; + datasetnumber=0; // initial + hasread=0; // and it hasn't been read yet... +} + +int IEEEIO::nextRecord(){ + RecordHdr rec; + // should have it check the datasetnumber before seeking + // this will require consistancy checks for the datasetnumber + // elsewhere in the code + Long8 src=current_rec_offset; + Long8 dst=src+current_rec.recordsize; + current_rec_offset=IEEEIO::lseek(dst,L_SET); // seek from start + // or use rec.read(rec,fid) + // or IEEEIO::RecordHdr::read(rec,fid) + if(RecordHdr::read(this,rec) <= 0) + return 0; + current_rec_offset=dst+RecordHdrSize; + current_rec=rec; + return 1; +} + +int IEEEIO::nextDataRecord(){ + hasread=0; // reset the hasread field + if(current_rec.recordtype==DataRecord && + datasetnumber!=current_rec.sequenceID){ + IEEEIO::lseek(current_rec_offset,L_SET); // seek to record start + } + else { + do { // scan through records for the next DataRecord + if(!nextRecord()) + return 0; // reached end of file + } while(current_rec.recordtype!=DataRecord); + } + // dat_offset is same as current_rec_offset for the data record + // so nextRecord() can be used for scanning for annotations + current_dat_offset=current_rec_offset; + DataRecordHdr::read(this,current_dat); + datasetnumber=current_rec.sequenceID; + return 1; +} + +//long IEEEIO::getLength(int immediate){ +//#ifdef FFIO +// long currentpos=::ffseek(fid,0,L_INCR); // find currentposition +// long auspos = ::ffseek(fid,0,L_XTND); // seek to end to find length +//#else +// long currentpos=::lseek(fid,0,L_INCR); // find currentposition +// long auspos = ::lseek(fid,0,L_XTND); // seek to end to find length +//#endif +// if(writebuffer && writebuffercount && !immediate){ +// // must compute real end of file +// register long pos1=currentpos+writebuffercount; +// if(pos1>auspos) auspos=pos1; +// } +//#ifdef FFIO +// ::ffseek(fid,currentpos,L_SET); // seek back to original position +//#else +// ::lseek(fid,currentpos,L_SET); // seek back to original position +//#endif +// return auspos; // return end position +//} + +void IEEEIO::byteswapBuffer(void *buf,Long8 nelements,int elementsize){ + char *buffer=(char *)buf; // treat as a character buffer + if(elementsize<=1) return; + for(Long8 i=0;i<nelements;i++,buffer+=elementsize){ + register int s,d; + register char c; + // do the swap thang on each element + for(s=0,d=elementsize-1;s<d;s++,d--){ + c=buffer[s]; + buffer[s]=buffer[d]; + buffer[d]=c; + } + } +} + +void IEEEIO::byteswapBuffer(void *source,void *dest,Long8 nelements,int elementsize){ + if(elementsize<=1) return; + // Lets optimize for integers + switch(elementsize){ + case 4: + { + Int *src=(Int*)source; + Int *dst=(Int*)dest; + for(Long8 i=0;i<nelements;i++){ + union IntChar { + int i; + char a[4]; + }; + register IntChar ts,td; + // do the swap thang on each element + td.i=ts.i=src[i]; + td.a[0]=ts.a[3]; + td.a[1]=ts.a[2]; + td.a[2]=ts.a[1]; + td.a[3]=ts.a[0]; + dst[i]=td.i; + } + } + break; + //#ifndef WIN32 // Win32 can't have 8byte integers + case 8: + { + Long8 *src=(Long8*)source; + Long8 *dst=(Long8*)dest; + for(long i=0;i<nelements;i++){ + union LongChar { + Long8 l; + char a[8]; + }; + register LongChar ts,td; + // do the swap thang on each element + td.l=ts.l=src[i]; + td.a[0]=ts.a[7]; + td.a[1]=ts.a[6]; + td.a[2]=ts.a[5]; + td.a[3]=ts.a[4]; + td.a[4]=ts.a[3]; + td.a[5]=ts.a[2]; + td.a[6]=ts.a[1]; + td.a[7]=ts.a[0]; + dst[i]=td.l; + } + } + break; + //#endif + default: + { + char *src=(char *)source; // treat as a character buffer + char *dst=(char *)dest; + for(Long8 i=0;i<nelements;i++,src+=elementsize,dst+=elementsize){ + register int s,d; + // do the swap thang on each element + for(s=0,d=elementsize-1;s<d;s++,d--){ + dst[d]=src[s]; + dst[s]=src[d]; + } + } + } + break; + } +} + +int IEEEIO::writeFileHeader(){ + // Long8 pos=getPosition(); // use virtual_position + // this->flush(); + //puts("WriteHeader"); + for(char c=0;c<4;c++) // make sure magic is correct + file_header.magic.c[c]=c+1; + if(swapbytes) + file_header.byteorder.i=IEEE_REVERSE_MAGIC; + else + file_header.byteorder.i=IEEE_NATIVE_MAGIC; + file_header.majorversion = IEEE_MAJORVERSION; + file_header.minorversion = IEEE_MINORVERSION; + IEEEIO::lseek(0,L_SET); // will force a flush (if needed) + //puts("done writeheader seek"); + if(swapbytes) file_header.byteswap(); + // T3E Kludge + int sz=FileHdr::write(this,file_header); + if(swapbytes) file_header.byteswap(); + // if(pos>=FileHdrSize) // T3E Kludge + // IEEEIO::lseek(pos,L_SET); + return sz; +} + +// reads the start of the file (including the magic number) +// and determines if this is +// 1) A valid IEEEIO file +// 2) what the byte order is +// 3) How many datasets are contained +int IEEEIO::readFileHeader(){ + Long8 pos=getPosition(); // use virtual_position + IEEEIO::lseek(0,L_SET); + // T3E Kludge + // int sz=FileHdr::read(this,file_header); + FileHdr::read(this,file_header); + IEEEIO::lseek(pos,L_SET); // return to original position + for(char c=0;c<4;c++){ + if((c+1)!=file_header.magic.c[c]){ + file_header.ndatasets=0; + // fprintf(stderr,"IEEEIO: File %s has the wrong magic number\n",filename); + return -1; // bad magic + } + } + // now compare byte order + if(file_header.byteorder.i==IEEE_NATIVE_MAGIC) + swapbytes=0; + else{ + swapbytes=1; + //puts("byteswapping is On !!!!!!!!!!!!!!!"); + } + if(swapbytes) file_header.byteswap(); + ndatasets=file_header.ndatasets; + return 1; +} + +void IEEEIO::rebuildFileHeader(){ + int lndatasets; + Long8 pos=getPosition(); // save file position (use virtual position + restart(); + // steal seek loop from the nextDataRecord() + for(lndatasets=0; + nextDataRecord()>0; + lndatasets++){ + // now check the length of the record + // for each record. + } + file_header.ndatasets=lndatasets; + writeFileHeader(); + IEEEIO::lseek(pos,L_SET); +} + +void IEEEIO::appendRecordTable(){ + //printf("appending records==================\n"); + while(nextRecord()>0){ + //printf("appending record\n"); + switch(current_rec.recordtype){ + case DataRecord: + //fprintf(stderr,"DataRecord"); + (rec_table[current_rec.sequenceID]).rec=current_rec; + // use virtual_position + (rec_table[current_rec.sequenceID]).offset=getPosition()-RecordHdrSize; + break; + case AnnotationRecord:{ + //fprintf(stderr,"\tAnnotationRecord\n"); + RecRef ref; + ref.rec=current_rec; + ref.offset=getPosition()- RecordHdrSize; // T3E Kludge + (rec_table[current_rec.sequenceID]).annotations.append(ref); + } + break; + case AttributeRecord:{ + //fprintf(stderr,"\tAttributeRecord\n"); + AttribRef ref,*refp; + AttributeRecordHdr attribhdr; + ref.rec=current_rec; + ref.offset=getPosition()- RecordHdrSize; // T3E Kludge + (rec_table[current_rec.sequenceID]).attributes.append(ref); + int idx=(rec_table[current_rec.sequenceID]).attributes.getSize()-1; + refp = &((rec_table[current_rec.sequenceID]).attributes[idx]); + AttributeRecordHdr::read(this,attribhdr); + IEEEIO::read(refp->name,attribhdr.namesize); + } + break; + default: + fprintf(stderr,"\tIEEEIO::Error UNKNOWN RECORD TYPE [%d]... recovering.", + (int)(current_rec.recordtype)); + return; + } + (rec_table[current_rec.sequenceID]).end_offset = + current_rec_offset + current_rec.recordsize; + } +} + +void IEEEIO::buildRecordTable(){ + if(file_header.ndatasets<0) + return; // failure + restart(); + rec_table.setSize(file_header.ndatasets); + appendRecordTable(); +} + +void IEEEIO::openFile(CONST char *fname,IObase::AccessMode access,int swbytes){ + switch(access){ + case IObase::Read: + fid=open(fname,O_RDONLY,0644); + if(fid<0){ + fprintf(stderr,"IEEEIO: Failed to open %s for reading\n",fname); + return; + } + initPosition(); + if(readFileHeader()<=0){ + close(fid); + // fprintf(stderr,"IEEEIO: File %s is empty (opened for reading)\n",fname); + fid=-1; // invalid file + return; + } + if(file_header.ndatasets<0){ + // must recover from crash + close(fid); + fid=open(fname,O_RDWR,0644); + rebuildFileHeader(); + close(fid); + fid=open(fname,O_RDONLY,0644); + readFileHeader(); // reread.. + } + buildRecordTable(); + restart(); // go to start of file + ndatasets = file_header.ndatasets; + nextRecord(); // prime the recordnumber + break; + case IObase::Write: // truncates + fid=open(fname,O_WRONLY|O_CREAT|O_TRUNC,0644); + if(fid<0){ + fprintf(stderr,"IEEEIO: Failed to create %s for writing\n",fname); + return; + } + initPosition(); + file_header.ndatasets=-1; + ndatasets=0; + writeFileHeader(); + restart(); + break; + case IObase::Append: + default: + fid=open(fname,O_RDWR,0644); // PW: We *don't* want O_APPEND here. + // O_Append moves the file ptr to end + // of file before a write; this means + // when we do the writeHeader() below + // this is stuck at the end of this file + // which makes it puke. + if(fid<0){ + fprintf(stderr,"IEEEIO: Failed to open %s for append\n",fname); + return; + } + initPosition(); + if(readFileHeader()<=0){ + close(fid); + fprintf(stderr,"IEEEIO: File %s is empty (opened for append)\n",fname); + fid=-1; // invalid file + return; + } + if(file_header.ndatasets<0){ + // must recover from crash + close(fid); + fid=open(fname,O_RDWR,0644); + initPosition(); + rebuildFileHeader(); + close(fid); + fid=open(fname,O_RDWR,0644); // PW: We want to open RDWR again + initPosition(); + readFileHeader(); // reread.. + } + buildRecordTable(); + restart(); // go to start of file + ndatasets = file_header.ndatasets; + // now we sync up in the way we would for a write + file_header.ndatasets=-1; + writeFileHeader(); // write header with -1 to indicate we are writing + // could refcount by increasing the - of numbers in header + // (needs extra flag for synced) + restart(); + nextRecord(); // prime the recordnumber + //seek(ndatasets); + break; + } +} + +IEEEIO::IEEEIO(IEEEIO *file): // read only dup + IObase(file->filename,IObase::Read),fid(dup(file->fid)), + datasetnumber(0),ndatasets(file->ndatasets), + swapbytes(file->swapbytes),hasread(0), + writebuffersize(0),writebuffercount(0),writebuffer(0), + savedposition(-1),virtual_position(-1),actual_position(-1), + file_length(-1) +{ + if(file->masterfile) masterfile=file->masterfile; + else masterfile=file; + initPosition(); // initial positional pointers + ndatasets = file_header.ndatasets = file->ndatasets; + buildRecordTable(); + restart(); // go to start of file + nextRecord(); // prime the recordnumber +} + + +IEEEIO::IEEEIO(CONST char *fname, ExtendedAccessMode access,int swbytes): + IObase(fname,mode(access)),fid(-1),datasetnumber(0), + ndatasets(0),swapbytes(swbytes),hasread(0),masterfile(0), + writebuffersize(0),writebuffercount(0),writebuffer(0), + savedposition(-1),virtual_position(-1),actual_position(-1), + file_length(-1) +{ + if(access==IEEEIO::SharedRead){ + masterfile=this; // we are multi-reading + fid=open(fname,O_RDONLY,0644); + if(fid<0){ + fprintf(stderr,"IEEEIO: Failed to open %s for reading\n",fname); + return; + } + this->initPosition(); + if(readFileHeader()<=0){ + close(fid); + fprintf(stderr,"IEEEIO: File %s is empty (opened for reading)\n",fname); + fid=-1; // invalid file + return; + } + buildRecordTable(); + restart(); // go to start of file + ndatasets = file_header.ndatasets; + nextRecord(); // prime the recordnumber + } + else + openFile(fname,mode(access),swbytes); +} + +IEEEIO::IEEEIO(CONST char *fname,IObase::AccessMode access,int swbytes): + IObase(fname,access),fid(-1),datasetnumber(0), + ndatasets(0),swapbytes(swbytes),hasread(0),masterfile(0), + writebuffersize(0),writebuffercount(0),writebuffer(0), + savedposition(-1) +{ + // Long8 fpos; + openFile(fname,access,swbytes); +} + +IEEEIO::~IEEEIO(){ + if(fid<0 && savedposition>=0) resume(); + // resume IO only if it is paused so that + // we can do the final writes to the file before + // closing + //puts("do bufferoff"); + if(writebuffer) bufferOff(); // automatically flushes buffer + //puts("now rewrite header"); + if(fid>=0){ + if(accessmode!=IObase::Read){ + file_header.ndatasets=ndatasets; + writeFileHeader(); + } + close(fid); + } + fid=-1; +} + +int IEEEIO::isValid(){ + if(fid>=0) return 1; + else return 0; +} + +int IEEEIO::write(IObase::DataType typeID,int rank,CONST int *dims,void *data){ + int i; + RecordHdr rec; + DataRecordHdr hdr; + // make sure its the EOF + if(accessmode==IObase::Read) return 0; + hasread=0; // reset hasread; (JMS: changed from local Thu Mar 12 13:53:13 CST 1998) + if(rec_table.getSize()>0){ + Long8 endpos = rec_table[rec_table.getSize()-1].end_offset; + IEEEIO::lseek(endpos,L_SET); // don't know if this is costly + } + else + IEEEIO::lseek(0,L_XTND); // seek to end of file + // if 0-length seeks are costly, then alternative + // logic can be constructed to ensure writes to end of file + for(i=0,hdr.datasize=1;i<rank;i++) + hdr.datasize*=dims[i]; + + if(chunkdims.getSize()<rank) + chunkdims.setSize(rank); + for(i=0;i<rank;i++) chunkdims[i]=dims[i]; + + hdr.datasize*=sizeOf(typeID); + hdr.numbertype=typeID; + hdr.rank=rank; + // if last annotation slot is filled, it is a pointer + // to another block of 8 annotation pointers. + rec.recordtype = DataRecord; + rec.recordsize = hdr.datasize + + DataRecordHdrSize + + sizeof(Int) * rank; + rec.sequenceID = datasetnumber = ndatasets++; + // need to byteswap the header and records if swapbytes==True + current_dat=hdr; // first copy native info to current + current_rec=rec; + RecordHdr::write(this,rec); + current_dat_offset=current_rec_offset=getPosition(); + DataRecordHdr::write(this,hdr); + // write the dims.... (byteswap if necessary) + if(swapbytes) byteswapBuffer(chunkdims.getData(),rank,sizeof(Int)); + IEEEIO::write(chunkdims.getData(),sizeof(Int)*rank); + if(swapbytes) byteswapBuffer(chunkdims.getData(),rank,sizeof(Int)); // swap back + if(swapbytes) byteswapBuffer(data,hdr.datasize/sizeOf(typeID),sizeOf(typeID)); + int sz = IEEEIO::write(data,hdr.datasize); + // yeah! double bytswap seem stupid, but consider the alternatives + // write one byte at a time (swapping as we go) == systemcall overhead + // copy to a temporary buffer and swap bytes == malloc, copy, and free! + // strangely its faster to swap twice + if(swapbytes) byteswapBuffer(data,hdr.datasize/sizeOf(typeID),sizeOf(typeID)); + DataRef dref; + dref.rec=current_rec; + // Must find exact size!!! + dref.offset = current_rec_offset - RecordHdrSize; + dref.end_offset = current_rec_offset + current_rec.recordsize; + if(accessmode!=IObase::Write) // do not store if in write-only mode + rec_table.append(dref); + return sz; +} + +//setCurrentRec(offset); +// storing in 8*1024 byte blocks (always aligned to chunk boundaries) +// will result in more efficient seeking behavior due to +// disk block size... thus file is always aligned to unix +// filesystem blocks. (for now, we'll use die method maximo-stupido... +int IEEEIO::readInfo(IObase::DataType &typeID,int &rank,int *dims,int maxdims){ + if(accessmode!=IObase::Read && accessmode!=IObase::Append) + return 0; + //int sz; + if(hasread) datasetnumber++; // increment to the next one if this has been read + if(datasetnumber>=rec_table.getSize()) return 0; // end of file + // read the record + header + hasread=1; // we've read this, so next time we hit it, we'll increment again + IEEEIO::lseek(rec_table[datasetnumber].offset,L_SET); + // T3E Kludge + RecordHdr::read(this,current_rec); + DataRecordHdr::read(this,current_dat); + rank=current_dat.rank; + if(chunkdims.getSize()<rank) chunkdims.setSize(rank); + typeID=Int2DataType(current_dat.numbertype); + IEEEIO::read(chunkdims.getData(),sizeof(Int)*rank); + if(swapbytes) byteswapBuffer(chunkdims.getData(),(rank>maxdims)?maxdims:rank,sizeof(Int)); + + for(int i=0;i<maxdims && i<rank;i++) dims[i]=chunkdims[i]; + streaming=0; + return 1; +} + +/* + It does not appear that the bytswapping is really configured here... + */ +int IEEEIO::read(void *data){ + if(accessmode!=IObase::Read && accessmode!=IObase::Append) + return 0; // can't readif write only + if(datasetnumber>=rec_table.getSize()) return 0; // seek past end. + Long8 datapos=rec_table[datasetnumber].offset+RecordHdrSize+DataRecordHdrSize+ + sizeof(Int)*current_dat.rank; + // should make certain current file position is correct + // if(getPosition() != datapos) (redundant call to lseek()) + IEEEIO::lseek(datapos,L_SET); // seek to position + int sz=IEEEIO::read(data,current_dat.datasize); // read nbytes + int typelen = sizeOf(Int2DataType(current_dat.numbertype));// compute elem sz + if(swapbytes) byteswapBuffer(data,current_dat.datasize/typelen,typelen); + return sz; +} + +int IEEEIO::seek(int idx){ + if(accessmode!=IObase::Read && + accessmode!=IObase::Append) // can't seek unless readable + return -1; // failed to seek + if (idx >= ndatasets || idx < 0) { + return -1; // do a bounds check (probably should just clip) + } + // bound the index + if((1+idx)>rec_table.getSize()) idx=rec_table.getSize(); + if(idx<0) idx=0; + index = idx; + IEEEIO::lseek(rec_table[index].offset,L_SET); + // T3E Kludge + RecordHdr::read(this,current_rec); + current_rec_offset=getPosition(); + datasetnumber=current_rec.sequenceID; // Changed: had -1 + hasread=0; // new file position + return current_rec.sequenceID; +} + +int IEEEIO::nDatasets() { + // can work across threads or across processes since + // it gathers information directly from the file. + // it does not need to share info with masterfile + // in fact you can delete the masterfile + if(masterfile){ // we are passive read-only. update nDatasets + // seek-scan to find datasets? + int oldlength = (rec_table.getSize())?(rec_table[rec_table.getSize()-1].end_offset):0; + //printf("oldlength=%u newlength=%u\n",oldlength,(unsigned int)(getLength())); + if(getLength()>oldlength){ + // lets scan to find the end + int lndatasets; + puts("We should clearly not be here!!!"); + restart(); // go to beginning + // steal seek loop from the nextDataRecord() + for(lndatasets=0; + nextDataRecord()>0; + lndatasets++){ + //printf("scan dataset[%u]\n",lndatasets); + } + file_header.ndatasets = lndatasets; + rec_table.setSize(lndatasets); + // printf("counted %u datasets. old was %u datasets\n",lndatasets,ndatasets); + seek(ndatasets); // seek to current last + ndatasets = lndatasets; // then reset the last + appendRecordTable(); // append new stuff to record table + } + } + return ndatasets; +} + +int IEEEIO::writeAnnotation(CONST char *annotation){ + int stringlen; + RecRef aref; + RecordHdr rec; + if(accessmode==IObase::Read || !annotation) return 0; + stringlen=strlen(annotation)+1; + + if(rec_table.getSize()>0){ + Long8 endpos = rec_table[rec_table.getSize()-1].end_offset; + IEEEIO::lseek(endpos,L_SET); // don't know if this is costly + } + else + IEEEIO::lseek(0,L_XTND); // seek to end of file + + rec.recordtype=AnnotationRecord; + rec.recordsize=stringlen; + if(datasetnumber>=0) rec.sequenceID=datasetnumber; + else rec.sequenceID=current_rec.sequenceID; // a kludge for error immunity + current_rec = rec; + // T3E Kludge + current_rec_offset = getPosition() + RecordHdrSize; + // T3E Kludge + RecordHdr::write(this,rec); + // if(swapbytes) byteswap(rec); + int sz=IEEEIO::write(annotation,stringlen); + + aref.rec=current_rec; + // T3E Kludge + aref.offset=current_rec_offset-RecordHdrSize; + if(accessmode!=IObase::Write){ // don't write to index cache if in write-only mode + rec_table[datasetnumber].annotations.append(aref); + rec_table[datasetnumber].end_offset=getPosition(); + } + return sz; +} +/* + If objects could have all attributes implicitly availible for querying + when passed to subroutines. Basic object methods for data movement like + linearize() or object.linearized[index] object.linearized.size. + Then for objects that a receiver can't deal with either + 1: have compiletime "gatekeepers" that restrict allowable types + that it can receive + 2: Do a treesearch through object space to find a convertor sequence + that can convert the current type into the one that the object + accepts. If no such object can be found, indicate runtime + object adaptor failure. +*/ +int IEEEIO::readAnnotationInfo(int number,int &length){ + if(datasetnumber<0 || + number>=rec_table[datasetnumber].annotations.getSize()){ + length=0; + return -1; + } + length=rec_table[datasetnumber].annotations[number].rec.recordsize; + return length; +} + +int IEEEIO::readAnnotation(int number,char *annotation,int maxsize){ + // returns actual size of annotation or -1 if error + if(datasetnumber<0 || accessmode==IObase::Write || + number>=rec_table[datasetnumber].annotations.getSize()){ + return -1; + } + IEEEIO::lseek(rec_table[datasetnumber].annotations[number].offset,L_SET); + // T3E Kludge + RecordHdr::read(this,current_rec); + IEEEIO::read(annotation,(maxsize<rec_table[datasetnumber].annotations[number].rec.recordsize)? + maxsize:(rec_table[datasetnumber].annotations[number].rec.recordsize)); + annotation[maxsize-1]='\0'; + return rec_table[datasetnumber].annotations[number].rec.recordsize; +} + +int IEEEIO::nAnnotations(){ + if(datasetnumber<0 || accessmode==IObase::Write) + return -1; + return rec_table[datasetnumber].annotations.getSize(); +} + +// for attributes +int IEEEIO::writeAttribute(CONST char *name,IObase::DataType typeID,Long length,void *data){ + int stringlen; + AttribRef aref; + RecordHdr rec; + AttributeRecordHdr attrib; + + if(datasetnumber<0){ + fprintf(stderr,"IEEEIO::writeAttribute(): Error, cannot write attribute before any datasets have been written!\n"); + return 0; + } + if(accessmode==IObase::Read) return 0; + stringlen=strlen(name)+1; + + if(rec_table.getSize()>0){ + Long8 endpos = rec_table[rec_table.getSize()-1].end_offset; + IEEEIO::lseek(endpos,L_SET); // don't know if this is costly + } + else + IEEEIO::lseek(0,L_XTND); // seek to end of file + attrib.datasize=length*sizeOf(typeID); + attrib.namesize=stringlen; + attrib.numbertype=typeID; + rec.recordtype=AttributeRecord; + rec.recordsize=attrib.datasize+attrib.namesize+AttributeRecordHdrSize; + if(datasetnumber>=0) rec.sequenceID=datasetnumber; + else rec.sequenceID=current_rec.sequenceID; // a kludge for error immunity + current_rec=rec; + current_rec_offset=getPosition() + RecordHdrSize; + aref.rec=current_rec; + aref.offset=current_rec_offset-RecordHdrSize; + // no copy constructor for aref, so must do manually + if(accessmode != IObase::Write){ + int lastindex; + rec_table[datasetnumber].attributes.append(aref); + lastindex=rec_table[datasetnumber].attributes.getSize()-1; + strcpy(rec_table[datasetnumber].attributes[lastindex].name,name); + } + // T3E Kludge + RecordHdr::write(this,rec); + AttributeRecordHdr::write(this,attrib); + //printf("\tnow write the string\n"); + IEEEIO::write(name,stringlen); + //printf("\tdone IEEEIO::stringlen=%u typeid=%u\n",attrib.namesize,attrib.numbertype); + // data is not byte-reversed... + int sz=0; + if(swapbytes) byteswapBuffer(data,length,sizeOf(typeID)); + IEEEIO::write(data,length*sizeOf(typeID)); + if(swapbytes) byteswapBuffer(data,length,sizeOf(typeID)); // swap back + if(accessmode != IObase::Write) + rec_table[datasetnumber].end_offset=getPosition(); + // doesn't appear to store attributes properly + return sz; +} + +int IEEEIO::readAttributeInfo(int number,char *name,IObase::DataType &typeID, + Long &nelem,int maxnamelen){ + if(accessmode==IObase::Write) return -1; + FlexArray<AttribRef> *attribs= &(rec_table[datasetnumber].attributes); + if(number>=(*attribs).getSize()) return -1; // > number of attributes + AttribRef *attrib=&((*attribs)[number]); + if(strlen(attrib->name)>(size_t)maxnamelen){ + strncpy(name,attrib->name,maxnamelen); // don't we want to copy the other way? + name[maxnamelen-1]='\0'; + } + else strcpy(name,attrib->name); + name[maxnamelen-1]='\0'; // make certain it is null capped + AttributeRecordHdr attribhdr; + IEEEIO::lseek((*attribs)[number].offset,L_SET); + RecordHdr::read(this,current_rec); + AttributeRecordHdr::read(this,attribhdr); +//printf("IEEEIO:attribrechdr = ds,nt,ns %d,%d,%d\n", +// attribhdr.datasize, +// attribhdr.numbertype, +// attribhdr.namesize); + typeID = Int2DataType(attribhdr.numbertype); + nelem = attribhdr.datasize/sizeOf(typeID); + return -1; +} + +int IEEEIO::readAttributeInfo(CONST char *name,IObase::DataType &typeID,Long &nelem){ + // by name + if(accessmode==IObase::Write) return -1; + FlexArray<AttribRef> *attribs= &(rec_table[datasetnumber].attributes); + for(int i=0;i<attribs->getSize();i++){ + if(!strcmp(name,(*attribs)[i].name)){ + // must read the record to get this info + AttributeRecordHdr attribhdr; + IEEEIO::lseek((*attribs)[i].offset,L_SET); + RecordHdr::read(this,current_rec); + AttributeRecordHdr::read(this,attribhdr); + typeID = Int2DataType(attribhdr.numbertype); + nelem = attribhdr.datasize/sizeOf(typeID); + return i; + } + } + return -1; // Attribute not found +} + +int IEEEIO::readAttribute(int number,void *data){ + if(accessmode==IObase::Write) return -1; + FlexArray<AttribRef> *attribs= &(rec_table[datasetnumber].attributes); + if(number>=(*attribs).getSize()) return -1; // > number of attributes + AttributeRecordHdr attribhdr; + IEEEIO::lseek((*attribs)[number].offset,L_SET); + RecordHdr::read(this,current_rec); + AttributeRecordHdr::read(this,attribhdr); + IObase::DataType typeID = Int2DataType(attribhdr.numbertype); + if(typeID==IObase::Error) return -1; // read failed due to bad datatype + // Long8 nelem = attribhdr.datasize/sizeOf(typeID); + IEEEIO::lseek(attribhdr.namesize,L_INCR); + int sz=IEEEIO::read(data,attribhdr.datasize)/sizeOf(typeID); + if(swapbytes) byteswapBuffer(data,sz,sizeOf(typeID)); + if(typeID==IObase::String){ + char *cdata=(char *)data; + cdata[sz]='\0'; /* Null Terminate String data */ + } + return sz; // returns number of elements read +} + +int IEEEIO::nAttributes(){ + if(datasetnumber<0 || accessmode == IObase::Write) return -1; + return rec_table[datasetnumber].attributes.getSize(); +} + +//================Chunking Interface----------------------- +void IEEEIO::clearChunk(int nbytes){ +#ifdef T3E +#define DISKBLOCKSIZE 128*1024 +#else +#define DISKBLOCKSIZE 8192 +#endif +// This is a wasteful feature that will be eliminated in later releases +// This is currently done because I needed the disk space to be zero'ed +// prior to writing for debugging purposes... Could have a writeStream +// class. + int nwritten; + char dummy[DISKBLOCKSIZE]; + for(int i=0;i<DISKBLOCKSIZE;i++) + dummy[i]=0; // bzero it (reserve space with zero'ed data) + while(nbytes>DISKBLOCKSIZE){ + nwritten=IEEEIO::write(dummy,DISKBLOCKSIZE); + if(nwritten<=0) return; // this aint working + nbytes-=nwritten; + } + if(nbytes>0) IEEEIO::write(dummy,nbytes); // write the remaining bytes +#undef DISKBLOCKSIZE +} + +int IEEEIO::reserveChunk(IObase::DataType typeID,int rank,CONST int *dims){ + reserveStream(typeID,rank,dims); // sets up the chunking state machine + // clearing does not appear to be needed... just need header + //clearChunk(IObase::nBytes(typeID,rank,dims)); // this pre-clears the reserved area to 0. (inefficient) + return 1; +} + +// Chunking should probably include striding.... +// But thats a pain since you'll need to read + write to +// Accomplish that (yuck!). Lots of seeking. +// Lets leave striding out for now. + +// should also check for contiguous data (eg. slicing) and optimize for that layout +// for now, the streaming interface best serves contiguous data. +int IEEEIO::writeChunk(CONST int *dims,CONST int *origin,void *data){ + int i,sz=-1; + // make sure its the EOF + if(accessmode==IObase::Read) { + fprintf(stderr,"IEEEIO::writeChunk(): Error! Access is ReadOnly\n"); + return 0; + } + // should have a "chunk reserved" flag set. + if(current_reserved_chunk!=datasetnumber){ + fprintf(stderr,"IEEEIO::writeChunk(): Error! You forgot to reserve space for the chunk using IO::reserveChunk()\n"); + return 0; + } + + // now we need to seek to the position of the data + int rank = current_dat.rank; + IObase::DataType typeID = IObase::Int2DataType(current_dat.numbertype); + int typesize=sizeOf(typeID); + // Long8 basefileoffset = rec_table[datasetnumber].offset+ + Long8 basefileoffset = stream_offset + + RecordHdrSize+DataRecordHdrSize+sizeof(Int)*current_dat.rank; // T3E Kludge + Long8 chunkcolumnsize=dims[0]*typesize; // stride between columns in chunk + Long8 filecolumnsize=chunkdims[0]*typesize; // stride between columns on disk (full array size) + Long8 originoffset; + Long8 accumdims; + for(originoffset=0,accumdims=typesize,i=0;i<rank;i++){ + originoffset += (origin[i]*accumdims); + accumdims *= chunkdims[i]; + } + for(i=0;i<rank;i++){ + if((origin[i]+dims[i])>chunkdims[i]){ + fprintf(stderr,"IEEEIO::writeChunk(): ERROR!! specified dims and origin exceed reserved block size\n"); + fprintf(stderr,"\tfor dimension %u origin=%u and dims=%u\n",i,origin[i], + dims[i]); + fprintf(stderr,"\torigin+dims=%u whereas the maximum must be less than %u\n",origin[i]+dims[i],chunkdims[i]); + } + } + originoffset+=basefileoffset; // for absolute seeking + Long8 maxindex,minindex; + minindex=basefileoffset; + maxindex=basefileoffset+current_dat.datasize; + int ncolumns; // computed in loop below + for(ncolumns=1,i=1;i<rank;i++) ncolumns*=dims[i]; + if(swapbytes) + byteswapBuffer(data,IObase::nElements(rank,dims),typesize); + for(i=0;i<ncolumns;i++){ // read the columns + if(originoffset<minindex){ + fprintf(stderr,"WriteChunk() inconsistency. Writing less than min index\n"); + fprintf(stderr,"\tCol[%u]: Requested %u, but minidex= %u\n", + i,(unsigned int)originoffset,(unsigned int)minindex); + } + if(originoffset>maxindex){ + fprintf(stderr,"WriteChunk() inconsistency. Writing greater than maximum index\n"); + fprintf(stderr,"\tCol[%u]: Requested %u, but maxindex= %u\n", + i,(unsigned int)originoffset,(unsigned int)maxindex); + } + if((originoffset+chunkcolumnsize)>maxindex){ + fprintf(stderr,"WriteChunk() inconsistency. This write will overrun the reserved data\n"); + fprintf(stderr,"\tCol[%u]: Requested %u, maxindex %u, and the write of %u will run to %u\n", + i,(unsigned int)originoffset,(unsigned int)maxindex,(unsigned int)chunkcolumnsize,(unsigned int)(originoffset+chunkcolumnsize)); + } + IEEEIO::lseek(originoffset,L_SET); + sz=IEEEIO::write(((char*)data)+i*chunkcolumnsize,(int)chunkcolumnsize); + originoffset+=filecolumnsize; + for(Long8 j=1,idx=dims[1],planesize=filecolumnsize; + j<(rank-1) && !((i+1)%idx); + idx*=dims[++j]){ + Long8 extraoffset=planesize*(chunkdims.getData()[j]-dims[j]); + originoffset+=extraoffset; + planesize*=dims[j]; + } + } + // now swap the data back to native order... + if(swapbytes) + byteswapBuffer(data,IObase::nElements(rank,dims),typesize); + + return sz; +} +int IEEEIO::readChunk(CONST int *dims,CONST int *origin,void *data){ + int sz=-1,i; + if(accessmode!=IObase::Read && accessmode!=IObase::Append) + return 0; + // gonna have to stride through this sucker... (yuck) + // use the same chunkdims for this. Must set during readinfo... + // now we need to seek to the position of the data + int rank = current_dat.rank; + IObase::DataType typeID = IObase::Int2DataType(current_dat.numbertype); + int typesize=sizeOf(typeID); + Long8 basefileoffset = rec_table[datasetnumber].offset+ + // sizeof(RecordHdr)+sizeof(DataRecordHdr)+sizeof(Int)*current_dat.rank; + RecordHdrSize+DataRecordHdrSize+sizeof(Int)*current_dat.rank; // T3E Kludge + Long8 chunkcolumnsize=dims[0]*typesize; // stride between columns in chunk + Long8 filecolumnsize=chunkdims[0]*typesize; // stride between columns on disk (full array size) + Long8 originoffset; + Long8 accumdims; + // compute the offset into the data on disk required by the chunk origin (initial offset) + for(originoffset=0,accumdims=typesize,i=0;i<rank;i++){ + originoffset += (origin[i]*accumdims); + accumdims *= chunkdims[i]; + } + originoffset+=basefileoffset; // for absolute seeking + Long8 ncolumns; // computed in loop below + for(ncolumns=1,i=1;i<rank;i++) ncolumns*=dims[i]; + for(i=0;i<ncolumns;i++){ // read the columns + IEEEIO::lseek(originoffset,L_SET); + sz=IEEEIO::read(((char*)data)+i*chunkcolumnsize,(int)chunkcolumnsize); + originoffset+=filecolumnsize; + for(Long8 j=1,idx=dims[1],planesize=filecolumnsize; + j<(rank-1) && !((i+1)%idx); + idx*=dims[++j]){ + Long8 extraoffset=planesize*(chunkdims.getData()[j]-dims[j]); + originoffset+=extraoffset; + planesize*=dims[j]; + } + } + // now swap the data back to native order... + if(swapbytes) + byteswapBuffer(data,IObase::nElements(rank,dims),typesize); + return sz; +} +// Nearly identical to reserveChunk except that we don't need to pre-clear +// the space to 0 for streamed data. +int IEEEIO::reserveStream(IObase::DataType typeID,int rank,CONST int *dims){ + int i; + RecordHdr rec; + DataRecordHdr hdr; + // make sure its the EOF + if(accessmode==IObase::Read) return 0; + + if(rec_table.getSize()>0){ + Long8 endpos = rec_table[rec_table.getSize()-1].end_offset; + IEEEIO::lseek(endpos,L_SET); // don't know if this is costly + } + else { + IEEEIO::lseek(0,L_XTND); // seek to end of file + } + // if 0-length seeks are costly, then alternative + // logic can be constructed to ensure writes to end of file + if(chunkdims.getSize() != rank) + chunkdims.setSize(rank); // KLUDGE! + for(i=0,hdr.datasize=1;i<rank;i++) { + hdr.datasize*=dims[i]; + chunkdims[i]=dims[i]; + } + cur_type_size=sizeOf(typeID); // KLUDGE: for writeStream() + hdr.datasize*=sizeOf(typeID); + hdr.numbertype=typeID; + hdr.rank=rank; + // if last annotation slot is filled, it is a pointer + // to another block of 8 annotation pointers. + rec.recordtype = DataRecord; + rec.recordsize = hdr.datasize + + DataRecordHdrSize + // T3E Kludge + sizeof(Int) * rank; // need to change sizeof(Int) to something larger? For 64, yes! + rec.sequenceID = datasetnumber = ndatasets++; + // need to byteswap the header and records if swapbytes==True + current_dat=hdr; // first copy native info to current + current_rec=rec; + RecordHdr::write(this,rec); + current_dat_offset = current_rec_offset = getPosition(); + DataRecordHdr::write(this,hdr); + if(swapbytes) byteswapBuffer(chunkdims.getData(),rank,sizeof(Int)); + IEEEIO::write(chunkdims.getData(),sizeof(Int)*rank); // for better for worse... + if(swapbytes) byteswapBuffer(chunkdims.getData(),rank,sizeof(Int)); // swap back + // OK, now writing 8k at a time, reserve the space with 0's + current_reserved_chunk=datasetnumber; + DataRef dref; + dref.rec=current_rec; + dref.offset=current_rec_offset-RecordHdrSize; + dref.end_offset=current_rec_offset+current_rec.recordsize; + if(accessmode!=IObase::Write) + rec_table.append(dref); + // else (JMS debugging change 5/12/98) + stream_offset = current_rec_offset-RecordHdrSize; + streaming=0; + return 1; +} + +int IEEEIO::writeStream(void *data,int length){ + Long8 len; + if(!streaming){// seek to starting offset + Long8 basefileoffset = stream_offset + + RecordHdrSize+DataRecordHdrSize+sizeof(Int)*current_dat.rank; + IEEEIO::lseek(basefileoffset,L_SET); + streaming=1; + } + // need to do a bounds check on the stream... for now it'll play dumb... + Long8 nbytes=cur_type_size * length; + len = IEEEIO::write((char *)data,nbytes); // record file position?? + if(len<0) + return -1; // write failure + return len; +} + +int IEEEIO::readStream(void *data,int length){ + int len; + if(!streaming){// seek to starting offset + Long8 basefileoffset = rec_table[datasetnumber].offset+ + RecordHdrSize+DataRecordHdrSize+sizeof(Int)*current_dat.rank; + IEEEIO::lseek(basefileoffset,L_SET); + streaming=1; + } + // need to do a bounds check on the stream... for now it'll play dumb... + int typesize= sizeOf(Int2DataType(current_dat.numbertype)); + Long8 nbytes = typesize * length; + len = IEEEIO::read((char *)data,nbytes); + if(len<0) + return -1; // read failure + else + if(swapbytes) byteswapBuffer(data,length,typesize); + return len; +} + +void IEEEIO::bufferOn(long size){ + if(writebuffer) { + if(size==0) + bufferOff(); + return; + } + else { +// if not Windows, use fstat() to choose optimal blocksiz +#if !defined(WIN32) && !defined(T3E) + if(size<0){ + struct stat mystat; + fstat(fid,&mystat); + size=mystat.st_blksize; + } +#endif + // if windows then take a wild guess +#ifdef T3E + size=(size<=64)?8*1024*1024:size; // 8Meg is a good guess for T3E +#else + size=(size<=64)?8*1024:size; //(8k is a good guess for workstations/WinTel) +#endif +#ifdef SGI + { // allocate the buffer block-aligned (most imp for DirIO) + struct stat mystat; + fstat(fid,&mystat); + writebuffer = (char*)memalign(mystat.st_blksize,size); + } +#else + writebuffer = new char[size]; +#endif + } + writebuffersize=size; + writebuffercount=0; +} + +void IEEEIO::bufferOff(){ + if(!writebuffer) return; + if(fid<0 && writebuffercount>0){ + fprintf(stderr,"IEEEIO::bufferOff() ERROR!!!!"); + fprintf(stderr,"\tFile %s is either paused or invalid, so I can't deallocate the write buffer safely\n",filename); + return; + } + //printf("bufferoff on a=%ld v=%ld f=%ld b=%d\n", + // actual_position,virtual_position,file_length,writebuffercount); + this->flush(); +#ifdef SGI // block-aligned write buffer + free(writebuffer); +#else + delete writebuffer; +#endif + writebuffer=0; +} + +int IEEEIO::pause(){ + if(fid<0) return 0; // fail + this->flush(); // flush the buffer to pause + savedposition=getPosition(); + close(fid); + fid=-1; + return 1; // success +} + +int IEEEIO::resume(){ + if(fid>=0 || savedposition<0) return 0; // fail + switch(IObase::accessmode){ + case IObase::Read: + fid=open(filename,O_RDONLY,0644); + break; + case IObase::Write: + fid=open(filename,O_WRONLY,0644); + break; + case IObase::Append: + fid=open(filename,O_RDWR,0644); + break; + } + if(fid<0){ + printf("IEEEIO::resume failed for file %s\n",filename); + return -1; + } + ::lseek(fid,savedposition,L_SET); // this is OK.. + savedposition=-1; + return 1; // success +} + +//=================== Experimental MPIO methods ================= +void IEEEIO::getFilename(char *fn,int maxlen){ + strncpy(fn,filename,maxlen-1); +} + +int IEEEIO::reserveStream(IObase::DataType typeID,int rank,CONST int *dims,Long8 &soffset){ + int rv=this->reserveStream(typeID,rank,dims); + soffset = stream_offset + RecordHdrSize+DataRecordHdrSize+sizeof(Int)* + current_dat.rank; + return rv; +} + +// writes to explicit offset in file! +// always overrides the current filepointer position! +// only useful for the master process *if* it +// must write to a non-zero location +// *** So the usage scenario is that the master +// has the IEEEIO file handle and getFilename() is +// used to pass the name of the file to the slave procs +// which open it O_WRITE. The master gets the offset +// for a particular stream from the special version +// of the method reserverStream and uses that to position +// their respective file pointers. All slaves and +// the master then write to the file simultaneously to +// different file offsets. It remains to be seen how +// well this works without O_DIRECT. We can use timing +// loops to stagger the writes somewhat though. +int IEEEIO::writeStream(void *data,int length,Long8 soffset){ + IEEEIO::lseek(soffset,L_SET); + streaming=1; + return writeStream(data,length); +} + +/*********************Fortran Interface**********************/ +Long8 f_ieee_open (char *file,char *accessname,int flen,int alen){ + // would have used tolower(), but it doesn't exist everywhere.... :( + IObase::AccessMode mode; + if(*accessname=='R' || *accessname=='r') + mode=IObase::Read; + else if(*accessname=='W' || *accessname=='w' || + *accessname=='C' || *accessname=='c') + mode=IObase::Write; + else if(*accessname=='A' || *accessname=='a') + mode=IObase::Append; + else { + fprintf(stderr,"IEEEopen(): Error unknown option [%s] to open file %s\n", + accessname,file); + return 0; + } + IObase *fid=new IEEEIO(file,mode); + if(fid->isValid()) + return (Long8)fid; + else + delete fid; // file open failed + return 0; +} + +Long8 f_ieee_openr(char *filename,int namelen){ + filename[namelen]='\0'; + return (Long8)(new IEEEIO(filename,IObase::Read)); +} + +Long8 f_ieee_openw(char *filename,int namelen){ + filename[namelen]='\0'; + return (Long8)(new IEEEIO(filename,IObase::Write)); +} + +Long8 f_ieee_opena(char *filename,int namelen){ + filename[namelen]='\0'; + return (Long8)(new IEEEIO(filename,IObase::Append)); +} + +void ieee_bufon(Long8 *fileID,int bufsize){ + IEEEIO *f=(IEEEIO*)(*fileID); + if(bufsize<0) f->bufferOn(); // use default size + else f->bufferOn(bufsize); // or specify +} + +void ieee_bufoff(Long8 *fileID){ + IEEEIO *f=(IEEEIO*)(*fileID); + f->bufferOff(); +} + +IOFile IEEEopen(char *filename,char *accessname){ + // Parse all of the ansi stdio access option strings + IObase::AccessMode mode; + if(!strcmp(accessname,"read") || + !strcmp(accessname,"r") || + !strcmp(accessname,"rb")) + mode=IObase::Read; + else if(*accessname=='a') + mode=IObase::Append; + else if(!strcmp(accessname,"write") || + !strcmp(accessname,"create") || + !strcmp(accessname,"w") || + !strcmp(accessname,"wb") || + !strcmp(accessname,"w+") || + !strcmp(accessname,"w+b") || + !strcmp(accessname,"wb+")) + mode=IObase::Write; + else{ + fprintf(stderr,"IEEEopen(): Error unknown option [%s] to open file %s\n", + accessname,filename); + return 0; + } + IObase *fid=new IEEEIO(filename,mode); + if(fid->isValid()) + return (IOFile)fid; + else + delete fid; // file open failed + return 0; // unknown option +} + +IOFile IEEEopenRead(char *filename){ + return (IOFile)(new IEEEIO(filename,IObase::Read)); +} + +IOFile IEEEopenWrite(char *filename){ + return (IOFile)(new IEEEIO(filename,IObase::Create)); +} + +IOFile IEEEopenAppend(char *filename){ + return (IOFile)(new IEEEIO(filename,IObase::Append)); +} + +void IEEEbufferOn(IOFile fileID,int bufsize){ + IEEEIO *f=(IEEEIO*)fileID; + if(bufsize<0) f->bufferOn(); // use default size + else f->bufferOn(bufsize); // or specify +} + +void IEEEbufferOff(IOFile fileID){ + IEEEIO *f=(IEEEIO*)fileID; + f->bufferOff(); +} + |