diff options
author | William Joye <wjoye@cfa.harvard.edu> | 2016-10-27 18:59:29 (GMT) |
---|---|---|
committer | William Joye <wjoye@cfa.harvard.edu> | 2016-10-27 18:59:29 (GMT) |
commit | d4d595fa7fb12903db9227d33d48b2b00120dbd1 (patch) | |
tree | 7d18365de0d6d1b29399b6a17c7eb01c2eb3ed49 /tksao/wcssubs/fitsfile.c | |
parent | 949f96e29bfe0bd8710d775ce220e597064e2589 (diff) | |
download | blt-d4d595fa7fb12903db9227d33d48b2b00120dbd1.zip blt-d4d595fa7fb12903db9227d33d48b2b00120dbd1.tar.gz blt-d4d595fa7fb12903db9227d33d48b2b00120dbd1.tar.bz2 |
Initial commit
Diffstat (limited to 'tksao/wcssubs/fitsfile.c')
-rw-r--r-- | tksao/wcssubs/fitsfile.c | 2325 |
1 files changed, 2325 insertions, 0 deletions
diff --git a/tksao/wcssubs/fitsfile.c b/tksao/wcssubs/fitsfile.c new file mode 100644 index 0000000..c832687 --- /dev/null +++ b/tksao/wcssubs/fitsfile.c @@ -0,0 +1,2325 @@ +/*** File libwcs/fitsfile.c + *** July 25, 2014 + *** By Jessica Mink, jmink@cfa.harvard.edu + *** Harvard-Smithsonian Center for Astrophysics + *** Copyright (C) 1996-2014 + *** Smithsonian Astrophysical Observatory, Cambridge, MA, USA + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Correspondence concerning WCSTools should be addressed as follows: + Internet email: jmink@cfa.harvard.edu + Postal address: Jessica Mink + Smithsonian Astrophysical Observatory + 60 Garden St. + Cambridge, MA 02138 USA + + * Module: fitsfile.c (FITS file reading and writing) + * Purpose: Read and write FITS image and table files + * fitsropen (inpath) + * Open a FITS file for reading, returning a FILE pointer + * fitsrhead (filename, lhead, nbhead) + * Read FITS header and return it + * fitsrtail (filename, lhead, nbhead) + * Read appended FITS header and return it + * fitsrsect (filename, nbhead, header, fd, x0, y0, nx, ny) + * Read section of a FITS image, having already read the header + * fitsrimage (filename, nbhead, header) + * Read FITS image, having already ready the header + * fitsrfull (filename, nbhead, header) + * Read a FITS image of any dimension + * fitsrtopen (inpath, nk, kw, nrows, nchar, nbhead) + * Open a FITS table file for reading; return header information + * fitsrthead (header, nk, kw, nrows, nchar, nbhead) + * Extract FITS table information from a FITS header + * fitsrtline (fd, nbhead, lbuff, tbuff, irow, nbline, line) + * Read next line of FITS table file + * ftgetr8 (entry, kw) + * Extract column from FITS table line as double + * ftgetr4 (entry, kw) + * Extract column from FITS table line as float + * ftgeti4 (entry, kw) + * Extract column from FITS table line as int + * ftgeti2 (entry, kw) + * Extract column from FITS table line as short + * ftgetc (entry, kw, string, maxchar) + * Extract column from FITS table line as a character string + * fitswimage (filename, header, image) + * Write FITS header and image + * fitswext (filename, header, image) + * Write FITS header and image as extension to existing FITS file + * fitswhdu (fd, filename, header, image) + * Write FITS header and image as extension to file descriptor + * fitscimage (filename, header, filename0) + * Write FITS header and copy FITS image + * fitswhead (filename, header) + * Write FITS header and keep file open for further writing + * fitswexhead (filename, header) + * Write FITS header only to FITS extension without writing data + * isfits (filename) + * Return 1 if file is a FITS file, else 0 + * fitsheadsize (header) + * Return size of FITS header in bytes + */ + +#include <stdlib.h> +#ifndef VMS +#include <unistd.h> +#endif +#include <stdio.h> +#include <fcntl.h> +#include <sys/file.h> +#include <errno.h> +#include <string.h> +#include "fitsfile.h" + +static int verbose=0; /* Print diagnostics */ +static char fitserrmsg[80]; +static int fitsinherit = 1; /* Append primary header to extension header */ +void +setfitsinherit (inh) +int inh; +{fitsinherit = inh; return;} + +static off_t ibhead = 0; /* Number of bytes read before header starts */ + +off_t +getfitsskip() +{return (ibhead);} + +/* FITSRHEAD -- Read a FITS header */ + +char * +fitsrhead (filename, lhead, nbhead) + +char *filename; /* Name of FITS image file */ +int *lhead; /* Allocated length of FITS header in bytes (returned) */ +int *nbhead; /* Number of bytes before start of data (returned) */ + /* This includes all skipped image extensions */ + +{ + int fd; + char *header; /* FITS image header (filled) */ + int extend; + int nbytes,naxis, i; + int ntry,nbr,irec,nrec, nbh, ipos, npos, nbprim, lprim, lext; + int nax1, nax2, nax3, nax4, nbpix, ibpix, nblock, nbskip; + char fitsbuf[2884]; + char *headend; /* Pointer to last line of header */ + char *headnext; /* Pointer to next line of header to be added */ + int hdu; /* header/data unit counter */ + int extnum; /* desired header data number + (0=primary -1=first with data -2=use EXTNAME) */ + char extname[32]; /* FITS extension name */ + char extnam[32]; /* Desired FITS extension name */ + char *ext; /* FITS extension name or number in header, if any */ + char *pheader; /* Primary header (naxis is 0) */ + char cext = 0; + char *rbrac; /* Pointer to right bracket if present in file name */ + char *mwcs; /* Pointer to WCS name separated by % */ + char *newhead; /* New larger header */ + int nbh0; /* Length of old too small header */ + char *pheadend; + int inherit = 1; /* Value of INHERIT keyword in FITS extension header */ + int extfound = 0; /* Set to one if desired FITS extension is found */ + int npcount; + + pheader = NULL; + lprim = 0; + header = NULL; + + /* Check for FITS WCS specification and ignore for file opening */ + mwcs = strchr (filename, '%'); + if (mwcs != NULL) + *mwcs = (char) 0; + + /* Check for FITS extension and ignore for file opening */ + rbrac = NULL; + ext = strchr (filename, ','); + if (ext == NULL) { + ext = strchr (filename, '['); + if (ext != NULL) { + rbrac = strchr (filename, ']'); + if (rbrac != NULL) + *rbrac = (char) 0; + } + } + if (ext != NULL) { + cext = *ext; + *ext = (char) 0; + } + + /* Open the image file and read the header */ + if (strncasecmp (filename,"stdin",5)) { + fd = -1; + fd = fitsropen (filename); + } +#ifndef VMS + else { + fd = STDIN_FILENO; + extnum = -1; + } +#endif + + if (ext != NULL) { + if (isnum (ext+1)) + extnum = atoi (ext+1); + else { + extnum = -2; + strcpy (extnam, ext+1); + } + } + else + extnum = -1; + + /* Repair the damage done to the file-name string during parsing */ + if (ext != NULL) + *ext = cext; + if (rbrac != NULL) + *rbrac = ']'; + if (mwcs != NULL) + *mwcs = '%'; + + if (fd < 0) { + fprintf (stderr,"FITSRHEAD: cannot read file %s\n", filename); + return (NULL); + } + + nbytes = FITSBLOCK; + *nbhead = 0; + headend = NULL; + nbh = FITSBLOCK * 20 + 4; + header = (char *) calloc ((unsigned int) nbh, 1); + (void) hlength (header, nbh); + headnext = header; + nrec = 1; + hdu = 0; + ibhead = 0; + + /* Read FITS header from input file one FITS block at a time */ + irec = 0; + ibhead = 0; + while (irec < 500) { + nbytes = FITSBLOCK; + for (ntry = 0; ntry < 10; ntry++) { + for (i = 0; i < 2884; i++) fitsbuf[i] = 0; + nbr = read (fd, fitsbuf, nbytes); + if (verbose) + fprintf (stderr,"FITSRHEAD: %d header bytes read\n",nbr); + + /* Short records allowed only if they have the last header line */ + if (nbr < nbytes) { + headend = ksearch (fitsbuf,"END"); + if (headend == NULL) { + if (ntry < 9) { + if (verbose) + fprintf (stderr,"FITSRHEAD: %d / %d bytes read %d\n", + nbr,nbytes,ntry); + } + else { + snprintf(fitserrmsg,79,"FITSRHEAD: '%d / %d bytes of header read from %s\n" + ,nbr,nbytes,filename); +#ifndef VMS + if (fd != STDIN_FILENO) +#endif + (void)close (fd); + free (header); + /* if (pheader != NULL) + return (pheader); */ + if (extnum != -1 && !extfound) { + *ext = (char) 0; + if (extnum < 0) { + snprintf (fitserrmsg,79, + "FITSRHEAD: Extension %s not found in file %s", + extnam, filename); + } + else { + snprintf (fitserrmsg,79, + "FITSRHEAD: Extension %d not found in file %s", + extnum, filename); + } + *ext = cext; + } + else if (hdu > 0) { + snprintf (fitserrmsg,79, + "FITSRHEAD: No extensions found in file %s", filename); + hdu = 0; + if (pheader != NULL) { + *lhead = nbprim; + *nbhead = nbprim; + return (pheader); + } + break; + } + else { + snprintf (fitserrmsg,79, + "FITSRHEAD: No header found in file %s", filename); + } + return (NULL); + } + } + else + break; + } + else + break; + } + + /* Replace control characters and nulls with spaces */ + for (i = 0; i < 2880; i++) + if (fitsbuf[i] < 32 || i > nbr) fitsbuf[i] = 32; + if (nbr < 2880) + nbr = 2880; + + /* Move current FITS record into header string */ + strncpy (headnext, fitsbuf, nbr); + *nbhead = *nbhead + nbr; + nrec = nrec + 1; + *(headnext+nbr+1) = 0; + ibhead = ibhead + 2880; + if (verbose) + fprintf (stderr,"FITSRHEAD: %d bytes in header\n",ibhead); + + /* Check to see if this is the final record in this header */ + headend = ksearch (fitsbuf,"END"); + if (headend == NULL) { + + /* Double size of header buffer if too small */ + if (nrec * FITSBLOCK > nbh) { + nbh0 = nbh - 4; + nbh = (nrec * 2 * FITSBLOCK) + 4; + newhead = (char *) calloc (1,(unsigned int) nbh); + if (newhead) { + for (i = 0; i < nbh0; i++) + newhead[i] = header[i]; + free (header); + newhead[nbh-3] = (char) 0; + header = newhead; + (void) hlength (header, nbh); + headnext = header + ((nrec-1) * FITSBLOCK); + } + else { + fprintf (stderr,"FITSRHEAD: %d bytes cannot be allocated for header\n",nbh); + exit (1); + } + } + else + headnext = headnext + FITSBLOCK; + } + + else { + naxis = 0; + hgeti4 (header,"NAXIS",&naxis); + + /* If header has no data, save it for appending to desired header */ + if (naxis < 1) { + nbprim = nrec * FITSBLOCK; + headend = ksearch (header,"END"); + lprim = headend + 80 - header; + pheader = (char *) calloc ((unsigned int) nbprim, 1); + for (i = 0; i < lprim; i++) + pheader[i] = header[i]; + for (i = lprim; i < nbprim; i++) + pheader[i] = ' '; + } + + /* If header has no data, start with the next record */ + if (naxis < 1 && extnum == -1) { + extend = 0; + hgetl (header,"EXTEND",&extend); + if (naxis == 0 && extend) { + headnext = header; + *headend = ' '; + headend = NULL; + nrec = 1; + hdu = hdu + 1; + } + else { + break; + } + } + + /* If this is the desired header data unit, keep it */ + else if (extnum != -1) { + if (extnum > -1 && hdu == extnum) { + extfound = 1; + break; + } + else if (extnum < 0) { + extname[0] = 0; + hgets (header, "EXTNAME", 32, extname); + if (!strcmp (extnam,extname)) { + extfound = 1; + break; + } + } + + /* If this is not desired header data unit, skip over data */ + hdu = hdu + 1; + nblock = 0; + ibhead = 0; + if (naxis > 0) { + ibpix = 0; + hgeti4 (header,"BITPIX",&ibpix); + if (ibpix < 0) { + nbpix = -ibpix / 8; + } + else { + nbpix = ibpix / 8; + } + nax1 = 1; + hgeti4 (header,"NAXIS1",&nax1); + nax2 = 1; + if (naxis > 1) { + hgeti4 (header,"NAXIS2",&nax2); + } + nax3 = 1; + if (naxis > 2) { + hgeti4 (header,"NAXIS3",&nax3); + } + nax4 = 1; + if (naxis > 3) { + hgeti4 (header,"NAXIS4",&nax4); + } + nbskip = nax1 * nax2 * nax3 * nax4 * nbpix; + nblock = nbskip / 2880; + if (nblock*2880 < nbskip) { + nblock = nblock + 1; + } + npcount = 0; + hgeti4 (header,"PCOUNT", &npcount); + if (npcount > 0) { + nbskip = nbskip + npcount; + nblock = nbskip / 2880; + if (nblock*2880 < nbskip) + nblock = nblock + 1; + } + } + else { + nblock = 0; + } + *nbhead = *nbhead + (nblock * 2880); + + /* Set file pointer to beginning of next header/data unit */ + if (nblock > 0) { +#ifndef VMS + if (fd != STDIN_FILENO) { + ipos = lseek (fd, *nbhead, SEEK_SET); + npos = *nbhead; + } + else { +#else + { +#endif + ipos = 0; + for (i = 0; i < nblock; i++) { + nbytes = FITSBLOCK; + nbr = read (fd, fitsbuf, nbytes); + if (nbr < nbytes) { + ipos = ipos + nbr; + break; + } + else { + ipos = ipos + nbytes; + } + } + npos = nblock * 2880; + } + if (ipos < npos) { + snprintf (fitserrmsg,79,"FITSRHEAD: %d / %d bytes skipped\n", + ipos,npos); + extfound = 0; + break; + } + } + headnext = header; + headend = NULL; + nrec = 1; + } + else { + break; + } + } + } + +#ifndef VMS + if (fd != STDIN_FILENO) + (void)close (fd); +#endif + +/* Print error message and return null if extension not found */ + if (extnum != -1 && !extfound) { + if (extnum < 0) + fprintf (stderr, "FITSRHEAD: Extension %s not found in file %s\n",extnam, filename); + else + fprintf (stderr, "FITSRHEAD: Extension %d not found in file %s\n",extnum, filename); + if (pheader != NULL) { + free (pheader); + pheader = NULL; + } + return (NULL); + } + + /* Allocate an extra block for good measure */ + *lhead = (nrec + 1) * FITSBLOCK; + if (*lhead > nbh) { + newhead = (char *) calloc (1,(unsigned int) *lhead); + for (i = 0; i < nbh; i++) + newhead[i] = header[i]; + free (header); + header = newhead; + (void) hlength (header, *lhead); + } + else + *lhead = nbh; + + /* If INHERIT keyword is FALSE, never append primary header */ + if (hgetl (header, "INHERIT", &inherit)) { + if (!inherit && fitsinherit) + fitsinherit = 0; + } + + /* Append primary data header to extension header */ + if (pheader != NULL && extnum != 0 && fitsinherit && hdu > 0) { + extname[0] = 0; + hgets (header, "XTENSION", 32, extname); + if (!strcmp (extname,"IMAGE")) { + strncpy (header, "SIMPLE ", 8); + hputl (header, "SIMPLE", 1); + } + headend = blsearch (header,"END"); + if (headend == NULL) + headend = ksearch (header, "END"); + lext = headend - header; + + /* Update primary header for inclusion at end of extension header */ + hchange (pheader, "SIMPLE", "ROOTHEAD"); + hchange (pheader, "NEXTEND", "NUMEXT"); + hdel (pheader, "BITPIX"); + hdel (pheader, "NAXIS"); + hdel (pheader, "EXTEND"); + hputl (pheader, "ROOTEND",1); + pheadend = ksearch (pheader,"END"); + lprim = pheadend + 320 - pheader; + if (lext + lprim > nbh) { + nrec = (lext + lprim) / FITSBLOCK; + if (FITSBLOCK*nrec < lext+lprim) + nrec = nrec + 1; + *lhead = (nrec+1) * FITSBLOCK; + newhead = (char *) calloc (1,(unsigned int) *lhead); + for (i = 0; i < nbh; i++) + newhead[i] = header[i]; + free (header); + header = newhead; + headend = header + lext; + (void) hlength (header, *lhead); + } + hputs (header,"COMMENT","-------------------------------------------"); + hputs (header,"COMMENT","Information from Primary Header"); + hputs (header,"COMMENT","-------------------------------------------"); + headend = blsearch (header,"END"); + if (headend == NULL) + headend = ksearch (header, "END"); + pheader[lprim] = 0; + strncpy (headend, pheader, lprim); + if (pheader != NULL) { + free (pheader); + pheader = NULL; + } + } + + ibhead = *nbhead - ibhead; + + return (header); +} + + +/* FITSRTAIL -- Read FITS header appended to graphics file */ + +char * +fitsrtail (filename, lhead, nbhead) + +char *filename; /* Name of image file */ +int *lhead; /* Allocated length of FITS header in bytes (returned) */ +int *nbhead; /* Number of bytes before start of data (returned) */ + /* This includes all skipped image extensions */ + +{ + int fd; + char *header; /* FITS image header (filled) */ + int nbytes, i, ndiff; + int nbr, irec; + off_t offset; + char *mwcs; /* Pointer to WCS name separated by % */ + char *headstart; + char *newhead; + + header = NULL; + + /* Check for FITS WCS specification and ignore for file opening */ + mwcs = strchr (filename, '%'); + if (mwcs != NULL) + *mwcs = (char) 0; + + /* Open the image file and read the header */ + if (strncasecmp (filename,"stdin",5)) { + fd = -1; + fd = fitsropen (filename); + } +#ifndef VMS + else { + fd = STDIN_FILENO; + } +#endif + + /* Repair the damage done to the file-name string during parsing */ + if (mwcs != NULL) + *mwcs = '%'; + + if (fd < 0) { + fprintf (stderr,"FITSRTAIL: cannot read file %s\n", filename); + return (NULL); + } + + nbytes = FITSBLOCK; + *nbhead = 0; + *lhead = 0; + + /* Read FITS header from end of input file one FITS block at a time */ + irec = 0; + while (irec < 100) { + nbytes = FITSBLOCK * (irec + 2); + header = (char *) calloc ((unsigned int) nbytes, 1); + offset = lseek (fd, -nbytes, SEEK_END); + if (offset < 0) { + free (header); + header = NULL; + nbytes = 0; + break; + } + for (i = 0; i < nbytes; i++) header[i] = 0; + nbr = read (fd, header, nbytes); + + /* Check for SIMPLE at start of header */ + for (i = 0; i < nbr; i++) + if (header[i] < 32) header[i] = 32; + if ((headstart = ksearch (header,"SIMPLE"))) { + if (headstart != header) { + ndiff = headstart - header; + newhead = (char *) calloc ((unsigned int) nbytes, 1); + for (i = 0; i < nbytes-ndiff; i++) + newhead[i] = headstart[i]; + free (header); + header = newhead; + } + *lhead = nbytes; + *nbhead = nbytes; + break; + } + free (header); + } + (void) hlength (header, nbytes); + +#ifndef VMS + if (fd != STDIN_FILENO) + (void)close (fd); +#endif + + return (header); +} + + +/* FITSRSECT -- Read a piece of a FITS image, having already read the header */ + +char * +fitsrsect (filename, header, nbhead, x0, y0, nx, ny, nlog) + +char *filename; /* Name of FITS image file */ +char *header; /* FITS header for image (previously read) */ +int nbhead; /* Actual length of image header(s) in bytes */ +int x0, y0; /* FITS image coordinate of first pixel */ +int nx; /* Number of columns to read (less than NAXIS1) */ +int ny; /* Number of rows to read (less than NAXIS2) */ +int nlog; /* Note progress mod this rows */ +{ + int fd; /* File descriptor */ + int nbimage, naxis1, naxis2, bytepix, nbread; + int bitpix, naxis, nblocks, nbytes, nbr; + int x1, y1, nbline, nyleft; + off_t impos, nblin; + char *image, *imline, *imlast; + int ilog = 0; + int row; + + /* Open the image file and read the header */ + if (strncasecmp (filename,"stdin", 5)) { + fd = -1; + + fd = fitsropen (filename); + if (fd < 0) { + snprintf (fitserrmsg,79, "FITSRSECT: cannot read file %s\n", filename); + return (NULL); + } + + /* Skip over FITS header and whatever else needs to be skipped */ + if (lseek (fd, nbhead, SEEK_SET) < 0) { + (void)close (fd); + snprintf (fitserrmsg,79, "FITSRSECT: cannot skip header of file %s\n", + filename); + return (NULL); + } + } +#ifndef VMS + else + fd = STDIN_FILENO; +#endif + + /* Compute size of image in bytes using relevant header parameters */ + naxis = 1; + hgeti4 (header,"NAXIS",&naxis); + naxis1 = 1; + hgeti4 (header,"NAXIS1",&naxis1); + naxis2 = 1; + hgeti4 (header,"NAXIS2",&naxis2); + bitpix = 0; + hgeti4 (header,"BITPIX",&bitpix); + if (bitpix == 0) { + /* snprintf (fitserrmsg,79, "FITSRSECT: BITPIX is 0; image not read\n"); */ + (void)close (fd); + return (NULL); + } + bytepix = bitpix / 8; + if (bytepix < 0) bytepix = -bytepix; + + /* Keep X coordinates within image limits */ + if (x0 < 1) + x0 = 1; + else if (x0 > naxis1) + x0 = naxis1; + x1 = x0 + nx - 1; + if (x1 < 1) + x1 = 1; + else if (x1 > naxis1) + x1 = naxis1; + nx = x1 - x0 + 1; + + /* Keep Y coordinates within image limits */ + if (y0 < 1) + y0 = 1; + else if (y0 > naxis2) + y0 = naxis2; + y1 = y0 + ny - 1; + if (y1 < 1) + y1 = 1; + else if (y1 > naxis2) + y1 = naxis2; + ny = y1 - y0 + 1; + + /* Number of bytes in output image */ + nbline = nx * bytepix; + nbimage = nbline * ny; + + /* Set number of bytes to integral number of 2880-byte blocks */ + nblocks = nbimage / FITSBLOCK; + if (nblocks * FITSBLOCK < nbimage) + nblocks = nblocks + 1; + nbytes = nblocks * FITSBLOCK; + + /* Allocate image section to be read */ + image = (char *) malloc (nbytes); + nyleft = ny; + imline = image; + nbr = 0; + + /* Computer pointer to first byte of input image to read */ + nblin = naxis1 * bytepix; + impos = ((y0 - 1) * nblin) + ((x0 - 1) * bytepix); + row = y0 - 1; + + /* Read image section one line at a time */ + while (nyleft-- > 0) { + if (lseek (fd, impos, SEEK_CUR) >= 0) { + nbread = read (fd, imline, nbline); + nbr = nbr + nbread; + impos = nblin - nbread; + imline = imline + nbline; + row++; + if (++ilog == nlog) { + ilog = 0; + fprintf (stderr, "Row %5d extracted ", row); + (void) putc (13,stderr); + } + } + } + if (nlog) + fprintf (stderr, "\n"); + + /* Fill rest of image with zeroes */ + imline = image + nbimage; + imlast = image + nbytes; + while (imline++ < imlast) + *imline = (char) 0; + + /* Byte-reverse image, if necessary */ + if (imswapped ()) + imswap (bitpix, image, nbytes); + + return (image); +} + + +/* FITSRIMAGE -- Read a FITS image */ + +char * +fitsrimage (filename, nbhead, header) + +char *filename; /* Name of FITS image file */ +int nbhead; /* Actual length of image header(s) in bytes */ +char *header; /* FITS header for image (previously read) */ +{ + int fd; + int nbimage, naxis1, naxis2, bytepix, nbread; + int bitpix, naxis, nblocks, nbytes, nbleft, nbr; + int simple; + char *image, *imleft; + + /* Open the image file and read the header */ + if (strncasecmp (filename,"stdin", 5)) { + fd = -1; + + fd = fitsropen (filename); + if (fd < 0) { + snprintf (fitserrmsg,79, "FITSRIMAGE: cannot read file %s\n", filename); + return (NULL); + } + + /* Skip over FITS header and whatever else needs to be skipped */ + if (lseek (fd, nbhead, SEEK_SET) < 0) { + (void)close (fd); + snprintf (fitserrmsg,79, "FITSRIMAGE: cannot skip header of file %s\n", + filename); + return (NULL); + } + } +#ifndef VMS + else + fd = STDIN_FILENO; +#endif + + /* If SIMPLE=F in header, simply put post-header part of file in buffer */ + hgetl (header, "SIMPLE", &simple); + if (!simple) { + nbytes = getfilesize (filename) - nbhead; + if ((image = (char *) malloc (nbytes + 1)) == NULL) { + /* snprintf (fitserrmsg,79, "FITSRIMAGE: %d-byte image buffer cannot be allocated\n"); */ + (void)close (fd); + return (NULL); + } + hputi4 (header, "NBDATA", nbytes); + nbread = read (fd, image, nbytes); + return (image); + } + + /* Compute size of image in bytes using relevant header parameters */ + naxis = 1; + hgeti4 (header,"NAXIS",&naxis); + naxis1 = 1; + hgeti4 (header,"NAXIS1",&naxis1); + naxis2 = 1; + hgeti4 (header,"NAXIS2",&naxis2); + bitpix = 0; + hgeti4 (header,"BITPIX",&bitpix); + if (bitpix == 0) { + /* snprintf (fitserrmsg,79, "FITSRIMAGE: BITPIX is 0; image not read\n"); */ + (void)close (fd); + return (NULL); + } + bytepix = bitpix / 8; + if (bytepix < 0) bytepix = -bytepix; + + /* If either dimension is one and image is 3-D, read all three dimensions */ + if (naxis == 3 && (naxis1 ==1 || naxis2 == 1)) { + int naxis3; + hgeti4 (header,"NAXIS3",&naxis3); + nbimage = naxis1 * naxis2 * naxis3 * bytepix; + } + else + nbimage = naxis1 * naxis2 * bytepix; + + /* Set number of bytes to integral number of 2880-byte blocks */ + nblocks = nbimage / FITSBLOCK; + if (nblocks * FITSBLOCK < nbimage) + nblocks = nblocks + 1; + nbytes = nblocks * FITSBLOCK; + + /* Allocate and read image */ + image = (char *) malloc (nbytes); + nbleft = nbytes; + imleft = image; + nbr = 0; + while (nbleft > 0) { + nbread = read (fd, imleft, nbleft); + nbr = nbr + nbread; +#ifndef VMS + if (fd == STDIN_FILENO && nbread < nbleft && nbread > 0) { + nbleft = nbleft - nbread; + imleft = imleft + nbread; + } + else +#endif + nbleft = 0; + } +#ifndef VMS + if (fd != STDIN_FILENO) + (void)close (fd); +#endif + if (nbr < nbimage) { + snprintf (fitserrmsg,79, "FITSRIMAGE: %d of %d bytes read from file %s\n", + nbr, nbimage, filename); + return (NULL); + } + + /* Byte-reverse image, if necessary */ + if (imswapped ()) + imswap (bitpix, image, nbytes); + + return (image); +} + + +/* FITSRFULL -- Read a FITS image of any dimension */ + +char * +fitsrfull (filename, nbhead, header) + +char *filename; /* Name of FITS image file */ +int nbhead; /* Actual length of image header(s) in bytes */ +char *header; /* FITS header for image (previously read) */ +{ + int fd; + int nbimage, naxisi, iaxis, bytepix, nbread; + int bitpix, naxis, nblocks, nbytes, nbleft, nbr, simple; + char keyword[16]; + char *image, *imleft; + + /* Open the image file and read the header */ + if (strncasecmp (filename,"stdin", 5)) { + fd = -1; + + fd = fitsropen (filename); + if (fd < 0) { + snprintf (fitserrmsg,79, "FITSRFULL: cannot read file %s\n", filename); + return (NULL); + } + + /* Skip over FITS header and whatever else needs to be skipped */ + if (lseek (fd, nbhead, SEEK_SET) < 0) { + (void)close (fd); + snprintf (fitserrmsg,79, "FITSRFULL: cannot skip header of file %s\n", + filename); + return (NULL); + } + } +#ifndef VMS + else + fd = STDIN_FILENO; +#endif + + /* If SIMPLE=F in header, simply put post-header part of file in buffer */ + hgetl (header, "SIMPLE", &simple); + if (!simple) { + nbytes = getfilesize (filename) - nbhead; + if ((image = (char *) malloc (nbytes + 1)) == NULL) { + snprintf (fitserrmsg,79, "FITSRFULL: %d-byte image buffer cannot be allocated\n",nbytes+1); + (void)close (fd); + return (NULL); + } + hputi4 (header, "NBDATA", nbytes); + nbread = read (fd, image, nbytes); + return (image); + } + + /* Find number of bytes per pixel */ + bitpix = 0; + hgeti4 (header,"BITPIX",&bitpix); + if (bitpix == 0) { + snprintf (fitserrmsg,79, "FITSRFULL: BITPIX is 0; image not read\n"); + (void)close (fd); + return (NULL); + } + bytepix = bitpix / 8; + if (bytepix < 0) bytepix = -bytepix; + nbimage = bytepix; + + /* Compute size of image in bytes using relevant header parameters */ + naxis = 1; + hgeti4 (header,"NAXIS",&naxis); + for (iaxis = 1; iaxis <= naxis; iaxis++) { + sprintf (keyword, "NAXIS%d", iaxis); + naxisi = 1; + hgeti4 (header,keyword,&naxisi); + nbimage = nbimage * naxisi; + } + + /* Set number of bytes to integral number of 2880-byte blocks */ + nblocks = nbimage / FITSBLOCK; + if (nblocks * FITSBLOCK < nbimage) + nblocks = nblocks + 1; + nbytes = nblocks * FITSBLOCK; + + /* Allocate and read image */ + image = (char *) malloc (nbytes); + nbleft = nbytes; + imleft = image; + nbr = 0; + while (nbleft > 0) { + nbread = read (fd, imleft, nbleft); + nbr = nbr + nbread; +#ifndef VMS + if (fd == STDIN_FILENO && nbread < nbleft && nbread > 0) { + nbleft = nbleft - nbread; + imleft = imleft + nbread; + } + else +#endif + nbleft = 0; + } +#ifndef VMS + if (fd != STDIN_FILENO) + (void)close (fd); +#endif + if (nbr < nbimage) { + snprintf (fitserrmsg,79, "FITSRFULL: %d of %d image bytes read from file %s\n", + nbr, nbimage, filename); + return (NULL); + } + + /* Byte-reverse image, if necessary */ + if (imswapped ()) + imswap (bitpix, image, nbytes); + + return (image); +} + + +/* FITSROPEN -- Open a FITS file, returning the file descriptor */ + +int +fitsropen (inpath) + +char *inpath; /* Pathname for FITS tables file to read */ + +{ + int ntry; + int fd; /* file descriptor for FITS tables file (returned) */ + char *ext; /* extension name or number */ + char cext = 0; + char *rbrac; + char *mwcs; /* Pointer to WCS name separated by % */ + +/* Check for FITS WCS specification and ignore for file opening */ + mwcs = strchr (inpath, '%'); + +/* Check for FITS extension and ignore for file opening */ + ext = strchr (inpath, ','); + rbrac = NULL; + if (ext == NULL) { + ext = strchr (inpath, '['); + if (ext != NULL) { + rbrac = strchr (inpath, ']'); + } + } + +/* Open input file */ + for (ntry = 0; ntry < 3; ntry++) { + if (ext != NULL) { + cext = *ext; + *ext = 0; + } + if (rbrac != NULL) + *rbrac = (char) 0; + if (mwcs != NULL) + *mwcs = (char) 0; + fd = open (inpath, O_RDONLY); + if (ext != NULL) + *ext = cext; + if (rbrac != NULL) + *rbrac = ']'; + if (mwcs != NULL) + *mwcs = '%'; + if (fd >= 0) + break; + else if (ntry == 2) { + snprintf (fitserrmsg,79, "FITSROPEN: cannot read file %s\n", inpath); + return (-1); + } + } + + if (verbose) + fprintf (stderr,"FITSROPEN: input file %s opened\n",inpath); + + return (fd); +} + + +static int offset1=0; +static int offset2=0; + +/* FITSRTOPEN -- Open FITS table file and fill structure with + * pointers to selected keywords + * Return file descriptor (-1 if unsuccessful) + */ + +int +fitsrtopen (inpath, nk, kw, nrows, nchar, nbhead) + +char *inpath; /* Pathname for FITS tables file to read */ +int *nk; /* Number of keywords to use */ +struct Keyword **kw; /* Structure for desired entries */ +int *nrows; /* Number of rows in table (returned) */ +int *nchar; /* Number of characters in one table row (returned) */ +int *nbhead; /* Number of characters before table starts */ + +{ + char temp[16]; + int fd; + int lhead; /* Maximum length in bytes of FITS header */ + char *header; /* Header for FITS tables file to read */ + +/* Read FITS header from input file */ + header = fitsrhead (inpath, &lhead, nbhead); + if (!header) { + snprintf (fitserrmsg,79,"FITSRTOPEN: %s is not a FITS file\n",inpath); + return (0); + } + +/* Make sure this file is really a FITS table file */ + temp[0] = 0; + (void) hgets (header,"XTENSION",16,temp); + if (strlen (temp) == 0) { + snprintf (fitserrmsg,79, + "FITSRTOPEN: %s is not a FITS table file\n",inpath); + free ((void *) header); + return (0); + } + +/* If it is a FITS file, get table information from the header */ + else if (!strcmp (temp, "TABLE") || !strcmp (temp, "BINTABLE")) { + if (fitsrthead (header, nk, kw, nrows, nchar)) { + snprintf (fitserrmsg,79, + "FITSRTOPEN: Cannot read FITS table from %s\n",inpath); + free ((void *) header); + return (-1); + } + else { + fd = fitsropen (inpath); + offset1 = 0; + offset2 = 0; + free ((void *) header); + return (fd); + } + } + +/* If it is another FITS extension note it and return */ + else { + snprintf (fitserrmsg,79, + "FITSRTOPEN: %s is a %s extension, not table\n", + inpath, temp); + free ((void *) header); + return (0); + } +} + +static struct Keyword *pw; /* Structure for all entries */ +static int *lpnam; /* length of name for each field */ +static int bfields = 0; + +/* FITSRTHEAD -- From FITS table header, read pointers to selected keywords */ + +int +fitsrthead (header, nk, kw, nrows, nchar) + +char *header; /* Header for FITS tables file to read */ +int *nk; /* Number of keywords to use */ +struct Keyword **kw; /* Structure for desired entries */ +int *nrows; /* Number of rows in table (returned) */ +int *nchar; /* Number of characters in one table row (returned) */ + +{ + struct Keyword *rw; /* Structure for desired entries */ + int nfields; + int ifield, ik, i, ikf, ltform, kl; + char *h0, *h1, *tf1, *tf2; + char tname[12]; + char temp[16]; + char tform[16]; + int tverb; + int bintable = 0; + + h0 = header; + +/* Make sure this is really a FITS table file header */ + temp[0] = 0; + hgets (header,"XTENSION",16,temp); + if (strlen (temp) == 0) { + snprintf (fitserrmsg,79, "FITSRTHEAD: Not a FITS table header\n"); + return (-1); + } + else if (!strcmp (temp, "BINTABLE")) { + bintable = 1; + } + else if (strcmp (temp, "TABLE")) { + snprintf (fitserrmsg,79, "FITSRTHEAD: %s extension, not TABLE\n",temp); + return (-1); + } + +/* Get table size from FITS header */ + *nchar = 0; + hgeti4 (header,"NAXIS1",nchar); + *nrows = 0; + hgeti4 (header,"NAXIS2", nrows); + if (*nrows <= 0 || *nchar <= 0) { + snprintf (fitserrmsg,79, "FITSRTHEAD: cannot read %d x %d table\n", + *nrows,*nchar); + return (-1); + } + +/* Set up table for access to individual fields */ + nfields = 0; + hgeti4 (header,"TFIELDS",&nfields); + if (verbose) + fprintf (stderr, "FITSRTHEAD: %d fields per table entry\n", nfields); + if (nfields > bfields) { + if (bfields > 0) + free ((void *)pw); + pw = (struct Keyword *) calloc (nfields, sizeof(struct Keyword)); + if (pw == NULL) { + snprintf (fitserrmsg,79,"FITSRTHEAD: cannot allocate table structure\n"); + return (-1); + } + if (bfields > 0) + free ((void *)lpnam); + lpnam = (int *) calloc (nfields, sizeof(int)); + if (lpnam == NULL) { + snprintf (fitserrmsg,79,"FITSRTHEAD: cannot allocate length structure\n"); + return (-1); + } + bfields = nfields; + } + + tverb = verbose; + verbose = 0; + ikf = 0; + + for (ifield = 0; ifield < nfields; ifield++) { + + /* Name of field */ + for (i = 0; i < 12; i++) tname[i] = 0; + sprintf (tname, "TTYPE%d", ifield+1);; + temp[0] = 0; + h1 = ksearch (h0,tname); + h0 = h1; + hgets (h0,tname,16,temp); + strcpy (pw[ifield].kname,temp); + pw[ifield].lname = strlen (pw[ifield].kname); + + /* Sequence of field on line */ + pw[ifield].kn = ifield + 1; + + /* First column of field */ + if (bintable) + pw[ifield].kf = ikf; + else { + for (i = 0; i < 12; i++) tname[i] = 0; + sprintf (tname, "TBCOL%d", ifield+1); + pw[ifield].kf = 0; + hgeti4 (h0,tname, &pw[ifield].kf); + } + + /* Length of field */ + for (i = 0; i < 12; i++) tname[i] = 0; + sprintf (tname, "TFORM%d", ifield+1);; + tform[0] = 0; + hgets (h0,tname,16,tform); + strcpy (pw[ifield].kform, tform); + ltform = strlen (tform); + if (tform[ltform-1] == 'A') { + pw[ifield].kform[0] = 'A'; + for (i = 0; i < ltform-1; i++) + pw[ifield].kform[i+1] = tform[i]; + pw[ifield].kform[ltform] = (char) 0; + tf1 = pw[ifield].kform + 1; + kl = atof (tf1); + } + else if (!strcmp (tform,"I")) + kl = 2; + else if (!strcmp (tform, "J")) + kl = 4; + else if (!strcmp (tform, "E")) + kl = 4; + else if (!strcmp (tform, "D")) + kl = 8; + else { + tf1 = tform + 1; + tf2 = strchr (tform,'.'); + if (tf2 != NULL) + *tf2 = ' '; + kl = atoi (tf1); + } + pw[ifield].kl = kl; + ikf = ikf + kl; + } + +/* Set up table for access to desired fields */ + verbose = tverb; + if (verbose) + fprintf (stderr, "FITSRTHEAD: %d keywords read\n", *nk); + +/* If nk = 0, allocate and return structures for all table fields */ + if (*nk <= 0) { + *kw = pw; + *nk = nfields; + return (0); + } + else + rw = *kw; + +/* Find each desired keyword in the header */ + for (ik = 0; ik < *nk; ik++) { + if (rw[ik].kn <= 0) { + for (ifield = 0; ifield < nfields; ifield++) { + if (rw[ik].lname != pw[ifield].lname) + continue; + if (strcmp (pw[ifield].kname, rw[ik].kname) == 0) { + break; + } + } + } + else + ifield = rw[ik].kn - 1; + +/* Set pointer, lentth, and name in returned array of structures */ + rw[ik].kn = ifield + 1; + rw[ik].kf = pw[ifield].kf - 1; + rw[ik].kl = pw[ifield].kl; + strcpy (rw[ik].kform, pw[ifield].kform); + strcpy (rw[ik].kname, pw[ifield].kname); + } + + return (0); +} + + +int +fitsrtline (fd, nbhead, lbuff, tbuff, irow, nbline, line) + +int fd; /* File descriptor for FITS file */ +int nbhead; /* Number of bytes in FITS header */ +int lbuff; /* Number of bytes in table buffer */ +char *tbuff; /* FITS table buffer */ +int irow; /* Number of table row to read */ +int nbline; /* Number of bytes to read for this line */ +char *line; /* One line of FITS table (returned) */ + +{ + int nbuff, nlbuff; + int nbr = 0; + int offset, offend, ntry, ioff; + char *tbuff1; + + offset = nbhead + (nbline * irow); + offend = offset + nbline - 1; + +/* Read a new buffer of the FITS table into memory if needed */ + if (offset < offset1 || offend > offset2) { + nlbuff = lbuff / nbline; + nbuff = nlbuff * nbline; + for (ntry = 0; ntry < 3; ntry++) { + ioff = lseek (fd, offset, SEEK_SET); + if (ioff < offset) { + if (ntry == 2) + return (0); + else + continue; + } + nbr = read (fd, tbuff, nbuff); + if (nbr < nbline) { + if (verbose) + fprintf (stderr, "FITSRTLINE: %d / %d bytes read %d\n", + nbr,nbuff,ntry); + if (ntry == 2) + return (nbr); + } + else + break; + } + offset1 = offset; + offset2 = offset + nbr - 1; + strncpy (line, tbuff, nbline); + return (nbline); + } + else { + tbuff1 = tbuff + (offset - offset1); + strncpy (line, tbuff1, nbline); + return (nbline); + } +} + + +void +fitsrtlset () +{ + offset1 = 0; + offset2 = 0; + return; +} + + +/* FTGETI2 -- Extract n'th column from FITS table line as short */ + +short +ftgeti2 (entry, kw) + +char *entry; /* Row or entry from table */ +struct Keyword *kw; /* Table column information from FITS header */ +{ + char temp[30]; + short i; + int j; + float r; + double d; + + if (ftgetc (entry, kw, temp, 30)) { + if (!strcmp (kw->kform, "I")) + moveb (temp, (char *) &i, 2, 0, 0); + else if (!strcmp (kw->kform, "J")) { + moveb (temp, (char *) &j, 4, 0, 0); + i = (short) j; + } + else if (!strcmp (kw->kform, "E")) { + moveb (temp, (char *) &r, 4, 0, 0); + i = (short) r; + } + else if (!strcmp (kw->kform, "D")) { + moveb (temp, (char *) &d, 8, 0, 0); + i = (short) d; + } + else + i = (short) atof (temp); + return (i); + } + else + return ((short) 0); +} + + +/* FTGETI4 -- Extract n'th column from FITS table line as int */ + +int +ftgeti4 (entry, kw) + +char *entry; /* Row or entry from table */ +struct Keyword *kw; /* Table column information from FITS header */ +{ + char temp[30]; + short i; + int j; + float r; + double d; + + if (ftgetc (entry, kw, temp, 30)) { + if (!strcmp (kw->kform, "I")) { + moveb (temp, (char *) &i, 2, 0, 0); + j = (int) i; + } + else if (!strcmp (kw->kform, "J")) + moveb (temp, (char *) &j, 4, 0, 0); + else if (!strcmp (kw->kform, "E")) { + moveb (temp, (char *) &r, 4, 0, 0); + j = (int) r; + } + else if (!strcmp (kw->kform, "D")) { + moveb (temp, (char *) &d, 8, 0, 0); + j = (int) d; + } + else + j = (int) atof (temp); + return (j); + } + else + return (0); +} + + +/* FTGETR4 -- Extract n'th column from FITS table line as float */ + +float +ftgetr4 (entry, kw) + +char *entry; /* Row or entry from table */ +struct Keyword *kw; /* Table column information from FITS header */ +{ + char temp[30]; + short i; + int j; + float r; + double d; + + if (ftgetc (entry, kw, temp, 30)) { + if (!strcmp (kw->kform, "I")) { + moveb (temp, (char *) &i, 2, 0, 0); + r = (float) i; + } + else if (!strcmp (kw->kform, "J")) { + moveb (temp, (char *) &j, 4, 0, 0); + r = (float) j; + } + else if (!strcmp (kw->kform, "E")) + moveb (temp, (char *) &r, 4, 0, 0); + else if (!strcmp (kw->kform, "D")) { + moveb (temp, (char *) &d, 8, 0, 0); + r = (float) d; + } + else + r = (float) atof (temp); + return (r); + } + else + return ((float) 0.0); +} + + +/* FTGETR8 -- Extract n'th column from FITS table line as double */ + +double +ftgetr8 (entry, kw) + +char *entry; /* Row or entry from table */ +struct Keyword *kw; /* Table column information from FITS header */ +{ + char temp[30]; + short i; + int j; + float r; + double d; + + if (ftgetc (entry, kw, temp, 30)) { + if (!strcmp (kw->kform, "I")) { + moveb (temp, (char *) &i, 2, 0, 0); + d = (double) i; + } + else if (!strcmp (kw->kform, "J")) { + moveb (temp, (char *) &j, 4, 0, 0); + d = (double) j; + } + else if (!strcmp (kw->kform, "E")) { + moveb (temp, (char *) &r, 4, 0, 0); + d = (double) r; + } + else if (!strcmp (kw->kform, "D")) + moveb (temp, (char *) &d, 8, 0, 0); + else + d = atof (temp); + return (d); + } + else + return ((double) 0.0); +} + + +/* FTGETC -- Extract n'th column from FITS table line as character string */ + +int +ftgetc (entry, kw, string, maxchar) + +char *entry; /* Row or entry from table */ +struct Keyword *kw; /* Table column information from FITS header */ +char *string; /* Returned string */ +int maxchar; /* Maximum number of characters in returned string */ +{ + int length = maxchar; + + if (kw->kl < length) + length = kw->kl; + if (length > 0) { + strncpy (string, entry+kw->kf, length); + string[length] = 0; + return ( 1 ); + } + else + return ( 0 ); +} + +extern int errno; + + +/*FITSWIMAGE -- Write FITS header and image */ + +int +fitswimage (filename, header, image) + +char *filename; /* Name of FITS image file */ +char *header; /* FITS image header */ +char *image; /* FITS image pixels */ + +{ + int fd; + + /* Open the output file */ + if (strcasecmp (filename,"stdout") ) { + + if (!access (filename, 0)) { + fd = open (filename, O_WRONLY); + if (fd < 3) { + snprintf (fitserrmsg,79, "FITSWIMAGE: file %s not writeable\n", filename); + return (0); + } + } + else { + fd = open (filename, O_RDWR+O_CREAT, 0666); + if (fd < 3) { + snprintf (fitserrmsg,79, "FITSWIMAGE: cannot create file %s\n", filename); + return (0); + } + } + } +#ifndef VMS + else + fd = STDOUT_FILENO; +#endif + + return (fitswhdu (fd, filename, header, image)); +} + + +/*FITSWEXT -- Write FITS header and image as extension to a file */ + +int +fitswext (filename, header, image) + +char *filename; /* Name of IFTS image file */ +char *header; /* FITS image header */ +char *image; /* FITS image pixels */ + +{ + int fd; + + /* Open the output file */ + if (strcasecmp (filename,"stdout") ) { + + if (!access (filename, 0)) { + fd = open (filename, O_WRONLY); + if (fd < 3) { + snprintf (fitserrmsg,79, "FITSWEXT: file %s not writeable\n", + filename); + return (0); + } + } + else { + fd = open (filename, O_APPEND, 0666); + if (fd < 3) { + snprintf (fitserrmsg,79, "FITSWEXT: cannot append to file %s\n", + filename); + return (0); + } + } + } +#ifndef VMS + else + fd = STDOUT_FILENO; +#endif + + return (fitswhdu (fd, filename, header, image)); +} + + +/* FITSWHDU -- Write FITS head and image as extension */ + +int +fitswhdu (fd, filename, header, image) + +int fd; /* File descriptor */ +char *filename; /* Name of IFTS image file */ +char *header; /* FITS image header */ +char *image; /* FITS image pixels */ +{ + int nbhead, nbimage, nblocks, bytepix, i, nbhw; + int bitpix, naxis, iaxis, naxisi, nbytes, nbw, nbpad, nbwp, simple; + char *endhead, *padding; + double bzero, bscale; + char keyword[32]; + + /* Change BITPIX=-16 files to BITPIX=16 with BZERO and BSCALE */ + bitpix = 0; + hgeti4 (header,"BITPIX",&bitpix); + if (bitpix == -16) { + if (!hgetr8 (header, "BZERO", &bzero) && + !hgetr8 (header, "BSCALE", &bscale)) { + bitpix = 16; + hputi4 (header, "BITPIX", bitpix); + hputr8 (header, "BZERO", 32768.0); + hputr8 (header, "BSCALE", 1.0); + } + } + + /* Write header to file */ + endhead = ksearch (header,"END") + 80; + nbhead = endhead - header; + nbhw = write (fd, header, nbhead); + if (nbhw < nbhead) { + snprintf (fitserrmsg,79, "FITSWHDU: wrote %d / %d bytes of header to file %s\n", + nbhw, nbhead, filename); + (void)close (fd); + return (0); + } + + /* Write extra spaces to make an integral number of 2880-byte blocks */ + nblocks = nbhead / FITSBLOCK; + if (nblocks * FITSBLOCK < nbhead) + nblocks = nblocks + 1; + nbytes = nblocks * FITSBLOCK; + nbpad = nbytes - nbhead; + padding = (char *)calloc (1, nbpad); + for (i = 0; i < nbpad; i++) + padding[i] = ' '; + nbwp = write (fd, padding, nbpad); + if (nbwp < nbpad) { + snprintf (fitserrmsg,79, "FITSWHDU: wrote %d / %d bytes of header padding to file %s\n", + nbwp, nbpad, filename); + (void)close (fd); + return (0); + } + nbhw = nbhw + nbwp; + free (padding); + + /* Return if file has no data */ + if (bitpix == 0 || image == NULL) { + /* snprintf (fitserrmsg,79, "FITSWHDU: BITPIX is 0; image not written\n"); */ + (void)close (fd); + return (0); + } + + /* If SIMPLE=F in header, just write whatever is in the buffer */ + hgetl (header, "SIMPLE", &simple); + if (!simple) { + hgeti4 (header, "NBDATA", &nbytes); + nbimage = nbytes; + } + + else { + + /* Compute size of pixel in bytes */ + bytepix = bitpix / 8; + if (bytepix < 0) bytepix = -bytepix; + nbimage = bytepix; + + /* Compute size of image in bytes using relevant header parameters */ + naxis = 1; + hgeti4 (header,"NAXIS",&naxis); + for (iaxis = 1; iaxis <= naxis; iaxis++) { + sprintf (keyword, "NAXIS%d", iaxis); + naxisi = 1; + hgeti4 (header,keyword,&naxisi); + nbimage = nbimage * naxisi; + } + + /* Number of bytes to write is an integral number of FITS blocks */ + nblocks = nbimage / FITSBLOCK; + if (nblocks * FITSBLOCK < nbimage) + nblocks = nblocks + 1; + nbytes = nblocks * FITSBLOCK; + + /* Byte-reverse image before writing, if necessary */ + if (imswapped ()) + imswap (bitpix, image, nbimage); + } + + /* Write image to file */ + nbw = write (fd, image, nbimage); + if (nbw < nbimage) { + snprintf (fitserrmsg,79, "FITSWHDU: wrote %d / %d bytes of image to file %s\n", + nbw, nbimage, filename); + return (0); + } + + /* Write extra zeroes to make an integral number of 2880-byte blocks */ + nbpad = nbytes - nbimage; + if (nbpad > 0) { + padding = (char *)calloc (1, nbpad); + nbwp = write (fd, padding, nbpad); + if (nbwp < nbpad) { + snprintf (fitserrmsg,79, "FITSWHDU: wrote %d / %d bytes of image padding to file %s\n", + nbwp, nbpad, filename); + (void)close (fd); + return (0); + } + free (padding); + } + else + nbwp = 0; + + (void)close (fd); + + /* Byte-reverse image after writing, if necessary */ + if (imswapped ()) + imswap (bitpix, image, nbimage); + + nbw = nbw + nbwp + nbhw; + return (nbw); +} + + +/*FITSCIMAGE -- Write FITS header and copy FITS image + Return number of bytes in output image, 0 if failure */ + +int +fitscimage (filename, header, filename0) + +char *filename; /* Name of output FITS image file */ +char *header; /* FITS image header */ +char *filename0; /* Name of input FITS image file */ + +{ + int fdout, fdin; + int nbhead, nbimage, nblocks, bytepix; + int bitpix, naxis, naxis1, naxis2, nbytes, nbw, nbpad, nbwp; + char *endhead, *lasthead, *padding; + char *image; /* FITS image pixels */ + char *oldhead; /* Input file image header */ + int nbhead0; /* Length of input file image header */ + int lhead0; + int nbbuff, nbuff, ibuff, nbr, nbdata; + + /* Compute size of image in bytes using relevant header parameters */ + naxis = 1; + hgeti4 (header, "NAXIS", &naxis); + naxis1 = 1; + hgeti4 (header, "NAXIS1", &naxis1); + naxis2 = 1; + hgeti4 (header, "NAXIS2", &naxis2); + hgeti4 (header, "BITPIX", &bitpix); + bytepix = bitpix / 8; + if (bytepix < 0) bytepix = -bytepix; + + /* If either dimension is one and image is 3-D, read all three dimensions */ + if (naxis == 3 && (naxis1 ==1 || naxis2 == 1)) { + int naxis3; + hgeti4 (header,"NAXIS3",&naxis3); + nbimage = naxis1 * naxis2 * naxis3 * bytepix; + } + else + nbimage = naxis1 * naxis2 * bytepix; + + nblocks = nbimage / FITSBLOCK; + if (nblocks * FITSBLOCK < nbimage) + nblocks = nblocks + 1; + nbytes = nblocks * FITSBLOCK; + + /* Allocate image buffer */ + nbbuff = FITSBLOCK * 100; + if (nbytes < nbbuff) + nbbuff = nbytes; + image = (char *) calloc (1, nbbuff); + nbuff = nbytes / nbbuff; + if (nbytes > nbuff * nbbuff) + nbuff = nbuff + 1; + + /* Read input file header */ + if ((oldhead = fitsrhead (filename0, &lhead0, &nbhead0)) == NULL) { + snprintf (fitserrmsg, 79,"FITSCIMAGE: header of input file %s cannot be read\n", + filename0); + return (0); + } + + /* Find size of output header */ + nbhead = fitsheadsize (header); + + /* If overwriting, be more careful if new header is longer than old */ + if (!strcmp (filename, filename0) && nbhead > nbhead0) { + if ((image = fitsrimage (filename0, nbhead0, oldhead)) == NULL) { + snprintf (fitserrmsg,79, "FITSCIMAGE: cannot read image from file %s\n", + filename0); + free (oldhead); + return (0); + } + return (fitswimage (filename, header, image)); + } + free (oldhead); + + /* Open the input file and skip over the header */ + if (strcasecmp (filename0,"stdin")) { + fdin = -1; + fdin = fitsropen (filename0); + if (fdin < 0) { + snprintf (fitserrmsg, 79,"FITSCIMAGE: cannot read file %s\n", filename0); + return (0); + } + + /* Skip over FITS header */ + if (lseek (fdin, nbhead0, SEEK_SET) < 0) { + (void)close (fdin); + snprintf (fitserrmsg,79, "FITSCIMAGE: cannot skip header of file %s\n", + filename0); + return (0); + } + } +#ifndef VMS + else + fdin = STDIN_FILENO; +#endif + + /* Open the output file */ + if (!access (filename, 0)) { + fdout = open (filename, O_WRONLY); + if (fdout < 3) { + snprintf (fitserrmsg,79, "FITSCIMAGE: file %s not writeable\n", filename); + return (0); + } + } + else { + fdout = open (filename, O_RDWR+O_CREAT, 0666); + if (fdout < 3) { + snprintf (fitserrmsg,79, "FITSCHEAD: cannot create file %s\n", filename); + return (0); + } + } + + /* Pad header with spaces */ + endhead = ksearch (header,"END") + 80; + lasthead = header + nbhead; + while (endhead < lasthead) + *(endhead++) = ' '; + + /* Write header to file */ + nbw = write (fdout, header, nbhead); + if (nbw < nbhead) { + snprintf (fitserrmsg, 79,"FITSCIMAGE: wrote %d / %d bytes of header to file %s\n", + nbw, nbytes, filename); + (void)close (fdout); + (void)close (fdin); + return (0); + } + + /* Return if no data */ + if (bitpix == 0) { + (void)close (fdout); + (void)close (fdin); + return (nbhead); + } + + nbdata = 0; + for (ibuff = 0; ibuff < nbuff; ibuff++) { + nbr = read (fdin, image, nbbuff); + if (nbr > 0) { + nbw = write (fdout, image, nbr); + nbdata = nbdata + nbw; + } + } + + /* Write extra to make integral number of 2880-byte blocks */ + nblocks = nbdata / FITSBLOCK; + if (nblocks * FITSBLOCK < nbdata) + nblocks = nblocks + 1; + nbytes = nblocks * FITSBLOCK; + nbpad = nbytes - nbdata; + padding = (char *)calloc (1,nbpad); + nbwp = write (fdout, padding, nbpad); + nbw = nbdata + nbwp; + free (padding); + + (void)close (fdout); + (void)close (fdin); + + if (nbw < nbimage) { + snprintf (fitserrmsg, 79, "FITSWIMAGE: wrote %d / %d bytes of image to file %s\n", + nbw, nbimage, filename); + return (0); + } + else + return (nbw); +} + + +/* FITSWHEAD -- Write FITS header and keep file open for further writing */ + +int +fitswhead (filename, header) + +char *filename; /* Name of IFTS image file */ +char *header; /* FITS image header */ + +{ + int fd; + int nbhead, nblocks; + int nbytes, nbw; + char *endhead, *lasthead; + + /* Open the output file */ + if (!access (filename, 0)) { + fd = open (filename, O_WRONLY); + if (fd < 3) { + snprintf (fitserrmsg, 79, "FITSWHEAD: file %s not writeable\n", filename); + return (0); + } + } + else { + fd = open (filename, O_RDWR+O_CREAT, 0666); + if (fd < 3) { + snprintf (fitserrmsg, 79, "FITSWHEAD: cannot create file %s\n", filename); + return (0); + } + } + + /* Write header to file */ + endhead = ksearch (header,"END") + 80; + nbhead = endhead - header; + nblocks = nbhead / FITSBLOCK; + if (nblocks * FITSBLOCK < nbhead) + nblocks = nblocks + 1; + nbytes = nblocks * FITSBLOCK; + + /* Pad header with spaces */ + lasthead = header + nbytes; + while (endhead < lasthead) + *(endhead++) = ' '; + + nbw = write (fd, header, nbytes); + if (nbw < nbytes) { + fprintf (stderr, "FITSWHEAD: wrote %d / %d bytes of header to file %s\n", + nbw, nbytes, filename); + (void)close (fd); + return (0); + } + return (fd); +} + + +/* FITSWEXHEAD -- Write FITS header in place */ + +int +fitswexhead (filename, header) + +char *filename; /* Name of FITS image file with ,extension */ +char *header; /* FITS image header */ + +{ + int fd; + int nbhead, lhead; + int nbw, nbnew, nbold; + char *endhead, *lasthead, *oldheader; + char *ext, cext; + + /* Compare size of existing header to size of new header */ + fitsinherit = 0; + oldheader = fitsrhead (filename, &lhead, &nbhead); + if (oldheader == NULL) { + snprintf (fitserrmsg, 79, "FITSWEXHEAD: file %s cannot be read\n", filename); + return (-1); + } + nbold = fitsheadsize (oldheader); + nbnew = fitsheadsize (header); + + /* Return if the new header is bigger than the old header */ + if (nbnew > nbold) { + snprintf (fitserrmsg, 79, "FITSWEXHEAD: old header %d bytes, new header %d bytes\n", nbold,nbnew); + free (oldheader); + oldheader = NULL; + return (-1); + } + + /* Add blank lines if new header is smaller than the old header */ + else if (nbnew < nbold) { + strcpy (oldheader, header); + endhead = ksearch (oldheader,"END"); + lasthead = oldheader + nbold; + while (endhead < lasthead) + *(endhead++) = ' '; + strncpy (lasthead-80, "END", 3); + } + + /* Pad header with spaces */ + else { + endhead = ksearch (header,"END") + 80; + lasthead = header + nbnew; + while (endhead < lasthead) + *(endhead++) = ' '; + strncpy (oldheader, header, nbnew); + } + + /* Check for FITS extension and ignore for file opening */ + ext = strchr (filename, ','); + if (ext == NULL) + ext = strchr (filename, '['); + if (ext != NULL) { + cext = *ext; + *ext = (char) 0; + } + + /* Open the output file */ + fd = open (filename, O_WRONLY); + if (ext != NULL) + *ext = cext; + if (fd < 3) { + snprintf (fitserrmsg, 79, "FITSWEXHEAD: file %s not writeable\n", filename); + return (-1); + } + + /* Skip to appropriate place in file */ + (void) lseek (fd, ibhead, SEEK_SET); + + /* Write header to file */ + nbw = write (fd, oldheader, nbold); + (void)close (fd); + free (oldheader); + oldheader = NULL; + if (nbw < nbold) { + fprintf (stderr, "FITSWHEAD: wrote %d / %d bytes of header to file %s\n", + nbw, nbold, filename); + return (-1); + } + return (0); +} + + +/* ISFITS -- Return 1 if FITS file, else 0 */ +int +isfits (filename) + +char *filename; /* Name of file for which to find size */ +{ + int diskfile; + char keyword[16]; + char *comma; + int nbr; + + /* First check to see if this is an assignment */ + if (strchr (filename, '=')) + return (0); + + /* Check for stdin (input from pipe) */ + else if (!strcasecmp (filename,"stdin")) + return (1); + + /* Then check file extension + else if (strsrch (filename, ".fit") || + strsrch (filename, ".fits") || + strsrch (filename, ".fts")) + return (1); */ + + /* If no FITS file extension, try opening the file */ + else { + if ((comma = strchr (filename,','))) + *comma = (char) 0; + if ((diskfile = open (filename, O_RDONLY)) < 0) { + if (comma) + *comma = ','; + return (0); + } + else { + nbr = read (diskfile, keyword, 8); + if (comma) + *comma = ','; + close (diskfile); + if (nbr < 8) + return (0); + else if (!strncmp (keyword, "SIMPLE", 6)) + return (1); + else + return (0); + } + } +} + + +/* FITSHEADSIZE -- Find size of FITS header */ + +int +fitsheadsize (header) + +char *header; /* FITS header */ +{ + char *endhead; + int nbhead, nblocks; + + endhead = ksearch (header,"END") + 80; + nbhead = endhead - header; + nblocks = nbhead / FITSBLOCK; + if (nblocks * FITSBLOCK < nbhead) + nblocks = nblocks + 1; + return (nblocks * FITSBLOCK); +} + + +/* Print error message */ +void +fitserr () +{ fprintf (stderr, "%s\n",fitserrmsg); + return; } + + +/* MOVEB -- Copy nbytes bytes from source+offs to dest+offd (any data type) */ + +void +moveb (source, dest, nbytes, offs, offd) + +char *source; /* Pointer to source */ +char *dest; /* Pointer to destination */ +int nbytes; /* Number of bytes to move */ +int offs; /* Offset in bytes in source from which to start copying */ +int offd; /* Offset in bytes in destination to which to start copying */ +{ +char *from, *last, *to; + from = source + offs; + to = dest + offd; + last = from + nbytes; + while (from < last) *(to++) = *(from++); + return; +} + +/* + * Feb 8 1996 New subroutines + * Apr 10 1996 Add subroutine list at start of file + * Apr 17 1996 Print error message to stderr + * May 2 1996 Write using stream IO + * May 14 1996 If FITSRTOPEN NK is zero, return all keywords in header + * May 17 1996 Make header internal to FITSRTOPEN + * Jun 3 1996 Use stream I/O for input as well as output + * Jun 10 1996 Remove unused variables after running lint + * Jun 12 1996 Deal with byte-swapped images + * Jul 11 1996 Rewrite code to separate header and data reading + * Aug 6 1996 Fixed small defects after lint + * Aug 6 1996 Drop unused NBHEAD argument from FITSRTHEAD + * Aug 13 1996 If filename is stdin, read from standard input instead of file + * Aug 30 1996 Use write for output, not fwrite + * Sep 4 1996 Fix mode when file is created + * Oct 15 1996 Drop column argument from FGET* subroutines + * Oct 15 1996 Drop unused variable + * Dec 17 1996 Add option to skip bytes in file before reading the header + * Dec 27 1996 Turn nonprinting header characters into spaces + * + * Oct 9 1997 Add FITS extension support as filename,extension + * Dec 15 1997 Fix minor bugs after lint + * + * Feb 23 1998 Do not append primary header if getting header for ext. 0 + * Feb 23 1998 Accept either bracketed or comma extension + * Feb 24 1998 Add SIMPLE keyword to start of extracted extension + * Apr 30 1998 Fix error return if not table file after Allan Brighton + * May 4 1998 Fix error in argument sequence in HGETS call + * May 27 1998 Include fitsio.h and imio.h + * Jun 1 1998 Add VMS fixes from Harry Payne at STScI + * Jun 3 1998 Fix bug reading EXTNAME + * Jun 11 1998 Initialize all header parameters before reading them + * Jul 13 1998 Clarify argument definitions + * Aug 6 1998 Rename fitsio.c to fitsfile.c to avoid conflict with CFITSIO + * Aug 13 1998 Add FITSWHEAD to write only header + * Sep 25 1998 Allow STDIN or stdin for standard input reading + * Oct 5 1998 Add isfits() to decide whether a file is FITS + * Oct 9 1998 Assume stdin and STDIN to be FITS files in isfits() + * Nov 30 1998 Fix bug found by Andreas Wicenec when reading large headers + * Dec 8 1998 Fix bug introduced by previous bug fix + * + * Jan 4 1999 Do not print error message if BITPIX is 0 + * Jan 27 1999 Read and write all of 3D images if one dimension is 1 + * Jan 27 1999 Pad out data to integral number of 2880-byte blocks + * Apr 29 1999 Write BITPIX=-16 files as BITPIX=16 with BSCALE and BZERO + * Apr 30 1999 Add % as alternative to , to denote sub-images + * May 25 1999 Set buffer offsets to 0 when FITS table file is opened + * Jul 14 1999 Do not try to write image data if BITPIX is 0 + * Sep 27 1999 Add STDOUT as output filename option in fitswimage() + * Oct 6 1999 Set header length global variable hget.lhead0 in fitsrhead() + * Oct 14 1999 Update header length as it is changed in fitsrhead() + * Oct 20 1999 Change | in if statements to || + * Oct 25 1999 Change most malloc() calls to calloc() + * Nov 24 1999 Add fitscimage() + * + * Feb 23 2000 Fix problem with some error returns in fitscimage() + * Mar 17 2000 Drop unused variables after lint + * Jul 20 2000 Drop BITPIX and NAXIS from primary header if extension printerd + * Jul 20 2000 Start primary part of header with ROOTHEAD keyword + * Jul 28 2000 Add loop to deal with buffered stdin + * + * Jan 11 2001 Print all messages to stderr + * Jan 12 2001 Add extension back onto filename after fitsropen() (Guy Rixon) + * Jan 18 2001 Drop EXTEND keyword when extracting an extension + * Jan 18 2001 Add fitswext() to append HDU and fitswhdu() to do actual writing + * Jan 22 2001 Ignore WCS name or letter following a : in file name in fitsrhead() + * Jan 30 2001 Fix FITSCIMAGE so it doesn't overwrite data when overwriting a file + * Feb 20 2001 Ignore WCS name or letter following a : in file name in fitsropen() + * Feb 23 2001 Initialize rbrac in fitsropen() + * Mar 8 2001 Use % instead of : for WCS specification in file name + * Mar 9 2001 Fix bug so primary header is always appended to secondary header + * Mar 9 2001 Change NEXTEND to NUMEXT in appended primary header + * Mar 20 2001 Declare fitsheadsize() in fitschead() + * Apr 24 2001 When matching column names, use longest length + * Jun 27 2001 In fitsrthead(), allocate pw and lpnam only if more space needed + * Aug 24 2001 In isfits(), return 0 if argument contains an equal sign + * + * Jan 28 2002 In fitsrhead(), allow stdin to include extension and/or WCS selection + * Jun 18 2002 Save error messages as fitserrmsg and use fitserr() to print them + * Oct 21 2002 Add fitsrsect() to read a section of an image + * + * Feb 4 2003 Open catalog file rb instead of r (Martin Ploner, Bern) + * Apr 2 2003 Drop unused variable in fitsrsect() + * Jul 11 2003 Use strcasecmp() to check for stdout and stdin + * Aug 1 2003 If no other header, return root header from fitsrhead() + * Aug 20 2003 Add fitsrfull() to read n-dimensional FITS images + * Aug 21 2003 Modify fitswimage() to always write n-dimensional FITS images + * Nov 18 2003 Fix minor bug in fitswhdu() + * Dec 3 2003 Remove unused variable lasthead in fitswhdu() + * + * May 3 2004 Do not always append primary header to extension header + * May 3 2004 Add ibhead as position of header read in file + * May 19 2004 Do not reset ext if NULL in fitswexhead() + * Jul 1 2004 Initialize INHERIT to 1 + * Aug 30 2004 Move fitsheadsize() declaration to fitsfile.h + * Aug 31 2004 If SIMPLE=F, put whatever is in file after header in image + * + * Mar 17 2005 Use unbuffered I/O in isfits() for robustness + * Jun 27 2005 Drop unused variable nblocks in fitswexhead() + * Aug 8 2005 Fix space-padding bug in fitswexhead() found by Armin Rest + * Sep 30 2005 Fix fitsrsect() to position relatively, not absolutely + * Oct 28 2005 Add error message if desired FITS extension is not found + * Oct 28 2005 Fix initialization problem found by Sergey Koposov + * + * Feb 23 2006 Add fitsrtail() to read appended FITS headers + * Feb 27 2006 Add file name to header-reading error messages + * May 3 2006 Remove declarations of unused variables + * Jun 20 2006 Initialize uninitialized variables + * Nov 2 2006 Change all realloc() calls to calloc() + * + * Jan 5 2007 In fitsrtail(), change control characters in header to spaces + * Apr 30 2007 Improve error reporting in FITSRFULL + * Nov 28 2007 Add support to BINTABLE in ftget*() and fitsrthead() + * Dec 20 2007 Add data heap numerated by PCOUNT when skipping HDU in fitsrhead() + * Dec 20 2007 Return NULL pointer if fitsrhead() cannot find requested HDU + * + * Apr 7 2008 Drop comma from name when reading file in isfits() + * Jun 27 2008 Do not append primary data header if it is the only header + * Nov 21 2008 In fitswhead(), print message if too few bytes written + * + * Sep 18 2009 In fitswexhead() write to error string instead of stderr + * Sep 22 2009 In fitsrthead(), fix lengths for ASCII numeric table entries + * Sep 25 2009 Add subroutine moveb() and fix calls to it + * Sep 25 2009 Fix several small errors found by Jessicalas Burke + * + * Mar 29 2010 In fitswhead(), always pad blocks to 2880 bytes with spaces + * Mar 31 2010 In fitsrhead(), fix bug reading long primary headers + * + * Sep 15 2011 In fitsrsect() declare impos and nblin off_t + * Sep 15 2011 In fitsrtail() declare offset off_t + * Sep 15 2011 Declare global variable ibhead off_t + * + * Jul 25 2014 Fix bug when reallocating buffer for long headers + */ |