/* This file, buffers.c, contains the core set of FITSIO routines */ /* that use or manage the internal set of IO buffers. */ /* The FITSIO software was written by William Pence at the High Energy */ /* Astrophysic Science Archive Research Center (HEASARC) at the NASA */ /* Goddard Space Flight Center. */ #include #include #include "fitsio2.h" static char iobuffer[NIOBUF][IOBUFLEN]; /* initialize to zero by default */ static FITSfile *bufptr[NIOBUF]; /* initialize to zero by default */ static long bufrecnum[NIOBUF]; /* initialize to zero by default */ static int dirty[NIOBUF], ageindex[NIOBUF]; /* ages get initialized in ffwhbf */ /*--------------------------------------------------------------------------*/ int ffmbyt(fitsfile *fptr, /* I - FITS file pointer */ LONGLONG bytepos, /* I - byte position in file to move to */ int err_mode, /* I - 1=ignore error, 0 = return error */ int *status) /* IO - error status */ { /* Move to the input byte location in the file. When writing to a file, a move may sometimes be made to a position beyond the current EOF. The err_mode parameter determines whether such conditions should be returned as an error or simply ignored. */ long record; if (*status > 0) return(*status); if (bytepos < 0) return(*status = NEG_FILE_POS); if (fptr->HDUposition != (fptr->Fptr)->curhdu) ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status); record = (long) (bytepos / IOBUFLEN); /* zero-indexed record number */ /* if this is not the current record, then load it */ if ( ((fptr->Fptr)->curbuf < 0) || (record != bufrecnum[(fptr->Fptr)->curbuf])) ffldrc(fptr, record, err_mode, status); if (*status <= 0) (fptr->Fptr)->bytepos = bytepos; /* save new file position */ return(*status); } /*--------------------------------------------------------------------------*/ int ffpbyt(fitsfile *fptr, /* I - FITS file pointer */ LONGLONG nbytes, /* I - number of bytes to write */ void *buffer, /* I - buffer containing the bytes to write */ int *status) /* IO - error status */ /* put (write) the buffer of bytes to the output FITS file, starting at the current file position. Write large blocks of data directly to disk; write smaller segments to intermediate IO buffers to improve efficiency. */ { int ii, nbuff; LONGLONG filepos; long recstart, recend; long ntodo, bufpos, nspace, nwrite; char *cptr; if (*status > 0) return(*status); if (fptr->HDUposition != (fptr->Fptr)->curhdu) ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status); cptr = (char *)buffer; ntodo = (long) nbytes; if ((fptr->Fptr)->curbuf < 0) /* no current data buffer for this file */ { /* so reload the last one that was used */ ffldrc(fptr, (long) (((fptr->Fptr)->bytepos) / IOBUFLEN), REPORT_EOF, status); } if (nbytes >= MINDIRECT) { /* write large blocks of data directly to disk instead of via buffers */ /* first, fill up the current IO buffer before flushing it to disk */ nbuff = (fptr->Fptr)->curbuf; /* current IO buffer number */ filepos = (fptr->Fptr)->bytepos; /* save the write starting position */ recstart = bufrecnum[nbuff]; /* starting record */ recend = (long) ((filepos + nbytes - 1) / IOBUFLEN); /* ending record */ /* bufpos is the starting position within the IO buffer */ bufpos = (long) (filepos - ((LONGLONG)recstart * IOBUFLEN)); nspace = IOBUFLEN - bufpos; /* amount of space left in the buffer */ if (nspace) { /* fill up the IO buffer */ memcpy(iobuffer[nbuff] + bufpos, cptr, nspace); ntodo -= nspace; /* decrement remaining number of bytes */ cptr += nspace; /* increment user buffer pointer */ filepos += nspace; /* increment file position pointer */ dirty[nbuff] = TRUE; /* mark record as having been modified */ } for (ii = 0; ii < NIOBUF; ii++) /* flush any affected buffers to disk */ { if (bufptr[ii] == fptr->Fptr && bufrecnum[ii] >= recstart && bufrecnum[ii] <= recend ) { if (dirty[ii]) /* flush modified buffer to disk */ ffbfwt(ii, status); bufptr[ii] = NULL; /* disassociate buffer from the file */ } } /* move to the correct write position */ if ((fptr->Fptr)->io_pos != filepos) ffseek(fptr->Fptr, filepos); nwrite = ((ntodo - 1) / IOBUFLEN) * IOBUFLEN; /* don't write last buff */ ffwrite(fptr->Fptr, nwrite, cptr, status); /* write the data */ ntodo -= nwrite; /* decrement remaining number of bytes */ cptr += nwrite; /* increment user buffer pointer */ (fptr->Fptr)->io_pos = filepos + nwrite; /* update the file position */ if ((fptr->Fptr)->io_pos >= (fptr->Fptr)->filesize) /* at the EOF? */ { (fptr->Fptr)->filesize = (fptr->Fptr)->io_pos; /* increment file size */ /* initialize the current buffer with the correct fill value */ if ((fptr->Fptr)->hdutype == ASCII_TBL) memset(iobuffer[nbuff], 32, IOBUFLEN); /* blank fill */ else memset(iobuffer[nbuff], 0, IOBUFLEN); /* zero fill */ } else { /* read next record */ ffread(fptr->Fptr, IOBUFLEN, iobuffer[nbuff], status); (fptr->Fptr)->io_pos += IOBUFLEN; } /* copy remaining bytes from user buffer into current IO buffer */ memcpy(iobuffer[nbuff], cptr, ntodo); dirty[nbuff] = TRUE; /* mark record as having been modified */ bufrecnum[nbuff] = recend; /* record number */ bufptr[nbuff] = fptr->Fptr; /* file pointer associated with IO buffer */ (fptr->Fptr)->logfilesize = maxvalue((fptr->Fptr)->logfilesize, (LONGLONG)(recend + 1) * IOBUFLEN); (fptr->Fptr)->bytepos = filepos + nwrite + ntodo; } else { /* bufpos is the starting position in IO buffer */ bufpos = (long) ((fptr->Fptr)->bytepos - ((LONGLONG)bufrecnum[(fptr->Fptr)->curbuf] * IOBUFLEN)); nspace = IOBUFLEN - bufpos; /* amount of space left in the buffer */ while (ntodo) { nwrite = minvalue(ntodo, nspace); /* copy bytes from user's buffer to the IO buffer */ memcpy(iobuffer[(fptr->Fptr)->curbuf] + bufpos, cptr, nwrite); ntodo -= nwrite; /* decrement remaining number of bytes */ cptr += nwrite; (fptr->Fptr)->bytepos += nwrite; /* increment file position pointer */ dirty[(fptr->Fptr)->curbuf] = TRUE; /* mark record as modified */ if (ntodo) /* load next record into a buffer */ { ffldrc(fptr, (long) ((fptr->Fptr)->bytepos / IOBUFLEN), IGNORE_EOF, status); bufpos = 0; nspace = IOBUFLEN; } } } return(*status); } /*--------------------------------------------------------------------------*/ int ffpbytoff(fitsfile *fptr, /* I - FITS file pointer */ long gsize, /* I - size of each group of bytes */ long ngroups, /* I - number of groups to write */ long offset, /* I - size of gap between groups */ void *buffer, /* I - buffer to be written */ int *status) /* IO - error status */ /* put (write) the buffer of bytes to the output FITS file, with an offset between each group of bytes. This function combines ffmbyt and ffpbyt for increased efficiency. */ { int bcurrent; long ii, bufpos, nspace, nwrite, record; char *cptr, *ioptr; if (*status > 0) return(*status); if (fptr->HDUposition != (fptr->Fptr)->curhdu) ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status); if ((fptr->Fptr)->curbuf < 0) /* no current data buffer for this file */ { /* so reload the last one that was used */ ffldrc(fptr, (long) (((fptr->Fptr)->bytepos) / IOBUFLEN), REPORT_EOF, status); } cptr = (char *)buffer; bcurrent = (fptr->Fptr)->curbuf; /* number of the current IO buffer */ record = bufrecnum[bcurrent]; /* zero-indexed record number */ bufpos = (long) ((fptr->Fptr)->bytepos - ((LONGLONG)record * IOBUFLEN)); /* start pos */ nspace = IOBUFLEN - bufpos; /* amount of space left in buffer */ ioptr = iobuffer[bcurrent] + bufpos; for (ii = 1; ii < ngroups; ii++) /* write all but the last group */ { /* copy bytes from user's buffer to the IO buffer */ nwrite = minvalue(gsize, nspace); memcpy(ioptr, cptr, nwrite); cptr += nwrite; /* increment buffer pointer */ if (nwrite < gsize) /* entire group did not fit */ { dirty[bcurrent] = TRUE; /* mark record as having been modified */ record++; ffldrc(fptr, record, IGNORE_EOF, status); /* load next record */ bcurrent = (fptr->Fptr)->curbuf; ioptr = iobuffer[bcurrent]; nwrite = gsize - nwrite; memcpy(ioptr, cptr, nwrite); cptr += nwrite; /* increment buffer pointer */ ioptr += (offset + nwrite); /* increment IO buffer pointer */ nspace = IOBUFLEN - offset - nwrite; /* amount of space left */ } else { ioptr += (offset + nwrite); /* increment IO bufer pointer */ nspace -= (offset + nwrite); } if (nspace <= 0) /* beyond current record? */ { dirty[bcurrent] = TRUE; record += ((IOBUFLEN - nspace) / IOBUFLEN); /* new record number */ ffldrc(fptr, record, IGNORE_EOF, status); bcurrent = (fptr->Fptr)->curbuf; bufpos = (-nspace) % IOBUFLEN; /* starting buffer pos */ nspace = IOBUFLEN - bufpos; ioptr = iobuffer[bcurrent] + bufpos; } } /* now write the last group */ nwrite = minvalue(gsize, nspace); memcpy(ioptr, cptr, nwrite); cptr += nwrite; /* increment buffer pointer */ if (nwrite < gsize) /* entire group did not fit */ { dirty[bcurrent] = TRUE; /* mark record as having been modified */ record++; ffldrc(fptr, record, IGNORE_EOF, status); /* load next record */ bcurrent = (fptr->Fptr)->curbuf; ioptr = iobuffer[bcurrent]; nwrite = gsize - nwrite; memcpy(ioptr, cptr, nwrite); } dirty[bcurrent] = TRUE; /* mark record as having been modified */ (fptr->Fptr)->bytepos = (fptr->Fptr)->bytepos + (ngroups * gsize) + (ngroups - 1) * offset; return(*status); } /*--------------------------------------------------------------------------*/ int ffgbyt(fitsfile *fptr, /* I - FITS file pointer */ LONGLONG nbytes, /* I - number of bytes to read */ void *buffer, /* O - buffer to read into */ int *status) /* IO - error status */ /* get (read) the requested number of bytes from the file, starting at the current file position. Read large blocks of data directly from disk; read smaller segments via intermediate IO buffers to improve efficiency. */ { int ii; LONGLONG filepos; long recstart, recend, ntodo, bufpos, nspace, nread; char *cptr; if (*status > 0) return(*status); if (fptr->HDUposition != (fptr->Fptr)->curhdu) ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status); cptr = (char *)buffer; if (nbytes >= MINDIRECT) { /* read large blocks of data directly from disk instead of via buffers */ filepos = (fptr->Fptr)->bytepos; /* save the read starting position */ /* note that in this case, ffmbyt has not been called, and so */ /* bufrecnum[(fptr->Fptr)->curbuf] does not point to the intended */ /* output buffer */ recstart = (long) (filepos / IOBUFLEN); /* starting record */ recend = (long) ((filepos + nbytes - 1) / IOBUFLEN); /* ending record */ for (ii = 0; ii < NIOBUF; ii++) /* flush any affected buffers to disk */ { if (dirty[ii] && bufptr[ii] == fptr->Fptr && bufrecnum[ii] >= recstart && bufrecnum[ii] <= recend) { ffbfwt(ii, status); /* flush modified buffer to disk */ } } /* move to the correct read position */ if ((fptr->Fptr)->io_pos != filepos) ffseek(fptr->Fptr, filepos); ffread(fptr->Fptr, (long) nbytes, cptr, status); /* read the data */ (fptr->Fptr)->io_pos = filepos + nbytes; /* update the file position */ } else { /* read small chucks of data using the IO buffers for efficiency */ if ((fptr->Fptr)->curbuf < 0) /* no current data buffer for this file */ { /* so reload the last one that was used */ ffldrc(fptr, (long) (((fptr->Fptr)->bytepos) / IOBUFLEN), REPORT_EOF, status); } /* bufpos is the starting position in IO buffer */ bufpos = (long) ((fptr->Fptr)->bytepos - ((LONGLONG)bufrecnum[(fptr->Fptr)->curbuf] * IOBUFLEN)); nspace = IOBUFLEN - bufpos; /* amount of space left in the buffer */ ntodo = (long) nbytes; while (ntodo) { nread = minvalue(ntodo, nspace); /* copy bytes from IO buffer to user's buffer */ memcpy(cptr, iobuffer[(fptr->Fptr)->curbuf] + bufpos, nread); ntodo -= nread; /* decrement remaining number of bytes */ cptr += nread; (fptr->Fptr)->bytepos += nread; /* increment file position pointer */ if (ntodo) /* load next record into a buffer */ { ffldrc(fptr, (long) ((fptr->Fptr)->bytepos / IOBUFLEN), REPORT_EOF, status); bufpos = 0; nspace = IOBUFLEN; } } } return(*status); } /*--------------------------------------------------------------------------*/ int ffgbytoff(fitsfile *fptr, /* I - FITS file pointer */ long gsize, /* I - size of each group of bytes */ long ngroups, /* I - number of groups to read */ long offset, /* I - size of gap between groups (may be < 0) */ void *buffer, /* I - buffer to be filled */ int *status) /* IO - error status */ /* get (read) the requested number of bytes from the file, starting at the current file position. This function combines ffmbyt and ffgbyt for increased efficiency. */ { int bcurrent; long ii, bufpos, nspace, nread, record; char *cptr, *ioptr; if (*status > 0) return(*status); if (fptr->HDUposition != (fptr->Fptr)->curhdu) ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status); if ((fptr->Fptr)->curbuf < 0) /* no current data buffer for this file */ { /* so reload the last one that was used */ ffldrc(fptr, (long) (((fptr->Fptr)->bytepos) / IOBUFLEN), REPORT_EOF, status); } cptr = (char *)buffer; bcurrent = (fptr->Fptr)->curbuf; /* number of the current IO buffer */ record = bufrecnum[bcurrent]; /* zero-indexed record number */ bufpos = (long) ((fptr->Fptr)->bytepos - ((LONGLONG)record * IOBUFLEN)); /* start pos */ nspace = IOBUFLEN - bufpos; /* amount of space left in buffer */ ioptr = iobuffer[bcurrent] + bufpos; for (ii = 1; ii < ngroups; ii++) /* read all but the last group */ { /* copy bytes from IO buffer to the user's buffer */ nread = minvalue(gsize, nspace); memcpy(cptr, ioptr, nread); cptr += nread; /* increment buffer pointer */ if (nread < gsize) /* entire group did not fit */ { record++; ffldrc(fptr, record, REPORT_EOF, status); /* load next record */ bcurrent = (fptr->Fptr)->curbuf; ioptr = iobuffer[bcurrent]; nread = gsize - nread; memcpy(cptr, ioptr, nread); cptr += nread; /* increment buffer pointer */ ioptr += (offset + nread); /* increment IO buffer pointer */ nspace = IOBUFLEN - offset - nread; /* amount of space left */ } else { ioptr += (offset + nread); /* increment IO bufer pointer */ nspace -= (offset + nread); } if (nspace <= 0 || nspace > IOBUFLEN) /* beyond current record? */ { if (nspace <= 0) { record += ((IOBUFLEN - nspace) / IOBUFLEN); /* new record number */ bufpos = (-nspace) % IOBUFLEN; /* starting buffer pos */ } else { record -= ((nspace - 1 ) / IOBUFLEN); /* new record number */ bufpos = IOBUFLEN - (nspace % IOBUFLEN); /* starting buffer pos */ } ffldrc(fptr, record, REPORT_EOF, status); bcurrent = (fptr->Fptr)->curbuf; nspace = IOBUFLEN - bufpos; ioptr = iobuffer[bcurrent] + bufpos; } } /* now read the last group */ nread = minvalue(gsize, nspace); memcpy(cptr, ioptr, nread); cptr += nread; /* increment buffer pointer */ if (nread < gsize) /* entire group did not fit */ { record++; ffldrc(fptr, record, REPORT_EOF, status); /* load next record */ bcurrent = (fptr->Fptr)->curbuf; ioptr = iobuffer[bcurrent]; nread = gsize - nread; memcpy(cptr, ioptr, nread); } (fptr->Fptr)->bytepos = (fptr->Fptr)->bytepos + (ngroups * gsize) + (ngroups - 1) * offset; return(*status); } /*--------------------------------------------------------------------------*/ int ffldrc(fitsfile *fptr, /* I - FITS file pointer */ long record, /* I - record number to be loaded */ int err_mode, /* I - 1=ignore EOF, 0 = return EOF error */ int *status) /* IO - error status */ { /* low-level routine to load a specified record from a file into a physical buffer, if it is not already loaded. Reset all pointers to make this the new current record for that file. Update ages of all the physical buffers. */ int ibuff, nbuff; LONGLONG rstart; /* check if record is already loaded in one of the buffers */ /* search from youngest to oldest buffer for efficiency */ if (fptr->HDUposition != (fptr->Fptr)->curhdu) ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status); for (ibuff = NIOBUF - 1; ibuff >= 0; ibuff--) { nbuff = ageindex[ibuff]; if (bufptr[nbuff] == fptr->Fptr && record == bufrecnum[nbuff]) goto updatebuf; /* use 'goto' for efficiency */ } /* record is not already loaded */ rstart = (LONGLONG)record * IOBUFLEN; if ( !err_mode && (rstart >= (fptr->Fptr)->logfilesize) ) /* EOF? */ return(*status = END_OF_FILE); if (ffwhbf(fptr, &nbuff) < 0) /* which buffer should we reuse? */ return(*status = TOO_MANY_FILES); if (dirty[nbuff]) ffbfwt(nbuff, status); /* write dirty buffer to disk */ if (rstart >= (fptr->Fptr)->filesize) /* EOF? */ { /* initialize an empty buffer with the correct fill value */ if ((fptr->Fptr)->hdutype == ASCII_TBL) memset(iobuffer[nbuff], 32, IOBUFLEN); /* blank fill */ else memset(iobuffer[nbuff], 0, IOBUFLEN); /* zero fill */ (fptr->Fptr)->logfilesize = maxvalue((fptr->Fptr)->logfilesize, rstart + IOBUFLEN); dirty[nbuff] = TRUE; /* mark record as having been modified */ } else /* not EOF, so read record from disk */ { if ((fptr->Fptr)->io_pos != rstart) ffseek(fptr->Fptr, rstart); ffread(fptr->Fptr, IOBUFLEN, iobuffer[nbuff], status); (fptr->Fptr)->io_pos = rstart + IOBUFLEN; /* set new IO position */ } bufptr[nbuff] = fptr->Fptr; /* file pointer for this buffer */ bufrecnum[nbuff] = record; /* record number contained in buffer */ updatebuf: (fptr->Fptr)->curbuf = nbuff; /* this is the current buffer for this file */ if (ibuff < 0) { /* find the current position of the buffer in the age index */ for (ibuff = 0; ibuff < NIOBUF; ibuff++) if (ageindex[ibuff] == nbuff) break; } /* increment the age of all the buffers that were younger than it */ for (ibuff++; ibuff < NIOBUF; ibuff++) ageindex[ibuff - 1] = ageindex[ibuff]; ageindex[NIOBUF - 1] = nbuff; /* this is now the youngest buffer */ return(*status); } /*--------------------------------------------------------------------------*/ int ffwhbf(fitsfile *fptr, /* I - FITS file pointer */ int *nbuff) /* O - which buffer to use */ { /* decide which buffer to (re)use to hold a new file record */ int ii, ibuff; static int ageinit = 0; if (!ageinit) /* first time thru, initialize default age of buffers */ { for (ii = 0; ii < NIOBUF; ii++) ageindex[ii] = ii; ageinit = 1; } for (ii = 0; ii < NIOBUF; ii++) { ibuff = ageindex[ii]; /* search from the oldest to youngest buffer */ if (bufptr[ibuff] == NULL || /* if buffer is empty, or */ bufptr[ibuff]->curbuf != ibuff) /* is not the current buffer */ return(*nbuff = ibuff); /* then choose this buffer */ } /* all the buffers are locked, so we have to reuse the current one */ /* If there is no current buffer (e.g., file has just been opened) */ /* then use the oldest buffer. */ if ((fptr->Fptr)->curbuf < 0) { bufptr[ageindex[0]]->curbuf = -1; /* this buffer no longer contains */ /* the current buffer of another file */ return(*nbuff = ageindex[0]); /* return oldest buffer */ } else { return(*nbuff = (fptr->Fptr)->curbuf); /* return current buffer */ } } /*--------------------------------------------------------------------------*/ int ffflus(fitsfile *fptr, /* I - FITS file pointer */ int *status) /* IO - error status */ /* Flush all the data in the current FITS file to disk. This ensures that if the program subsequently dies, the disk FITS file will be closed correctly. */ { int hdunum, hdutype; if (*status > 0) return(*status); ffghdn(fptr, &hdunum); /* get the current HDU number */ if (ffchdu(fptr,status) > 0) /* close out the current HDU */ ffpmsg("ffflus could not close the current HDU."); ffflsh(fptr, FALSE, status); /* flush any modified IO buffers to disk */ if (ffgext(fptr, hdunum - 1, &hdutype, status) > 0) /* reopen HDU */ ffpmsg("ffflus could not reopen the current HDU."); return(*status); } /*--------------------------------------------------------------------------*/ int ffflsh(fitsfile *fptr, /* I - FITS file pointer */ int clearbuf, /* I - also clear buffer contents? */ int *status) /* IO - error status */ { /* flush all dirty IO buffers associated with the file to disk */ int ii; /* no need to move to a different HDU if (fptr->HDUposition != (fptr->Fptr)->curhdu) ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status); */ for (ii = 0; ii < NIOBUF; ii++) { if (bufptr[ii] == fptr->Fptr) { if (dirty[ii]) /* flush modified buffer to disk */ ffbfwt(ii, status); if (clearbuf) bufptr[ii] = NULL; /* set contents of buffer as undefined */ } } if (*status != READONLY_FILE) ffflushx(fptr->Fptr); /* flush system buffers to disk */ return(*status); } /*--------------------------------------------------------------------------*/ int ffbfeof(fitsfile *fptr, /* I - FITS file pointer */ int *status) /* IO - error status */ { /* clear any buffers beyond the end of file */ int ii; for (ii = 0; ii < NIOBUF; ii++) { if (bufptr[ii] == fptr->Fptr) { if ( (LONGLONG) bufrecnum[ii] * IOBUFLEN >= fptr->Fptr->filesize) { bufptr[ii] = NULL; /* set contents of buffer as undefined */ } } } return(*status); } /*--------------------------------------------------------------------------*/ int ffbfwt(int nbuff, /* I - which buffer to write */ int *status) /* IO - error status */ { /* write contents of buffer to file; If the position of the buffer is beyond the current EOF, then the file may need to be extended with fill values, and/or with the contents of some of the other i/o buffers. */ FITSfile *Fptr; int ii,ibuff; long jj, irec, minrec, nloop; LONGLONG filepos; static char zeros[IOBUFLEN]; /* initialized to zero by default */ Fptr = bufptr[nbuff]; if (!(Fptr->writemode) ) { ffpmsg("Error: trying to write to READONLY file."); dirty[nbuff] = FALSE; /* reset buffer status to prevent later probs */ *status = READONLY_FILE; return(*status); } filepos = (LONGLONG)bufrecnum[nbuff] * IOBUFLEN; if (filepos <= Fptr->filesize) { /* record is located within current file, so just write it */ /* move to the correct write position */ if (Fptr->io_pos != filepos) ffseek(Fptr, filepos); ffwrite(Fptr, IOBUFLEN, iobuffer[nbuff], status); Fptr->io_pos = filepos + IOBUFLEN; if (filepos == Fptr->filesize) /* appended new record? */ Fptr->filesize += IOBUFLEN; /* increment the file size */ dirty[nbuff] = FALSE; } else /* if record is beyond the EOF, append any other records */ /* and/or insert fill values if necessary */ { /* move to EOF */ if (Fptr->io_pos != Fptr->filesize) ffseek(Fptr, Fptr->filesize); ibuff = NIOBUF; /* initialize to impossible value */ while(ibuff != nbuff) /* repeat until requested buffer is written */ { minrec = (long) (Fptr->filesize / IOBUFLEN); /* write lowest record beyond the EOF first */ irec = bufrecnum[nbuff]; /* initially point to the requested buffer */ ibuff = nbuff; for (ii = 0; ii < NIOBUF; ii++) { if (bufptr[ii] == Fptr && bufrecnum[ii] >= minrec && bufrecnum[ii] < irec) { irec = bufrecnum[ii]; /* found a lower record */ ibuff = ii; } } filepos = (LONGLONG)irec * IOBUFLEN; /* byte offset of record in file */ /* append 1 or more fill records if necessary */ if (filepos > Fptr->filesize) { nloop = (long) ((filepos - (Fptr->filesize)) / IOBUFLEN); for (jj = 0; jj < nloop && !(*status); jj++) ffwrite(Fptr, IOBUFLEN, zeros, status); /* ffseek(Fptr, filepos); */ Fptr->filesize = filepos; /* increment the file size */ } /* write the buffer itself */ ffwrite(Fptr, IOBUFLEN, iobuffer[ibuff], status); dirty[ibuff] = FALSE; Fptr->filesize += IOBUFLEN; /* increment the file size */ } /* loop back if more buffers need to be written */ Fptr->io_pos = Fptr->filesize; /* currently positioned at EOF */ } return(*status); } /*--------------------------------------------------------------------------*/ int ffgrsz( fitsfile *fptr, /* I - FITS file pionter */ long *ndata, /* O - optimal amount of data to access */ int *status) /* IO - error status */ /* Returns an optimal value for the number of rows in a binary table or the number of pixels in an image that should be read or written at one time for maximum efficiency. Accessing more data than this may cause excessive flushing and rereading of buffers to/from disk. */ { int nfiles, typecode, bytesperpixel; long repeat, width; /* There are NIOBUF internal buffers available each IOBUFLEN bytes long. */ if (fptr->HDUposition != (fptr->Fptr)->curhdu) ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status); else if ((fptr->Fptr)->datastart == DATA_UNDEFINED) if ( ffrdef(fptr, status) > 0) /* rescan header to get hdu struct */ return(*status); /* determine how many different FITS files are currently open */ nfiles = fits_get_num_files(); /* one buffer (at least) is always allocated to each open file */ if ((fptr->Fptr)->hdutype == IMAGE_HDU ) /* calc pixels per buffer size */ { /* image pixels are in column 2 of the 'table' */ ffgtcl(fptr, 2, &typecode, &repeat, &width, status); bytesperpixel = typecode / 10; *ndata = ((NIOBUF - nfiles) * IOBUFLEN) / bytesperpixel; } else /* calc number of rows that fit in buffers */ { *ndata = (long) (((NIOBUF - nfiles) * IOBUFLEN) / maxvalue(1, (fptr->Fptr)->rowlength)); *ndata = maxvalue(1, *ndata); } return(*status); } /*--------------------------------------------------------------------------*/ int fits_get_num_files(void) /* Returns the number of FITS files currently opened in CFITSIO */ { int ii, jj, unique, nfiles; /* determine how many different FITS files are currently open */ nfiles = 0; for (ii = 0; ii < NIOBUF; ii++) { if (bufptr[ii]) { unique = TRUE; for (jj = 0; jj < ii; jj++) { if (bufptr[ii] == bufptr[jj]) { unique = FALSE; break; } } if (unique) nfiles++; } } return(nfiles); } /*--------------------------------------------------------------------------*/ int ffgtbb(fitsfile *fptr, /* I - FITS file pointer */ LONGLONG firstrow, /* I - starting row (1 = first row) */ LONGLONG firstchar, /* I - starting byte in row (1=first) */ LONGLONG nchars, /* I - number of bytes to read */ unsigned char *values, /* I - array of bytes to read */ int *status) /* IO - error status */ /* read a consecutive string of bytes from an ascii or binary table. This will span multiple rows of the table if nchars + firstchar is greater than the length of a row. */ { LONGLONG bytepos, endrow; if (*status > 0 || nchars <= 0) return(*status); else if (firstrow < 1) return(*status=BAD_ROW_NUM); else if (firstchar < 1) return(*status=BAD_ELEM_NUM); if (fptr->HDUposition != (fptr->Fptr)->curhdu) ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status); /* check that we do not exceed number of rows in the table */ endrow = ((firstchar + nchars - 2) / (fptr->Fptr)->rowlength) + firstrow; if (endrow > (fptr->Fptr)->numrows) { ffpmsg("attempt to read past end of table (ffgtbb)"); return(*status=BAD_ROW_NUM); } /* move the i/o pointer to the start of the sequence of characters */ bytepos = (fptr->Fptr)->datastart + ((fptr->Fptr)->rowlength * (firstrow - 1)) + firstchar - 1; ffmbyt(fptr, bytepos, REPORT_EOF, status); ffgbyt(fptr, nchars, values, status); /* read the bytes */ return(*status); } /*--------------------------------------------------------------------------*/ int ffgi1b(fitsfile *fptr, /* I - FITS file pointer */ LONGLONG byteloc, /* I - position within file to start reading */ long nvals, /* I - number of pixels to read */ long incre, /* I - byte increment between pixels */ unsigned char *values, /* O - returned array of values */ int *status) /* IO - error status */ /* get (read) the array of values from the FITS file, doing machine dependent format conversion (e.g. byte-swapping) if necessary. */ { LONGLONG postemp; if (incre == 1) /* read all the values at once (contiguous bytes) */ { if (nvals < MINDIRECT) /* read normally via IO buffers */ { ffmbyt(fptr, byteloc, REPORT_EOF, status); ffgbyt(fptr, nvals, values, status); } else /* read directly from disk, bypassing IO buffers */ { postemp = (fptr->Fptr)->bytepos; /* store current file position */ (fptr->Fptr)->bytepos = byteloc; /* set to the desired position */ ffgbyt(fptr, nvals, values, status); (fptr->Fptr)->bytepos = postemp; /* reset to original position */ } } else /* have to read each value individually (not contiguous ) */ { ffmbyt(fptr, byteloc, REPORT_EOF, status); ffgbytoff(fptr, 1, nvals, incre - 1, values, status); } return(*status); } /*--------------------------------------------------------------------------*/ int ffgi2b(fitsfile *fptr, /* I - FITS file pointer */ LONGLONG byteloc, /* I - position within file to start reading */ long nvals, /* I - number of pixels to read */ long incre, /* I - byte increment between pixels */ short *values, /* O - returned array of values */ int *status) /* IO - error status */ /* get (read) the array of values from the FITS file, doing machine dependent format conversion (e.g. byte-swapping) if necessary. */ { LONGLONG postemp; if (incre == 2) /* read all the values at once (contiguous bytes) */ { if (nvals * 2 < MINDIRECT) /* read normally via IO buffers */ { ffmbyt(fptr, byteloc, REPORT_EOF, status); ffgbyt(fptr, nvals * 2, values, status); } else /* read directly from disk, bypassing IO buffers */ { postemp = (fptr->Fptr)->bytepos; /* store current file position */ (fptr->Fptr)->bytepos = byteloc; /* set to the desired position */ ffgbyt(fptr, nvals * 2, values, status); (fptr->Fptr)->bytepos = postemp; /* reset to original position */ } } else /* have to read each value individually (not contiguous ) */ { ffmbyt(fptr, byteloc, REPORT_EOF, status); ffgbytoff(fptr, 2, nvals, incre - 2, values, status); } #if BYTESWAPPED ffswap2(values, nvals); /* reverse order of bytes in each value */ #endif return(*status); } /*--------------------------------------------------------------------------*/ int ffgi4b(fitsfile *fptr, /* I - FITS file pointer */ LONGLONG byteloc, /* I - position within file to start reading */ long nvals, /* I - number of pixels to read */ long incre, /* I - byte increment between pixels */ INT32BIT *values, /* O - returned array of values */ int *status) /* IO - error status */ /* get (read) the array of values from the FITS file, doing machine dependent format conversion (e.g. byte-swapping) if necessary. */ { LONGLONG postemp; if (incre == 4) /* read all the values at once (contiguous bytes) */ { if (nvals * 4 < MINDIRECT) /* read normally via IO buffers */ { ffmbyt(fptr, byteloc, REPORT_EOF, status); ffgbyt(fptr, nvals * 4, values, status); } else /* read directly from disk, bypassing IO buffers */ { postemp = (fptr->Fptr)->bytepos; /* store current file position */ (fptr->Fptr)->bytepos = byteloc; /* set to the desired position */ ffgbyt(fptr, nvals * 4, values, status); (fptr->Fptr)->bytepos = postemp; /* reset to original position */ } } else /* have to read each value individually (not contiguous ) */ { ffmbyt(fptr, byteloc, REPORT_EOF, status); ffgbytoff(fptr, 4, nvals, incre - 4, values, status); } #if BYTESWAPPED ffswap4(values, nvals); /* reverse order of bytes in each value */ #endif return(*status); } /*--------------------------------------------------------------------------*/ int ffgi8b(fitsfile *fptr, /* I - FITS file pointer */ LONGLONG byteloc, /* I - position within file to start reading */ long nvals, /* I - number of pixels to read */ long incre, /* I - byte increment between pixels */ long *values, /* O - returned array of values */ int *status) /* IO - error status */ /* get (read) the array of values from the FITS file, doing machine dependent format conversion (e.g. byte-swapping) if necessary. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! This routine reads 'nvals' 8-byte integers into 'values'. This works both on platforms that have sizeof(long) = 64, and 32, as long as 'values' has been allocated to large enough to hold 8 * nvals bytes of data. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ { LONGLONG postemp; if (incre == 8) /* read all the values at once (contiguous bytes) */ { if (nvals * 8 < MINDIRECT) /* read normally via IO buffers */ { ffmbyt(fptr, byteloc, REPORT_EOF, status); ffgbyt(fptr, nvals * 8, values, status); } else /* read directly from disk, bypassing IO buffers */ { postemp = (fptr->Fptr)->bytepos; /* store current file position */ (fptr->Fptr)->bytepos = byteloc; /* set to the desired position */ ffgbyt(fptr, nvals * 8, values, status); (fptr->Fptr)->bytepos = postemp; /* reset to original position */ } } else /* have to read each value individually (not contiguous ) */ { ffmbyt(fptr, byteloc, REPORT_EOF, status); ffgbytoff(fptr, 8, nvals, incre - 8, values, status); } #if BYTESWAPPED ffswap8((double *) values, nvals); /* reverse bytes in each value */ #endif return(*status); } /*--------------------------------------------------------------------------*/ int ffgr4b(fitsfile *fptr, /* I - FITS file pointer */ LONGLONG byteloc, /* I - position within file to start reading */ long nvals, /* I - number of pixels to read */ long incre, /* I - byte increment between pixels */ float *values, /* O - returned array of values */ int *status) /* IO - error status */ /* get (read) the array of values from the FITS file, doing machine dependent format conversion (e.g. byte-swapping) if necessary. */ { LONGLONG postemp; #if MACHINE == VAXVMS long ii; #elif (MACHINE == ALPHAVMS) && (FLOATTYPE == GFLOAT) short *sptr; long ii; #endif if (incre == 4) /* read all the values at once (contiguous bytes) */ { if (nvals * 4 < MINDIRECT) /* read normally via IO buffers */ { ffmbyt(fptr, byteloc, REPORT_EOF, status); ffgbyt(fptr, nvals * 4, values, status); } else /* read directly from disk, bypassing IO buffers */ { postemp = (fptr->Fptr)->bytepos; /* store current file position */ (fptr->Fptr)->bytepos = byteloc; /* set to the desired position */ ffgbyt(fptr, nvals * 4, values, status); (fptr->Fptr)->bytepos = postemp; /* reset to original position */ } } else /* have to read each value individually (not contiguous ) */ { ffmbyt(fptr, byteloc, REPORT_EOF, status); ffgbytoff(fptr, 4, nvals, incre - 4, values, status); } #if MACHINE == VAXVMS ii = nvals; /* call VAX macro routine to convert */ ieevur(values, values, &ii); /* from IEEE float -> F float */ #elif (MACHINE == ALPHAVMS) && (FLOATTYPE == GFLOAT) ffswap2( (short *) values, nvals * 2); /* swap pairs of bytes */ /* convert from IEEE float format to VMS GFLOAT float format */ sptr = (short *) values; for (ii = 0; ii < nvals; ii++, sptr += 2) { if (!fnan(*sptr) ) /* test for NaN or underflow */ values[ii] *= 4.0; } #elif BYTESWAPPED ffswap4((INT32BIT *)values, nvals); /* reverse order of bytes in values */ #endif return(*status); } /*--------------------------------------------------------------------------*/ int ffgr8b(fitsfile *fptr, /* I - FITS file pointer */ LONGLONG byteloc, /* I - position within file to start reading */ long nvals, /* I - number of pixels to read */ long incre, /* I - byte increment between pixels */ double *values, /* O - returned array of values */ int *status) /* IO - error status */ /* get (read) the array of values from the FITS file, doing machine dependent format conversion (e.g. byte-swapping) if necessary. */ { LONGLONG postemp; #if MACHINE == VAXVMS long ii; #elif (MACHINE == ALPHAVMS) && (FLOATTYPE == GFLOAT) short *sptr; long ii; #endif if (incre == 8) /* read all the values at once (contiguous bytes) */ { if (nvals * 8 < MINDIRECT) /* read normally via IO buffers */ { ffmbyt(fptr, byteloc, REPORT_EOF, status); ffgbyt(fptr, nvals * 8, values, status); } else /* read directly from disk, bypassing IO buffers */ { postemp = (fptr->Fptr)->bytepos; /* store current file position */ (fptr->Fptr)->bytepos = byteloc; /* set to the desired position */ ffgbyt(fptr, nvals * 8, values, status); (fptr->Fptr)->bytepos = postemp; /* reset to original position */ } } else /* have to read each value individually (not contiguous ) */ { ffmbyt(fptr, byteloc, REPORT_EOF, status); ffgbytoff(fptr, 8, nvals, incre - 8, values, status); } #if MACHINE == VAXVMS ii = nvals; /* call VAX macro routine to convert */ ieevud(values, values, &ii); /* from IEEE float -> D float */ #elif (MACHINE == ALPHAVMS) && (FLOATTYPE == GFLOAT) ffswap2( (short *) values, nvals * 4); /* swap pairs of bytes */ /* convert from IEEE float format to VMS GFLOAT float format */ sptr = (short *) values; for (ii = 0; ii < nvals; ii++, sptr += 4) { if (!dnan(*sptr) ) /* test for NaN or underflow */ values[ii] *= 4.0; } #elif BYTESWAPPED ffswap8(values, nvals); /* reverse order of bytes in each value */ #endif return(*status); } /*--------------------------------------------------------------------------*/ int ffptbb(fitsfile *fptr, /* I - FITS file pointer */ LONGLONG firstrow, /* I - starting row (1 = first row) */ LONGLONG firstchar, /* I - starting byte in row (1=first) */ LONGLONG nchars, /* I - number of bytes to write */ unsigned char *values, /* I - array of bytes to write */ int *status) /* IO - error status */ /* write a consecutive string of bytes to an ascii or binary table. This will span multiple rows of the table if nchars + firstchar is greater than the length of a row. */ { LONGLONG bytepos, endrow, nrows; char message[81]; if (*status > 0 || nchars <= 0) return(*status); else if (firstrow < 1) return(*status=BAD_ROW_NUM); else if (firstchar < 1) return(*status=BAD_ELEM_NUM); if (fptr->HDUposition != (fptr->Fptr)->curhdu) ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status); else if ((fptr->Fptr)->datastart < 0) /* rescan header if data undefined */ ffrdef(fptr, status); endrow = ((firstchar + nchars - 2) / (fptr->Fptr)->rowlength) + firstrow; /* check if we are writing beyond the current end of table */ if (endrow > (fptr->Fptr)->numrows) { /* if there are more HDUs following the current one, or */ /* if there is a data heap, then we must insert space */ /* for the new rows. */ if ( !((fptr->Fptr)->lasthdu) || (fptr->Fptr)->heapsize > 0) { nrows = endrow - ((fptr->Fptr)->numrows); /* ffirow also updates the heap address and numrows */ if (ffirow(fptr, (fptr->Fptr)->numrows, nrows, status) > 0) { sprintf(message, "ffptbb failed to add space for %.0f new rows in table.", (double) nrows); ffpmsg(message); return(*status); } } else { /* manally update heap starting address */ (fptr->Fptr)->heapstart += ((LONGLONG)(endrow - (fptr->Fptr)->numrows) * (fptr->Fptr)->rowlength ); (fptr->Fptr)->numrows = endrow; /* update number of rows */ } } /* move the i/o pointer to the start of the sequence of characters */ bytepos = (fptr->Fptr)->datastart + ((fptr->Fptr)->rowlength * (firstrow - 1)) + firstchar - 1; ffmbyt(fptr, bytepos, IGNORE_EOF, status); ffpbyt(fptr, nchars, values, status); /* write the bytes */ return(*status); } /*--------------------------------------------------------------------------*/ int ffpi1b(fitsfile *fptr, /* I - FITS file pointer */ long nvals, /* I - number of pixels in the values array */ long incre, /* I - byte increment between pixels */ unsigned char *values, /* I - array of values to write */ int *status) /* IO - error status */ /* put (write) the array of values to the FITS file, doing machine dependent format conversion (e.g. byte-swapping) if necessary. */ { if (incre == 1) /* write all the values at once (contiguous bytes) */ ffpbyt(fptr, nvals, values, status); else /* have to write each value individually (not contiguous ) */ ffpbytoff(fptr, 1, nvals, incre - 1, values, status); return(*status); } /*--------------------------------------------------------------------------*/ int ffpi2b(fitsfile *fptr, /* I - FITS file pointer */ long nvals, /* I - number of pixels in the values array */ long incre, /* I - byte increment between pixels */ short *values, /* I - array of values to write */ int *status) /* IO - error status */ /* put (write) the array of values to the FITS file, doing machine dependent format conversion (e.g. byte-swapping) if necessary. */ { #if BYTESWAPPED ffswap2(values, nvals); /* reverse order of bytes in each value */ #endif if (incre == 2) /* write all the values at once (contiguous bytes) */ ffpbyt(fptr, nvals * 2, values, status); else /* have to write each value individually (not contiguous ) */ ffpbytoff(fptr, 2, nvals, incre - 2, values, status); return(*status); } /*--------------------------------------------------------------------------*/ int ffpi4b(fitsfile *fptr, /* I - FITS file pointer */ long nvals, /* I - number of pixels in the values array */ long incre, /* I - byte increment between pixels */ INT32BIT *values, /* I - array of values to write */ int *status) /* IO - error status */ /* put (write) the array of values to the FITS file, doing machine dependent format conversion (e.g. byte-swapping) if necessary. */ { #if BYTESWAPPED ffswap4(values, nvals); /* reverse order of bytes in each value */ #endif if (incre == 4) /* write all the values at once (contiguous bytes) */ ffpbyt(fptr, nvals * 4, values, status); else /* have to write each value individually (not contiguous ) */ ffpbytoff(fptr, 4, nvals, incre - 4, values, status); return(*status); } /*--------------------------------------------------------------------------*/ int ffpi8b(fitsfile *fptr, /* I - FITS file pointer */ long nvals, /* I - number of pixels in the values array */ long incre, /* I - byte increment between pixels */ long *values, /* I - array of values to write */ int *status) /* IO - error status */ /* put (write) the array of values to the FITS file, doing machine dependent format conversion (e.g. byte-swapping) if necessary. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! This routine writes 'nvals' 8-byte integers from 'values'. This works both on platforms that have sizeof(long) = 64, and 32, as long as 'values' has been allocated to large enough to hold 8 * nvals bytes of data. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ { #if BYTESWAPPED ffswap8((double *) values, nvals); /* reverse bytes in each value */ #endif if (incre == 8) /* write all the values at once (contiguous bytes) */ ffpbyt(fptr, nvals * 8, values, status); else /* have to write each value individually (not contiguous ) */ ffpbytoff(fptr, 8, nvals, incre - 8, values, status); return(*status); } /*--------------------------------------------------------------------------*/ int ffpr4b(fitsfile *fptr, /* I - FITS file pointer */ long nvals, /* I - number of pixels in the values array */ long incre, /* I - byte increment between pixels */ float *values, /* I - array of values to write */ int *status) /* IO - error status */ /* put (write) the array of values to the FITS file, doing machine dependent format conversion (e.g. byte-swapping) if necessary. */ { #if MACHINE == VAXVMS long ii; ii = nvals; /* call VAX macro routine to convert */ ieevpr(values, values, &ii); /* from F float -> IEEE float */ #elif (MACHINE == ALPHAVMS) && (FLOATTYPE == GFLOAT) long ii; /* convert from VMS FFLOAT float format to IEEE float format */ for (ii = 0; ii < nvals; ii++) values[ii] *= 0.25; ffswap2( (short *) values, nvals * 2); /* swap pairs of bytes */ #elif BYTESWAPPED ffswap4((INT32BIT *) values, nvals); /* reverse order of bytes in values */ #endif if (incre == 4) /* write all the values at once (contiguous bytes) */ ffpbyt(fptr, nvals * 4, values, status); else /* have to write each value individually (not contiguous ) */ ffpbytoff(fptr, 4, nvals, incre - 4, values, status); return(*status); } /*--------------------------------------------------------------------------*/ int ffpr8b(fitsfile *fptr, /* I - FITS file pointer */ long nvals, /* I - number of pixels in the values array */ long incre, /* I - byte increment between pixels */ double *values, /* I - array of values to write */ int *status) /* IO - error status */ /* put (write) the array of values to the FITS file, doing machine dependent format conversion (e.g. byte-swapping) if necessary. */ { #if MACHINE == VAXVMS long ii; ii = nvals; /* call VAX macro routine to convert */ ieevpd(values, values, &ii); /* from D float -> IEEE float */ #elif (MACHINE == ALPHAVMS) && (FLOATTYPE == GFLOAT) long ii; /* convert from VMS GFLOAT float format to IEEE float format */ for (ii = 0; ii < nvals; ii++) values[ii] *= 0.25; ffswap2( (short *) values, nvals * 4); /* swap pairs of bytes */ #elif BYTESWAPPED ffswap8(values, nvals); /* reverse order of bytes in each value */ #endif if (incre == 8) /* write all the values at once (contiguous bytes) */ ffpbyt(fptr, nvals * 8, values, status); else /* have to write each value individually (not contiguous ) */ ffpbytoff(fptr, 8, nvals, incre - 8, values, status); return(*status); }