From 953d2cb3ec228b1806a1931ef989997ff76b0f32 Mon Sep 17 00:00:00 2001 From: Jeff Moe Date: Sat, 6 Aug 2022 21:03:09 -0600 Subject: [PATCH] More bits from qfits --- qfits/main/Makefile | 55 ++ qfits/main/dfits.c | 319 +++++++++ qfits/main/dtfits.c | 542 +++++++++++++++ qfits/main/flipx.c | 168 +++++ qfits/main/frameq.c | 461 +++++++++++++ qfits/main/qextract.c | 267 +++++++ qfits/main/replacekey.c | 212 ++++++ qfits/saft/Makefile | 41 ++ qfits/saft/fitsmd5.c | 790 +++++++++++++++++++++ qfits/saft/fitsort.c | 373 ++++++++++ qfits/saft/hierarch28.c | 603 ++++++++++++++++ qfits/saft/iofits.c | 1374 +++++++++++++++++++++++++++++++++++++ qfits/saft/stripfits.c | 340 +++++++++ qfits/src/cache.h | 122 ++++ qfits/src/config.h | 20 + qfits/src/expkey.h | 53 ++ qfits/src/fits_h.h | 475 +++++++++++++ qfits/src/fits_md5.h | 56 ++ qfits/src/fits_p.h | 80 +++ qfits/src/fits_rw.h | 135 ++++ qfits/src/fits_std.h | 69 ++ qfits/src/get_name.h | 155 +++++ qfits/src/ieeefp-compat.h | 104 +++ qfits/src/md5.h | 24 + qfits/src/pafs.h | 110 +++ qfits/src/pixio.h | 448 ++++++++++++ qfits/src/qerror.h | 97 +++ qfits/src/simple.h | 311 +++++++++ qfits/src/static_sz.h | 42 ++ qfits/src/t_iso8601.h | 93 +++ qfits/src/tfits.h | 546 +++++++++++++++ 31 files changed, 8485 insertions(+) create mode 100644 qfits/main/Makefile create mode 100644 qfits/main/dfits.c create mode 100644 qfits/main/dtfits.c create mode 100644 qfits/main/flipx.c create mode 100644 qfits/main/frameq.c create mode 100644 qfits/main/qextract.c create mode 100644 qfits/main/replacekey.c create mode 100644 qfits/saft/Makefile create mode 100644 qfits/saft/fitsmd5.c create mode 100644 qfits/saft/fitsort.c create mode 100644 qfits/saft/hierarch28.c create mode 100644 qfits/saft/iofits.c create mode 100644 qfits/saft/stripfits.c create mode 100644 qfits/src/cache.h create mode 100644 qfits/src/config.h create mode 100644 qfits/src/expkey.h create mode 100644 qfits/src/fits_h.h create mode 100644 qfits/src/fits_md5.h create mode 100644 qfits/src/fits_p.h create mode 100644 qfits/src/fits_rw.h create mode 100644 qfits/src/fits_std.h create mode 100644 qfits/src/get_name.h create mode 100644 qfits/src/ieeefp-compat.h create mode 100644 qfits/src/md5.h create mode 100644 qfits/src/pafs.h create mode 100644 qfits/src/pixio.h create mode 100644 qfits/src/qerror.h create mode 100644 qfits/src/simple.h create mode 100644 qfits/src/static_sz.h create mode 100644 qfits/src/t_iso8601.h create mode 100644 qfits/src/tfits.h diff --git a/qfits/main/Makefile b/qfits/main/Makefile new file mode 100644 index 0000000..aae0c11 --- /dev/null +++ b/qfits/main/Makefile @@ -0,0 +1,55 @@ +# +# qfits tools Makefile +# + +# +# General definitions +# + +include ../config.make + +RM = rm -f +CP = cp +MV = mv +BINDIR = ../bin + +COMPF = $(CFLAGS) -I../include +LINKF = $(LFLAGS) -L../lib -lqfits + +default: all + + +PROGS= $(BINDIR)/dtfits \ + $(BINDIR)/flipx \ + $(BINDIR)/dfits \ + $(BINDIR)/frameq \ + $(BINDIR)/replacekey \ + $(BINDIR)/qextract + + +all: $(PROGS) + +veryclean: + @(echo "cleaning qfits programs...") + @($(RM) $(PROGS)) + + +$(BINDIR)/dfits: dfits.c + $(CC) $(COMPF) -o $(BINDIR)/dfits dfits.c $(LINKF) + +$(BINDIR)/dtfits: dtfits.c + $(CC) $(COMPF) -o $(BINDIR)/dtfits dtfits.c $(LINKF) + +$(BINDIR)/flipx: flipx.c + $(CC) $(COMPF) -o $(BINDIR)/flipx flipx.c $(LINKF) + +$(BINDIR)/frameq: frameq.c + $(CC) $(COMPF) -o $(BINDIR)/frameq frameq.c $(LINKF) + +$(BINDIR)/replacekey: replacekey.c + $(CC) $(COMPF) -o $(BINDIR)/replacekey replacekey.c $(LINKF) + +$(BINDIR)/qextract: qextract.c + $(CC) $(COMPF) -o $(BINDIR)/qextract qextract.c $(LINKF) + + diff --git a/qfits/main/dfits.c b/qfits/main/dfits.c new file mode 100644 index 0000000..86740a3 --- /dev/null +++ b/qfits/main/dfits.c @@ -0,0 +1,319 @@ +/*----------------------------------------------------------------------------*/ +/** + @file dfits.c + @author Nicolas Devillard + @date 30 Mar 2000 + @version $Revision: 1.3 $ + @brief FITS header display +*/ +/*----------------------------------------------------------------------------*/ + +/* + $Id: dfits.c,v 1.3 2005/07/19 15:38:52 yjung Exp $ + $Author: yjung $ + $Date: 2005/07/19 15:38:52 $ + $Revision: 1.3 $ + */ + +/*----------------------------------------------------------------------------- + Includes + -----------------------------------------------------------------------------*/ + +#include +#include +#include +#include "qfits.h" + +/*----------------------------------------------------------------------------- + Define + -----------------------------------------------------------------------------*/ + +#define BLOCK_SIZE 2880 +#define LGTH 80 +#define MAGIC "SIMPLE =" + +/* If compiled against zlib, include support for gzipped files */ +#if HAVE_ZLIB +#include "zlib.h" +#define FILE gzFile +#define fopen gzopen +#define fclose gzclose +#define fread(b,s,n,f) gzread(f,b,n*s) +#endif + +/*----------------------------------------------------------------------------- + Function prototypes + -----------------------------------------------------------------------------*/ + +void usage(char * pname) ; +void parse_cmd_line(int, char **, int *, int *, int *) ; +int dump_fits_filter(FILE *, int) ; +int dump_fits(char *, int) ; +char * rstrip(char *) ; + +/*----------------------------------------------------------------------------- + Main + -----------------------------------------------------------------------------*/ +int main(int argc, char *argv[]) +{ + int xtnum ; + int c_arg ; + int filter ; + int err ; + + /* No arguments prints out a usage message */ + if (argc<2) usage(argv[0]); + + /* Parse command-line options */ + parse_cmd_line(argc, argv, &xtnum, &filter, &c_arg); + + /* Filter mode: process data received from stdin */ + if (filter) { +#if HAVE_ZLIB + printf("filter mode does not support gzipped files\n"); + printf("use: gunzip -c file.fits | dfits -\n"); + return 1 ; +#else + return dump_fits_filter(stdin, xtnum); +#endif + } + + /* Normal mode: loop on all file names given on command-line */ + err = 0 ; + while (c_arg < argc) { + err += dump_fits(argv[c_arg], xtnum); + c_arg++; + } + return err ; /* Returns number of errors during process */ +} + +void usage(char * pname) +{ + printf( +"\n\n" +"usage: %s [-x xtnum] \n" +"usage: %s [-x xtnum] -\n" +"\n" +"The former version expects file names.\n" +"The latter expects data coming in from stdin.\n" +"\n" +"-x xtnum specifies the extension header to print\n" +"-x 0 specifies main header + all extensions\n" +"\n\n", + pname, pname); + +#if HAVE_ZLIB + printf( +"This program was compiled against zlib %s\n" +"This means you can use it with gzipped FITS files\n" +"as with uncompressed FITS files.\n" +"NB: this does not apply to the '-' option (input from stdin)\n" +"\n\n", ZLIB_VERSION); +#endif + exit(1) ; +} + +void parse_cmd_line( + int argc, + char ** argv, + int * xtnum, + int * filter, + int * c_arg) +{ + *filter = 0 ; + *xtnum = -1 ; + *c_arg = argc-1 ; + + /* If '-' is on the command-line, it must be the last argument */ + if (!strcmp(argv[argc-1], "-")) *filter = 1 ; + /* If -x xtnum is on the command-line, it must be the first two arguments */ + if (!strcmp(argv[1], "-x")) { + *xtnum = atoi(argv[2]); + *c_arg = 3 ; + } else { + *c_arg = 1 ; + } + return ; +} + +/* Strip off all blank characters in a string from the right-side. */ +char * rstrip(char * s) +{ + int len ; + if (s==NULL) return s ; + len = strlen(s); + if (len<1) return s ; + len -- ; + while (s[len]== ' ') { + s[len]=(char)0 ; + len --; + if (len<0) break ; + } + return s ; +} + +/* Dump the requested header (main or extension) from a filename. */ +int dump_fits(char * name, int xtnum) +{ + FILE * in ; + int err ; + + if ((in=fopen(name, "r"))==NULL) { + fprintf(stderr, "error: cannot open file [%s]\n", name); + return 1 ; + } + + printf("====> file %s (main) <====\n", name) ; + err = dump_fits_filter(in, xtnum); + fclose(in); + return err ; +} + +/* Dump the requested header (main or extension) from a FILE * */ +int dump_fits_filter(FILE * in, int xtnum) +{ + int n_xt ; + char buf[LGTH+1]; + int err ; + int data_bytes, naxis ; + char * read_val ; + int skip_blocks ; + int seeked ; + + /* Try getting the first 80 chars */ + memset(buf, 0, LGTH+1); + if (fread(buf, sizeof(char), LGTH, in)!=LGTH) { + fprintf(stderr, "error reading input\n"); + return 1; + } + /* Check that it is indeed FITS */ + if (strncmp(buf, MAGIC, strlen(MAGIC))) { + fprintf(stderr, "not a FITS file\n"); + return 1 ; + } + naxis = 0 ; + data_bytes = 1 ; + if (xtnum<1) { + /* Output main header */ + printf("%s\n", rstrip(buf)); + data_bytes = 1 ; + naxis = 0 ; + while ((err=fread(buf, sizeof(char), LGTH, in))==LGTH) { + printf("%s\n", rstrip(buf)); + /* Look for BITPIX keyword */ + if (buf[0]=='B' && + buf[1]=='I' && + buf[2]=='T' && + buf[3]=='P' && + buf[4]=='I' && + buf[5]=='X' && + buf[6]==' ') { + read_val = qfits_getvalue(buf); + data_bytes *= (int)atoi(read_val) / 8 ; + if (data_bytes<0) data_bytes *= -1 ; + } else + /* Look for NAXIS keyword */ + if (buf[0]=='N' && + buf[1]=='A' && + buf[2]=='X' && + buf[3]=='I' && + buf[4]=='S') { + + if (buf[5]==' ') { + /* NAXIS keyword */ + read_val = qfits_getvalue(buf); + naxis = (int)atoi(read_val); + } else { + /* NAXIS?? keyword (axis size) */ + read_val = qfits_getvalue(buf); + data_bytes *= (int)atoi(read_val); + } + } else + /* Look for END keyword */ + if (buf[0]=='E' && + buf[1]=='N' && + buf[2]=='D') { + break ; + } + } + if (err!=LGTH) return 1 ; + } + if (xtnum<0) return 0 ; + + n_xt=0 ; + while (1) { + /* + * Skip the previous data section if pixels were declared + */ + if (naxis>0) { + /* Skip as many blocks as there are declared pixels */ + skip_blocks = data_bytes/BLOCK_SIZE ; + if ((data_bytes % BLOCK_SIZE)!=0) skip_blocks ++ ; + seeked = fseek(in, skip_blocks*BLOCK_SIZE, SEEK_CUR); + if (seeked<0) return -1 ; + } + + /* Look for next XTENSION keyword */ + while ((err=fread(buf, sizeof(char), LGTH, in))==LGTH) { + if (buf[0]=='X' && + buf[1]=='T' && + buf[2]=='E' && + buf[3]=='N' && + buf[4]=='S' && + buf[5]=='I' && + buf[6]=='O' && + buf[7]=='N') break ; + } + if (err==0) break ; + if (err!=LGTH) return 1 ; + + n_xt++ ; + + if (xtnum==0 || xtnum==n_xt) { + printf("===> xtension %d\n", n_xt) ; + printf("%s\n", rstrip(buf)); + } + + data_bytes = 1 ; + naxis = 0 ; + while ((err=fread(buf, sizeof(char), LGTH, in))==LGTH) { + if (xtnum==0 || xtnum==n_xt) printf("%s\n", rstrip(buf)); + + /* Look for BITPIX keyword */ + if (buf[0]=='B' && + buf[1]=='I' && + buf[2]=='T' && + buf[3]=='P' && + buf[4]=='I' && + buf[5]=='X' && + buf[6]==' ') { + read_val = qfits_getvalue(buf); + data_bytes *= (int)atoi(read_val) / 8 ; + if (data_bytes<0) data_bytes *= -1 ; + } else + /* Look for NAXIS keyword */ + if (buf[0]=='N' && + buf[1]=='A' && + buf[2]=='X' && + buf[3]=='I' && + buf[4]=='S') { + + if (buf[5]==' ') { + /* NAXIS keyword */ + read_val = qfits_getvalue(buf); + naxis = (int)atoi(read_val); + } else { + /* NAXIS?? keyword (axis size) */ + read_val = qfits_getvalue(buf); + data_bytes *= (int)atoi(read_val); + } + } else + /* Look for END keyword */ + if (buf[0]=='E' && + buf[1]=='N' && + buf[2]=='D') break ; + } + if (n_xt==xtnum) break ; + } + return 0 ; +} diff --git a/qfits/main/dtfits.c b/qfits/main/dtfits.c new file mode 100644 index 0000000..77504a0 --- /dev/null +++ b/qfits/main/dtfits.c @@ -0,0 +1,542 @@ +/*----------------------------------------------------------------------------*/ +/** + @file dtfits.c + @date July 1999 + @version $Revision: 1.14 $ + @brief FITS table dump +*/ +/*----------------------------------------------------------------------------*/ + +/* + $Id: dtfits.c,v 1.14 2005/07/20 14:25:16 yjung Exp $ + $Author: yjung $ + $Date: 2005/07/20 14:25:16 $ + $Revision: 1.14 $ +*/ + +/*----------------------------------------------------------------------------- + Includes + -----------------------------------------------------------------------------*/ + +#include +#include +#include "qfits.h" +#include "xmemory.h" + +/*----------------------------------------------------------------------------- + Define + -----------------------------------------------------------------------------*/ + +#define ELEMENT_MAX_DISP_SIZE 50 +#define DISP_SIZE_INT 5 +#define DISP_SIZE_DOUBLE 8 +#define DISP_SIZE_FLOAT 7 +#define DISP_SIZE_CHAR 1 + +/*----------------------------------------------------------------------------- + Function prototypes + -----------------------------------------------------------------------------*/ + +static int dump_extension_bin(qfits_table *, FILE *, void **, char, int, + int) ; +static int dump_extension_ascii(qfits_table *, FILE *, void **, char, + int, int) ; +static int dump_extension(qfits_table *, FILE *, char, int, int) ; +static void qfits_dump(char *, char *, int, char, int); +static void usage(char * pname) ; +static char prog_desc[] = "FITS table dump" ; + +/*----------------------------------------------------------------------------- + Main + -----------------------------------------------------------------------------*/ +int main(int argc, char *argv[]) +{ + char name_i[FILENAMESZ] ; + char name_o[FILENAMESZ] ; + int i ; + int data_only ; + char separator ; + int ext ; + + /* Initialize */ + data_only = 0 ; + separator = '|' ; + ext = -1 ; + + i=1 ; + + if (argc<2) usage(argv[0]); + + while (i=argc) { + fprintf(stderr, "option -s needs an argument\n"); + return -1 ; + } + i++ ; + separator = argv[i][0] ; + + + } else if (!strcmp(argv[i], "-x")) { + if ((i+1)>=argc) { + fprintf(stderr, "option -x needs an argument\n"); + return -1 ; + } + i++ ; + ext = atoi(argv[i]) ; + } else { + break ; + } + i++ ; + } + if ((argc-i)<1) { + fprintf(stderr, "missing input file name\n"); + return -1 ; + } + strcpy(name_i, argv[i]); + i++ ; + if ((argc-i)<1) name_o[0] = 0 ; + else strcpy(name_o, argv[i]); + + qfits_dump(name_i, name_o, data_only, separator, ext); + return 0 ; +} + +static void usage(char * pname) +{ + printf("%s -- %s\n", pname, prog_desc); + printf( + "use : %s [options] [out]\n" + "options are:\n" + "\t-d to dump data only (no headers)\n" + "\t-s to output data with separator \n" + "\n", + pname); + exit(0) ; +} + +static void qfits_dump( + char * name_i, + char * name_o, + int data_only, + char separator, + int ext) +{ + qfits_table * tdesc ; + FILE * out ; + int xtnum_start, xtnum_stop ; + int n_ext ; + int i ; + + /* Set where to send the output */ + if (name_o[0]==(char)0) { + out = stdout ; + } else { + if ((out = fopen(name_o, "w"))==NULL) { + fprintf(stderr, "cannot create output file [%s]\n", name_o); + return ; + } + } + + if (!data_only) { + fprintf(out, "#\n"); + fprintf(out, "# file %s\n", name_i); + } + + /* Query number of extensions in the file */ + n_ext = qfits_query_n_ext(name_i); + if (!data_only) { + fprintf(out, "# extensions %d\n", n_ext); + } + /* If no extension, bail out */ + if (n_ext<1) { + if (out!=stdout) fclose(out) ; + return ; + } + + /* 1 extension required or all */ + if (ext < 1) { + xtnum_start = 1 ; + xtnum_stop = n_ext ; + } else if (ext > n_ext) { + fprintf(out, "# requested extension does not exist %d\n", ext) ; + if (out!=stdout) fclose(out) ; + return ; + } else { + xtnum_start = xtnum_stop = ext ; + } + + /* Loop over all extensions */ + for (i=xtnum_start ; i<=xtnum_stop ; i++) { + if (!data_only) { + fprintf(out, "# --------------------------------------------\n"); + fprintf(out, "# XTENSION %d\n", i); + } + if ((tdesc = qfits_table_open(name_i, i)) == NULL) { + printf("cannot open table [%s]:[%d]\n", name_i, i); + if (out!=stdout) fclose(out); + return ; + } + dump_extension(tdesc, out, separator, data_only, 1) ; + qfits_table_close(tdesc); + } + fclose(out) ; + return ; +} + +static int dump_extension( + qfits_table * tdesc, + FILE * out, + char separator, + int data_only, + int use_zero_scale) +{ + void ** cols ; + int i, j ; + + if (!data_only) { + fprintf(out, "# Number of columns %d\n", tdesc->nc); + fprintf(out, "#\n"); + } + + /* First read the columns in memory */ + cols = malloc(tdesc->nc * sizeof(void*)) ; + for (i=0 ; inc ; i++) { + cols[i] = qfits_query_column_data(tdesc, i, NULL, NULL) ; + if (cols[i] == NULL) { + fprintf(out, "# Cannot load column nb %d\n", i+1) ; + } + } + + switch (tdesc->tab_t) { + case QFITS_BINTABLE: + dump_extension_bin(tdesc, out, cols, separator, data_only, + use_zero_scale) ; + break ; + case QFITS_ASCIITABLE: + dump_extension_ascii(tdesc, out, cols, separator, data_only, + use_zero_scale) ; + break ; + default: + fprintf(out, "Table type not recognized") ; + break ; + } + + for (i=0 ; inc ; i++) if (cols[i]) free(cols[i]) ; + free(cols) ; + return 0 ; +} + +static int dump_extension_bin( + qfits_table * tdesc, + FILE * out, + void ** cols, + char separator, + int data_only, + int use_zero_scale) +{ + int * col_sizes ; + qfits_col * col ; + char * ccol ; + unsigned char * ucol ; + double * dcol ; + float * fcol ; + short * scol ; + int * icol ; + int size ; + int field_size ; + char * str ; + char ctmp[512]; + int i, j, k ; + + /* GET THE FIELDS SIZES */ + col_sizes = calloc(tdesc->nc, sizeof(int)) ; + for (i=0 ; inc ; i++) { + col = tdesc->col + i ; + col_sizes[i] = (int)strlen(col->tlabel) ; + switch(col->atom_type) { + case TFITS_BIN_TYPE_A: + size = col->atom_size * col->atom_nb ; + break ; + case TFITS_BIN_TYPE_B: + size = col->atom_nb * (DISP_SIZE_INT + 2) ; + break ; + case TFITS_BIN_TYPE_D: + case TFITS_BIN_TYPE_M: + size = col->atom_nb * (DISP_SIZE_DOUBLE + 2) ; + break ; + case TFITS_BIN_TYPE_E: + case TFITS_BIN_TYPE_C: + size = col->atom_nb * (DISP_SIZE_FLOAT + 2) ; + break ; + case TFITS_BIN_TYPE_I: + size = col->atom_nb * (DISP_SIZE_INT + 2) ; + break ; + case TFITS_BIN_TYPE_J: + size = col->atom_nb * (DISP_SIZE_INT + 2) ; + break ; + case TFITS_BIN_TYPE_L: + size = col->atom_nb * (DISP_SIZE_CHAR + 2) ; + break ; + case TFITS_BIN_TYPE_X: + size = col->atom_nb * (DISP_SIZE_INT + 2) ; + break ; + case TFITS_BIN_TYPE_P: + size = col->atom_nb * (DISP_SIZE_INT + 2) ; + break ; + default: + fprintf(out, "Type not recognized") ; + break ; + } + if (size > col_sizes[i]) col_sizes[i] = size ; + } + + /* Print out the column names */ + if (!data_only) { + for (i=0 ; inc ; i++) { + col = tdesc->col + i ; + fprintf(out, "%*s", col_sizes[i], col->tlabel); + if (i!=(tdesc->nc-1)) printf("%c", separator); + } + fprintf(out, "\n"); + } + + /* Get the string to write according to the type */ + for (j=0 ; jnr ; j++) { + for (i=0 ; inc ; i++) { + if (cols[i] == NULL) continue ; + col = tdesc->col + i ; + field_size = col->atom_nb * ELEMENT_MAX_DISP_SIZE ; + str = malloc(field_size * sizeof(char)) ; + str[0] = (char)0 ; + switch(col->atom_type) { + case TFITS_BIN_TYPE_A: + ccol = (char*)(cols[i]) ; + ccol += col->atom_size * col->atom_nb * j ; + strncpy(ctmp, ccol, col->atom_size * col->atom_nb) ; + ctmp[col->atom_size*col->atom_nb] = (char)0 ; + strcpy(str, ctmp) ; + break ; + case TFITS_BIN_TYPE_B: + ucol = (unsigned char*)(cols[i]) ; + ucol += col->atom_nb * j ; + /* For each atom of the column */ + for (k=0 ; katom_nb-1 ; k++) { + sprintf(ctmp, "%d, ", (int)ucol[k]) ; + strcat(str, ctmp) ; + } + /* Handle the last atom differently: no ',' */ + sprintf(ctmp,"%d",(int)ucol[col->atom_nb-1]); + strcat(str, ctmp) ; + break ; + case TFITS_BIN_TYPE_D: + case TFITS_BIN_TYPE_M: + dcol = (double*)(cols[i]) ; + dcol += col->atom_nb * j ; + /* For each atom of the column */ + for (k=0 ; katom_nb-1 ; k++) { + sprintf(ctmp, "%g, ", dcol[k]) ; + strcat(str, ctmp) ; + } + /* Handle the last atom differently: no ',' */ + sprintf(ctmp, "%g", dcol[col->atom_nb-1]) ; + strcat(str, ctmp) ; + break ; + case TFITS_BIN_TYPE_E: + case TFITS_BIN_TYPE_C: + fcol = (float*)(cols[i]) ; + fcol += col->atom_nb * j ; + /* For each atom of the column */ + for (k=0 ; katom_nb-1 ; k++) { + sprintf(ctmp, "%f, ", fcol[k]) ; + strcat(str, ctmp) ; + } + /* Handle the last atom differently: no ',' */ + sprintf(ctmp, "%f", fcol[col->atom_nb-1]) ; + strcat(str, ctmp) ; + break ; + case TFITS_BIN_TYPE_I: + scol = (short*)(cols[i]) ; + scol += col->atom_nb * j ; + /* For each atom of the column */ + for (k=0 ; katom_nb-1 ; k++) { + sprintf(ctmp, "%d, ", scol[k]) ; + strcat(str, ctmp) ; + } + /* Handle the last atom differently: no ',' */ + sprintf(ctmp, "%d", scol[col->atom_nb-1]) ; + strcat(str, ctmp) ; + break ; + case TFITS_BIN_TYPE_J: + icol = (int*)(cols[i]) ; + icol += col->atom_nb * j ; + /* For each atom of the column */ + for (k=0 ; katom_nb-1 ; k++) { + sprintf(ctmp, "%d, ", icol[k]) ; + strcat(str, ctmp) ; + } + /* Handle the last atom differently: no ',' */ + sprintf(ctmp, "%d", icol[col->atom_nb-1]) ; + strcat(str, ctmp) ; + break ; + case TFITS_BIN_TYPE_L: + ccol = (char*)(cols[i]) ; + ccol += col->atom_nb * j ; + /* For each atom of the column */ + for (k=0 ; katom_nb-1 ; k++) { + sprintf(ctmp, "%c, ", ccol[k]) ; + strcat(str, ctmp) ; + } + /* Handle the last atom differently: no ',' */ + sprintf(ctmp, "%c", ccol[col->atom_nb-1]) ; + strcat(str, ctmp) ; + break ; + case TFITS_BIN_TYPE_X: + ucol = (unsigned char*)(cols[i]) ; + ucol += col->atom_nb * j ; + /* For each atom of the column */ + for (k=0 ; katom_nb-1 ; k++) { + sprintf(ctmp, "%d, ", ucol[k]) ; + strcat(str, ctmp) ; + } + /* Handle the last atom differently: no ',' */ + sprintf(ctmp, "%d", ucol[col->atom_nb-1]) ; + strcat(str, ctmp) ; + break ; + case TFITS_BIN_TYPE_P: + icol = (int*)(cols[i]) ; + icol += col->atom_nb * j ; + /* For each atom of the column */ + for (k=0 ; katom_nb-1 ; k++) { + sprintf(ctmp, "%d, ", icol[k]) ; + strcat(str, ctmp) ; + } + /* Handle the last atom differently: no ',' */ + sprintf(ctmp, "%d", icol[col->atom_nb-1]) ; + strcat(str, ctmp) ; + break ; + default: + fprintf(out, "Type not recognized") ; + break ; + } + fprintf(out, "%*s", col_sizes[i], str); + if (i!=(tdesc->nc-1)) printf("%c", separator); + free(str) ; + } + fprintf(out, "\n"); + } + return 0 ; +} + +static int dump_extension_ascii( + qfits_table * tdesc, + FILE * out, + void ** cols, + char separator, + int data_only, + int use_zero_scale) +{ + int * col_sizes ; + qfits_col * col ; + char * ccol ; + double * dcol ; + float * fcol ; + int * icol ; + int size ; + int field_size ; + char * str ; + char ctmp[512]; + int i, j, k ; + + /* GET THE FIELDS SIZES */ + col_sizes = calloc(tdesc->nc, sizeof(int)) ; + for (i=0 ; inc ; i++) { + col = tdesc->col + i ; + col_sizes[i] = (int)strlen(col->tlabel) ; + switch(col->atom_type) { + case TFITS_ASCII_TYPE_A: + size = col->atom_nb ; + break ; + case TFITS_ASCII_TYPE_I: + size = DISP_SIZE_INT ; + break ; + case TFITS_ASCII_TYPE_E: + case TFITS_ASCII_TYPE_F: + size = DISP_SIZE_FLOAT ; + break ; + case TFITS_ASCII_TYPE_D: + size = DISP_SIZE_DOUBLE ; + break ; + default: + fprintf(out, "Type not recognized") ; + break ; + } + if (size > col_sizes[i]) col_sizes[i] = size ; + } + + /* Print out the column names */ + if (!data_only) { + for (i=0 ; inc ; i++) { + col = tdesc->col + i ; + fprintf(out, "%*s", col_sizes[i], col->tlabel); + if (i!=(tdesc->nc-1)) printf("%c", separator); + } + fprintf(out, "\n"); + } + + /* Get the string to write according to the type */ + for (j=0 ; jnr ; j++) { + for (i=0 ; inc ; i++) { + if (cols[i] == NULL) continue ; + col = tdesc->col + i ; + field_size = col->atom_nb * ELEMENT_MAX_DISP_SIZE ; + str = malloc(field_size * sizeof(char)) ; + str[0] = (char)0 ; + switch(col->atom_type) { + case TFITS_ASCII_TYPE_A: + ccol = (char*)(cols[i]) ; + ccol += col->atom_nb * j ; + strncpy(ctmp, ccol, col->atom_nb) ; + ctmp[col->atom_nb] = (char)0 ; + strcpy(str, ctmp) ; + break ; + case TFITS_ASCII_TYPE_I: + icol = (int*)(cols[i]) ; + icol += j ; + sprintf(ctmp, "%d", icol[0]) ; + strcat(str, ctmp) ; + break ; + case TFITS_ASCII_TYPE_E: + case TFITS_ASCII_TYPE_F: + fcol = (float*)(cols[i]) ; + fcol += j ; + sprintf(ctmp, "%f", fcol[0]) ; + strcat(str, ctmp) ; + break ; + case TFITS_ASCII_TYPE_D: + dcol = (double*)(cols[i]) ; + dcol += j ; + sprintf(ctmp, "%g", dcol[0]) ; + strcat(str, ctmp) ; + break ; + default: + fprintf(out, "Type not recognized") ; + break ; + } + fprintf(out, "%*s", col_sizes[i], str); + if (i!=(tdesc->nc-1)) printf("%c", separator); + free(str) ; + } + fprintf(out, "\n"); + } + + return 0 ; + +} + + diff --git a/qfits/main/flipx.c b/qfits/main/flipx.c new file mode 100644 index 0000000..a0c93c3 --- /dev/null +++ b/qfits/main/flipx.c @@ -0,0 +1,168 @@ +/*----------------------------------------------------------------------------*/ +/** + @file flipx.c + @author N. Devillard + @date July 2001 + @version $Revision: 1.5 $ + @brief flip x axis in a FITS image +*/ +/*----------------------------------------------------------------------------*/ + +/* + $Id: flipx.c,v 1.5 2002/12/04 13:28:25 yjung Exp $ + $Author: yjung $ + $Date: 2002/12/04 13:28:25 $ + $Revision: 1.5 $ +*/ + +/*----------------------------------------------------------------------------- + Includes + -----------------------------------------------------------------------------*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "qfits.h" + +/*----------------------------------------------------------------------------- + Private functions + -----------------------------------------------------------------------------*/ + +/* + * Swap pixels between position p1 and p2, regardless of the pixel + * type and endian-ness of the local host. + */ +static void swap_pix(char * buf, int p1, int p2, int psize) +{ + int i ; + char c ; + + for (i=0 ; i\n", argv[0]); + return 1 ; + } + err=0 ; + for (i=1 ; i0) { + fprintf(stderr, "%s: %d error(s) occurred\n", argv[0], err); + return -1 ; + } + return 0 ; +} diff --git a/qfits/main/frameq.c b/qfits/main/frameq.c new file mode 100644 index 0000000..f83d1e7 --- /dev/null +++ b/qfits/main/frameq.c @@ -0,0 +1,461 @@ +/*----------------------------------------------------------------------------*/ +/** + @file frameq.c + @author N. Devillard + @date Aug 2000 + @version $Revision: 1.7 $ + @brief Classify frames +*/ +/*----------------------------------------------------------------------------*/ + +/* + $Id: frameq.c,v 1.7 2004/07/21 16:03:21 yjung Exp $ + $Author: yjung $ + $Date: 2004/07/21 16:03:21 $ + $Revision: 1.7 $ +*/ + +/*----------------------------------------------------------------------------- + Includes + -----------------------------------------------------------------------------*/ + +#include +#include +#include +#include +#include +#include +#include +#include "qfits.h" + +/*----------------------------------------------------------------------------- + New types + -----------------------------------------------------------------------------*/ + +/* Frame informations needed to classify it */ +typedef struct _framei { + char * name ; + char * tplid ; + char * origfile ; + int expno ; + int nexp ; + + struct _framei * next ; +} framei ; + +/* Frame queue: is mostly a pointer to a list of frame information objects */ +typedef struct _frameq { + framei * first ; + int n ; +} frameq ; + +/*----------------------------------------------------------------------------- + Global variables + -----------------------------------------------------------------------------*/ + +/* List of strings to identify unwanted templates. */ +char * tpl_filter[] = { + "_acq_", + "_CheckAoCorrection", + NULL +}; + +/*----------------------------------------------------------------------------- + Functions code + -----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/** + @brief Build a new framei object + @param filename FITS file name + @return A newly allocated framei obj. NULL in error case + */ +/*----------------------------------------------------------------------------*/ +static framei * framei_new(char * filename) +{ + framei * fi ; + char * sval ; + char * sval2 ; + int i ; + + fi = malloc(sizeof(framei)); + fi->name = strdup(filename); + sval = qfits_query_hdr(filename, "tpl.id"); + if (sval!=NULL) { + /* Filter out unwanted template IDs */ + i=0 ; + while (tpl_filter[i]!=NULL) { + if (strstr(sval, tpl_filter[i])!=NULL) return NULL ; + i++ ; + } + fi->tplid = strdup(qfits_pretty_string(sval)) ; + } else { + fi->tplid = NULL ; + } + sval = qfits_query_hdr(filename, "origfile"); + if (sval!=NULL) { + sval2 = qfits_pretty_string(sval) ; + fi->origfile = strdup(qfits_get_root_name(sval2)) ; + } else { + fi->origfile = NULL ; + } + sval = qfits_query_hdr(filename, "tpl.expno"); + if (sval!=NULL) fi->expno = (int)atoi(sval); + else fi->expno = -1 ; + sval = qfits_query_hdr(filename, "tpl.nexp"); + if (sval!=NULL) fi->nexp = (int)atoi(sval); + else fi->nexp = -1 ; + + fi->next = NULL ; + return fi ; +} + +/*----------------------------------------------------------------------------*/ +/** + @brief Delete a framei object + @param fi Object to delete + */ +/*----------------------------------------------------------------------------*/ +static void framei_del(framei * fi) +{ + if (fi==NULL) return ; + if (fi->name!=NULL) + free(fi->name); + if (fi->tplid!=NULL) { + free(fi->tplid); + } + if (fi->origfile!=NULL) { + free(fi->origfile); + } + free(fi); +} + +/*----------------------------------------------------------------------------*/ +/** + @brief Create a frameq object + @return A newly allocated empty frameq object + */ +/*----------------------------------------------------------------------------*/ +frameq * frameq_new(void) +{ + frameq * fq ; + + fq = malloc(sizeof(frameq)); + fq->first = NULL ; + fq->n = 0 ; + return fq ; +} + +/*----------------------------------------------------------------------------*/ +/** + @brief Delete a frameq object + @param fq The object to delete + */ +/*----------------------------------------------------------------------------*/ +void frameq_del(frameq * fq) +{ + framei * fi ; + framei * fin ; + + if (fq==NULL) return ; + + fi = fq->first ; + while (fi!=NULL) { + fin = fi->next ; + framei_del(fi); + fi = fin ; + } + free(fq); + return ; +} + +/*----------------------------------------------------------------------------*/ +/** + @brief Append a new frame to an existing frame queue + @param fq The existing frame queue + @param filename The file to append name + */ +/*----------------------------------------------------------------------------*/ +void frameq_append(frameq * fq, char * filename) +{ + framei * fi ; + framei * fn ; + + if (fq==NULL || filename==NULL) return ; + fi = framei_new(filename); + if (fi==NULL) + return ; + if (fq->n==0) { + fq->first = fi ; + fq->n = 1 ; + return ; + } + + fn = fq->first ; + while (fn->next!=NULL) + fn = fn->next ; + + fn->next = fi ; + fq->n ++ ; + return ; +} + +/*----------------------------------------------------------------------------*/ +/** + @brief Pop a frame out of the queue + @param fq The frame queue + */ +/*----------------------------------------------------------------------------*/ +void frameq_pop(frameq * fq) +{ + framei * first ; + + first = fq->first->next ; + framei_del(fq->first); + fq->first = first ; + fq->n -- ; +} + +/*----------------------------------------------------------------------------*/ +/** + @brief Dump a frame queue in a file + @param fq Frame queue to dump + @param out File where the queue is dumped + */ +/*----------------------------------------------------------------------------*/ +void frameq_dump(frameq * fq, FILE * out) +{ + int i ; + framei * fi ; + + fi = fq->first ; + for (i=0 ; in ; i++) { + fprintf(out, + "%s %s %02d/%02d\n", + fi->name, + fi->tplid, + fi->expno, + fi->nexp); + fi = fi->next ; + } +} + +/*----------------------------------------------------------------------------*/ +/** + @brief Create a frame queue from a directory + @param dirname Directory name + @return A newly allocated frame queue + */ +/*----------------------------------------------------------------------------*/ +frameq * frameq_load(char * dirname) +{ + frameq * fq ; + int i ; + glob_t pglob ; + char filename[FILENAMESZ]; + + /* Look for *.fits *.FITS *.fits.gz *.FITS.gz */ + sprintf(filename, "%s/*.fits", dirname); + glob(filename, GLOB_MARK, NULL, &pglob); + sprintf(filename, "%s/*.FITS", dirname); + glob(filename, GLOB_APPEND, NULL, &pglob); + sprintf(filename, "%s/*.fits.gz", dirname); + glob(filename, GLOB_APPEND, NULL, &pglob); + sprintf(filename, "%s/*.FITS.gz", dirname); + glob(filename, GLOB_APPEND, NULL, &pglob); + if (pglob.gl_pathc<1) { + printf("found no frame\n"); + return NULL ; + } + + /* Build frame queue */ + fq = frameq_new(); + for (i=0 ; in * sizeof(char*)); + fn = fq->first ; + for (i=0 ; in ; i++) { + if (fn->tplid==NULL) { + tplid_all[i] = strdup("none"); + } else { + tplid_all[i] = strdup(fn->tplid); + } + fn = fn->next ; + } + /* Sort all tplid's */ + qsort(tplid_all, fq->n, sizeof(char*), stringsort); + + /* Compute how many different tplid's can be found */ + ntplid=1 ; + for (i=1 ; in ; i++) { + if (strcmp(tplid_all[i], tplid_all[i-1])) { + ntplid++ ; + } + } + + tplid = malloc(ntplid * sizeof(char*)); + tplid[0] = tplid_all[0] ; + tplid_all[0] = NULL ; + j=0 ; + for (i=1 ; in ; i++) { + if (strcmp(tplid_all[i], tplid[j])) { + j++ ; + tplid[j] = tplid_all[i] ; + } else { + free(tplid_all[i]); + } + tplid_all[i] = NULL ; + } + free(tplid_all); + + *n = ntplid ; + return tplid ; +} + +/*----------------------------------------------------------------------------*/ +/** + @brief Get the setting number + @param dirname Directory name + @return Setting number + */ +/*----------------------------------------------------------------------------*/ +int frameq_getsetnum(char * dirname) +{ + char pattern[FILENAMESZ]; + glob_t pglob ; + int i ; + int max ; + int num ; + + sprintf(pattern, "%s/set*", dirname); + glob(pattern, GLOB_MARK, NULL, &pglob); + if (pglob.gl_pathc<1) { + max=0 ; + } else { + sprintf(pattern, "%s/set%%02d", dirname); + max=0 ; + for (i=0 ; imax) + max=num ; + } + } + globfree(&pglob); + return max+1 ; +} + +/*----------------------------------------------------------------------------*/ +/** + @brief Classify the frames + @param fq Frame queue + */ +/*----------------------------------------------------------------------------*/ +void frameq_makelists(frameq * fq) +{ + FILE * list ; + char filename[FILENAMESZ]; + framei * fi ; + int setnum ; + int count ; + int batches ; + + /* Count # of batches in input */ + fi = fq->first ; + batches=0 ; + while (fi!=NULL) { + if (fi->expno==1) + batches++ ; + fi = fi->next ; + } + + fi = fq->first ; + count=0 ; + list=NULL ; + while (fi!=NULL) { + printf("\rclassifying batches: %d of %d", count, batches); + fflush(stdout); + if (fi->expno<0) { + fi=fi->next ; + continue ; + } + if (fi->expno==1) { + count++ ; + if (list!=NULL) { + fclose(list); + } + if (fi->tplid == NULL) { + printf("No TPL ID - abort\n") ; + return ; + } + if (fi->origfile == NULL) { + printf("No ORIGFILE - abort\n") ; + return ; + } + mkdir(fi->tplid, 0755); + setnum = frameq_getsetnum(fi->tplid); + sprintf(filename, "%s/%s_%02d", fi->tplid, fi->origfile, fi->nexp); + mkdir(filename, 0755); + sprintf(filename, "%s/%s_%02d/IN", fi->tplid,fi->origfile,fi->nexp); + list = fopen(filename, "w"); + fprintf(list,"# TPL.ID= %s\n", fi->tplid); + fprintf(list,"# NEXP = %02d\n", fi->nexp); + } + if (list) fprintf(list, "%s\n", fi->name); + fi = fi->next ; + } + printf("\n"); + return ; +} + +/*----------------------------------------------------------------------------- + Main + -----------------------------------------------------------------------------*/ +int main(int argc, char * argv[]) +{ + frameq * fq ; + + if (argc<2) { + printf("use: %s \n", argv[0]); + return 1 ; + } + + printf("loading frames from %s...\n", argv[1]); + fq = frameq_load(argv[1]); + printf("processing lists...\n"); + frameq_makelists(fq); + frameq_del(fq); + printf("done\n"); + + return 0 ; +} + diff --git a/qfits/main/qextract.c b/qfits/main/qextract.c new file mode 100644 index 0000000..c926021 --- /dev/null +++ b/qfits/main/qextract.c @@ -0,0 +1,267 @@ +/*----------------------------------------------------------------------------*/ +/** + @file qextract.c + @author Y. Jung + @date Nov, 2002 + @version $Revision: 1.5 $ + @brief Extract a FITS extension and write it in a new FITS file +*/ +/*----------------------------------------------------------------------------*/ + +/* + $Id: qextract.c,v 1.5 2005/06/29 15:14:50 yjung Exp $ + $Author: yjung $ + $Date: 2005/06/29 15:14:50 $ + $Revision: 1.5 $ + */ + +/*----------------------------------------------------------------------------- + Includes + -----------------------------------------------------------------------------*/ + +#include "qfits.h" + +/*----------------------------------------------------------------------------- + Function prototypes + -----------------------------------------------------------------------------*/ + +static int textract_write_ext(char *, int) ; +static int iextract_write_ext(char *, int) ; +static char prog_desc[] = "Extract and write FITS extensions" ; +static void usage(char *) ; + +/*----------------------------------------------------------------------------- + Main + -----------------------------------------------------------------------------*/ +int main(int argc, char *argv[]) +{ + char * name_in ; + int ext ; + int nb_ext ; + int ext_type ; + + if (argc<3) usage(argv[0]) ; + + /* Get input file name and extension number */ + name_in = strdup(argv[1]) ; + ext = (int)atoi(argv[2]) ; + + /* Check if the file is a FITS file */ + if (!is_fits_file(name_in)) { + printf("[%s] is not a FITS file\n", name_in) ; + free(name_in) ; + return -1 ; + } + + /* Check if the extension is valid */ + nb_ext = qfits_query_n_ext(name_in) ; + if (nb_ext < ext) { + printf("Only %d extensions in this file\n", nb_ext) ; + free(name_in) ; + return -1 ; + } + + /* Check if it's a table or an image */ + ext_type = qfits_is_table(name_in, ext) ; + + switch (ext_type) { + case QFITS_BINTABLE: + case QFITS_ASCIITABLE: + if (textract_write_ext(name_in, ext) == -1) { + printf("cannot read-write extension no %d\n", ext) ; + free(name_in) ; + return -1 ; + } + break ; + case QFITS_INVALIDTABLE: + if (iextract_write_ext(name_in, ext) == -1) { + printf("cannot read-write extension no %d\n", ext) ; + free(name_in) ; + return -1 ; + } + break ; + default: + printf("Unrecognized FITS type\n") ; + free(name_in) ; + return -1 ; + } + free(name_in) ; + + return 0 ; +} + +/*----------------------------------------------------------------------------- + Functions code + -----------------------------------------------------------------------------*/ + +static void usage(char * pname) +{ + printf("%s : %s\n", pname, prog_desc) ; + printf( + "use : %s \n" + "\n", pname) ; + exit(0) ; +} + +static int textract_write_ext( + char * in, + int ext) +{ + qfits_table * th ; + void ** array ; + qfits_header * fh ; + int array_size ; + int i ; + + /* Get the table infos */ + if ((th = qfits_table_open(in, ext)) == NULL) { + printf("cannot read extension: %d\n", ext) ; + return -1 ; + } + + /* Compute array_size */ + array_size = 0 ; + for (i=0 ; inc ; i++) { + switch (th->col[i].atom_type) { + case TFITS_ASCII_TYPE_A: + case TFITS_ASCII_TYPE_I: + case TFITS_ASCII_TYPE_E: + case TFITS_ASCII_TYPE_F: + case TFITS_ASCII_TYPE_D: + case TFITS_BIN_TYPE_A: + case TFITS_BIN_TYPE_L: + case TFITS_BIN_TYPE_B: + case TFITS_BIN_TYPE_X: + array_size += sizeof(char*) ; + break ; + + case TFITS_BIN_TYPE_I: + array_size += sizeof(short*) ; + break ; + + case TFITS_BIN_TYPE_J: + case TFITS_BIN_TYPE_E: + array_size += sizeof(int*) ; + break ; + + case TFITS_BIN_TYPE_C: + case TFITS_BIN_TYPE_P: + array_size += sizeof(float*) ; + break ; + + case TFITS_BIN_TYPE_D: + case TFITS_BIN_TYPE_M: + array_size += sizeof(double*) ; + break ; + default: + return -1 ; + } + } + + /* Allocate memory for array */ + array = malloc(array_size) ; + + /* Load columns in array */ + for (i=0 ; inc ; i++) { + array[i] = qfits_query_column_data(th, i, NULL, NULL) ; + if (array[i] == NULL) { + printf("cannot read column %d\n", i+1) ; + } + } + + /* Update th : filename */ + sprintf(th->filename, "ext%d.tfits", ext) ; + + /* Get fits primary header */ + if ((fh = qfits_header_read(in)) == NULL) { + for (i=0 ; inc ; i++) if (array[i] != NULL) free(array[i]) ; + qfits_table_close(th) ; + free(array) ; + printf("cannot read fits header\n") ; + return -1 ; + } + + if (ext != 0) { + /* No data in primary HDU */ + qfits_header_mod(fh, "NAXIS", "0", NULL) ; + qfits_header_del(fh, "NAXIS1") ; + qfits_header_del(fh, "NAXIS2") ; + } + + /* Write the tfits file */ + if (qfits_save_table_hdrdump((void **)array, th, fh) == -1) { + qfits_header_destroy(fh) ; + for (i=0 ; inc ; i++) if (array[i] != NULL) free(array[i]) ; + qfits_table_close(th) ; + free(array) ; + printf("cannot write fits table\n") ; + return -1 ; + } + + /* Free and return */ + qfits_header_destroy(fh) ; + for (i=0 ; inc ; i++) if (array[i] != NULL) free(array[i]) ; + qfits_table_close(th) ; + free(array) ; + return 0 ; +} + +static int iextract_write_ext( + char * in, + int ext) +{ + qfitsloader ql ; + qfitsdumper qd ; + qfits_header * fh ; + char outname[1024] ; + FILE * out ; + + sprintf(outname, "ext%d.fits", ext) ; + + /* Initialize a FITS loader */ + ql.filename = in ; + ql.xtnum = ext ; + ql.pnum = 0 ; + ql.map = 1 ; + ql.ptype = PTYPE_DOUBLE ; + if (qfitsloader_init(&ql)!=0) return -1 ; + + /* Load the primary header */ + if ((fh = qfits_header_read(ql.filename)) == NULL) return -1 ; + + if (ext != 0) { + /* No data in primary HDU */ + qfits_header_mod(fh, "NAXIS", "0", NULL) ; + qfits_header_del(fh, "NAXIS1") ; + qfits_header_del(fh, "NAXIS2") ; + } + + /* Dump the primary header */ + if ((out = fopen(outname, "w")) == NULL) return -1 ; + qfits_header_dump(fh, out); + qfits_header_destroy(fh) ; + + if (ext != 0) { + /* Load the extension header */ + if ((fh = qfits_header_readext(ql.filename, ext)) == NULL) return -1 ; + /* Dump the extension header */ + qfits_header_dump(fh, out); + qfits_header_destroy(fh) ; + } + fclose(out) ; + + /* Load the FITS image */ + if (qfits_loadpix(&ql)!=0) return -1 ; + + /* Write the FITS image */ + qd.filename = outname ; + qd.npix = ql.lx * ql.ly ; + qd.ptype = PTYPE_DOUBLE ; + qd.dbuf = ql.dbuf ; + qd.out_ptype = ql.bitpix ; + if (qfits_pixdump(&qd)!=0) return -1 ; + /* qfits_zeropad(outname) ; */ + free(ql.dbuf) ; + + return 0 ; +} diff --git a/qfits/main/replacekey.c b/qfits/main/replacekey.c new file mode 100644 index 0000000..824dd69 --- /dev/null +++ b/qfits/main/replacekey.c @@ -0,0 +1,212 @@ +/*----------------------------------------------------------------------------*/ +/** + @file replacekey.c + @author N. Devillard + @date July 14th, 1998 + @version $Revision: 1.6 $ + @brief Search & Replace operations in FITS headers +*/ +/*----------------------------------------------------------------------------*/ + +/* + $Id: replacekey.c,v 1.6 2003/08/21 10:44:32 yjung Exp $ + $Author: yjung $ + $Date: 2003/08/21 10:44:32 $ + $Revision: 1.6 $ + */ + +/*----------------------------------------------------------------------------- + Include + -----------------------------------------------------------------------------*/ + +#include "qfits.h" + +/*----------------------------------------------------------------------------- + Define + -----------------------------------------------------------------------------*/ + +#define NM_SIZ 512 + +/*----------------------------------------------------------------------------- + Functions prototypes + -----------------------------------------------------------------------------*/ + +static char prog_desc[] = "replace keyword in a FITS header" ; +static void usage(char *) ; + +/*----------------------------------------------------------------------------- + Main + -----------------------------------------------------------------------------*/ +int main(int argc, char *argv[]) +{ + char * name_in ; + char * card ; + char * place ; + char * key ; + char * key_tmp ; + char * val ; + char * val_tmp ; + char * com ; + char * com_tmp ; + int keep_com ; + int numeric ; + char * stmp ; + int i ; + + char card_tmp[NM_SIZ] ; + + if (argc<2) usage(argv[0]) ; + + /* Initialize */ + name_in = NULL ; + card = NULL ; + place = NULL ; + key = NULL ; + val = NULL ; + com = NULL ; + keep_com = 0 ; + numeric = 0 ; + + /* Command line handling */ + i=1 ; + while (i=argc) { + fprintf(stderr, "option -p needs an argument\n"); + return -1 ; + } + i++ ; + place = strdup(argv[i]); + } else if (!strcmp(argv[i], "-k")) { + if ((i+1)>=argc) { + fprintf(stderr, "option -k needs an argument\n"); + return -1 ; + } + i++ ; + key = strdup(argv[i]); + } else if (!strcmp(argv[i], "-v")) { + if ((i+1)>=argc) { + fprintf(stderr, "option -v needs an argument\n"); + return -1 ; + } + i++ ; + val = strdup(argv[i]); + } else if (!strcmp(argv[i], "-c")) { + if ((i+1)>=argc) { + fprintf(stderr, "option -c needs an argument\n"); + return -1 ; + } + i++ ; + com = strdup(argv[i]); + } else if (!strcmp(argv[i], "-C")) { + keep_com = 1 ; + } else if (!strcmp(argv[i], "-n")) { + numeric = 1 ; + } else { + break ; + } + i++ ; + } + + /* Check options coherence */ + if ((keep_com == 1) && (com != NULL)) { + fprintf(stderr, "options -c and -C should not be used together\n") ; + if (place) free(place) ; + if (key) free(key) ; + if (val) free(val) ; + free(com) ; + return -1 ; + } + if (place == NULL) { + fprintf(stderr, "options -p has to be used\n") ; + if (key) free(key) ; + if (val) free(val) ; + if (com) free(com) ; + return -1 ; + } + + /* Get input file name */ + if ((argc-i)<1) { + fprintf(stderr, "missing input file name\n"); + return -1 ; + } + + /* Loop on the input files */ + while (argc-i >= 1) { + name_in = strdup(argv[i]) ; + + /* Set keyword to write */ + key_tmp = NULL ; + if (key==NULL) key_tmp = strdup(place) ; + else key_tmp = strdup(key) ; + + /* Set value to write */ + val_tmp = NULL ; + if (val==NULL) { + card = qfits_query_card(name_in, place) ; + if (card!= NULL) { + stmp = qfits_getvalue(card) ; + val_tmp = strdup(stmp) ; + } + } else val_tmp = strdup(val) ; + + com_tmp = NULL ; + /* Set comment to write */ + if ((com == NULL) && (keep_com == 1)) { + if (card == NULL) card = qfits_query_card(name_in, place) ; + if (card != NULL) { + stmp = qfits_getcomment(card) ; + com_tmp = strdup(stmp) ; + } + } else if (com != NULL) com_tmp = strdup(com) ; + if (card != NULL) free(card) ; + card = NULL ; + printf("DEBUG: %s\n", key_tmp) ; + + /* Create the card */ + keytuple2str(card_tmp, key_tmp, val_tmp, com_tmp) ; + if (key_tmp) free(key_tmp) ; + if (val_tmp) free(val_tmp) ; + if (com_tmp) free(com_tmp) ; + card = strdup(card_tmp) ; + + /* Display what will be written where */ + printf("File %s\n", name_in) ; + printf("\tcard : \n\t\t%s\n", card) ; + printf("\tplace : \n\t\t%s\n", place) ; + + /* Try to replace the first key */ + if (qfits_replace_card(name_in, place, card) == -1) { + fprintf(stderr, "cannot replace the key %s\n", place) ; + } + free(name_in); + free(card) ; + card = NULL ; + i++ ; + } + + if (val) free(val) ; + if (com) free(com) ; + if (key) free(key) ; + free(place) ; + /* Free and return */ + return 0 ; +} + +static void usage(char * pname) +{ + printf("%s : %s\n", pname, prog_desc) ; + printf( + "use : %s [options] \n" + "options are:\n" + "\t-p place gives the keyword to write over (required).\n" + "\t-k key gives the new keyword name (optional).\n" + "\t-v val gives the value to write (optional).\n" + "\t-c com gives the comment to write (optional).\n" + "\t-C flag to keep comment\n" + "\n", pname) ; + exit(0) ; +} + diff --git a/qfits/saft/Makefile b/qfits/saft/Makefile new file mode 100644 index 0000000..18a6b49 --- /dev/null +++ b/qfits/saft/Makefile @@ -0,0 +1,41 @@ +# General definitions +# + +include ../config.make + +RM = rm -f +CP = cp +MV = mv +BINDIR = ../bin + +default: all + + +PROGS = $(BINDIR)/fitsort \ + $(BINDIR)/hierarch28 \ + $(BINDIR)/iofits \ + $(BINDIR)/fitsmd5 + +all: $(PROGS) + +veryclean: + @(echo "cleaning saft programs...") + @($(RM) $(PROGS)) + + +$(BINDIR)/fitsort: fitsort.c + @(echo "building $@ ...") + @($(CC) $(CFLAGS) $(LFLAGS) -o $(BINDIR)/fitsort fitsort.c) + +$(BINDIR)/hierarch28: hierarch28.c + @(echo "building $@ ...") + @($(CC) $(CFLAGS) $(LFLAGS) -o $(BINDIR)/hierarch28 hierarch28.c) + +$(BINDIR)/iofits: iofits.c + @(echo "building $@ ...") + @($(CC) $(CFLAGS) $(LFLAGS) -o $(BINDIR)/iofits iofits.c) + +$(BINDIR)/fitsmd5: fitsmd5.c + @(echo "building $@ ...") + @($(CC) $(CFLAGS) $(LFLAGS) -o $(BINDIR)/fitsmd5 fitsmd5.c) + diff --git a/qfits/saft/fitsmd5.c b/qfits/saft/fitsmd5.c new file mode 100644 index 0000000..ff0e36f --- /dev/null +++ b/qfits/saft/fitsmd5.c @@ -0,0 +1,790 @@ +/*----------------------------------------------------------------------------*/ +/** + @file fitsmd5.c + @author N. Devillard + @date May 2001 + @version $Revision: 1.5 $ + @brief Display/Add/Update the DATAMD5 keyword/value + This is a stand-alone utility. Compile it with any ANSI C compiler: + % cc -o fitsmd5 fitsmd5.c [optional optimization options] +*/ +/*----------------------------------------------------------------------------*/ + +/* + $Id: fitsmd5.c,v 1.5 2003/07/04 15:08:04 yjung Exp $ + $Author: yjung $ + $Date: 2003/07/04 15:08:04 $ + $Revision: 1.5 $ +*/ + +/*----------------------------------------------------------------------------- + Includes + -----------------------------------------------------------------------------*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +/*----------------------------------------------------------------------------- + Support for gzipped files if linked against zlib. + -----------------------------------------------------------------------------*/ + +#if HAVE_ZLIB +#include "zlib.h" + +#define FILE gzFile +#define fopen gzopen +#define fclose gzclose +#define fread(b,s,n,f) gzread(f,b,n*s) + +#define GZIP_MAGIC1 0x1f +#define GZIP_MAGIC2 0x8b + +static is_gzipped(char * filename) +{ + FILE * in ; + unsigned char b1, b2 ; + int r1, r2 ; + + if ((in=fopen(filename, "r"))==NULL) { + return -1 ; + } + r1 = fread(&b1, 1, 1, in); + r2 = fread(&b2, 1, 1, in); + fclose(in); + if (r1!=1 || r2!=1) + return 0 ; + if ((int)b1!=GZIP_MAGIC1 || (int)b2!=GZIP_MAGIC2) { + return 0 ; + } + return 1 ; +} +#endif + +/*----------------------------------------------------------------------------- + Define + -----------------------------------------------------------------------------*/ + +/* Definitions related to FITS */ +#define FITSLINESZ 80 /* a FITS line is 80 chars */ +#define FITSCARDS 36 /* 36 cards per block */ +#define FITSBLOCKSZ (FITSLINESZ*FITSCARDS) /* FITS block size=2880 */ + +/* Definitions related to MD5 */ +#define MD5HASHSZ 32 /* an MD5 key length is 32 bytes = 128 bits */ + +/* FITS keyword used to store MD5 key */ +#define FITSMD5KEY "DATAMD5 " + +/*----------------------------------------------------------------------------- + New types + -----------------------------------------------------------------------------*/ + +/* The following types defined for MD5 computation only */ +typedef unsigned int word32 ; + +struct MD5Context { + word32 buf[4]; + word32 bits[2]; + unsigned char in[64]; +}; + +/*----------------------------------------------------------------------------- + Private function prototypes + -----------------------------------------------------------------------------*/ + +static void MD5Init(struct MD5Context *); +static void MD5Update(struct MD5Context *, unsigned char *, unsigned); +static void MD5Final(unsigned char *, struct MD5Context *); +static void MD5Transform(word32 *, word32 *); +static void byteReverse(unsigned char *, unsigned); + +static int fits_md5_check(char *, int); +static char * fits_pretty_string(char *); +static char * fits_getvalue(char *); + +static void usage(void); + +/*----------------------------------------------------------------------------- + Global variables + -----------------------------------------------------------------------------*/ + +static char * pname = NULL ; +static char prog_desc[] = "Compute/Update the DATAMD5 keyword/value" ; +static int silent_process=0 ; + +/*----------------------------------------------------------------------------- + MD5 function code + -----------------------------------------------------------------------------*/ + +/* Reverse bytes in a 32-bit word. Harmless on little endian machines */ +static void byteReverse(unsigned char *buf, unsigned longs) +{ + word32 t; + do { + t = (word32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | + ((unsigned) buf[1] << 8 | buf[0]); + *(word32 *) buf = t; + buf += 4; + } while (--longs); +} + +/* Start MD5 accumulation. Set bit count to 0 and buffer to MD5 init. const. */ +static void MD5Init(struct MD5Context *ctx) +{ + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + ctx->bits[0] = 0; + ctx->bits[1] = 0; +} + +/* Update to reflect the concatenation of another buffer full of bytes. */ +static void MD5Update(struct MD5Context *ctx, unsigned char *buf, unsigned len) +{ + register word32 t; + + /* Update bitcount */ + t = ctx->bits[0]; + if ((ctx->bits[0] = t + ((word32) len << 3)) < t) + ctx->bits[1]++; /* Carry from low to high */ + ctx->bits[1] += len >> 29; + + t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ + + /* Handle any leading odd-sized chunks */ + if (t) { + unsigned char *p = (unsigned char *) ctx->in + t; + t = 64 - t; + if (len < t) { + memmove(p, buf, len); + return; + } + memmove(p, buf, t); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (word32 *) ctx->in); + buf += t; + len -= t; + } + /* Process data in 64-byte chunks */ + while (len >= 64) { + memmove(ctx->in, buf, 64); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (word32 *) ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + memmove(ctx->in, buf, len); +} + +/* Final wrapup - pad to 64-byte boundary with the bit pattern 1 0* */ + /* (64-bit count of bits processed, MSB-first) */ +static void MD5Final(unsigned char digest[16], struct MD5Context *ctx) +{ + unsigned int count ; + unsigned char * p ; + + /* Compute number of bytes mod 64 */ + count = (ctx->bits[0] >> 3) & 0x3F; + + /* Set the first char of padding to 0x80. This is safe since there is + always at least one byte free */ + p = ctx->in + count; + *p++ = 0x80; + + /* Bytes of padding needed to make 64 bytes */ + count = 64 - 1 - count; + + /* Pad out to 56 mod 64 */ + if (count < 8) { + /* Two lots of padding: Pad the first block to 64 bytes */ + memset(p, 0, count); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (word32 *) ctx->in); + + /* Now fill the next block with 56 bytes */ + memset(ctx->in, 0, 56); + } else { + /* Pad block to 56 bytes */ + memset(p, 0, count - 8); + } + byteReverse(ctx->in, 14); + + /* Append length in bits and transform */ + ((word32 *) ctx->in)[14] = ctx->bits[0]; + ((word32 *) ctx->in)[15] = ctx->bits[1]; + + MD5Transform(ctx->buf, (word32 *) ctx->in); + byteReverse((unsigned char *) ctx->buf, 4); + memmove(digest, ctx->buf, 16); + memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ +} + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f, w, x, y, z, data, s) \ + ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +static void MD5Transform(word32 buf[4], word32 in[16]) +{ + register word32 a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + + +/*----------------------------------------------------------------------------- + FITS-related functions + -----------------------------------------------------------------------------*/ + +/* Pretty-print a FITS string value */ +static char * fits_pretty_string(char * s) +{ + static char pretty[FITSLINESZ+1] ; + int i,j ; + + if (s==NULL) return NULL ; + + pretty[0] = (char)0 ; + if (s[0]!='\'') return s ; + + /* skip first quote */ + i=1 ; + j=0 ; + /* trim left-side blanks */ + while (s[i]==' ') { + if (i==(int)strlen(s)) break ; + i++ ; + } + if (i>=(int)(strlen(s)-1)) return pretty ; + /* copy string, changing double quotes to single ones */ + while (i<(int)strlen(s)) { + if (s[i]=='\'') i++ ; + pretty[j]=s[i]; + i++ ; + j++ ; + } + /* NULL-terminate the pretty string */ + pretty[j+1]=(char)0; + /* trim right-side blanks */ + j = (int)strlen(pretty)-1; + while (pretty[j]==' ') j-- ; + pretty[j+1]=(char)0; + return pretty; +} + +/* Get the FITS value in a FITS card */ +static char * fits_getvalue(char * line) +{ + static char value[FITSLINESZ+1] ; + int from, to ; + int inq ; + int i ; + + if (line==NULL) return NULL ; + memset(value, 0, FITSLINESZ+1); + /* Get past the keyword */ + i=0 ; + while (line[i]!='=' && iFITSLINESZ) return NULL ; + i++ ; + while (line[i]==' ' && iFITSLINESZ) return NULL ; + from=i; + /* Now in the value section */ + /* Look for the first slash '/' outside of a string */ + inq = 0 ; + while (i=0) i-- ; + if (i<0) return NULL ; + to=i ; + if (to\n" + "options are:\n" + "\t-u update MD5 keyword in the file: %s\n" + "\t-s silent mode\n" + "\n" + "\t-a compute MD5 sum of the complete file (incl.header)\n" + "\n" + "This utility computes the MD5 checksum of all data sections\n" + "in a given FITS file, and compares it against the value\n" + "declared in DATAMD5 if present. It can also update the value\n" + "of this keyword (if present) with its own computed MD5 sum.\n" + "\n", pname, FITSMD5KEY) ; + printf( + "You can also use it with the -a option to compute the MD5 sum\n" + "on the complete file (all bits). In this case, the file needs\n" + "not be FITS. This option is only provided to check this program\n" + "against other MD5 computation tools.\n" + "NB: Other options cannot be used together with -a.\n" + "\n"); + +#if HAVE_ZLIB + printf( + "\n" + "This program was compiled against zlib %s\n" + "which allows to process gzipped FITS files\n" + "as if they were normal FITS files.\n" + "Notice that you cannot use the -u option on\n" + "gzipped files, though.\n" + "\n" + "\n", + ZLIB_VERSION + ); +#endif + exit(0) ; +} + +/*----------------------------------------------------------------------------- + Main + -----------------------------------------------------------------------------*/ +int main(int argc, char *argv[]) +{ + int i ; + int update_header ; + int total_md5 ; + int err ; + + /* Initialize */ + pname=argv[0]; + update_header = 0 ; + total_md5 = 0 ; + + if (argc<2) usage(); + + /* Parse arguments for options */ + for (i=1 ; i0) { + fprintf(stderr, "%s: %d error(s) during process\n", pname, err); + } + return err ; +} diff --git a/qfits/saft/fitsort.c b/qfits/saft/fitsort.c new file mode 100644 index 0000000..1a58ce0 --- /dev/null +++ b/qfits/saft/fitsort.c @@ -0,0 +1,373 @@ +/*----------------------------------------------------------------------------*/ +/** + @file fitsort.c + @author Nicolas Devillard + @date May 1st, 1996 + @version $Revision: 1.4 $ + @brief Sorts out FITS keywords + + The input is a succession of FITS headers delivered through stdin by + 'dfits'. On the command line, specify which keywords you wish to display, the + output contains for each file, the file name and the keyword values in + column format. Example: + + dfits *.fits | fitsort BITPIX NAXIS NAXIS1 NAXIS2 NAXIS3 + The output would be like: + File BITPIX NAXIS NAXIS1 NAXIS2 NAXIS3 + image1.fits 32 2 256 256 + image2.fits -32 3 128 128 40 + + Using 'fitsort -d ...' would prevent printing the first line (filename and + keyword names). + The output format is simple: values are separated by tabs, records by + linefeeds. When no value is present (no keyword in this header), only a tab + is printed out. Example: + + file1.fits contains NAXIS1=100 NAXIS2=200 + file2.fits contains NAXIS1=20 + dfits file1.fits file2.fits | fitsort NAXIS2 NAXIS1 + would litterally print out (\t stands for tab, \n for linefeed): + file1.fits\t200\t100\n + file2.fits\t\t20\n +*/ +/*----------------------------------------------------------------------------*/ + +/* + $Id: fitsort.c,v 1.4 2005/07/04 14:21:31 yjung Exp $ + $Author: yjung $ + $Date: 2005/07/04 14:21:31 $ + $Revision: 1.4 $ + */ + +/*----------------------------------------------------------------------------- + Include + -----------------------------------------------------------------------------*/ + +#include +#include +#include +#include + +/*----------------------------------------------------------------------------- + Define + -----------------------------------------------------------------------------*/ + +#define MAX_STRING 128 +#define MAX_KEY 512 +#define FMT_STRING "%%-%ds\t" + +/*----------------------------------------------------------------------------- + New types + -----------------------------------------------------------------------------*/ + +/* This holds a keyword value and a flag to indicate its presence */ +typedef struct _KEYWORD_ { + char value[MAX_STRING] ; + int present ; +} keyword ; + +/* Each detected file in input has such an associated structure */ +typedef struct _RECORD_ { + char filename[MAX_STRING] ; + keyword listkw[MAX_KEY] ; +} record ; + +/*----------------------------------------------------------------------------- + Function prototypes + -----------------------------------------------------------------------------*/ + +static int isfilename(char *string) ; +static void getfilename(char *line, char *word) ; +static char * expand_hierarch_keyword(char *, char *) ; +static int isdetectedkeyword(char *line, char *keywords[], int nkeys) ; +static void getkeywordvalue(char *line, char *word) ; + +/*----------------------------------------------------------------------------- + Main + -----------------------------------------------------------------------------*/ +int main(int argc, char *argv[]) +{ + char curline[MAX_STRING] ; + char word[MAX_STRING] ; + int i, j ; + int nfiles ; + record *allrecords ; + int kwnum ; + int len ; + int max_width[MAX_KEY] ; + int max_filnam ; + char fmt[8] ; + int flag ; + int printnames ; + int print_hdr ; + + if (argc<2) { + printf("\n\nuse : %s [-d] KEY1 KEY2 ... KEYn\n", argv[0]) ; + printf("Input data is received from stdin\n") ; + printf("See man page for more details and examples\n\n") ; + return 0 ; + } + + /* Initialize */ + printnames = 0 ; + print_hdr = 1 ; + nfiles = 0 ; + allrecords = (record*)calloc(1, sizeof(record)); + if (!strcmp(argv[1], "-d")) { + print_hdr = 0; + argv++ ; + argc-- ; + } + argv++ ; + + /* Uppercase all inputs */ + for (i=0 ; i<(argc-1) ; i++) { + j=0 ; + while (argv[i][j]!=0) { + argv[i][j] = toupper(argv[i][j]); + j++ ; + } + } + + while (fgets(curline, MAX_STRING, stdin) != (char*)NULL) { + flag=isfilename(curline) ; + if (flag == 1) { + /* New file name is detected, get the new file name */ + printnames = 1 ; + getfilename(curline, allrecords[nfiles].filename) ; + nfiles++ ; + + /* Initialize a new record structure to store data for this file. */ + allrecords = (record*)realloc(allrecords,(nfiles+1)*sizeof(record)); + for (i=0 ; i0) { + /* It has been detected as a searched keyword. */ + /* Get its value, store it, present flag up */ + getkeywordvalue(curline, word) ; + strcpy(allrecords[nfiles-1].listkw[kwnum].value, word) ; + allrecords[nfiles-1].listkw[kwnum].present ++ ; + } + } + } + } + for (i=0 ; imax_filnam) max_filnam=len ; + for (kwnum=0 ; kwnummax_width[kwnum]) max_width[kwnum] = len ; + } + } + + /* Print out header line */ + if (print_hdr) { + sprintf(fmt, FMT_STRING, max_filnam) ; + if (printnames) printf(fmt, "FILE"); + for (i=0 ; i", 5)) return 1 ; + if (!strncmp(string, "===>", 4)) return 2 ; + return 0 ; +} + +/*----------------------------------------------------------------------------*/ +/** + @brief returns a file name from a dfits output line + @param line dfits output line + @param word file name + @return a file name from a dfits output line + This is dfits dependent. + */ +/*----------------------------------------------------------------------------*/ +static void getfilename(char * line, char * word) +{ + /* get filename from a dfits output */ + sscanf(line, "%*s %*s %s", word) ; + return ; +} + +/*----------------------------------------------------------------------------*/ +/** + @brief detects a if a keyword is present in a FITS line + @param line FITS line + @param keywords set of keywords + @param nkeys number of kw in the set + @return keyword rank, -1 if unidentified + Feed this function a FITS line, a set of keywords in the *argv[] fashion + (*keywords[]). If the provided line appears to contain one of the keywords + registered in the list, the rank of the keyword in the list is returned, + otherwise, -1 is returned. + */ +/*----------------------------------------------------------------------------*/ +static int isdetectedkeyword( + char * line, + char * keywords[], + int nkeys) +{ + char kw[MAX_STRING] ; + char esokw[MAX_STRING] ; + int i ; + + /* The keyword is up to the equal character, with trailing blanks removed */ + strcpy(kw, line) ; + strtok(kw, "=") ; + /* Now remove all trailing blanks (if any) */ + i = (int)strlen(kw) -1 ; + while (kw[i] == ' ') i -- ; + kw[i+1] = (char)0 ; + + /* Now compare what we got with what's available */ + for (i=0 ; i=80) search = 0 ; + else if ((line[c] == '/') && (quote == 0)) search = 0 ; + if (line[c] == '\'') quote = !quote ; + tmp[w++] = line[c++] ; + } + + /* NULL termination of the string */ + tmp[--w] = (char)0 ; + + /* Return the keyword only : a diff is made between text fields and nbs. */ + if ((begin = strchr(tmp, '\'')) != (char*)NULL) { + /* A quote has been found: it is a string value */ + begin++ ; + end = strrchr(tmp, '\'') ; + length = (int)strlen(begin) - (int)strlen(end) ; + strncpy(word, begin, length) ; + } else { + /* No quote, just get the value (only one, no complex supported) */ + sscanf(tmp, "%s", word) ; + } + + return ; +} + diff --git a/qfits/saft/hierarch28.c b/qfits/saft/hierarch28.c new file mode 100644 index 0000000..4e22ca7 --- /dev/null +++ b/qfits/saft/hierarch28.c @@ -0,0 +1,603 @@ +/*----------------------------------------------------------------------------*/ +/** + @file hierarch28.c + @author N. Devillard + @date July 14th, 1998 + @version $Revision: 1.6 $ + @brief header conversion from ESO-FITS to standard FITS +*/ +/*----------------------------------------------------------------------------*/ + +/* + $Id: hierarch28.c,v 1.6 2005/06/29 15:14:50 yjung Exp $ + $Author: yjung $ + $Date: 2005/06/29 15:14:50 $ + $Revision: 1.6 $ + */ + +/*----------------------------------------------------------------------------- + Include + -----------------------------------------------------------------------------*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/*----------------------------------------------------------------------------- + Define + -----------------------------------------------------------------------------*/ + +#define NM_SIZ 512 +#define FITS_LINE 80 + +/*----------------------------------------------------------------------------- + Function prototypes + -----------------------------------------------------------------------------*/ + +static char prog_desc[] = "header conversion from ESO to standard FITS" ; +static void usage(char *) ; +static int convert_eso_to_std_FITS(char *, char *) ; +static void free_keys(char **, int n) ; +static void strip_beg_end(char *) ; +static int search_and_replace_kw(char *, int, char **, char **, int) ; +static void search_rep(char *, char *, char *); +static void generate_default_convtab(void); +static char * convert_deg_to_str(double deg) ; + +/*----------------------------------------------------------------------------- + Static variables + -----------------------------------------------------------------------------*/ + +static char CONVTAB_DEFAULT1[] = +"#\n" +"# Example of conversion table for hierarch28\n" +"#\n" +"# A note about this file's format:\n" +"# Any blank line or line starting with a hash is ignored.\n" +"# Declare the keyword names to search and replace with:\n" +"#\n" +"# OLDKEYWORD = NEWKEYWORD\n" +"#\n" +"# Spaces are allowed within keyword names, to allow e.g.:\n" +"#\n" +"# HIERARCH ESO DET NDIT = DET NDIT\n" +"#\n" +"# The most important restriction is that new keywords shall not be\n" +"# longer than the keywords they replace.\n" +"#\n" ; + + +static char CONVTAB_DEFAULT2[] = +"#\n" +"# Translation table for basic keywords used by IRAF\n" +"# -------------------------------------------------\n" +"#\n" +"# Note: hierarch28 will replace keywords in the main header\n" +"# and also in extensions.\n" +"#\n" +"# Disclaimer:\n" +"# this table has been compiled to best knowledge of present\n" +"# IRAF packages. Please let us know of any addition/change.\n" +"#\n" +"\n" ; + + +static char CONVTAB_DEFAULT3[] = +"UTC = UT\n" +"LST = ST\n" +"RA = RA\n" +"DEC = DEC\n" +"\n" +"HIERARCH ESO TEL AIRM START = AIRMASS\n" +"HIERARCH ESO DPR TYPE = IMAGETYP\n" +"HIERARCH ESO INS FILT1 NAME = FILTER1\n" +"HIERARCH ESO INS SLIT2 NAME = SLIT\n" +"HIERARCH ESO INS GRIS1 NAME = GRISM\n" +"HIERARCH ESO INS GRAT NAME = GRAT\n" +"HIERARCH ESO INS GRAT1 NAME = GRAT1\n" +"HIERARCH ESO INS GRAT2 NAME = GRAT2\n" +"HIERARCH ESO INS GRAT WLEN = WLEN\n" +"HIERARCH ESO INS GRAT1 WLEN = WLEN1\n" +"HIERARCH ESO INS GRAT2 WLEN = WLEN2\n" +"HIERARCH ESO INS GRAT ORDER = ORDER\n" +"\n" ; + +static char CONVTAB_DEFAULT4[] = +"#\n" +"# A note for IRAF users:\n" +"# Be aware also that the ESO convention names the keywords UTC and\n" +"# LST, whereas the IRAF convention is 'UT' and 'ST'.\n" +"#\n" +"# The ESO standard (see http://archive.eso.org/dicb) defines these\n" +"# keywords as floating point values with the units degrees for RA/DEC\n" +"# and elapsed seconds since midnight for UT/ST.\n" +"#\n" +"# In order to have this tranlation performed, add\n" +"# RA = RA\n" +"# DEC = DEC\n" +"# UTC = UT\n" +"# LST = ST\n" +"# to the conversion table.\n" +"#\n"; + +/*----------------------------------------------------------------------------- + Main + -----------------------------------------------------------------------------*/ +int main(int argc, char *argv[]) +{ + char name_conv[NM_SIZ] ; + char name_in[NM_SIZ] ; + + if (argc<2) usage(argv[0]) ; + if (!strcmp(argv[1], "-g")) { + generate_default_convtab() ; + return 0 ; + } + + strcpy(name_in, argv[1]) ; + if (argc==3) { + strcpy(name_conv, argv[2]) ; + } else { + strcpy(name_conv, "table.conv") ; + } + + if (convert_eso_to_std_FITS(name_in, name_conv) != 0) { + fprintf(stderr, "error during conversion: aborting\n") ; + } + return 0 ; +} + +static void usage(char * pname) +{ + printf( +"\n\n" +"hierarch28 (hierarch-to-eight)\n" +"%s : %s\n" +"use : %s [options] [table]\n" +"options are:\n" +"\t-g generates a generic table\n" +"\n" +"default conversion table name is 'table.conv'\n" +"\n" +"More help can be found in the comments included in the default\n" +"conversion table. Generate one with the -g option and read it.\n" +"\n\n", + pname, prog_desc, pname); + exit(0) ; +} + + +/*----------------------------------------------------------------------------*/ +/** + @brief Search and replace FITS keywords in main/extension headers. + @param name_in File to modify. + @param name_conv Conversion table name. + @return int 0 if Ok, non-zero if error occurred. + + The input file is modified in place. Keyword names are replaced + according to the input conversion table. In some special cases, the + keyword values are also modified to follow the IRAF convention. + */ +/*----------------------------------------------------------------------------*/ +static int convert_eso_to_std_FITS(char * name_in, char * name_conv) +{ + FILE * convtab ; + int nkeys ; + int i ; + char ** key_in ; + char ** key_out ; + int fd ; + char * buf ; + char line[NM_SIZ] ; + char kw1[FITS_LINE], + kw2[FITS_LINE] ; + int lineno ; + int fs ; + struct stat fileinfo ; + + /* Read conversion table and translate it to key_in, key_out */ + if ((convtab = fopen(name_conv, "r")) == NULL) { + fprintf(stderr, "cannot open conversion table: %s\n", name_conv) ; + return -1 ; + } + + /* First, count how many keywords we need to translate */ + nkeys = 0 ; + while (fgets(line, FITS_LINE, convtab)!=NULL) { + if ((line[0] != '#') && (line[0] != '\n')) { + nkeys ++ ; + } + } + rewind(convtab) ; + + /* Allocate space to store keyword info */ + key_in = malloc(nkeys * sizeof(char*)) ; + key_out = malloc(nkeys * sizeof(char*)) ; + + /* Now read the file through and get the keywords */ + i = 0 ; + lineno = 0 ; + while (fgets(line, FITS_LINE, convtab)!=NULL) { + lineno++ ; + if ((line[0]!='#') && (line[0]!='\n')) { + if (sscanf(line, "%[^=] = %[^;#]", kw1, kw2)!=2) { + fprintf(stderr, + "*** error parsing table file %s\n", name_conv); + fprintf(stderr, "line: %d\n", lineno) ; + free_keys(key_in, i) ; + free_keys(key_out, i) ; + fclose(convtab) ; + return -1 ; + } + strip_beg_end(kw1) ; + strip_beg_end(kw2) ; + if (strlen(kw2)>strlen(kw1)) { + fprintf(stderr, + "*** error in conversion table %s (line %d)\n", + name_conv, lineno); + fprintf(stderr, + "*** error: dest keyword is longer than original\n"); + fprintf(stderr, "orig: [%s] dest: [%s]\n", kw1, kw2); + fclose(convtab) ; + free_keys(key_in, i) ; + free_keys(key_out, i) ; + return -1 ; + } + key_in[i] = strdup(kw1) ; + key_out[i] = strdup(kw2) ; + i++ ; + } + } + fclose(convtab) ; + + /* Print out some information about what is being done */ + printf("\n\n") ; + printf("*** hierarch28\n") ; + printf("\n") ; + printf("searching %s and replacing the following keywords:\n", name_in) ; + for (i=0 ; i\t[%s]\n", key_in[i], key_out[i]) ; + } + printf("\n\n") ; + + /* mmap the input file entirely */ + if (stat(name_in, &fileinfo)!=0) { + fprintf(stderr, "*** error: accessing file [%s]\n", name_in); + free_keys(key_in, nkeys) ; + free_keys(key_out, nkeys) ; + return -1 ; + } + fs = (int)fileinfo.st_size ; + if (fs < 1) { + fprintf(stderr, "error getting FITS header size for %s\n", name_in); + free_keys(key_in, nkeys) ; + free_keys(key_out, nkeys) ; + return -1 ; + } + fd = open(name_in, O_RDWR) ; + if (fd == -1) { + fprintf(stderr, "cannot open %s: aborting\n", name_in) ; + free_keys(key_in, nkeys) ; + free_keys(key_out, nkeys) ; + return -1 ; + } + buf = (char*)mmap(0, + fs, + PROT_READ | PROT_WRITE, + MAP_SHARED, + fd, + 0) ; + if (buf == (char*)-1) { + perror("mmap") ; + fprintf(stderr, "cannot mmap file: %s\n", name_in) ; + free_keys(key_in, nkeys) ; + free_keys(key_out, nkeys) ; + close(fd) ; + return -1 ; + } + + /* Apply search and replace for the input keyword lists */ + if (search_and_replace_kw(buf, fs, key_in, key_out, nkeys) != 0) { + fprintf(stderr, "error while doing search and replace\n") ; + } + free_keys(key_in, nkeys) ; + free_keys(key_out, nkeys) ; + close(fd) ; + munmap(buf, fs) ; + return 0 ; +} + +/*----------------------------------------------------------------------------*/ +/** + @brief Strips out blank characters off a character string. + @param s NULL-terminated string to process. + @return void + + This function removes heading and trailing blanks from a + NULL-terminated character string. The input string is modified. The + input string is assumed to contain only blanks or alphanumeric + characters (like FITS keywords). + */ +/*----------------------------------------------------------------------------*/ +static void strip_beg_end(char * s) +{ + int beg, len ; + + beg = 0 ; + while (!isalnum((unsigned char)(s[beg]))) beg++ ; + + len = (int)strlen(s) -1 ; + while (!isalnum((unsigned char)(s[len]))) len -- ; + + strncpy(s, s+beg, len-beg+1) ; + s[len-beg+1] = (char)0 ; + return ; +} + +/*----------------------------------------------------------------------------*/ +/** + @brief Free memory associated to an array of keys. + @param keyt Key table. + @param n Number of keys in the table. + @return void + + Memory was initially allocated using strdup(). This frees all the + keys and the master table pointer. + */ +/*----------------------------------------------------------------------------*/ +static void free_keys(char ** keyt, int n) +{ + int i ; + + if (n<1) return ; + for (i=0 ; i +#include +#include +#include +#include +#include +#include +#include +#include + +/*----------------------------------------------------------------------------- + Define + -----------------------------------------------------------------------------*/ + +#define NM_SIZ 512 +#define FITS_BLSZ 2880 +#define ONE_MEGABYTE (1024 * 1024) + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif + +#define ENDIAN_UNKNOWN -1 +#define ENDIAN_MOTOROLA 0 +#define ENDIAN_INTEL 1 + +/*----------------------------------------------------------------------------- + Macros + -----------------------------------------------------------------------------*/ + +#define ENDIAN_NESS(f) ((f)&1) +#define IEEE_FLOAT_COMPAT(f) ((f)&2) +#define IEEE_DOUBLE_COMPAT(f) ((f)&4) + +/*----------------------------------------------------------------------------- + typedefs + -----------------------------------------------------------------------------*/ + +typedef short short16 ; +typedef unsigned short ushort16 ; +typedef int long32 ; +typedef unsigned char byte ; + +/*----------------------------------------------------------------------------- + Function prototypes + -----------------------------------------------------------------------------*/ + +static int bits_per_byte(void); +static int convert_fits_pixel_depth(char*, char*, int) ; +static int get_FITS_header_size(char*); +static int filesize(char*) ; +static int get_bitpix(char*) ; +static int set_bitpix(char*, int) ; +static int get_npix(char*) ; +static int write_pixbuf(char*, char*, int, int, int) ; +static int test_machine_formats(void) ; +static void swap_bytes(void*, int); +static void check_all_types(int) ; + +/*----------------------------------------------------------------------------- + Global variables + -----------------------------------------------------------------------------*/ + +static unsigned compat_flags ; + +/*----------------------------------------------------------------------------- + Main + -----------------------------------------------------------------------------*/ +int main(int argc, char *argv[]) +{ + int ptype ; + + if (argc!=4) { + printf("\n\n") ; + printf("use: %s <8|16|32|-32|-64>\n", argv[0]) ; + printf("\n") ; + printf("\t is a valid FITS file in the current directory\n") ; + printf("\t is the name of the output file\n") ; + printf("\t<8|16|32|-32|-64> is the output file pixel type\n") ; + printf("\n\n") ; + return 0 ; + } + ptype = (int)atoi(argv[3]) ; + check_all_types(ptype) ; + if (!strcmp(argv[1], argv[2])) { + fprintf(stderr, "cannot convert a file to itself\n") ; + fprintf(stderr, "specify another name for the output\n") ; + return -1 ; + } + return convert_fits_pixel_depth(argv[1], argv[2], ptype) ; +} + +/*----------------------------------------------------------------------------- + Functions code + -----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/** + @brief convert FITS files from one pixel depth to another + @param name_in input file name + @param name_out output file name + @param ptype_out Output pixel type + @return int 0 if Ok, anything else otherwise + Heavy use of mmap() to speed up the process + */ +/*----------------------------------------------------------------------------*/ +static int convert_fits_pixel_depth( + char * name_in, + char * name_out, + int ptype_out) +{ + int fd_in, + fd_out ; + char * buf_in ; + char * buf_out ; + int fsize_in, + fsize_out, + header_size, + padd_size ; + int ptype_in ; + int bpp_out ; + int npix ; + char * zero ; + int yet_to_dump ; + int buf_dump ; + + /* Open input file and get pixel depth and number of pixels */ + fsize_in = filesize(name_in) ; + header_size = get_FITS_header_size(name_in) ; + if ((fd_in = open(name_in, O_RDONLY)) == -1) { + fprintf(stderr, "cannot open file %s: aborting\n", name_in) ; + return -1 ; + } + buf_in = (char*)mmap(0, fsize_in, PROT_READ, MAP_SHARED, fd_in, 0) ; + if (buf_in == (char*)-1) { + perror("mmap") ; + fprintf(stderr, "cannot mmap file: %s\n", name_in) ; + close(fd_in) ; + return -1 ; + } + ptype_in = get_bitpix(buf_in) ; + if (ptype_in == 0) { + close(fd_in) ; munmap(buf_in, fsize_in) ; + return -1 ; + } + if (ptype_in == -32) { + if (!IEEE_FLOAT_COMPAT(compat_flags)) { + fprintf(stderr, + "this machine does not support IEEE floating point values\n"); + fprintf(stderr, + "cannot convert from -32 type\n"); + exit(-1) ; + } + } + if (ptype_in == -64) { + if (!IEEE_DOUBLE_COMPAT(compat_flags)) { + fprintf(stderr, + "this machine does not support IEEE double values\n"); + fprintf(stderr, + "cannot convert from -64 type\n"); + exit(-1) ; + } + } + + /* Compute the size of the output file: header size+pixel area+padding */ + npix = get_npix(buf_in) ; + if (npix < 1) { + close(fd_in) ; + munmap(buf_in, fsize_in) ; + return -1 ; + } + bpp_out = ptype_out / 8 ; + if (bpp_out < 0) { + bpp_out = - bpp_out ; + } + fsize_out = header_size + npix * bpp_out ; + if ((fsize_out % FITS_BLSZ) == 0) { + padd_size = 0 ; + } else { + padd_size = FITS_BLSZ - fsize_out % FITS_BLSZ ; + } + fsize_out += padd_size ; + + /* Now create the output file and fill it with zeros, then mmap it. */ + /* The permissions are rw-rw-r-- by default. */ + if ((fd_out=creat(name_out,S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH))==-1){ + perror("creat") ; + fprintf(stderr, "cannot create file %s: aborting\n", name_out) ; + close(fd_in) ; munmap(buf_in, fsize_in) ; + return -1 ; + } + zero = calloc(ONE_MEGABYTE, 1) ; + yet_to_dump = fsize_out ; + if (fsize_out < ONE_MEGABYTE) { + buf_dump = fsize_out ; + } else { + buf_dump = ONE_MEGABYTE ; + } + while (yet_to_dump>0) { + if (write(fd_out, zero, buf_dump) != buf_dump) { + perror("write") ; + fprintf(stderr, "error writing to the output file: aborting\n") ; + close(fd_in) ; close(fd_out) ; munmap(buf_in, fsize_in) ; + free(zero) ; + return -1 ; + } + yet_to_dump -= buf_dump ; + if (yet_to_dump > ONE_MEGABYTE) { + buf_dump = ONE_MEGABYTE ; + } else { + buf_dump = yet_to_dump ; + } + } + free(zero) ; + close(fd_out) ; + if ((fd_out = open(name_out, O_RDWR)) == -1) { + perror("open") ; + fprintf(stderr, "cannot reopen file %s for writing\n", name_out); + close(fd_in) ; munmap(buf_in, fsize_in) ; + return -1 ; + } + + buf_out = (char*)mmap(0, + fsize_out, + PROT_READ | PROT_WRITE, + MAP_SHARED, + fd_out, + 0) ; + if (buf_out == (char*)-1) { + perror("mmap") ; + fprintf(stderr, "cannot mmap file: %s\n", name_out) ; + munmap(buf_in, fsize_in) ; close(fd_in) ; close(fd_out) ; + return -1 ; + } + + /* Copy FITS header from input to output, modify BITPIX */ + memcpy(buf_out, buf_in, header_size) ; + if (set_bitpix(buf_out, ptype_out)!=0) { + fprintf(stderr, "error writing BITPIX in output: aborting\n"); + munmap(buf_in, fsize_in) ; munmap(buf_out, fsize_out) ; + close(fd_in) ; close(fd_out) ; + return -1 ; + } + + /* Now write pixels */ + write_pixbuf(buf_in + header_size, + buf_out + header_size, + npix, + ptype_in, + ptype_out) ; + + /* Blank-pad the output file if needed */ + if (padd_size) { + if (lseek(fd_out, fsize_out-padd_size, SEEK_SET)==-1) { + perror("lseek"); + fprintf(stderr, "error seeking output file: aborting\n"); + } else { + zero = calloc(padd_size, 1) ; + if (write(fd_out, zero, 1)==-1) { + perror("write") ; + fprintf(stderr, "error writing into output file: aborting\n"); + } + free(zero) ; + } + } + + /* Close, unmap, goodbye */ + close(fd_in) ; + close(fd_out) ; + munmap(buf_in, fsize_in) ; + munmap(buf_out, fsize_out) ; + return 0 ; +} + +/*----------------------------------------------------------------------------*/ +/** + @brief compute the size (in bytes) of a FITS header + @param name FITS file name + @return int + Should always be a multiple of 2880. This implementation assumes only that 80 + characters are found per line. + */ +/*----------------------------------------------------------------------------*/ +static int get_FITS_header_size(char * name) +{ + FILE * in ; + char line[81] ; + int found = 0 ; + int count ; + int hs ; + + if ((in = fopen(name, "r")) == NULL) { + fprintf(stderr, "cannot open %s: aborting\n", name) ; + return 0 ; + } + count = 0 ; + while (!found) { + if (fread(line, 1, 80, in)!=80) break ; + count ++ ; + if (!strncmp(line, "END ", 4)) found = 1 ; + } + fclose(in); + + if (!found) return 0 ; + /* The size is the cards nb x 80, rounded to the nextmultiple of 2880 */ + hs = count * 80 ; + if ((hs % FITS_BLSZ) != 0) hs = (1+(hs/FITS_BLSZ)) * FITS_BLSZ ; + return hs ; +} + +/*----------------------------------------------------------------------------*/ +/** + @brief how many bytes can I read from this file + @param filename Name of file + @return size of the file in bytes + Strongly non portable. Only on Unix systems! + */ +/*----------------------------------------------------------------------------*/ +static int filesize(char *filename) +{ + int size ; + struct stat fileinfo ; + + /* POSIX compliant */ + if (stat(filename, &fileinfo) != 0) size = (int)0 ; + else size = (int)fileinfo.st_size ; + return size ; +} + +/*----------------------------------------------------------------------------*/ +/** + @brief gets the value of BITPIX from a FITS header + @param buf allocated char buffer containing the whole FITS header + @return int 8 16 32 -32 or -64 or 0 if cannot find it + */ +/*----------------------------------------------------------------------------*/ +static int get_bitpix(char * buf) +{ + int bitpix ; + char * where ; + + where = strstr(buf, "BITPIX") ; + if (where == NULL) { + fprintf(stderr, "cannot find BITPIX in header: aborting\n") ; + return 0 ; + } + sscanf(where, "%*[^=] = %d", &bitpix) ; + /* Check the returned value makes sense */ + if ((bitpix != 8) && + (bitpix != 16) && + (bitpix != 32) && + (bitpix != -32) && + (bitpix != -64)) { + bitpix = 0 ; + } + return bitpix ; +} + +/*----------------------------------------------------------------------------*/ +/** + @brief overwrites the value of BITPIX in a FITS header + @param buf allocated char buffer containing the whole FITS header + @param ptype pixel type to write + @return int 0 if Ok, anything else otherwise + */ +/*----------------------------------------------------------------------------*/ +static int set_bitpix(char * buf, int ptype) +{ + char * where ; + char replace[81] ; + + where = strstr(buf, "BITPIX") ; + if (where == NULL) { + fprintf(stderr, "cannot find BITPIX in header: aborting\n") ; + return -1 ; + } + sprintf(replace, + "BITPIX = % 3d / Bits per pixel ", + ptype) ; + memcpy(where, replace, 80) ; + return 0 ; +} + +/*----------------------------------------------------------------------------*/ +/** + @brief retrieves how many pixels in a FITS file from the header + @param buf allocated char buffer containing the whole FITS header + @return int # of pixels in the file + Does not support extensions! + */ +/*----------------------------------------------------------------------------*/ +static int get_npix(char * buf) +{ + int naxes ; + int npix ; + int naxis ; + char * where ; + char lookfor[80] ; + int i ; + + where = strstr(buf, "NAXIS") ; + if (where == NULL) { + fprintf(stderr, "cannot find NAXIS in header: aborting\n") ; + return 0 ; + } + sscanf(where, "%*[^=] = %d", &naxes) ; + if ((naxes<1) || (naxes>999)) { + fprintf(stderr, "illegal value for %s: %d\n", lookfor, naxes) ; + return 0 ; + } + npix = 1 ; + for (i=1 ; i<=naxes ; i++) { + sprintf(lookfor, "NAXIS%d", i) ; + where = strstr(buf, lookfor) ; + if (where == NULL) { + fprintf(stderr, "cannot find %s in header: aborting\n", + lookfor) ; + return 0 ; + } + sscanf(where, "%*[^=] = %d", &naxis) ; + if (naxis<1) { + fprintf(stderr, "error: found %s=%d\n", lookfor, naxis); + return 0 ; + } + npix *= naxis ; + } + return npix ; +} + +/*----------------------------------------------------------------------------*/ +/** + @brief transfers a pixel buffer from one area to another + @param bi allocated char buffer containing the whole in FITS header + @param bo allocated char buffer containing the whole out FITS header + @param npix number of pixels in input area + @param ptype_in input pixel type + @param ptype_out output pixel type + @return int 0 if Ok, anything else otherwise + Optimized code, very limited readability!!! + Pixel format conversion on the fly if needed. + */ +/*----------------------------------------------------------------------------*/ +static int write_pixbuf( + char * bi, + char * bo, + int npix, + int ptype_in, + int ptype_out) +{ + int bpp ; + register int i ; + register char * ip ; + register char * op ; + double d ; + float f ; + char a2[2] ; + char a4[4] ; + char a8[8] ; + + /* + * Trivial case of identical copies + * 8 to 8 + * 16 to 16 + * 32 to 32 + * -32 to-32 + * -64 to-64 + */ + + if (ptype_in == ptype_out) { + /* How many bytes per pixel? */ + bpp = ptype_in / 8 ; if (bpp < 0) bpp = - bpp ; + /* Copy the buffer as it is and return */ + memcpy(bo, bi, npix * bpp) ; + return 0 ; + } + + /* Use registers to boost speed */ + ip = bi ; + op = bo ; + + /* ---------- 8 bit to something */ + + /* + * 8 to 16 + * one byte in input becomes the LSB in the 2 output bytes + * we transfer it directly in the LSB, this is independent from + * machine endian-ness. + */ + + if ((ptype_in == 8) && (ptype_out == 16)) { + for (i=0 ; i8 we try to find if the + * input is negative by looking at the MSB and in that case clip to + * zero. If the MSB is cleared but any other of the upper 24 bits is + * set, the number is greater than 0xff and is clipped to 0xff. + */ + if ((ptype_in == 32) && (ptype_out == 8)) { + fprintf(stderr, "warning: loss of precision in output\n") ; + for (i=0 ; i 32767) { + *op++ = (byte)0x7f ; + *op++ = (byte)0xff ; + ip += 4 ; + } else if ((*(long32*)ip) < -32768) { + *op++ = (byte)0x80 ; + *op++ = (byte)0x00 ; + ip += 4 ; + } else { + ip+=2 ; + *op++ = *ip++ ; + *op++ = *ip++ ; + } + } + } else { + for (i=0 ; i 32767) { + *op++ = (byte)0x7f ; + *op++ = (byte)0xff ; + ip += 4 ; + } else if ((*(long32*)&a4[0]) < -32768) { + *op++ = (byte)0x80 ; + *op++ = (byte)0x00 ; + ip += 4 ; + } else { + ip+=2 ; + *op++ = *ip++ ; + *op++ = *ip++ ; + } + } + } + return 0 ; + } + + /* + * 32 to -32 + * We cast the input to a local float, then output it to disk. + */ + if ((ptype_in == 32) && (ptype_out == -32)) { + if (ENDIAN_NESS(compat_flags) == ENDIAN_MOTOROLA) { + for (i=0 ; i255.0) { + *op++ = (byte)0xff ; + } else if (f<0.0) { + *op++ = (byte)0x00 ; + } else { + *op++ = (byte)(f+0.5) ; + } + ip += 4; + } + } else { + for (i=0 ; i255.0) { + *op++ = (byte)0xff ; + } else if (f<0.0) { + *op++ = (byte)0x00 ; + } else { + *op++ = (byte)(f+0.5) ; + } + ip += 4; + } + } + + return 0 ; + } + + /* + * -32 to 16 + * Construct the input float through cast (need to know endian-ness) + * Clip it to [-32768..32767], round the value to the smaller + * integer. + */ + if ((ptype_in == -32) && (ptype_out == 16)) { + fprintf(stderr, "warning: loss of precision in output\n") ; + if (ENDIAN_NESS(compat_flags) == ENDIAN_MOTOROLA) { + for (i=0 ; i32767.0) { + *op++ = (byte)0x7f ; + *op++ = (byte)0xff ; + } else if (f<-32768.0) { + *op++ = (byte)0x80 ; + *op++ = 0x00 ; + } else { + *op++ = (short16)f >> 8 ; + *op++ = (short16)f & (byte)0xff ; + } + ip+=4 ; + } + } else { + for (i=0 ; i32767.0) { + *op++ = (byte)0x7f ; + *op++ = (byte)0xff ; + } else if (f<-32768.0) { + *op++ = (byte)0x80 ; + *op++ = (byte)0x00 ; + } else { + *op++ = (short16)f >> 8 ; + *op++ = (short16)f & (byte)0xff ; + } + ip+=4 ; + } + } + return 0 ; + } + + /* + * -32 to 32 + * Construct the input float through cast (need to know endian-ness) + * Clip it to [-2147483648 .. 2147483647], then round to the smaller + * integer. + */ + if ((ptype_in == -32) && (ptype_out == 32)) { + fprintf(stderr, "warning: probable loss of precision in output\n") ; + if (ENDIAN_NESS(compat_flags) == ENDIAN_MOTOROLA) { + for (i=0 ; i2147483647.0) { + *op++ = (byte)0x7f ; + *op++ = (byte)0xff ; + *op++ = (byte)0xff ; + *op++ = (byte)0xff ; + } else if (f<-2147483648.0) { + *op++ = (byte)0x80 ; + *op++ = (byte)0x00 ; + *op++ = (byte)0x00 ; + *op++ = (byte)0x00 ; + } else { + *op++ = (long32)f >> 24 ; + *op++ = ((long32)f >> 16) & 0xff ; + *op++ = ((long32)f >> 8) & 0xff ; + *op++ = (long32)f & 0xff ; + } + ip+=4 ; + } + } else { + for (i=0 ; i2147483647.0) { + *op++ = (byte)0x7f ; + *op++ = (byte)0xff ; + *op++ = (byte)0xff ; + *op++ = (byte)0xff ; + } else if (f<-2147483648.0) { + *op++ = (byte)0x80 ; + *op++ = (byte)0x00 ; + *op++ = (byte)0x00 ; + *op++ = (byte)0x00 ; + } else { + *op++ = (long32)f >> 24 ; + *op++ = ((long32)f >> 16) & 0xff ; + *op++ = ((long32)f >> 8) & 0xff ; + *op++ = (long32)f & 0xff ; + } + ip+=4 ; + } + } + return 0 ; + } + + /* + * -32 to -64 + * Conversion achieved through cast. Need to know endian-ness. + */ + if ((ptype_in == -32) && (ptype_out == -64)) { + if (ENDIAN_NESS(compat_flags) == ENDIAN_MOTOROLA) { + for (i=0 ; i255.0) { + *op++ = (byte)0xff ; + } else if (d<0.0) { + *op++ = (byte)0x00 ; + } else { + *op++ = (byte)(d+0.5) ; + } + ip+=8 ; + } + } else { + for (i=0 ; i255.0) { + *op++ = (byte)0xff ; + } else if (d<0.0) { + *op++ = (byte)0x00 ; + } else { + *op++ = (byte)(d+0.5) ; + } + ip+=8 ; + } + } + return 0 ; + } + + /* + * -64 to 16 + * Heavy loss of input precision! + * The input double is constructed through swap and cast. It is then + * clipped to [-32768..32767] and rounded to the smaller integer. + */ + if ((ptype_in == -64) && (ptype_out == 16)) { + fprintf(stderr, "warning: loss of precision in output\n") ; + if (ENDIAN_NESS(compat_flags) == ENDIAN_MOTOROLA) { + for (i=0 ; i32767.0) { + *op++ = (byte)0x7f ; + *op++ = (byte)0xff ; + } else if (d<-32768.0) { + *op++ = (byte)0x80 ; + *op++ = (byte)0x00 ; + } else { + *op++ = (short16)d >> 8 ; + *op++ = (short16)d & (byte)0xff ; + } + ip+=8 ; + } + } else { + for (i=0 ; i32767.0) { + *op++ = (byte)0x7f ; + *op++ = (byte)0xff ; + } else if (d<-32768.0) { + *op++ = (byte)0x80 ; + *op++ = (byte)0x00 ; + } else { + *op++ = (short16)d >> 8 ; + *op++ = (short16)d & (byte)0xff ; + } + ip+=8 ; + } + } + return 0 ; + } + + /* + * -64 to 32 + * Heavy loss of input precision! + * The input double is constructed through swap and cast. It is then + * clipped to [-2147483648..2147483647] and rounded to the smaller + * integer. + */ + if ((ptype_in == -64) && (ptype_out == 32)) { + fprintf(stderr, "warning: loss of precision in output\n") ; + if (ENDIAN_NESS(compat_flags) == ENDIAN_MOTOROLA) { + for (i=0 ; i2147483647.0) { + *op++ = (byte)0x7f ; + *op++ = (byte)0xff ; + *op++ = (byte)0xff ; + *op++ = (byte)0xff ; + } else if (d<-2147483648.0) { + *op++ = (byte)0x80 ; + *op++ = (byte)0x00 ; + *op++ = (byte)0x00 ; + *op++ = (byte)0x00 ; + } else { + *op++ = (long32)d >> 24 ; + *op++ = ((long32)d >> 16) & (byte)0xff ; + *op++ = ((long32)d >> 8) & (byte)0xff ; + *op++ = (long32)d & (byte)0xff ; + } + ip+=8 ; + } + } else { + for (i=0 ; i2147483647.0) { + *op++ = (byte)0x7f ; + *op++ = (byte)0xff ; + *op++ = (byte)0xff ; + *op++ = (byte)0xff ; + } else if (d<-2147483648.0) { + *op++ = (byte)0x80 ; + *op++ = (byte)0x00 ; + *op++ = (byte)0x00 ; + *op++ = (byte)0x00 ; + } else { + *op++ = (long32)d >> 24 ; + *op++ = ((long32)d >> 16) & 0xff ; + *op++ = ((long32)d >> 8) & 0xff ; + *op++ = (long32)d & 0xff ; + } + ip+=8 ; + } + } + return 0 ; + } + + /* + * -64 to -32 + * Heavy loss of input precision! + * The input double is constructed through swap and cast. It is then + * simply cast to a float using the local algorithm for this + * conversion. + */ + if ((ptype_in == -64) && (ptype_out == -32)) { + fprintf(stderr, "warning: loss of precision in output\n") ; + if (ENDIAN_NESS(compat_flags) == ENDIAN_MOTOROLA) { + for (i=0 ; i BA + ABCD -> DCBA + ABCDEFGH -> HGFEDCBA + */ +/*----------------------------------------------------------------------------*/ +static void swap_bytes(void * p, int s) +{ + byte tmp, *a, *b ; + + a = (byte*)p ; + b = a + s ; + + while (a +#include +#include +#include +#include +#include +#include +#include +#include + +/*----------------------------------------------------------------------------- + Define + -----------------------------------------------------------------------------*/ + +#define NM_SIZ 512 +#define FITS_BLSZ 2880 +#define ONE_MEGABYTE (1024 * 1024) + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif + +/*----------------------------------------------------------------------------- + Function prototypes + -----------------------------------------------------------------------------*/ + +static int dump_pix(char*, char*); +static int get_FITS_header_size(char *) ; +static int filesize(char*) ; +static int get_bitpix(char*) ; +static int get_npix(char*) ; + +/*----------------------------------------------------------------------------- + Main + -----------------------------------------------------------------------------*/ +int main(int argc, char *argv[]) +{ + if (argc<3) { + printf("\n\n") ; + printf("use: %s \n", argv[0]) ; + printf("\n") ; + printf("\t is a valid FITS file in the current directory\n") ; + printf("\t is the name of the output file\n") ; + printf("\n\n") ; + return 0 ; + } + if (!strcmp(argv[1], argv[2])) { + fprintf(stderr, "cannot convert a file to itself\n") ; + fprintf(stderr, "specify another name for the output\n") ; + return -1 ; + } + return dump_pix(argv[1], argv[2]); +} + +/*----------------------------------------------------------------------------*/ +/** + @brief dump pixels from a FITS file to a binary file + @param name_in Input file name + @param name_out Output file name + @return int 0 if Ok, anything else otherwise + Heavy use of mmap() to speed up the process + */ +/*----------------------------------------------------------------------------*/ +static int dump_pix( + char * name_in, + char * name_out) +{ + int fd_in, + fd_out ; + char * buf_in ; + char * buf_out ; + int fsize_in, + fsize_out, + header_size ; + int npix ; + + /* + * Open input file and get information we need: + * - pixel depth + * - number of pixels + */ + + fsize_in = filesize(name_in) ; + header_size = get_FITS_header_size(name_in) ; + if ((fd_in = open(name_in, O_RDONLY)) == -1) { + fprintf(stderr, "cannot open file %s: aborting\n", name_in) ; + return -1 ; + } + buf_in = (char*)mmap(0, fsize_in, PROT_READ, MAP_SHARED, fd_in, 0) ; + if (buf_in == (char*)-1) { + perror("mmap") ; + fprintf(stderr, "cannot mmap file: %s\n", name_in) ; + close(fd_in) ; + return -1 ; + } + if (get_bitpix(buf_in) != -32) { + fprintf(stderr, "only 32-bit IEEE floating point format supported\n"); + close(fd_in) ; munmap(buf_in, fsize_in) ; + return -1 ; + } + + /* + * Compute the size of the output file + * same header size, + pixel area + blank padding + */ + npix = get_npix(buf_in) ; + if (npix < 1) { + fprintf(stderr, "cannot compute number of pixels\n"); + close(fd_in) ; + munmap(buf_in, fsize_in) ; + return -1 ; + } + fsize_out = npix * 4 ; + /* + * Now create the output file and fill it with zeros, then mmap it. + * The permissions are rw-rw-r-- by default. + */ + if ((fd_out=creat(name_out,S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH))==-1){ + perror("creat") ; + fprintf(stderr, "cannot create file %s: aborting\n", name_out) ; + close(fd_in) ; munmap(buf_in, fsize_in) ; + return -1 ; + } + + buf_out = malloc(fsize_out) ; + if (buf_out == NULL) { + fprintf(stderr, "not enough memory\n"); + fprintf(stderr, "failed to allocate %d bytes\n", fsize_out); + close(fd_in) ; munmap(buf_in, fsize_in) ; + return -1; + } + write(fd_out, buf_out, fsize_out); + close(fd_out); + free(buf_out); + + fd_out = open(name_out, O_RDWR); + if (fd_out==-1) { + fprintf(stderr, "error opening file %s\n", name_out); + close(fd_in) ; munmap(buf_in, fsize_in) ; + return -1; + } + buf_out = (char*)mmap(0, + fsize_out, + PROT_READ | PROT_WRITE, + MAP_SHARED, + fd_out, + 0) ; + if (buf_out == (char*)-1) { + perror("mmap") ; + fprintf(stderr, "cannot mmap file: %s\n", name_out) ; + munmap(buf_in, fsize_in) ; close(fd_in) ; close(fd_out) ; + return -1 ; + } + /* + * Copy FITS header from input to output, modify BITPIX + */ + memcpy(buf_out, buf_in+header_size, fsize_out) ; + /* + * Close, unmap, goodbye + */ + close(fd_in) ; + close(fd_out) ; + munmap(buf_in, fsize_in) ; + munmap(buf_out, fsize_out) ; + return 0 ; +} + +/*----------------------------------------------------------------------------*/ +/** + @brief compute the size (in bytes) of a FITS header + @param name FITS file name + @return unsigned long + Should always be a multiple of 2880. This implementation assumes only that + 80 characters are found per line. + */ +/*----------------------------------------------------------------------------*/ +static int get_FITS_header_size(char * name) +{ + FILE * in ; + char line[81] ; + int found = 0 ; + int count ; + int hs ; + + if ((in = fopen(name, "r")) == NULL) { + fprintf(stderr, "cannot open %s: aborting\n", name) ; + return 0 ; + } + count = 0 ; + while (!found) { + if (fread(line, 1, 80, in)!=80) { + break ; + } + count ++ ; + if (!strncmp(line, "END ", 4)) { + found = 1 ; + } + } + fclose(in); + + if (!found) return 0 ; + /* + * The size is the number of found cards times 80, + * rounded to the closest higher multiple of 2880. + */ + hs = count * 80 ; + if ((hs % FITS_BLSZ) != 0) { + hs = (1+(hs/FITS_BLSZ)) * FITS_BLSZ ; + } + return hs ; +} + +/*----------------------------------------------------------------------------*/ +/** + @brief how many bytes can I read from this file + @param filename File name + @return size of the file in bytes + Strongly non portable. Only on Unix systems! + */ +/*----------------------------------------------------------------------------*/ +static int filesize(char *filename) +{ + int size ; + struct stat fileinfo ; + + /* POSIX compliant */ + if (stat(filename, &fileinfo) != 0) { + size = (int)0 ; + } else { + size = (int)fileinfo.st_size ; + } + return size ; +} + +/*----------------------------------------------------------------------------*/ +/** + @brief gets the value of BITPIX from a FITS header + @param buf allocated char buffer containing the whole FITS header + @return int 8 16 32 -32 or -64 or 0 if cannot find it + */ +/*----------------------------------------------------------------------------*/ +static int get_bitpix(char * buf) +{ + int bitpix ; + char * where ; + + where = strstr(buf, "BITPIX") ; + if (where == NULL) { + fprintf(stderr, "cannot find BITPIX in header: aborting\n") ; + return 0 ; + } + sscanf(where, "%*[^=] = %d", &bitpix) ; + /* + * Check the returned value makes sense + */ + if ((bitpix != 8) && + (bitpix != 16) && + (bitpix != 32) && + (bitpix != -32) && + (bitpix != -64)) { + bitpix = 0 ; + } + return bitpix ; +} + +/*----------------------------------------------------------------------------*/ +/** + @brief retrieves how many pixels in a FITS file from the header + @param buf allocated char buffer containing the whole FITS header + @return unsigned long: # of pixels in the file + Does not support extensions! + */ +/*----------------------------------------------------------------------------*/ +static int get_npix(char * buf) +{ + int naxes ; + int npix ; + int naxis ; + char * where ; + char lookfor[80] ; + int i ; + + where = strstr(buf, "NAXIS") ; + if (where == NULL) { + fprintf(stderr, "cannot find NAXIS in header: aborting\n") ; + return 0 ; + } + sscanf(where, "%*[^=] = %d", &naxes) ; + if ((naxes<1) || (naxes>999)) { + fprintf(stderr, "illegal value for %s: %d\n", lookfor, naxes) ; + return 0 ; + } + npix = 1 ; + for (i=1 ; i<=naxes ; i++) { + sprintf(lookfor, "NAXIS%d", i) ; + where = strstr(buf, lookfor) ; + if (where == NULL) { + fprintf(stderr, "cannot find %s in header: aborting\n", + lookfor) ; + return 0 ; + } + sscanf(where, "%*[^=] = %d", &naxis) ; + if (naxis<1) { + fprintf(stderr, "error: found %s=%d\n", lookfor, naxis); + return 0 ; + } + npix *= (int)naxis ; + } + return npix ; +} + diff --git a/qfits/src/cache.h b/qfits/src/cache.h new file mode 100644 index 0000000..22fb13b --- /dev/null +++ b/qfits/src/cache.h @@ -0,0 +1,122 @@ +/*----------------------------------------------------------------------------*/ +/** + @file cache.h + @author N. Devillard + @date Mar 2001 + @version $Revision: 1.5 $ + @brief FITS caching capabilities + + This modules implements a cache for FITS access routines. + The first time a FITS file is seen by the library, all corresponding + pointers are cached here. This speeds up multiple accesses to large + files by magnitudes. +*/ +/*----------------------------------------------------------------------------*/ + +/* + $Id: cache.h,v 1.5 2003/11/24 09:44:53 yjung Exp $ + $Author: yjung $ + $Date: 2003/11/24 09:44:53 $ + $Revision: 1.5 $ +*/ + +#ifndef CACHE_H +#define CACHE_H + +/*----------------------------------------------------------------------------- + Includes + -----------------------------------------------------------------------------*/ + +#include + +/*----------------------------------------------------------------------------- + Defines + -----------------------------------------------------------------------------*/ + +/** Query the number of extensions */ +#define QFITS_QUERY_N_EXT (1<<30) +/** Query the offset to header start */ +#define QFITS_QUERY_HDR_START (1<<29) +/** Query the offset to data start */ +#define QFITS_QUERY_DAT_START (1<<28) +/** Query header size in bytes */ +#define QFITS_QUERY_HDR_SIZE (1<<27) +/** Query data size in bytes */ +#define QFITS_QUERY_DAT_SIZE (1<<26) + +/* */ +/*----------------------------------------------------------------------------*/ +/** + @brief Purge the qfits cache. + @return void + + This function is useful for programs running for a long period, + to clean up the cache. Ideally in a daemon, it should be called + by a timer at regular intervals. Notice that since the cache is + fairly small, you should not need to care too much about this. + */ +/*----------------------------------------------------------------------------*/ +void qfits_cache_purge(void); +/* */ + +/*----------------------------------------------------------------------------*/ +/** + @brief Query a FITS file offset from the cache. + @param filename Name of the file to examine. + @param what What should be queried (see below). + @return an integer offset, or -1 if an error occurred. + + This function queries the cache for FITS offset information. If the + requested file name has never been seen before, it is completely parsed + to extract all offset informations, which are then stored in the cache. + The next query will get the informations from the cache, avoiding + a complete re-parsing of the file. This is especially useful for large + FITS files with lots of extensions, because querying the extensions + is an expensive operation. + + This operation has side-effects: the cache is an automatically + allocated structure in memory, that can only grow. Every request + on a new FITS file will make it grow. The structure is pretty + light-weight in memory, but nonetheless this is an issue for daemon-type + programs which must run over long periods. The solution is to clean + the cache using qfits_cache_purge() at regular intervals. This is left + to the user of this library. + + To request information about a FITS file, you must pass an integer + built from the following symbols: + + - @c QFITS_QUERY_N_EXT + - @c QFITS_QUERY_HDR_START + - @c QFITS_QUERY_DAT_START + - @c QFITS_QUERY_HDR_SIZE + - @c QFITS_QUERY_DAT_SIZE + + Querying the number of extensions present in a file is done + simply with: + + @code + next = qfits_query(filename, QFITS_QUERY_N_EXT); + @endcode + + Querying the offset to the i-th extension header is done with: + + @code + off = qfits_query(filename, QFITS_QUERY_HDR_START | i); + @endcode + + i.e. you must OR (|) the extension number with the + @c QFITS_QUERY_HDR_START symbol. Requesting offsets to extension data is + done in the same way: + + @code + off = qfits_query(filename, QFITS_QUERY_DAT_START | i); + @endcode + + Notice that extension 0 is the main header and main data part + of the FITS file. + */ +/*----------------------------------------------------------------------------*/ +int qfits_query(char * filename, int what); + +#endif +/* vim: set ts=4 et sw=4 tw=75 */ diff --git a/qfits/src/config.h b/qfits/src/config.h new file mode 100644 index 0000000..7ce0158 --- /dev/null +++ b/qfits/src/config.h @@ -0,0 +1,20 @@ +/* This file automatically generated */ +#ifndef _CONFIG_H_ +#define _CONFIG_H_ + + +#define SIZEOF_CHAR 1 +#define SIZEOF_SHORT 2 +#define SIZEOF_INT 4 +#define SIZEOF_LONG 8 +#define SIZEOF_FLOAT 4 +#define SIZEOF_DOUBLE 8 + +#ifndef CHAR_BIT +#define CHAR_BIT 8 +#endif + + + +#define OS_LINUX 1 +#endif diff --git a/qfits/src/expkey.h b/qfits/src/expkey.h new file mode 100644 index 0000000..046f259 --- /dev/null +++ b/qfits/src/expkey.h @@ -0,0 +1,53 @@ +/*----------------------------------------------------------------------------*/ +/** + @file expkey.h + @author N. Devillard + @date Feb 2001 + @version $Revisions$ + @brief Expand keyword from shortFITS to HIERARCH notation + + This module offers a function that is reused in a number of different + places. +*/ +/*----------------------------------------------------------------------------*/ + +/* + $Id: expkey.h,v 1.6 2005/05/18 14:38:01 yjung Exp $ + $Author: yjung $ + $Date: 2005/05/18 14:38:01 $ + $Revision: 1.6 $ +*/ + +#ifndef EXPKEY_H +#define EXPKEY_H + +/*----------------------------------------------------------------------------- + Function prototypes + -----------------------------------------------------------------------------*/ + +/* */ +/*----------------------------------------------------------------------------*/ +/** + @brief Expand a keyword from shortFITS to HIERARCH notation. + @param keyword Keyword to expand. + @return 1 pointer to statically allocated string. + + This function expands a given keyword from shortFITS to HIERARCH + notation, bringing it to uppercase at the same time. + + Examples: + + @verbatim + det.dit expands to HIERARCH ESO DET DIT + ins.filt1.id expands to HIERARCH ESO INS FILT1 ID + @endverbatim + + If the input keyword is a regular FITS keyword (i.e. it contains + not dots '.') the result is identical to the input. + */ +/*----------------------------------------------------------------------------*/ +char * qfits_expand_keyword(const char * keyword); +/* */ + +#endif +/* vim: set ts=4 et sw=4 tw=75 */ diff --git a/qfits/src/fits_h.h b/qfits/src/fits_h.h new file mode 100644 index 0000000..fe259a7 --- /dev/null +++ b/qfits/src/fits_h.h @@ -0,0 +1,475 @@ +/*----------------------------------------------------------------------------*/ +/** + @file fits_h.h + @author N. Devillard + @date Mar 2000 + @version $Revision: 1.13 $ + @brief FITS header handling + + This file contains definition and related methods for the FITS header + structure. This structure is meant to remain opaque to the user, who + only accesses it through the dedicated functions offered in this module. +*/ +/*----------------------------------------------------------------------------*/ + +/* + $Id: fits_h.h,v 1.13 2005/05/18 14:38:01 yjung Exp $ + $Author: yjung $ + $Date: 2005/05/18 14:38:01 $ + $Revision: 1.13 $ +*/ + +#ifndef FITS_HEADER_H +#define FITS_HEADER_H + +#ifdef __cplusplus +extern "C" { +#endif + +/*----------------------------------------------------------------------------- + Includes + -----------------------------------------------------------------------------*/ + +#include +#include +#include +#include + +/*----------------------------------------------------------------------------- + New types + -----------------------------------------------------------------------------*/ + +/* */ +/*----------------------------------------------------------------------------*/ +/** + @brief FITS header object + + This structure represents a FITS header in memory. It is actually no + more than a thin layer on top of the keytuple object. No field in this + structure should be directly modifiable by the user, only through + accessor functions. + */ +/*----------------------------------------------------------------------------*/ +typedef struct qfits_header { + void * first ; /* Pointer to list start */ + void * last ; /* Pointer to list end */ + int n ; /* Number of cards in list */ +} qfits_header ; + +/*----------------------------------------------------------------------------- + Function ANSI prototypes + -----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/** + @brief FITS header constructor + @return 1 newly allocated (empty) FITS header object. + + This is the main constructor for a qfits_header object. It returns + an allocated linked-list handler with an empty card list. + */ +/*----------------------------------------------------------------------------*/ +qfits_header * qfits_header_new(void) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief FITS header default constructor. + @return 1 newly allocated qfits_header object. + + This is a secondary constructor for a qfits_header object. It returns + an allocated linked-list handler containing two cards: the first one + (SIMPLE=T) and the last one (END). + */ +/*----------------------------------------------------------------------------*/ +qfits_header * qfits_header_default(void) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Add a new card to a FITS header + @param hdr qfits_header object to modify + @param key FITS key + @param val FITS value + @param com FITS comment + @param lin FITS original line if exists + @return void + + This function adds a new card into a header, at the one-before-last + position, i.e. the entry just before the END entry if it is there. + The key must always be a non-NULL string, all other input parameters + are allowed to get NULL values. + */ +/*----------------------------------------------------------------------------*/ +void qfits_header_add( + qfits_header * hdr, + char * key, + char * val, + char * com, + char * lin) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief add a new card to a FITS header + @param hdr qfits_header object to modify + @param after Key to specify insertion place + @param key FITS key + @param val FITS value + @param com FITS comment + @param lin FITS original line if exists + @return void + + Adds a new card to a FITS header, after the specified key. Nothing + happens if the specified key is not found in the header. All fields + can be NULL, except after and key. + */ +/*----------------------------------------------------------------------------*/ +void qfits_header_add_after( + qfits_header * hdr, + char * after, + char * key, + char * val, + char * com, + char * lin) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Append a new card to a FITS header. + @param hdr qfits_header object to modify + @param key FITS key + @param val FITS value + @param com FITS comment + @param lin FITS original line if exists + @return void + + Adds a new card in a FITS header as the last one. All fields can be + NULL except key. + */ +/*----------------------------------------------------------------------------*/ +void qfits_header_append( + qfits_header * hdr, + const char * key, + const char * val, + const char * com, + const char * lin) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Delete a card in a FITS header. + @param hdr qfits_header to modify + @param key specifies which card to remove + @return void + + Removes a card from a FITS header. The first found card that matches + the key is removed. + */ +/*----------------------------------------------------------------------------*/ +void qfits_header_del(qfits_header * hdr, char * key) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Modifies a FITS card. + @param hdr qfits_header to modify + @param key FITS key + @param val FITS value + @param com FITS comment + @return void + + Finds the first card in the header matching 'key', and replaces its + value and comment fields by the provided values. The initial FITS + line is set to NULL in the card. + */ +/*----------------------------------------------------------------------------*/ +void qfits_header_mod(qfits_header * hdr, char * key, char * val, char * com) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Sort a FITS header + @param hdr Header to sort (modified) + @return -1 in error case, 0 otherwise + */ +/*----------------------------------------------------------------------------*/ +int qfits_header_sort(qfits_header ** hdr) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Copy a FITS header + @param src Header to replicate + @return Pointer to newly allocated qfits_header object. + + Makes a strict copy of all information contained in the source + header. The returned header must be freed using qfits_header_destroy. + */ +/*----------------------------------------------------------------------------*/ +qfits_header * qfits_header_copy(qfits_header * src) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Touch all cards in a FITS header + @param hdr qfits_header to modify + @return void + + Touches all cards in a FITS header, i.e. all original FITS lines are + freed and set to NULL. Useful when a header needs to be reformatted. + */ +/*----------------------------------------------------------------------------*/ +void qfits_header_touchall(qfits_header * hdr) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Dump a FITS header to stdout + @param hdr qfits_header to dump + @return void + + Dump a FITS header to stdout. Mostly for debugging purposes. + */ +/*----------------------------------------------------------------------------*/ +void qfits_header_consoledump(qfits_header * hdr) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief qfits_header destructor + @param hdr qfits_header to deallocate + @return void + + Frees all memory associated to a given qfits_header object. + */ +/*----------------------------------------------------------------------------*/ +void qfits_header_destroy(qfits_header * hdr) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Return the value associated to a key, as a string + @param hdr qfits_header to parse + @param key key to find + @return pointer to statically allocated string + + Finds the value associated to the given key and return it as a + string. The returned pointer is statically allocated, so do not + modify its contents or try to free it. + + Returns NULL if no matching key is found or no value is attached. + */ +/*----------------------------------------------------------------------------*/ +char * qfits_header_getstr(qfits_header * hdr, const char * key) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Find a matching key in a header. + @param hdr qfits_header to parse + @param key Key prefix to match + @return pointer to statically allocated string. + + This function finds the first keyword in the given header for + which the given 'key' is a prefix, and returns the full name + of the matching key (NOT ITS VALUE). This is useful to locate + any keyword starting with a given prefix. Careful with HIERARCH + keywords, the shortFITS notation is not likely to be accepted here. + + Examples: + + @verbatim + s = qfits_header_findmatch(hdr, "SIMP") returns "SIMPLE" + s = qfits_header_findmatch(hdr, "HIERARCH ESO DET") returns + the first detector keyword among the HIERACH keys. + @endverbatim + */ +/*----------------------------------------------------------------------------*/ +char * qfits_header_findmatch(qfits_header * hdr, char * key) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Return the i-th key/val/com/line tuple in a header. + @param hdr Header to consider + @param idx Index of the requested card + @param key Output key + @param val Output value + @param com Output comment + @param lin Output initial line + @return int 0 if Ok, -1 if error occurred. + + This function is useful to browse a FITS header object card by card. + By iterating on the number of cards (available in the 'n' field of + the qfits_header struct), you can retrieve the FITS lines and their + components one by one. Indexes run from 0 to n-1. You can pass NULL + values for key, val, com or lin if you are not interested in a + given field. + + @code + int i ; + char key[FITS_LINESZ+1] ; + char val[FITS_LINESZ+1] ; + char com[FITS_LINESZ+1] ; + char lin[FITS_LINESZ+1] ; + + for (i=0 ; in ; i++) { + qfits_header_getitem(hdr, i, key, val, com, lin); + printf("card[%d] key[%s] val[%s] com[%s]\n", i, key, val, com); + } + @endcode + + This function has primarily been written to interface a qfits_header + object to other languages (C++/Python). If you are working within a + C program, you should use the other header manipulation routines + available in this module. + */ +/*----------------------------------------------------------------------------*/ +int qfits_header_getitem( + qfits_header * hdr, + int idx, + char * key, + char * val, + char * com, + char * lin) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Return the FITS line associated to a key, as a string + @param hdr qfits_header to parse + @param key key to find + @return pointer to statically allocated string + + Finds the FITS line associated to the given key and return it as a + string. The returned pointer is statically allocated, so do not + modify its contents or try to free it. + + Returns NULL if no matching key is found or no line is attached. + */ +/*----------------------------------------------------------------------------*/ +char * qfits_header_getline(qfits_header * hdr, char * key) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Return the comment associated to a key, as a string + @param hdr qfits_header to parse + @param key key to find + @return pointer to statically allocated string + @doc + + Finds the comment associated to the given key and return it as a + string. The returned pointer is statically allocated, so do not + modify its contents or try to free it. + + Returns NULL if no matching key is found or no comment is attached. + */ +/*----------------------------------------------------------------------------*/ +char * qfits_header_getcom(qfits_header * hdr, char * key) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Return the value associated to a key, as an int + @param hdr qfits_header to parse + @param key key to find + @param errval default value to return if nothing is found + @return int + + Finds the value associated to the given key and return it as an + int. Returns errval if no matching key is found or no value is + attached. + */ +/*----------------------------------------------------------------------------*/ +int qfits_header_getint(qfits_header * hdr, const char * key, int errval) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Return the value associated to a key, as a double + @param hdr qfits_header to parse + @param key key to find + @param errval default value to return if nothing is found + @return double + + Finds the value associated to the given key and return it as a + double. Returns errval if no matching key is found or no value is + attached. + */ +/*----------------------------------------------------------------------------*/ +double qfits_header_getdouble(qfits_header * hdr, const char * key, double errval) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Return the value associated to a key, as a boolean (int). + @param hdr qfits_header to parse + @param key key to find + @param errval default value to return if nothing is found + @return int + + Finds the value associated to the given key and return it as a + boolean. Returns errval if no matching key is found or no value is + attached. A boolean is here understood as an int taking the value 0 + or 1. errval can be set to any other integer value to reflect that + nothing was found. + + errval is returned if no matching key is found or no value is + attached. + + A true value is any character string beginning with a 'y' (yes), a + 't' (true) or the digit '1'. A false value is any character string + beginning with a 'n' (no), a 'f' (false) or the digit '0'. + */ +/*----------------------------------------------------------------------------*/ +int qfits_header_getboolean(qfits_header * hdr, const char * key, int errval) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Write out a key tuple to a string on 80 chars. + @param line Allocated output character buffer. + @param key Key to write. + @param val Value to write. + @param com Comment to write. + @return void + + Write out a key, value and comment into an allocated character buffer. + The buffer must be at least 80 chars to receive the information. + Formatting is done according to FITS standard. + */ +/*----------------------------------------------------------------------------*/ +void keytuple2str(char * line, char * key, char * val, char * com) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Dump a FITS header to an opened file. + @param hdr FITS header to dump + @param out Opened file pointer + @return int 0 if Ok, -1 otherwise + + Dumps a FITS header to an opened file pointer. + */ +/*----------------------------------------------------------------------------*/ +int qfits_header_dump(qfits_header * hdr, FILE * out) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Dump a FITS header to an opened file (one card per line). + @param hdr FITS header to dump + @param out Opened file pointer + @return int 0 if Ok, -1 otherwise + @see qfits_header_dump() + Dumps a FITS header to an opened file pointer. + This function is meant to create hdr files. + */ +/*----------------------------------------------------------------------------*/ +int qfits_header_dump_hdr(qfits_header * hdr, FILE * out) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Dump a fits header into a memory block. + @param fh FITS header to dump + @param hsize Size of the returned header, in bytes (output). + @return 1 newly allocated memory block containing the FITS header. + + This function dumps a FITS header structure into a newly allocated + memory block. The block is composed of characters, just as they would + appear in a FITS file. This function is useful to make a FITS header + in memory. + + The returned block size is indicated in the passed output variable + 'hsize'. The returned block must be deallocated using free(). + */ +/*----------------------------------------------------------------------------*/ +char * qfits_header_to_memblock(qfits_header * fh, int * hsize) ; +/* */ + +#ifdef __cplusplus +} +#endif + +#endif +/* vim: set ts=4 et sw=4 tw=75 */ diff --git a/qfits/src/fits_md5.h b/qfits/src/fits_md5.h new file mode 100644 index 0000000..23399b5 --- /dev/null +++ b/qfits/src/fits_md5.h @@ -0,0 +1,56 @@ +/*----------------------------------------------------------------------------*/ +/** + @file fits_md5.h + @author N. Devillard + @date May 2001 + @version $Revision: 1.5 $ + @brief FITS data block MD5 computation routine. + + This module offers MD5 computation over all data areas of a FITS file. +*/ +/*----------------------------------------------------------------------------*/ + +/* + $Id: fits_md5.h,v 1.5 2003/11/24 09:44:53 yjung Exp $ + $Author: yjung $ + $Date: 2003/11/24 09:44:53 $ + $Revision: 1.5 $ +*/ + +#ifndef FITS_MD5_H +#define FITS_MD5_H + +/*----------------------------------------------------------------------------- + Includes + -----------------------------------------------------------------------------*/ + +#include +#include +#include + +/*----------------------------------------------------------------------------- + Function ANSI prototypes + -----------------------------------------------------------------------------*/ + +/* */ +/*----------------------------------------------------------------------------*/ +/** + @brief Compute the MD5 hash of data zones in a FITS file. + @param filename Name of the FITS file to examine. + @return 1 statically allocated character string, or NULL. + + This function expects the name of a FITS file. + It will compute the MD5 hash on all data blocks in the main data section + and possibly extensions (including zero-padding blocks if necessary) and + return it as a string suitable for inclusion into a FITS keyword. + + The returned string is statically allocated inside this function, + so do not free it or modify it. This function returns NULL in case + of error. + */ +/*----------------------------------------------------------------------------*/ +char * qfits_datamd5(char * filename); +/* */ + +#endif +/* vim: set ts=4 et sw=4 tw=75 */ diff --git a/qfits/src/fits_p.h b/qfits/src/fits_p.h new file mode 100644 index 0000000..b3dcd8d --- /dev/null +++ b/qfits/src/fits_p.h @@ -0,0 +1,80 @@ +/*----------------------------------------------------------------------------*/ +/** + @file fits_p.h + @author N. Devillard + @date Mar 2000 + @version $Revision: 1.5 $ + @brief FITS parser for a single card + + This module contains various routines to help parsing a single FITS + card into its components: key, value, comment. +*/ +/*----------------------------------------------------------------------------*/ + +/* + $Id: fits_p.h,v 1.5 2003/11/24 09:44:53 yjung Exp $ + $Author: yjung $ + $Date: 2003/11/24 09:44:53 $ + $Revision: 1.5 $ +*/ + +#ifndef FITSEP_H +#define FITSEP_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* */ +/*----------------------------------------------------------------------------- + Function ANSI C prototypes + -----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/** + @brief Find the keyword in a key card (80 chars) + @param line allocated 80-char line from a FITS header + @return statically allocated char * + + Find out the part of a FITS line corresponding to the keyword. + Returns NULL in case of error. The returned pointer is statically + allocated in this function, so do not modify or try to free it. + */ +/*----------------------------------------------------------------------------*/ +char * qfits_getkey(char * line) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Find the value in a key card (80 chars) + @param line allocated 80-char line from a FITS header + @return statically allocated char * + + Find out the part of a FITS line corresponding to the value. + Returns NULL in case of error, or if no value can be found. The + returned pointer is statically allocated in this function, so do not + modify or try to free it. + */ +/*----------------------------------------------------------------------------*/ +char * qfits_getvalue(char * line) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Find the comment in a key card (80 chars) + @param line allocated 80-char line from a FITS header + @return statically allocated char * + + Find out the part of a FITS line corresponding to the comment. + Returns NULL in case of error, or if no comment can be found. The + returned pointer is statically allocated in this function, so do not + modify or try to free it. + */ +/*----------------------------------------------------------------------------*/ +char * qfits_getcomment(char * line) ; +/* */ + +#ifdef __cplusplus +} +#endif + +#endif +/* vim: set ts=4 et sw=4 tw=75 */ diff --git a/qfits/src/fits_rw.h b/qfits/src/fits_rw.h new file mode 100644 index 0000000..92a666a --- /dev/null +++ b/qfits/src/fits_rw.h @@ -0,0 +1,135 @@ +/*----------------------------------------------------------------------------*/ +/** + @file fits_rw.h + @author N. Devillard + @date Mar 2000 + @version $Revision: 1.11 $ + @brief FITS header reading/writing. +*/ +/*----------------------------------------------------------------------------*/ + +/* + $Id: fits_rw.h,v 1.11 2004/06/03 15:42:06 yjung Exp $ + $Author: yjung $ + $Date: 2004/06/03 15:42:06 $ + $Revision: 1.11 $ +*/ + +#ifndef FITS_RW_H +#define FITS_RW_H + +#ifdef __cplusplus +extern "C" { +#endif + +/*----------------------------------------------------------------------------- + Includes + -----------------------------------------------------------------------------*/ + +#include "fits_std.h" +#include "fits_h.h" + +/*----------------------------------------------------------------------------- + Function ANSI prototypes + -----------------------------------------------------------------------------*/ + +/* */ +/*----------------------------------------------------------------------------*/ +/** + @brief Read a FITS header from a file to an internal structure. + @param filename Name of the file to be read + @return Pointer to newly allocated qfits_header or NULL in error case. + + This function parses a FITS (main) header, and returns an allocated + qfits_header object. The qfits_header object contains a linked-list of + key "tuples". A key tuple contains: + + - A keyword + - A value + - A comment + - An original FITS line (as read from the input file) + + Direct access to the structure is not foreseen, use accessor + functions in fits_h.h + + Value, comment, and original line might be NULL pointers. + */ +/*----------------------------------------------------------------------------*/ +qfits_header * qfits_header_read(char * filename) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Read a FITS header from a 'hdr' file. + @param filename Name of the file to be read + @return Pointer to newly allocated qfits_header or NULL in error case + + This function parses a 'hdr' file, and returns an allocated qfits_header + object. A hdr file is an ASCII format were the header is written with a + carriage return after each line. The command dfits typically displays + a hdr file. + */ +/*----------------------------------------------------------------------------*/ +qfits_header * qfits_header_read_hdr(char * filename) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Read a FITS header from a 'hdr' string + @param hdr_str String containing the hdr file + @param nb_char Number of characters in the string + @return Pointer to newly allocated qfits_header or NULL in error case + + This function parses a 'hdr' string, and returns an allocated qfits_header + object. + */ +/*----------------------------------------------------------------------------*/ +qfits_header * qfits_header_read_hdr_string( + unsigned char * hdr_str, + int nb_char) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Read an extension header from a FITS file. + @param filename Name of the FITS file to read + @param xtnum Extension number to read, starting from 0. + @return Newly allocated qfits_header structure. + + Strictly similar to qfits_header_read() but reads headers from + extensions instead. If the requested xtension is 0, this function + calls qfits_header_read() to return the main header. + + Returns NULL in case of error. + */ +/*----------------------------------------------------------------------------*/ +qfits_header * qfits_header_readext(char * filename, int xtnum) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Pad an existing file with zeros to a multiple of 2880. + @param filename Name of the file to pad. + @return void + + This function simply pads an existing file on disk with enough zeros + for the file size to reach a multiple of 2880, as required by FITS. + */ +/*----------------------------------------------------------------------------*/ +void qfits_zeropad(char * filename) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Identify if a file is a FITS file. + @param filename name of the file to check + @return int 0, 1, or -1 + + Returns 1 if the file name looks like a valid FITS file. Returns + 0 else. If the file does not exist, returns -1. + */ +/*----------------------------------------------------------------------------*/ +int is_fits_file(char *filename) ; +/* */ + +#ifdef __cplusplus +} +#endif + +#endif +/* vim: set ts=4 et sw=4 tw=75 */ diff --git a/qfits/src/fits_std.h b/qfits/src/fits_std.h new file mode 100644 index 0000000..f7ad336 --- /dev/null +++ b/qfits/src/fits_std.h @@ -0,0 +1,69 @@ +/*----------------------------------------------------------------------------*/ +/** + @file fits_std.h + @author N. Devillard + @date November 2001 + @version $Revision: 1.5 $ + @brief + + This header file gathers a number of definitions strictly related + to the FITS format. Include it if you need to get definitions for + a FITS line size, header metrics, and other FITS-only symbols. +*/ +/*----------------------------------------------------------------------------*/ + +/* + $Id: fits_std.h,v 1.5 2003/11/24 09:44:53 yjung Exp $ + $Author: yjung $ + $Date: 2003/11/24 09:44:53 $ + $Revision: 1.5 $ +*/ + +#ifndef FITS_STD_H +#define FITS_STD_H + +/*----------------------------------------------------------------------------- + Defines + -----------------------------------------------------------------------------*/ + +/* */ +/* FITS header constants */ + +/** FITS block size */ +#define FITS_BLOCK_SIZE (2880) +/** FITS number of cards per block */ +#define FITS_NCARDS (36) +/** FITS size of each line in bytes */ +#define FITS_LINESZ (80) + +/** FITS magic number */ +#define FITS_MAGIC "SIMPLE" +/** Size of the FITS magic number */ +#define FITS_MAGIC_SZ 6 + + +/* FITS pixel depths */ + +/** FITS BITPIX=8 */ +#define BPP_8_UNSIGNED (8) +/** FITS BITPIX=16 */ +#define BPP_16_SIGNED (16) +/** FITS BITPIX=32 */ +#define BPP_32_SIGNED (32) +/** FITS BITPIX=-32 */ +#define BPP_IEEE_FLOAT (-32) +/** FITS BITPIX=-64 */ +#define BPP_IEEE_DOUBLE (-64) + +/** Default BITPIX for output */ +#define BPP_DEFAULT BPP_IEEE_FLOAT + +/** Compute the number of bytes per pixel for a given BITPIX value */ +#define BYTESPERPIXEL(x) ( ((x) == BPP_8_UNSIGNED) ? 1 : \ + ((x) == BPP_16_SIGNED) ? 2 : \ + ((x) == BPP_32_SIGNED) ? 4 : \ + ((x) == BPP_IEEE_FLOAT) ? 4 : \ + ((x) == BPP_IEEE_DOUBLE) ? 8 : 0 ) +/* */ +#endif +/* vim: set ts=4 et sw=4 tw=75 */ diff --git a/qfits/src/get_name.h b/qfits/src/get_name.h new file mode 100644 index 0000000..e62df31 --- /dev/null +++ b/qfits/src/get_name.h @@ -0,0 +1,155 @@ +/*----------------------------------------------------------------------------*/ +/** + @file get_name.h + @author Y. Jung + @date Jan 2004 + @version $Revision: 1.4 $ + @brief Get various names (filenames, dir names, login name, etc...) +*/ +/*----------------------------------------------------------------------------*/ + +/* + $Id: get_name.h,v 1.4 2004/01/20 15:05:55 yjung Exp $ + $Author: yjung $ + $Date: 2004/01/20 15:05:55 $ + $Revision: 1.4 $ + +*/ + +#ifndef GET_NAME_H +#define GET_NAME_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/* */ +/*----------------------------------------------------------------------------- + Function ANSI C prototypes + -----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/** + @brief Find the directory name in the given string. + @param filename Full path name to scan. + @return Pointer to statically allocated string. + + Provide a full path name and you get in return a pointer to a statically + allocated string containing the name of the directory only, without trailing + slash. If the input string does not contain a slash (i.e. it is not a full + path), the returned string is '.', corresponding to the current working + directory. Since the returned string is statically allocated, do not try to + free it or modify it. + + This function does not check for the existence of the path or the file. + + Examples: + @verbatim + get_dir_name("/cdrom/data/image.fits") returns "/cdrom/data" + get_dir_name("filename.fits") returns "." + @endverbatim + */ +/*----------------------------------------------------------------------------*/ +char * qfits_get_dir_name(char * filename) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Find out the base name of a file (i.e. without prefix path) + @param filename Full path name to scan. + @return Pointer to char within the input string. + + Provide a full path name and you get in return a pointer to a statically + allocated string containing the name of the file only, without prefixing + directory names. If the input string does not contain a slash (i.e. it is + not a full path), the returned string is a copy of the input string. + + This function does not check for the existence of the path or the file. + + Examples: + @verbatim + qfits_get_base_name("/cdrom/data/image.fits") returns "image.fits" + qfits_get_base_name("filename.fits") returns "filename.fits" + @endverbatim + */ +/*----------------------------------------------------------------------------*/ +char * qfits_get_base_name(const char *filename) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Find out the root part of a basename (name without extension). + @param filename File name to scan. + @return Pointer to statically allocated string. + + Find out the root part of a file name, i.e. the file name without extension. + Since in Unix a file name can have several dots, only a number of extensions + are supported. This includes: + + - .fits and .FITS + - .tfits and .TFITS + - .paf and .PAF + - .ascii and .ASCII + - .dat and .DAT + + This function does not check for the existence of the path or the file. + + Examples: + @verbatim + get_root_name("/cdrom/filename.fits") returns "/cdrom/filename" + get_root_name("filename.paf") returns "filename" + get_root_name("filename") returns "filename" + get_root_name("filename.ext") returns "filename.ext" + @endverbatim + + Since the returned string is statically allocated in this module, do not try + to free it or modify its contents. + */ +/*----------------------------------------------------------------------------*/ +char * qfits_get_root_name(char * filename) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Find out the extension of a file name + @param filename File name without path prefix. + @return Pointer to char within the input string. + + Find out the extension of a given file name. Notice that the input character + string must not contain a path prefix (typically, you feed in the output of + @c qfits_get_base_name). + + Works with all kinds of extensions: returns the part of the string after the + last dot. If no dot is found in the input string, NULL is returned. + + Examples: + @verbatim + get_ext_name("filename.fits") returns "fits" + get_ext_name("hello.c") returns "c" + get_ext_name("readme") returns NULL + @endverbatim + */ +/*----------------------------------------------------------------------------*/ +char * qfits_get_ext_name(char * filename) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Returns the user login name. + @return Pointer to statically allocated character string. + + Finds out what the login name of the current user is. The result is + placed in a static character string inside this module and a pointer + to the first character in this string is returned. Do not modify or + free the returned string! + + If the user name cannot be determined, the returned pointer will + point to a string which first character is a null character. + */ +/*----------------------------------------------------------------------------*/ +char * qfits_get_login_name(void) ; + +/* */ +#ifdef __cplusplus +} +#endif + +#endif +/* vim: set ts=4 et sw=4 tw=75 */ diff --git a/qfits/src/ieeefp-compat.h b/qfits/src/ieeefp-compat.h new file mode 100644 index 0000000..c8598e2 --- /dev/null +++ b/qfits/src/ieeefp-compat.h @@ -0,0 +1,104 @@ +/*----------------------------------------------------------------------------*/ +/** + @file ieeefp-compat.h + @author N. Devillard + @date Feb 2002 + @version $Revision: 2.11 $ + @brief This module implements the isnan() and isinf() macros. + + The isnan() and isinf() macros are unfortunately not yet part of + the standard C math library everywhere. They can usually be found + in different places, if they are offered at all, and require the + application to link against the math library. To avoid portability + problems and linking against -lm, this module implements a fast + and portable way of finding out whether a floating-point value + (float or double) is a NaN or an Inf. + + Instead of calling isnan() and isinf(), the programmer including + this file should call qfits_isnan() and qfits_isinf(). +*/ +/*----------------------------------------------------------------------------*/ + +/* + $Id: ieeefp-compat.h,v 2.11 2003/11/24 09:44:53 yjung Exp $ + $Author: yjung $ + $Date: 2003/11/24 09:44:53 $ + $Revision: 2.11 $ +*/ + +#ifndef IEEEFP_COMPAT_H +#define IEEEFP_COMPAT_H + +/*----------------------------------------------------------------------------- + Macros + -----------------------------------------------------------------------------*/ + +/* */ +/*----------------------------------------------------------------------------*/ +/** + @brief Test a floating-point variable for NaN value. + @param n Number to test (float or double) + @return 1 if n is NaN, 0 else. + + This macro is needed to support both float and double variables + as input parameter. It checks on the size of the input variable + to branch to the float or double version. + + Portability is an issue for this function which is present on + most Unixes but not all, under various libraries (C lib on BSD, + Math lib on Linux, sunmath on Solaris, ...). Integrating the + code for this function makes qfits independent from any math + library. + */ +/*----------------------------------------------------------------------------*/ +#define qfits_isnan(n) ((sizeof(n)==sizeof(float)) ? _qfits_isnanf(n) : \ + (sizeof(n)==sizeof(double)) ? _qfits_isnand(n) : -1) + +/*----------------------------------------------------------------------------*/ +/** + @brief Test a floating-point variable for Inf value. + @param n Number to test (float or double) + @return 1 if n is Inf or -Inf, 0 else. + + This macro is needed to support both float and double variables + as input parameter. It checks on the size of the input variable + to branch to the float or double version. + + Portability is an issue for this function which is missing on most + Unixes. Most of the time, another function called finite() is + offered to perform the opposite task, but it is not consistent + among platforms and found in various libraries. Integrating the + code for this function makes qfits independent from any math + library. + */ +/*----------------------------------------------------------------------------*/ +#define qfits_isinf(n) ((sizeof(n)==sizeof(float)) ? _qfits_isinff(n) : \ + (sizeof(n)==sizeof(double)) ? _qfits_isinfd(n) : -1) + +/*----------------------------------------------------------------------------- + Function prototypes + -----------------------------------------------------------------------------*/ +/** + * Test a float variable for NaN value. + * Do not call directly, call qfits_isnan(). + */ +int _qfits_isnanf(float f); +/** + * Test a float variable for Inf value. + * Do not call directly, call qfits_isinf(). + */ +int _qfits_isinff(float f); +/** + * Test a double variable for NaN value. + * Do not call directly, call qfits_isnan(). + */ +int _qfits_isnand(double d); +/** + * Test a double variable for Inf value. + * Do not call directly, call qfits_isinf(). + */ +int _qfits_isinfd(double d); + +/* */ +#endif +/* vim: set ts=4 et sw=4 tw=75 */ diff --git a/qfits/src/md5.h b/qfits/src/md5.h new file mode 100644 index 0000000..d1d5e7c --- /dev/null +++ b/qfits/src/md5.h @@ -0,0 +1,24 @@ +#ifndef MD5_H +#define MD5_H + +typedef unsigned int word32 ; + +struct MD5Context { + word32 buf[4]; + word32 bits[2]; + unsigned char in[64]; +}; + +void MD5Init(struct MD5Context *context); +void MD5Update(struct MD5Context *context, unsigned char const *buf, + unsigned len); +void MD5Final(unsigned char digest[16], struct MD5Context *context); +void MD5Transform(word32 buf[4], word32 const in[16]); + +/* + * This is needed to make RSAREF happy on some MS-DOS compilers. + */ +typedef struct MD5Context MD5_CTX; + +#endif /* !MD5_H */ +/* vim: set ts=4 et sw=4 tw=75 */ diff --git a/qfits/src/pafs.h b/qfits/src/pafs.h new file mode 100644 index 0000000..a0f6f12 --- /dev/null +++ b/qfits/src/pafs.h @@ -0,0 +1,110 @@ +/*----------------------------------------------------------------------------*/ +/** + @file pafs.h + @author N. Devillard + @date Feb 1999 + @version $Revision: 1.4 $ + @brief PAF format I/O. + + This module contains various routines related to PAF file I/O. +*/ +/*----------------------------------------------------------------------------*/ + +/* + $Id: pafs.h,v 1.4 2003/11/24 09:44:53 yjung Exp $ + $Author: yjung $ + $Date: 2003/11/24 09:44:53 $ + $Revision: 1.4 $ +*/ + +#ifndef PAFS_H +#define PAFS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/*----------------------------------------------------------------------------- + Includes + ---------ii------------------------------------------------------------------*/ + +#include +#include +#include +#include +#include "static_sz.h" + +/* */ +/*----------------------------------------------------------------------------- + Function prototypes + -----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/** + @brief Open a new PAF file, output a default header. + @param filename Name of the file to create. + @param paf_id PAF identificator. + @param paf_desc PAF description. + @param login_name Login name + @param datetime Date + @return Opened file pointer. + + This function creates a new PAF file with the requested file name. + If another file already exists with the same name, it will be + overwritten (if the file access rights allow it). + + A default header is produced according to the VLT DICB standard. You + need to provide an identificator (paf_id) of the producer of the + file. Typically, something like "ISAAC/zero_point". + + The PAF description (paf_desc) is meant for humans. Typically, + something like "Zero point computation results". + + This function returns an opened file pointer, ready to receive more + data through fprintf's. The caller is responsible for fclose()ing + the file. + */ +/*----------------------------------------------------------------------------*/ +FILE * qfits_paf_print_header( + char * filename, + char * paf_id, + char * paf_desc, + char * login_name, + char * datetime) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Query a PAF file for a value. + @param filename Name of the PAF to query. + @param key Name of the key to query. + @return 1 pointer to statically allocated string, or NULL. + + This function parses a PAF file and returns the value associated to a + given key, as a pointer to an internal statically allocated string. + Do not try to free or modify the contents of the returned string! + + If the key is not found, this function returns NULL. + */ +/*----------------------------------------------------------------------------*/ +char * qfits_paf_query( + char * filename, + char * key) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief returns 1 if file is in PAF format, 0 else + @param filename name of the file to check + @return int 0, 1, or -1 + Returns 1 if the file name corresponds to a valid PAF file. Returns + 0 else. If the file does not exist, returns -1. Validity of the PAF file + is checked with the presence of PAF.HDR.START at the beginning + */ +/*----------------------------------------------------------------------------*/ +int qfits_is_paf_file(char * filename) ; + +/* */ +#ifdef __cplusplus +} +#endif + +#endif diff --git a/qfits/src/pixio.h b/qfits/src/pixio.h new file mode 100644 index 0000000..4374afd --- /dev/null +++ b/qfits/src/pixio.h @@ -0,0 +1,448 @@ +/*----------------------------------------------------------------------------*/ +/** + @file pixload.h + @author N. Devillard + @date Nov 2001 + @version $Revision: 1.12 $ + @brief Pixel loader for FITS images. +*/ +/*----------------------------------------------------------------------------*/ + +/* + $Id: pixio.h,v 1.12 2003/11/24 09:44:53 yjung Exp $ + $Author: yjung $ + $Date: 2003/11/24 09:44:53 $ + $Revision: 1.12 $ +*/ + +#ifndef PIXLOAD_H +#define PIXLOAD_H + +/*----------------------------------------------------------------------------- + Includes + -----------------------------------------------------------------------------*/ + +#include +#include +#include +#include +#include "xmemory.h" +#include "fits_std.h" + +/* */ +/*----------------------------------------------------------------------------- + Defines + -----------------------------------------------------------------------------*/ + +/** Symbol to set returned pixel type to float */ +#define PTYPE_FLOAT 0 +/** Symbol to set returned pixel type to int */ +#define PTYPE_INT 1 +/** Symbol to set returned pixel type to double */ +#define PTYPE_DOUBLE 2 + +/*----------------------------------------------------------------------------- + New types + -----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/** + @brief Alias for unsigned char + + A 'byte' is just an alias for an unsigned char. It is only defined + for readability. + */ +/*----------------------------------------------------------------------------*/ +typedef unsigned char byte ; + +/*----------------------------------------------------------------------------*/ +/** + @brief qfits loader control object + + This structure serves two purposes: input and output for the qfits + pixel loading facility. To request pixels from a FITS file, you + need to allocate (statically or dynamically) such a structure and + fill up the input fields (filename, xtension number, etc.) to specify + the pixels you want from the file. + + Before performing the actual load, you must pass the initialized + structure to qfitsloader_init() which will check whether the operation + is feasible or not (check its returned value). + + If the operation was deemed feasible, you can proceed to load the pixels, + passing the same structure to qfits_loadpix() which will fill up the + output fields of the struct. Notice that a pixel buffer will have been + allocated (through malloc or mmap) and placed into the structure. You + need to call free() on this pointer when you are done with it, + typically in the image or cube destructor. + + The qfitsloader_init() function is also useful to probe a FITS file + for useful informations, like getting the size of images in the file, + the pixel depth, or data offset. + + Example of a code that prints out various informations about + a plane to load, without actually loading it: + + @code +int main(int argc, char * argv[]) +{ + qfitsloader ql ; + + ql.filename = argv[1] ; + ql.xtnum = 0 ; + ql.pnum = 0 ; + + if (qfitsloader_init(&ql)!=0) { + printf("cannot read info about %s\n", argv[1]); + return -1 ; + } + + printf( "file : %s\n" + "xtnum : %d\n" + "pnum : %d\n" + "# xtensions : %d\n" + "size X : %d\n" + "size Y : %d\n" + "planes : %d\n" + "bitpix : %d\n" + "datastart : %d\n" + "datasize : %d\n" + "bscale : %g\n" + "bzero : %g\n", + ql.filename, + ql.xtnum, + ql.pnum, + ql.exts, + ql.lx, + ql.ly, + ql.np, + ql.bitpix, + ql.seg_start, + ql.seg_size, + ql.bscale, + ql.bzero); + return 0 ; +} + @endcode + */ +/*----------------------------------------------------------------------------*/ +typedef struct qfitsloader { + + /** Private field to see if structure has been initialized */ + int _init ; + + /** input: Name of the file you want to read pixels from */ + char * filename ; + /** input: xtension number you want to read */ + int xtnum ; + /** input: Index of the plane you want, from 0 to np-1 */ + int pnum ; + /** input: Pixel type you want (PTYPE_FLOAT, PTYPE_INT or PTYPE_DOUBLE) */ + int ptype ; + /** input: Guarantee file copy or allow file mapping */ + int map ; + + /** output: Total number of extensions found in file */ + int exts ; + /** output: Size in X of the requested plane */ + int lx ; + /** output: Size in Y of the requested plane */ + int ly ; + /** output: Number of planes present in this extension */ + int np ; + /** output: BITPIX for this extension */ + int bitpix ; + /** output: Start of the data segment (in bytes) for your request */ + int seg_start ; + /** output: Size of the data segment (in bytes) for your request */ + int seg_size ; + /** output: BSCALE found for this extension */ + double bscale ; + /** output: BZERO found for this extension */ + double bzero ; + + /** output: Pointer to pixel buffer loaded as integer values */ + int * ibuf ; + /** output: Pointer to pixel buffer loaded as float values */ + float * fbuf ; + /** output: Pointer to pixel buffer loaded as double values */ + double * dbuf ; + +} qfitsloader ; + + +/*----------------------------------------------------------------------------*/ +/** + @brief qfits dumper control object + + This structure offers various control parameters to dump a pixel + buffer to a FITS file. The buffer will be dumped as requested + to the requested file in append mode. Of course, the requested file + must be writeable for the operation to succeed. + + The following example demonstrates how to save a linear ramp sized + 100x100 to a FITS file with BITPIX=16. Notice that this code only + dumps the pixel buffer, no header information is provided in this + case. + + @code + int i, j ; + int * ibuf ; + qfitsdumper qd ; + + // Fill a buffer with 100x100 int pixels + ibuf = malloc(100 * 100 * sizeof(int)); + for (j=0 ; j<100 ; j++) { + for (i=0 ; i<100 ; i++) { + ibuf[i+j*100] = i+j ; + } + } + + qd.filename = "out.fits" ; // Output file name + qd.npix = 100 * 100 ; // Number of pixels + qd.ptype = PTYPE_INT ; // Input buffer type + qd.ibuf = ibuf ; // Set buffer pointer + qd.out_ptype = BPP_16_SIGNED ; // Save with BITPIX=16 + + // Dump buffer to file (error checking omitted for clarity) + qfits_pixdump(&qd); + + free(ibuf); + @endcode + + If the provided output file name is "STDOUT" (all capitals), the + function will dump the pixels to the stdout steam (usually the console, + could have been re-directed). + */ +/*----------------------------------------------------------------------------*/ +typedef struct qfitsdumper { + + /** Name of the file to dump to, "STDOUT" to dump to stdout */ + char * filename ; + /** Number of pixels in the buffer to dump */ + int npix ; + /** Buffer type: PTYPE_FLOAT, PTYPE_INT or PTYPE_DOUBLE */ + int ptype ; + + /** Pointer to input integer pixel buffer */ + int * ibuf ; + /** Pointer to input float pixel buffer */ + float * fbuf ; + /** Pointer to input double pixel buffer */ + double * dbuf ; + + /** Requested BITPIX in output FITS file */ + int out_ptype ; +} qfitsdumper ; + + +/*----------------------------------------------------------------------------- + Function prototypes + -----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/** + @brief Initialize a qfitsloader control object. + @param ql qfitsloader object to initialize. + @return int 0 if Ok, -1 if error occurred. + + This function expects a qfitsloader object with a number of input + fields correctly filled in. The minimum fields to set are: + + - filename: Name of the file to examine. + - xtnum: Extension number to examine (0 for main section). + - pnum: Plane number in the requested extension. + + You can go ahead with these fields only if you only want to get + file information for this plane in this extension. If you want + to later load the plane, you must additionally fill the 'ptype' + field to a correct value (PTYPE_INT, PTYPE_FLOAT, PTYPE_DOUBLE) + before calling qfits_loadpix() so that it knows which conversion + to perform. + + This function is basically a probe sent on a FITS file to ask + qfits if loading these data would be Ok or not. The actual loading + is performed by qfits_loadpix() afterwards. + */ +/*----------------------------------------------------------------------------*/ +int qfitsloader_init(qfitsloader * ql); + +/*----------------------------------------------------------------------------*/ +/** + @brief Load a pixel buffer for one image. + @param ql Allocated and initialized qfitsloader control object. + @return int 0 if Ok, -1 if error occurred. + + This function performs a load of a pixel buffer into memory. It + expects an allocated and initialized qfitsloader object in input. + See qfitsloader_init() about initializing the object. + + This function will fill up the ibuf/fbuf/dbuf field, depending + on the requested pixel type (resp. int, float or double). + + The returned buffer has been allocated using one of the special + memory operators present in xmemory.c. To deallocate the buffer, + you must call the version of free() offered by xmemory, not the + usual system free(). It is enough to include "xmemory.h" in your + code before you make calls to the pixel loader here. + */ +/*----------------------------------------------------------------------------*/ +int qfits_loadpix(qfitsloader * ql); + +/*----------------------------------------------------------------------------*/ +/** + @brief Load a pixel buffer as floats. + @param p_source Pointer to source buffer (as bytes). + @param npix Number of pixels to load. + @param bitpix FITS BITPIX in original file. + @param bscale FITS BSCALE in original file. + @param bzero FITS BZERO in original file. + @return 1 pointer to a newly allocated buffer of npix floats. + + This function takes in input a pointer to a byte buffer as given + in the original FITS file (big-endian format). It converts the + buffer to an array of float (whatever representation is used for + floats by this platform is used) and returns the newly allocated + buffer, or NULL if an error occurred. + + The returned buffer must be deallocated using the free() offered + by xmemory. It is enough to #include "xmemory.h" before calling + free on the returned pointer. + */ +/*----------------------------------------------------------------------------*/ +float * qfits_pixin_float (byte *, int, int, double, double); + +/*----------------------------------------------------------------------------*/ +/** + @brief Load a pixel buffer as ints. + @param p_source Pointer to source buffer (as bytes). + @param npix Number of pixels to load. + @param bitpix FITS BITPIX in original file. + @param bscale FITS BSCALE in original file. + @param bzero FITS BZERO in original file. + @return 1 pointer to a newly allocated buffer of npix ints. + + This function takes in input a pointer to a byte buffer as given + in the original FITS file (big-endian format). It converts the + buffer to an array of int (whatever representation is used for + int by this platform is used) and returns the newly allocated + buffer, or NULL if an error occurred. + + The returned buffer must be deallocated using the free() offered + by xmemory. It is enough to #include "xmemory.h" before calling + free on the returned pointer. + */ +/*----------------------------------------------------------------------------*/ +int * qfits_pixin_int (byte *, int, int, double, double); + +/*----------------------------------------------------------------------------*/ +/** + @brief Load a pixel buffer as doubles. + @param p_source Pointer to source buffer (as bytes). + @param npix Number of pixels to load. + @param bitpix FITS BITPIX in original file. + @param bscale FITS BSCALE in original file. + @param bzero FITS BZERO in original file. + @return 1 pointer to a newly allocated buffer of npix doubles. + + This function takes in input a pointer to a byte buffer as given + in the original FITS file (big-endian format). It converts the + buffer to an array of double (whatever representation is used for + int by this platform is used) and returns the newly allocated + buffer, or NULL if an error occurred. + + The returned buffer must be deallocated using the free() offered + by xmemory. It is enough to #include "xmemory.h" before calling + free on the returned pointer. + */ +/*----------------------------------------------------------------------------*/ +double * qfits_pixin_double(byte *, int, int, double, double); + +/*----------------------------------------------------------------------------*/ +/** + @brief Dump a pixel buffer to an output FITS file in append mode. + @param qd qfitsdumper control object. + @return int 0 if Ok, -1 otherwise. + + This function takes in input a qfitsdumper control object. This object + must be allocated beforehand and contain valid references to the data + to save, and how to save it. + + The minimum fields to fill are: + + - filename: Name of the FITS file to dump to. + - npix: Number of pixels in the buffer to be dumped. + - ptype: Type of the passed buffer (PTYPE_FLOAT, PTYPE_INT, PTYPE_DOUBLE) + - out_ptype: Requested FITS BITPIX for the output. + + One of the following fields must point to the corresponding pixel + buffer: + + - ibuf for an int pixel buffer (ptype=PTYPE_INT) + - fbuf for a float pixel buffer (ptype=PTYPE_FLOAT) + - dbuf for a double pixel buffer (ptype=PTYPE_DOUBLE) + + This is a fairly low-level function, in the sense that it does not + check that the output file already contains a proper header or even + that the file it is appending to is indeed a FITS file. It will + convert the pixel buffer to the requested BITPIX type and append + the data to the file, without padding with zeros. See qfits_zeropad() + about padding. + + If the given output file name is "STDOUT" (all caps), the dump + will be performed to stdout. + */ +/*----------------------------------------------------------------------------*/ +int qfits_pixdump(qfitsdumper * qd) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Convert a float pixel buffer to a byte buffer. + @param buf Input float buffer. + @param npix Number of pixels in the input buffer. + @param ptype Requested output BITPIX type. + @return 1 pointer to a newly allocated byte buffer. + + This function converts the given float buffer to a buffer of bytes + suitable for dumping to a FITS file (i.e. big-endian, in the + requested pixel type). The returned pointer must be deallocated + using the free() function offered by xmemory. + */ +/*----------------------------------------------------------------------------*/ +byte * qfits_pixdump_float(float * buf, int npix, int ptype); + +/*----------------------------------------------------------------------------*/ +/** + @brief Convert an int pixel buffer to a byte buffer. + @param buf Input int buffer. + @param npix Number of pixels in the input buffer. + @param ptype Requested output BITPIX type. + @return 1 pointer to a newly allocated byte buffer. + + This function converts the given int buffer to a buffer of bytes + suitable for dumping to a FITS file (i.e. big-endian, in the + requested pixel type). The returned pointer must be deallocated + using the free() function offered by xmemory. + */ +/*----------------------------------------------------------------------------*/ +byte * qfits_pixdump_int(int * buf, int npix, int ptype); + +/*----------------------------------------------------------------------------*/ +/** + @brief Convert a double pixel buffer to a byte buffer. + @param buf Input double buffer. + @param npix Number of pixels in the input buffer. + @param ptype Requested output BITPIX type. + @return 1 pointer to a newly allocated byte buffer. + + This function converts the given double buffer to a buffer of bytes + suitable for dumping to a FITS file (i.e. big-endian, in the + requested pixel type). The returned pointer must be deallocated + using the free() function offered by xmemory. + */ +/*----------------------------------------------------------------------------*/ +byte * qfits_pixdump_double(double * buf, int npix, int ptype); + +/* */ +#endif +/* vim: set ts=4 et sw=4 tw=75 */ diff --git a/qfits/src/qerror.h b/qfits/src/qerror.h new file mode 100644 index 0000000..eb70fe7 --- /dev/null +++ b/qfits/src/qerror.h @@ -0,0 +1,97 @@ +/*----------------------------------------------------------------------------*/ +/** + @file qerror.h + @author N. Devillard + @date Nov 2001 + @version $Revision: 1.8 $ + @brief qfits error handling +*/ +/*----------------------------------------------------------------------------*/ + +/* + $Id: qerror.h,v 1.8 2005/05/18 14:38:01 yjung Exp $ + $Author: yjung $ + $Date: 2005/05/18 14:38:01 $ + $Revision: 1.8 $ +*/ + +#ifndef QERROR_H +#define QERROR_H + +/*----------------------------------------------------------------------------- + Includes + -----------------------------------------------------------------------------*/ + +#include +#include + +/*----------------------------------------------------------------------------- + Function prototypes + -----------------------------------------------------------------------------*/ + +/* */ +/*----------------------------------------------------------------------------*/ +/** + @brief Get the current status of error display. + @return int 1 if error display is active, 0 if not. + + This function returns the current error display status. If it returns 1, + it means that all calls to qfits_error/qfits_warning will display + messages using the registered functions, otherwise they do nothing. + */ +/*----------------------------------------------------------------------------*/ +int qfits_err_statget(void); + +/*----------------------------------------------------------------------------*/ +/** + @brief Set the current status of error display. + @param sta New status to be set. + @return int giving the previous display status. + + This function sets the current error display status to the required + value, and returns the previous value. It is useful to store the + previous value, in view of restoring it afterwards, e.g. to make a + function silent on all its errors. Example: + + \begin{verbatim} + int prev_stat = qfits_err_statset(0) ; + function_call() ; + qfits_err_statset(prev_stat); + \end{verbatim} + */ +/*----------------------------------------------------------------------------*/ +int qfits_err_statset(int sta); + +/*----------------------------------------------------------------------------*/ +/** + @brief Register a function to display error/warning messages. + @param dispfn Display function (see doc below). + @return int 0 if function was registered, -1 if not. + + This function registers a display function into the error-handling + module. Display functions have the following prototype: + + @code + void display_function(char * msg); + @endcode + + They are simple functions that expect a ready-made error message + and return void. They can do whatever they want with the message + (log it to a file, send it to a GUI, to the syslog, ...). The + message is built using a printf-like statement in qfits_error and + qfits_warning, then passed to all registered display functions. + + A maximum of QFITS_ERR_MAXERRDISP can be registered (see source code). + If the limit has been reached, this function will signal it by + returning -1. + */ +/*----------------------------------------------------------------------------*/ +int qfits_err_register( void (*dispfn)(char*) ) ; +/* */ + +/* Public warning/error functions */ +void qfits_warning(const char *fmt, ...); +void qfits_error(const char *fmt, ...); + +#endif +/* vim: set ts=4 et sw=4 tw=75 */ diff --git a/qfits/src/simple.h b/qfits/src/simple.h new file mode 100644 index 0000000..d42d345 --- /dev/null +++ b/qfits/src/simple.h @@ -0,0 +1,311 @@ +/*----------------------------------------------------------------------------*/ +/** + @file simple.h + @author N. Devillard + @date Jan 1999 + @version $Revision: 1.12 $ + @brief Simple FITS access routines. + + This module offers a number of very basic low-level FITS access + routines. +*/ +/*----------------------------------------------------------------------------*/ + +/* + $Id: simple.h,v 1.12 2005/05/18 14:38:01 yjung Exp $ + $Author: yjung $ + $Date: 2005/05/18 14:38:01 $ + $Revision: 1.12 $ +*/ + +#ifndef SIMPLE_H +#define SIMPLE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/*----------------------------------------------------------------------------- + Includes + -----------------------------------------------------------------------------*/ + +#include +#include +#include + +/* */ +/*----------------------------------------------------------------------------- + Defines + -----------------------------------------------------------------------------*/ + +/** Unknown type for FITS value */ +#define QFITS_UNKNOWN 0 +/** Boolean type for FITS value */ +#define QFITS_BOOLEAN 1 +/** Int type for FITS value */ +#define QFITS_INT 2 +/** Float type for FITS value */ +#define QFITS_FLOAT 3 +/** Complex type for FITS value */ +#define QFITS_COMPLEX 4 +/** String type for FITS value */ +#define QFITS_STRING 5 + +/*----------------------------------------------------------------------------- + Function codes + -----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/** + @brief Retrieve the value of a key in a FITS header + @param filename Name of the FITS file to browse + @param keyword Name of the keyword to find + @return pointer to statically allocated character string + + Provide the name of a FITS file and a keyword to look for. The input + file is memory-mapped and the first keyword matching the requested one is + located. The value corresponding to this keyword is copied to a + statically allocated area, so do not modify it or free it. + + The input keyword is first converted to upper case and expanded to + the HIERARCH scheme if given in the shortFITS notation. + + This function is pretty fast due to the mmapping. Due to buffering + on most Unixes, it is possible to call many times this function in a + row on the same file and do not suffer too much from performance + problems. If the file contents are already in the cache, the file + will not be re-opened every time. + + It is possible, though, to modify this function to perform several + searches in a row. See the source code. + + Returns NULL in case the requested keyword cannot be found. + */ +/*----------------------------------------------------------------------------*/ +char * qfits_query_hdr(char * filename, const char * keyword) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Retrieve the value of a keyin a FITS extension header. + @param filename name of the FITS file to browse. + @param keyword name of the FITS key to look for. + @param xtnum xtension number + @return pointer to statically allocated character string + + Same as qfits_query_hdr but for extensions. xtnum starts from 1 to + the number of extensions. If xtnum is zero, this function is + strictly identical to qfits_query_hdr(). + */ +/*----------------------------------------------------------------------------*/ +char * qfits_query_ext(char * filename, const char * keyword, int xtnum) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Counts the number of extensions in a FITS file + @param filename Name of the FITS file to browse. + @return int + + Counts how many extensions are in the file. Returns 0 if no + extension is found, and -1 if an error occurred. + */ +/*----------------------------------------------------------------------------*/ +int qfits_query_n_ext(char * filename) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Counts the number of planes in a FITS extension. + @param filename Name of the FITS file to browse. + @param exnum Extensin number + @return int + Counts how many planes are in the extension. Returns 0 if no plane is found, + and -1 if an error occurred. + */ +/*----------------------------------------------------------------------------*/ +int qfits_query_nplanes(char * filename, int extnum) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Clean out a FITS string value. + @param s pointer to allocated FITS value string. + @return pointer to statically allocated character string + + From a string FITS value like 'marvin o''hara', remove head and tail + quotes, replace double '' with simple ', trim blanks on each side, + and return the result in a statically allocated area. + + Examples: + + - ['o''hara'] becomes [o'hara] + - [' H '] becomes [H] + - ['1.0 '] becomes [1.0] + + */ +/*----------------------------------------------------------------------------*/ +char * qfits_pretty_string(char * s) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Identify if a FITS value is boolean + @param s FITS value as a string + @return int 0 or 1 + + Identifies if a FITS value is boolean. + */ +/*----------------------------------------------------------------------------*/ +int qfits_is_boolean(char * s) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Identify if a FITS value is an int. + @param s FITS value as a string + @return int 0 or 1 + + Identifies if a FITS value is an integer. + */ +/*----------------------------------------------------------------------------*/ +int qfits_is_int(char * s) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Identify if a FITS value is float. + @param s FITS value as a string + @return int 0 or 1 + + Identifies if a FITS value is float. + */ +/*----------------------------------------------------------------------------*/ +int qfits_is_float(char * s) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Identify if a FITS value is complex. + @param s FITS value as a string + @return int 0 or 1 + + Identifies if a FITS value is complex. + */ +/*----------------------------------------------------------------------------*/ +int qfits_is_complex(char * s) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Identify if a FITS value is string. + @param s FITS value as a string + @return int 0 or 1 + + Identifies if a FITS value is a string. + */ +/*----------------------------------------------------------------------------*/ +int qfits_is_string(char * s) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Identify the type of a FITS value given as a string. + @param s FITS value as a string + @return integer naming the FITS type + + Returns the following value: + + - QFITS_UNKNOWN (0) for an unknown type. + - QFITS_BOOLEAN (1) for a boolean type. + - QFITS_INT (2) for an integer type. + - QFITS_FLOAT (3) for a floating-point type. + - QFITS_COMPLEX (4) for a complex number. + - QFITS_STRING (5) for a FITS string. + */ +/*----------------------------------------------------------------------------*/ +int qfits_get_type(char * s) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Retrieve offset to start and size of a header in a FITS file. + @param filename Name of the file to examine + @param xtnum Extension number (0 for main) + @param seg_start Segment start in bytes (output) + @param seg_size Segment size in bytes (output) + @return int 0 if Ok, -1 otherwise. + + This function retrieves the two most important informations about + a header in a FITS file: the offset to its beginning, and the size + of the header in bytes. Both values are returned in the passed + pointers to ints. It is Ok to pass NULL for any pointer if you do + not want to retrieve the associated value. + + You must provide an extension number for the header, 0 meaning the + main header in the file. + */ +/*----------------------------------------------------------------------------*/ +int qfits_get_hdrinfo( + char * filename, + int xtnum, + int * seg_start, + int * seg_size) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Retrieve offset to start and size of a data section in a file. + @param filename Name of the file to examine. + @param xtnum Extension number (0 for main). + @param seg_start Segment start in bytes (output). + @param seg_size Segment size in bytes (output). + @return int 0 if Ok, -1 otherwise. + + This function retrieves the two most important informations about + a data section in a FITS file: the offset to its beginning, and the size + of the section in bytes. Both values are returned in the passed + pointers to ints. It is Ok to pass NULL for any pointer if you do + not want to retrieve the associated value. + + You must provide an extension number for the header, 0 meaning the + main header in the file. + */ +/*----------------------------------------------------------------------------*/ +int qfits_get_datinfo( + char * filename, + int xtnum, + int * seg_start, + int * seg_size) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Query a card in a FITS (main) header by a given key + @param filename Name of the FITS file to check. + @param keyword Where to read a card in the header. + @return Allocated string containing the card or NULL + */ +/*----------------------------------------------------------------------------*/ +char * qfits_query_card( + char * filename, + char * keyword) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Replace a card in a FITS (main) header by a given card + @param filename Name of the FITS file to modify. + @param keyword Where to substitute a card in the header. + @param substitute What to replace the line with. + @return int 0 if Ok, -1 otherwise + + Replaces a whole card (80 chars) in a FITS header by a given FITS + line (80 chars). The replacing line is assumed correctly formatted + and containing at least 80 characters. The file is modified: it must + be accessible in read/write mode. + + The input keyword is first converted to upper case and expanded to + the HIERARCH scheme if given in the shortFITS notation. + + Returns 0 if everything worked Ok, -1 otherwise. + */ +/*----------------------------------------------------------------------------*/ +int qfits_replace_card( + char * filename, + const char * keyword, + char * substitute) ; + +/* */ +#ifdef __cplusplus +} +#endif + +#endif +/* vim: set ts=4 et sw=4 tw=75 */ diff --git a/qfits/src/static_sz.h b/qfits/src/static_sz.h new file mode 100644 index 0000000..126061b --- /dev/null +++ b/qfits/src/static_sz.h @@ -0,0 +1,42 @@ +/*----------------------------------------------------------------------------*/ +/** + @file static_sz.h + @author N. Devillard + @date Dec 1999 + @version $Revision: 1.5 $ + @brief Definitions for various fixed sizes. +*/ +/*----------------------------------------------------------------------------*/ + +/* + $Id: static_sz.h,v 1.5 2003/11/24 09:44:53 yjung Exp $ + $Author: yjung $ + $Date: 2003/11/24 09:44:53 $ + $Revision: 1.5 $ +*/ + +#ifndef STATIC_SZ_H +#define STATIC_SZ_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* */ +/*----------------------------------------------------------------------------- + Defines + -----------------------------------------------------------------------------*/ + +/** Maximum supported file name size */ +#define FILENAMESZ 512 + +/** Maximum number of characters per line in an ASCII file */ +#define ASCIILINESZ 1024 + +/* */ +#ifdef __cplusplus +} +#endif + +#endif +/* vim: set ts=4 et sw=4 tw=75 */ diff --git a/qfits/src/t_iso8601.h b/qfits/src/t_iso8601.h new file mode 100644 index 0000000..535ddb8 --- /dev/null +++ b/qfits/src/t_iso8601.h @@ -0,0 +1,93 @@ +/*----------------------------------------------------------------------------*/ +/** + @file t_iso8601.h + @author N. Devillard + @date Aug 1999 + @version $Revision: 1.8 $ + @brief Get date/time, possibly in ISO8601 format. + + This module contains various utilities to get the current date/time, + and possibly format it according to the ISO 8601 format. +*/ +/*----------------------------------------------------------------------------*/ + +/* + $Id: t_iso8601.h,v 1.8 2004/01/20 11:47:59 yjung Exp $ + $Author: yjung $ + $Date: 2004/01/20 11:47:59 $ + $Revision: 1.8 $ + +*/ + +#ifndef T_ISO8601_H +#define T_ISO8601_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/* */ +/*----------------------------------------------------------------------------- + Function ANSI C prototypes + -----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/** + @brief Returns the current date as a long (CCYYMMDD). + @return The current date as a long number. + + Returns the current date as a long value (CCYYMMDD). Since most + system clocks do not return a century, this function assumes that + all years 80 and above are in the 20th century, and all years 00 to + 79 are in the 21st century. For best results, consume before 1 Jan + 2080. + + Example: 19 Oct 2000 is returned as 20001019 + */ +/*----------------------------------------------------------------------------*/ +long qfits_date_now (void); + +/*----------------------------------------------------------------------------*/ +/** + @brief Returns the current time as a long (HHMMSSCC). + @return The current time as a long number. + + Returns the current time as a long value (HHMMSSCC). If the system + clock does not return centiseconds, these are set to zero. + Example: 15:36:12.84 is returned as 15361284 + */ +/*----------------------------------------------------------------------------*/ +long qfits_time_now(void); + +/*----------------------------------------------------------------------------*/ +/** + @brief Returns the current date as a static string. + @return Pointer to statically allocated string. + + Build and return a string containing the date of today in ISO8601 + format. The returned pointer points to a statically allocated string + in the function, so no need to free it. + */ +/*----------------------------------------------------------------------------*/ +char * qfits_get_date_iso8601(void); + +/*----------------------------------------------------------------------------*/ +/** + @brief Returns the current date and time as a static string. + @return Pointer to statically allocated string + + Build and return a string containing the date of today and the + current time in ISO8601 format. The returned pointer points to a + statically allocated string in the function, so no need to free it. + */ +/*----------------------------------------------------------------------------*/ +char * qfits_get_datetime_iso8601(void); + +/* */ +#ifdef __cplusplus +} +#endif + +#endif +/* vim: set ts=4 et sw=4 tw=75 */ diff --git a/qfits/src/tfits.h b/qfits/src/tfits.h new file mode 100644 index 0000000..d5daba4 --- /dev/null +++ b/qfits/src/tfits.h @@ -0,0 +1,546 @@ +/*----------------------------------------------------------------------------*/ +/** + @file tfits.h + @author Yves Jung + @date July 1999 + @version $Revision: 1.25 $ + @brief FITS table handling +*/ +/*----------------------------------------------------------------------------*/ + +/* + $Id: tfits.h,v 1.25 2003/11/24 09:44:53 yjung Exp $ + $Author: yjung $ + $Date: 2003/11/24 09:44:53 $ + $Revision: 1.25 $ +*/ + +#ifndef TFITS_H +#define TFITS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/*----------------------------------------------------------------------------- + Includes + -----------------------------------------------------------------------------*/ + +#include +#include +#include +#include + +#include "fits_h.h" +#include "static_sz.h" + +/* */ +/*----------------------------------------------------------------------------- + Defines + -----------------------------------------------------------------------------*/ + +/* The following defines the maximum acceptable size for a FITS value */ +#define FITSVALSZ 60 + +#define QFITS_INVALIDTABLE 0 +#define QFITS_BINTABLE 1 +#define QFITS_ASCIITABLE 2 + +/*----------------------------------------------------------------------------- + New types + -----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/** + @brief Column data type + */ +/*----------------------------------------------------------------------------*/ +typedef enum _TFITS_DATA_TYPE_ { + TFITS_ASCII_TYPE_A, + TFITS_ASCII_TYPE_D, + TFITS_ASCII_TYPE_E, + TFITS_ASCII_TYPE_F, + TFITS_ASCII_TYPE_I, + TFITS_BIN_TYPE_A, + TFITS_BIN_TYPE_B, + TFITS_BIN_TYPE_C, + TFITS_BIN_TYPE_D, + TFITS_BIN_TYPE_E, + TFITS_BIN_TYPE_I, + TFITS_BIN_TYPE_J, + TFITS_BIN_TYPE_L, + TFITS_BIN_TYPE_M, + TFITS_BIN_TYPE_P, + TFITS_BIN_TYPE_X, + TFITS_BIN_TYPE_UNKNOWN +} tfits_type ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Column object + + This structure contains all information needed to read a column in a table. + These informations come from the header. + The qfits_table object contains a list of qfits_col objects. + + This structure has to be created from scratch and filled if one want to + generate a FITS table. + */ +/*----------------------------------------------------------------------------*/ +typedef struct qfits_col +{ + /** + Number of atoms in one field. + In ASCII tables, it is the number of characters in the field as defined + in TFORM%d keyword. + In BIN tables, it is the number of atoms in each field. For type 'A', + it is the number of characters. A field with two complex object will + have atom_nb = 4. + */ + int atom_nb ; + + /** + Number of decimals in a ASCII field. + This value is always 0 for BIN tables + */ + int atom_dec_nb ; + + /** + Size of one element in bytes. In ASCII tables, atom_size is the size + of the element once it has been converted in its 'destination' type. + For example, if "123" is contained in an ASCII table in a column + defined as I type, atom_nb=3, atom_size=4. + In ASCII tables: + - type 'A' : atom_size = atom_nb = number of chars + - type 'I', 'F' or 'E' : atom_size = 4 + - type 'D' : atom_size = 8 + In BIN tables : + - type 'A', 'L', 'X', 'B': atom_size = 1 + - type 'I' : atom_size = 2 + - type 'E', 'J', 'C', 'P' : atom_size = 4 + - type 'D', 'M' : atom_size = 8 + In ASCII table, there is one element per field. The size in bytes and + in number of characters is atom_nb, and the size in bytes after + conversion of the field is atom_size. + In BIN tables, the size in bytes of a field is always atom_nb*atom_size. + */ + int atom_size ; + + /** + Type of data in the column as specified in TFORM keyword + In ASCII tables : TFITS_ASCII_TYPE_* with *=A, I, F, E or D + In BIN tables : TFITS_BIN_TYPE_* with *=L, X, B, I, J, A, E, D, C, M or P + */ + tfits_type atom_type ; + + /** Label of the column */ + char tlabel[FITSVALSZ] ; + + /** Unit of the data */ + char tunit[FITSVALSZ] ; + + /** Null value */ + char nullval[FITSVALSZ] ; + + /** Display format */ + char tdisp[FITSVALSZ] ; + + /** + zero and scale are used when the quantity in the field does not + represent a true physical quantity. Basically, thez should be used + when they are present: physical_value = zero + scale * field_value + They are read from TZERO and TSCAL in the header + */ + int zero_present ; + float zero ; + int scale_present ; + float scale ; + + /** Offset between the beg. of the table and the beg. of the column. */ + int off_beg ; + + /** Flag to know if the column is readable. An empty col is not readable */ + int readable ; +} qfits_col ; + + +/*----------------------------------------------------------------------------*/ +/** + @brief Table object + + This structure contains all information needed to read a FITS table. + These information come from the header. The object is created by + qfits_open(). + + To read a FITS table, here is a code example: + @code + int main(int argc, char* argv[]) + { + qfits_table * table ; + int n_ext ; + int i ; + + // Query the number of extensions + n_ext = qfits_query_n_ext(argv[1]) ; + + // For each extension + for (i=0 ; inatoms * col->atom_size + + Numeric types are correctly understood and byte-swapped if needed, + to be converted to the local machine type. + + NULL values have to be handled by the caller. + + The returned buffer has been allocated using one of the special memory + operators present in xmemory.c. To deallocate the buffer, you must call + the version of free() offered by xmemory, not the usual system free(). It + is enough to include "xmemory.h" in your code before you make calls to + the pixel loader here. + */ +/*----------------------------------------------------------------------------*/ +unsigned char * qfits_query_column( + qfits_table * th, + int colnum, + int * selection) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Extract consequtive values from a column in a FITS table + @param th Allocated qfits_table + @param colnum Number of the column to extract (from 0 to colnum-1) + @param start_ind Index of the first row (0 for the first) + @param nb_rows Number of rows to extract + @return unsigned char array + Does the same as qfits_query_column() but on a consequtive sequence of rows + Spares the overhead of the selection object allocation + */ +/*----------------------------------------------------------------------------*/ +unsigned char * qfits_query_column_seq( + qfits_table * th, + int colnum, + int start_ind, + int nb_rows) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Compute the table width in bytes from the columns infos + @param th Allocated qfits_table + @return the width (-1 in error case) + */ +/*----------------------------------------------------------------------------*/ +int qfits_compute_table_width(qfits_table * th) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Extract binary data from a column in a FITS table + @param th Allocated qfits_table + @param colnum Number of the column to extract (from 0 to colnum-1) + @param selection bollean array to identify selected rows + @param null_value Value to return when a NULL value comes + @return Pointer to void * + + Extract a column from a FITS table and return the data as a generic + void* array. The returned array type and size are determined by the + column object in the qfits_table. + + Returned array size in bytes is: + nb_selected * col->atom_nb * col->atom_size + + NULL values are recognized and replaced by the specified value. + + The returned buffer has been allocated using one of the special memory + operators present in xmemory.c. To deallocate the buffer, you must call + the version of free() offered by xmemory, not the usual system free(). It + is enough to include "xmemory.h" in your code before you make calls to + the pixel loader here. + */ +/*----------------------------------------------------------------------------*/ +void * qfits_query_column_data( + qfits_table * th, + int colnum, + int * selection, + void * null_value) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Extract binary data from a column in a FITS table + @param th Allocated qfits_table + @param colnum Number of the column to extract (from 0 to colnum-1) + @param start_ind Index of the first row (0 for the first) + @param nb_rows Number of rows to extract + @param null_value Value to return when a NULL value comes + @return Pointer to void * + Does the same as qfits_query_column_data() but on a consequtive sequence + of rows. Spares the overhead of the selection object allocation + */ +/*----------------------------------------------------------------------------*/ +void * qfits_query_column_seq_data( + qfits_table * th, + int colnum, + int start_ind, + int nb_rows, + void * null_value) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Detect NULL values in a column + @param th Allocated qfits_table + @param colnum Number of the column to check (from 0 to colnum-1) + @param selection Array to identify selected rows + @param nb_vals Gives the size of the output array + @param nb_nulls Gives the number of detected null values + @return array with 1 for NULLs and 0 for non-NULLs + */ +/*----------------------------------------------------------------------------*/ +int * qfits_query_column_nulls( + qfits_table * th, + int colnum, + int * selection, + int * nb_vals, + int * nb_nulls) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Save a table to a FITS file with a given FITS header. + @param array Data array. + @param table table + @param fh FITS header to insert in the output file. + @return -1 in error case, 0 otherwise + */ +/*----------------------------------------------------------------------------*/ +int qfits_save_table_hdrdump( + void ** array, + qfits_table * table, + qfits_header * fh) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Appends a std extension header + data to a FITS table file. + @param outfile Pointer to (opened) file ready for writing. + @param t Pointer to qfits_table + @param data Table data to write + @return int 0 if Ok, -1 otherwise + + Dumps a FITS table to a file. The whole table described by qfits_table, and + the data arrays contained in 'data' are dumped to the file. An extension + header is produced with all keywords needed to describe the table, then the + data is dumped to the file. + The output is then padded to reach a multiple of 2880 bytes in size. + Notice that no main header is produced, only the extension part. + */ +/*----------------------------------------------------------------------------*/ +int qfits_table_append_xtension( + FILE * outfile, + qfits_table * t, + void ** data) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief Appends a specified extension header + data to a FITS table file. + @param outfile Pointer to (opened) file ready for writing. + @param t Pointer to qfits_table + @param data Table data to write + @param hdr Specified extension header + @return int 0 if Ok, -1 otherwise + + Dumps a FITS table to a file. The whole table described by qfits_table, and + the data arrays contained in 'data' are dumped to the file following the + specified fits header. + The output is then padded to reach a multiple of 2880 bytes in size. + Notice that no main header is produced, only the extension part. + */ +/*----------------------------------------------------------------------------*/ +int qfits_table_append_xtension_hdr( + FILE * outfile, + qfits_table * t, + void ** data, + qfits_header * hdr) ; + +/*----------------------------------------------------------------------------*/ +/** + @brief given a col and a row, find out the string to write for display + @param table table structure + @param col_id col id (0 -> nbcol-1) + @param row_id row id (0 -> nrow-1) + @param use_zero_scale Flag to use or not zero and scale + @return the string to write + */ +/*----------------------------------------------------------------------------*/ +char * qfits_table_field_to_string( + qfits_table * table, + int col_id, + int row_id, + int use_zero_scale) ; + +/* */ +#ifdef __cplusplus +} +#endif + +#endif +/* vim: set ts=4 et sw=4 tw=75 */