/********************************************************************************* * Sterrewacht Leiden - PRIMA project * * "@(#) $Id: $" * * who when what * -------- -------- ---------------------------------------------- * mathar 2004-08-21 created from mioFitsCnvrt * mathar 2004-08-30 implemented default for missing row filter; implemented Fits2Ascii * mathar 2008-04-29 renamed source Ascii2Fits.cpp; replaced tempnam; eclipse mode * * NAME * * Ascii2Fits, Fits2Ascii - converts an ASCII file into a FITS file * * SYNOPSIS * * Ascii2Fits infile.tpl > outfile.fits * Fits2Ascii infile.fits [infile.fits ...] > outfile.txt * Fits2Ascii -p [-x xtNo] infile.fits [infile.fits ...] > outfile.txt * Fits2Ascii -t [-s char] [-d] infile.fits > outfile.txt * * DESCRIPTION * * Ascii2Fits: * * The input file 'infile.tpl' is read and interpreted as a template file * following the syntax defined in Chapter 11 of the cfitsio User's Guide. The * resulting FITS file is written to standard output, which most probably will * be re-directed into some file 'outfile.fits' unless it is piped into another * command that accepts FITS files as standard input. * This includes lines of the type * # comment lines * keyword = keyvalue / commment * TFORM ... * TFORM# ... * TTYPE ... * TTYPE# ... * TUNIT ... * TUNIT# ... * EXTANME ... * xtension * naxis2 ... * \include ... * Details are given in chapter 11 of the cfitsio User's Guide. * The file name extensions .tpl and .fits are chosen just for illustration in the * Synopsis and are not mandatory. * * The syntax of the template files is extended to allow assignment to data * elements in rows/columns by lines of the format * [myextname][col mycol][rowfilter] = myvalue * or * [myextname][col mycol] = myvalue * which would remain undefined (though allocated) with the * original cfitsio template file parser. The string 'myextname', * may only contain alphanumeric characters and the underscore, as recommended by * the FITS standard, and qualifies the HDU. * White space (blanks and tabs) may be inserted before the triple of brackets, between * the brackets, and around the assignement sign. In the second bracket, right after * the opening, the 4-byte string "col " must be present, but may be also * written in uppercase or mixed upper/lowercase. * The 'mycol' syntax supports the the syntax @myfile to refer to a file, * the syntax file1[;file2...] to supply a list of column names, and the * wildcard expressions with ? and *, but not the rename and delete operations * listed in Chapter 10.9 of the cfitsio user guide. * The 'rowfilter' is a row filter expression as described in Chapter 10.10 of * the cfitsio User's Guide. If this third bracket is missing in the line, * the assignment is made to all rows, the number of which has been defined * with an naxis2 keyword on another line. * * Fits2Ascii: * * Inverts the operation: an ASCII dump of the headers and tables is produced * for all existing files of the command line. * The output file may become huge, for obvious reasons. * * The option -p can be used to create an output which is compatible with * the dfits program of ESO's eclipse library, which means only the primary * header(s) are shown by default, and the -x switch can be used in * addition with an argument of 0 to show all headers or with an argument * larger than 1 to select another HDU. * * The option -t can be used to create an output which is compatible with * the dtfits program of ESO's eclipse library, which shows the contents * of binary tables in a row by row layout. The option -s can be used to * specify a column separator which differs from the default (which is * the vertical bar), and the option -d can be used to suppress some more * verbose output of the column names. * * FILES * infile.tpl - the input ASCII file * outfile.fits - the FITS file created * $TMPDIR/Ascii2* - temporary ASCII files * * ENVIRONMENT * TMP - directory for temporary files * * EXAMPLES * The input ASCII file could contain s.th. like * xtension BINTABLE * EXTNAME ARRAY_DESCRIPTION * naxis2 = 5 * ORIGIN = 'ESO-PARANAL' / Origin of file * TELESCOP = ' ' / ESO Telescope Name * DATE = ' ' / HDU creation date (YYYY-MM-DDThh:mm:ss UTC) * HIERARCH ESO ISS DID = ' ' / Data dictionary name * HIERARCH ESO ISS ID = ' ' / ISS software version string * TTYPE# BINTABLE * TFORM# 32A * TTYPE# OPTI_NAME * # example for the extended syntax with complex value * [ARRAY_DESCRIPTION][col STOK] = 2. 3.1 * TFORM# 32A * TTYPE# STOK * TFORM# C * TTYPE# VALUE * TFORM# I * TTYPE# DESCRIPTION * TFORM# 128A * TTYPE# REFERENCE * TFORM# 128A * xtension BINTABLE * EXTNAME ARRAY_GEOMETRY * naxis2 = 3 * ORIGIN = 'ESO-PARANAL' / Origin of file * TELESCOP = ' ' / ESO Telescope Name * DATE = ' ' / HDU creation date (YYYY-MM-DDThh:mm:ss UTC) * HIERARCH ESO ISS DID = ' ' / Data dictionary name * HIERARCH ESO ISS ID = ' ' / ISS software version string * ARRNAME = ' ' / Name of the array, e.g. 'VLTI' * FRAME = ' ' / Coordinate frame, e.g. 'GEOCENTRIC' * ARRAYX = 0 / X coordinate of array center in the above frame [m] * ARRAYY = 0 / Y coordinate of array center [m] * ARRAYZ = 0 / Z coordinate of array center [m] * TTYPE# TEL_NAME * TFORM# 8A * TTYPE# STA_NAME * TFORM# 8A * TTYPE# STA_INDEX * TFORM# I * TTYPE# DIAMETER * # examples for the extended syntax; the row count starts at 1, not at 0 * # modify rows 3,4,5,6... * [ARRAY_GEOMETRY][col DIAMETER][#row >3] = 3. * # modify rows 1,4,7,.... * [ARRAY_GEOMETRY][col DIAMETER][#row %3 == 1] = 3. * # modify rows 3 * [2][col DIAMETER][#row.eq.3] = 3.E3 * # modify rows 3 to 5 in two different columns * [ARRAY_GEOMETRY][col DIAMETER;STA_INDEX][#row>2 && #row<6] = 2. * [ARRAY_GEOMETRY][col STA_NAME][#row==1] = 'G0' * # look into file colspec to obtain an expression for the column names * [ARRAY_GEOMETRY][col @colspec][#row.lt.4] = 'U1' * # if the third bracke is absent, the entire column is set to the same value * [ARRAY_GEOMETRY][col @colspec] = 'EGON' * TFORM# E * TUNIT# 'm' * TTYPE# STAXYZ * TFORM# 3D * TUNIT# 'm' * TTYPE# MNTSTA * TFORM# I * * NOTES * The \include directive does not work with file names that contain white space or * with file names that start or end with single or double quotes. * * The setting of HIERARCH header keywords is only supported with cfitsio 2.420 * or later. * * Ascii template files for MIDI can be created as explained by mioFitsCnvrt(1). * * The extended syntax recognizes only row selections which are within the index * range defined already with the naxis2 keyword for the particular table. This * means that attempts at silent expansions like * naxis2 = 30 * [....][col ...][#row>40] = ... * in the template file have no effect. * * If the output regions of the assignments overlap, the order matters: * the assignments that are made earlier in the template file are patched * by the assignments later on in the template file. * * The program first scans the generic \include, TTYPE, TFORM, TUNIT etc * keywords of the cfitsio parser in a first pass, and follows with the * assignments in a second pass. Therefore one may use assignments already * early in the template file, though the lines that construct the corresponding * tables may follow later. * * TODO * Implement assignments for vector columns. * Implement a merger/update version with two input files. * * BUGS * * MAKEFILE * # Linux example; * work = `pwd`/.. * Ascii2Fits: Ascii2Fits.C * $(CXX) -I../include -o $@ -Llib -lm -lnsl -lcfitsio $? * - ln -s Ascii2Fits Fits2Ascii * * cfitsio: * - gunzip cfitsio*.tar.gz * tar xf cfitsio*.tar * cd cfitsio ; CC=gcc ../configure --prefix=$(work) ; make ; make install * * SEE ALSO * fv(1) * http://heasarc.gsfc.nasa.gov/docs/software/fitsio/fitsio.html (cfitsio User Guide) * ********************************************************************************/ #include #include #include #include #include #include #include #include #include // define MAX_CANON in HP-UX (not on Sun-Solaris as it seems) #include #include #include #ifndef MAX_CANON #define MAX_CANON 512 #endif #define FITS2ASC_COMPRESS using namespace std ; void usage() { cerr << "usage: Ascii2Fits infile.tpl > outfile.fits " << endl ; cerr << "usage: Fits2Ascii infile.fits [infile2.fits ...] > outfile.txt " << endl ; cerr << "usage: Fits2Ascii -p [-x hdrnum] infile.fits [infile2.fits ...] > outfile.txt " << endl ; } class CFITSIO { public: // creator with template file name CFITSIO(char *tplfile) { status =0 ; // a valid assignment is a triple square bracket expression status = regcomp(&pregass3, "^[[:space:]]*\\[\\([[:alnum:]_]\\{1,\\}\\)\\][[:space:]]*\\[col[[:space:]]\\{1,\\}\\([^]]\\{1,\\}\\)\\][[:space:]]*\\[\\(.\\{1,\\}\\)\\][[:space:]]*=[[:space:]]*[\"']\\{0,1\\}\\([[:alnum:]. _]\\{1,\\}\\)[\"']\\{0,1\\}", REG_ICASE|REG_NEWLINE) ; if( status ) { char errbuf[132] ; regerror(status,&pregass3,errbuf,132) ; cerr << __FILE__ << " " << __LINE__ << " internal error " << errbuf << endl ; } // or a double square bracket expression status = regcomp(&pregass2, "^[[:space:]]*\\[\\([[:alnum:]_]\\{1,\\}\\)\\][[:space:]]*\\[col[[:space:]]\\{1,\\}\\([^]]\\{1,\\}\\)\\][[:space:]]*=[[:space:]]*[\"']\\{0,1\\}\\([[:alnum:]. _]\\{1,\\}\\)[\"']\\{0,1\\}", REG_ICASE|REG_NEWLINE) ; if( status ) { char errbuf[132] ; regerror(status,&pregass2,errbuf,132) ; cerr << __FILE__ << " " << __LINE__ << " internal error " << errbuf << endl ; } fits_create_template(& fptr,"mem://",tplfile, &status); report_error() ; } // creator with an existing FITS file; doesn't initialize pregass[23] CFITSIO(fitsfile *fpt) : fptr(fpt), status(0) { } // dtor; If we don't close the file, we may run into problems since // cfitsio allows only NIOBUF=40 files to be opened at the same time. ~CFITSIO() { // should this rather be fits_delete_file()? fits_close_file(fptr,&status) ; } void tostdout(const char *fnam="-") { fitsfile * outfptr ; fits_create_file(& outfptr,fnam,&status); report_error() ; int hdunum ; fits_get_num_hdus(fptr,&hdunum,&status) ; report_error() ; // move through all HDU's, primary HDU = 1 for( int hdu=1 ; hdu<=hdunum; hdu++) { fits_movabs_hdu(fptr,hdu,NULL,&status) ; report_error() ; fits_copy_hdu(fptr,outfptr,0,&status) ; report_error() ; } fits_close_file(outfptr,&status); report_error() ; } /* * @param dfits eclipse dfits compatibility flag * @param dfitsx the parameter of the x option of dfits * @param dtfits eclipse dtfits compatibility flag * @param dtfitsBare true if the d option of the dtfits compatible mode was set * @param dtfitsSep the character of the s option of the dtfits compatible mode */ void asci(const bool dfits, const int dfitsx, const bool dtfits, const bool dtfitsBare, const char dtfitsSep) { char fname[MAX_CANON+1] ; if ( dfits || dtfits) { /* in eclipse compatibility mode, each new file is announced verbously * by name. */ fits_file_name(fptr,fname,&status) ; report_error() ; if ( dfits) cout << "====> file " << fname << " (main) <====\n" ; } int hdunum ; fits_get_num_hdus(fptr,&hdunum,&status) ; report_error() ; for( int hdu=1 ; hdu<=hdunum; hdu++) { /* In eclipse compatibility mode, only the HDU number dfitsx is listed, * with the exception of dfitsx being zero which selects all HDU's. */ if ( dfits && ( dfitsx && hdu-1 != dfitsx ) ) continue ; if ( dfits && hdu>1 ) cout << "===> xtension " << hdu-1 << endl ; fits_movabs_hdu(fptr,hdu,NULL,&status) ; report_error() ; int hdutype ; char extname[FLEN_VALUE] ; fits_get_hdu_type(fptr,&hdutype,&status) ; report_error() ; if (hdutype != IMAGE_HDU) { if (fits_read_key_str(fptr, "EXTNAME", extname, 0, &status) > 0) /* name */ { status = 0; /* look for HDUNAME, since EXTNAME didn't exist */ fits_read_key_str(fptr, "HDUNAME", extname, 0, &status); } } if ( !dtfits ) { int keysexist ; fits_get_hdrspace(fptr,&keysexist,NULL,&status) ; report_error() ; for(int keynum=1; keynum < keysexist && status==0; keynum++) { char card[FLEN_CARD] ; fits_read_record(fptr,keynum,card,&status) ; report_error() ; cout << card << endl ; // includes the special keys TTYPE, TUNIT etc } } /* no listing of the tables in compatibility mode */ if ( dfits ) continue ; if( hdutype != IMAGE_HDU) { int ncols ; fits_get_num_cols(fptr,&ncols,&status) ; report_error() ; if ( dtfits && !dtfitsBare) { if ( hdu ==2) { cout << "#\n" ; cout << "# file " << fname << endl ; cout << "# extensions " << hdunum-1 << endl ; } cout << "# --------------------------------------------\n" ; cout << "# XTENSION " << hdu-1 << endl ; cout << "# Number of columns " << ncols << endl ; cout << "#\n" ; } long nrows=0 ; fits_get_num_rows(fptr,&nrows,&status) ; report_error() ; /* dtfits compatible mode prints row by row, the standard mode column by column */ if( dtfits) { if ( !dtfitsBare) { for(int colnum= 1 ; colnum <= ncols; colnum++) { char colname[FLEN_VALUE] ; char tmplt[9] ; sprintf(tmplt,"%d",colnum) ; fits_get_colname(fptr,CASEINSEN,tmplt,colname,&colnum,&status) ; report_error() ; int typecode ; fits_get_coltype(fptr,colnum,&typecode,NULL,NULL,&status) ; report_error() ; int displw ; fits_get_col_display_width(fptr,colnum,&displw,&status) ; report_error() ; char * o= new char[displw+1] ; sprintf(tmplt,"%%%d.%ds",displw,displw) ; snprintf(o,displw+1,tmplt,colname) ; cout << o ; delete [] o ; if ( colnum < ncols) cout << dtfitsSep ; } cout << endl ; } for(long n = 1L ; n <= nrows ; n++) { for(int colnum= 1 ; colnum <= ncols; colnum++) { char colname[FLEN_VALUE] ; char tmplt[4] ; sprintf(tmplt,"%d",colnum) ; fits_get_colname(fptr,CASEINSEN,tmplt,colname,&colnum,&status) ; report_error() ; int typecode ; long repeat ; fits_get_coltype(fptr,colnum,&typecode,&repeat,NULL,&status) ; report_error() ; #if 0 cout << __LINE__ << " " << colnum << " " << typecode << " " << repeat << " " << colname << endl ; #endif int displw ; fits_get_col_display_width(fptr,colnum,&displw,&status) ; report_error() ; char * o= new char[displw+1] ; char * nulval= new char[displw+1] ; for(int i=0 ; i < displw ; i++) nulval[i]=' ' ; nulval[displw]='\0' ; if(typecode == TSTRING) nulval[0]=nulval[displw-1]='\'' ; int anynul ; for(LONGLONG e=1LL; e <= repeat; e++) { fits_read_col(fptr,TSTRING,colnum,(long)n, e,1L,&nulval,&o, &anynul,&status) ; /* there are instruments, like MIDI/VLTI, who have wrong * A specifications, which means 16A appears where * A16 ought to be used. To catch these errors gently, * we just suppress the corresponding output. */ #if 0 report_error() ; #else if( status == 0 ) { if( anynul) { ; // cout << nulval << endl ; } else cout << o ; if ( e < repeat) cout << "," ; } #endif status=0 ; } delete [] nulval ; delete [] o ; if ( colnum < ncols) cout << dtfitsSep << " " ; } cout << endl ; } } else for(int colnum= 1 ; colnum <= ncols; colnum++) { char colname[FLEN_VALUE] ; char tmplt[4] ; sprintf(tmplt,"%d",colnum) ; fits_get_colname(fptr,CASEINSEN,tmplt,colname,&colnum,&status) ; report_error() ; int typecode ; fits_get_coltype(fptr,colnum,&typecode,NULL,NULL,&status) ; report_error() ; int displw ; fits_get_col_display_width(fptr,colnum,&displw,&status) ; report_error() ; char * o= new char[displw+1] ; char * nulval= new char[displw+1] ; for(int i=0 ; i < displw ; i++) nulval[i]=' ' ; nulval[displw]='\0' ; if(typecode == TSTRING) nulval[0]=nulval[displw-1]='\'' ; int anynul ; #ifdef FITS2ASC_COMPRESS char * oold= new char[displw+1] ; oold[0] = '\0' ; long nold= 1L ; int anynulold= 1 ; for(long n = 1L ; n <= nrows ; n++) { fits_read_col(fptr,TSTRING,colnum,(long)n, 1L,1L,&nulval,&o,&anynul,&status) ; report_error() ; if( anynul) { if(! anynulold) { cout << "[" << extname << "][col " << colname << "][#row>=" << nold << " && #row< " << n <<"] = " << oold << endl ; nold=n ; } oold[0] = '\0' ; } else { if( strcmp(oold,o) && n > 1L ) { cout << "[" << extname << "][col " << colname << "][#row>=" << nold << " && #row< " << n <<"] = " << oold << endl ; nold=n ; } strcpy(oold,o) ; } anynulold = anynul ; } if (!anynul) cout << "[" << extname << "][col " << colname << "][#row>=" << nold << "] = " << oold << endl ; delete [] oold ; #else for(long n = 1L ; n <= nrows ; n++) { fits_read_col(fptr,TSTRING,colnum,(long)n, 1L,1L,&nulval,&o,&anynul,&status) ; report_error() ; if( anynul) { ; // cout << nulval << endl ; } else { cout << "[" << extname << "][col " << colname << "][#row.eq." << n << "] = " << o << endl ; } } #endif delete [] nulval ; delete [] o ; } } cout << endl ; } } // taken from ffrprt() in cfileio.o void report_error() { char status_str[FLEN_STATUS], errmsg[FLEN_ERRMSG]; if (status) { fits_get_errstatus(status, status_str); /* get the error description */ cerr << "\ncfitsio FITSIO status = " << status << ": " << status_str << endl ; while ( fits_read_errmsg(errmsg) ) /* get error stack messages */ cerr << errmsg << endl ; fits_clear_errmsg() ; status =0 ; } } void assign(char *fname) { FILE *sets = fopen(fname,"r") ; char inpline[MAX_CANON] ; while( fgets(inpline,MAX_CANON,sets) ) { int movetotype, extvers ,extnum=0; char extname[FLEN_VALUE]; char extspec[FLEN_FILENAME], rowfilter[FLEN_FILENAME]; char clause[FLEN_FILENAME], colspec[FLEN_FILENAME]; char imagecolname[FLEN_VALUE], rowexpress[FLEN_FILENAME], value[FLEN_VALUE] ; regmatch_t pmatchass[5] ; // space for the entire [0], the EXTNAME [1], the column [2], // the row [3], and the r.h.s [4] if( regexec(&pregass3,inpline,5,pmatchass,0) == 0 ) { strncpy(extspec,inpline+pmatchass[1].rm_so,pmatchass[1].rm_eo-pmatchass[1].rm_so) ; extspec[pmatchass[1].rm_eo-pmatchass[1].rm_so]='\0' ; strncpy(colspec,inpline+pmatchass[2].rm_so,pmatchass[2].rm_eo-pmatchass[2].rm_so) ; colspec[pmatchass[2].rm_eo-pmatchass[2].rm_so]='\0' ; strncpy(rowfilter,inpline+pmatchass[3].rm_so,pmatchass[3].rm_eo-pmatchass[3].rm_so) ; rowfilter[pmatchass[3].rm_eo-pmatchass[3].rm_so]='\0' ; strncpy(value,inpline+pmatchass[4].rm_so,pmatchass[4].rm_eo-pmatchass[4].rm_so) ; value[pmatchass[4].rm_eo-pmatchass[4].rm_so]='\0' ; // cerr << "|"<< extspec <<"|" << colspec <<"|" << rowfilter <<"|" << value << endl ; } else if( regexec(&pregass2,inpline,4,pmatchass,0) == 0 ) { strncpy(extspec,inpline+pmatchass[1].rm_so,pmatchass[1].rm_eo-pmatchass[1].rm_so) ; extspec[pmatchass[1].rm_eo-pmatchass[1].rm_so]='\0' ; strncpy(colspec,inpline+pmatchass[2].rm_so,pmatchass[2].rm_eo-pmatchass[2].rm_so) ; colspec[pmatchass[2].rm_eo-pmatchass[2].rm_so]='\0' ; strncpy(value,inpline+pmatchass[3].rm_so,pmatchass[3].rm_eo-pmatchass[3].rm_so) ; value[pmatchass[3].rm_eo-pmatchass[3].rm_so]='\0' ; strcpy(rowfilter,"#row >=1") ; } int status =0 ; // parse the HDU specification ffexts(extspec, &extnum, extname, &extvers, &movetotype, imagecolname, rowexpress,&status); report_error() ; int hdunum ; fits_get_num_hdus(fptr,&hdunum,&status) ; report_error() ; if ( strlen(extname) ) { fits_movnam_hdu(fptr,movetotype,extname,extvers,&status) ; } else { if ( extnum > hdunum) { cerr << "Extension " << extnum << " does not exist; skipping " << inpline ; continue ; } fits_movabs_hdu(fptr,extnum,&movetotype,&status) ; report_error() ; } if( status) { report_error() ; continue ; } long firstrow=1, nrows ; fits_get_num_rows(fptr,&nrows,&status) ; if ( nrows == 0 ) { cerr << "No rows in HDU " << nrows << "; skipping " << inpline ; continue ; } // similar to ffedit_columns() in cfileio.c char *cptr =colspec ; char * file_exp=NULL ; if ( *cptr == '@') { if ( ffimport_file(cptr+1, &file_exp,&status) ) { report_error() ; break ; } cptr = file_exp ; while( *cptr == ' ') cptr ++ ; } int slen ; while( ( slen=fits_get_token(&cptr, ";", clause, NULL)) > 0 ) { if( *cptr==';') cptr++ ; clause[slen] = '\0' ; char colname[FLEN_VALUE] ; char *cptr2 = clause ; slen = fits_get_token(&cptr2, "( =", colname, NULL) ; if ( slen == 0 ) { cerr << "error: column or keyword name is blank:" << clause << endl ; break ; } for(;;) // loop over columns { int colnum ; int gcnostat=0 ; fits_get_colnum(fptr,CASEINSEN,colname,&colnum,&gcnostat) ; if( gcnostat == 0 || gcnostat == COL_NOT_UNIQUE ) { long n_good_rows; char *row_status = new char[nrows]; fits_find_rows(fptr,rowfilter,1L,nrows,&n_good_rows,row_status,&status) ; report_error() ; if( n_good_rows && status==0) { int typecode ; long repeat, width ; fits_get_coltype(fptr,colnum,&typecode,&repeat,&width,&status) ; for(int n=1; n <= nrows ; n++) if ( row_status[n-1] ) // note that the array is filled 0-based... setvalue(colnum,n,typecode,value) ; } delete [] row_status ; } else report_error() ; if ( gcnostat != COL_NOT_UNIQUE) break ; } } free(file_exp) ; } fclose(sets) ; } protected: private: regex_t pregass3; // assignment includes a row qualifier regex_t pregass2; // assignment without row filter fitsfile *fptr ; int status ; void setvalue(int colnum,int rownum,int typecode, char *value) { char c ; unsigned char uc ; short s ; ushort us ; long l ; long long ll ; ulong ul ; int i ; uint ui ; float f ; double d ; #if 0 std::complex cf ; std::complex cd ; #else struct { float re; float im; } cf ; struct { double re; double im; } cd ; #endif istringstream valStream(value) ; // assign value to column 'colnum' and row 'n' #ifdef DEBUG cerr << __LINE__ << "colnum " << colnum << " rownum " << rownum << " typecoe " << typecode << " " << value << endl ; #endif switch(typecode) { case TBYTE : valStream >> uc ; fits_write_col(fptr,typecode,colnum,(long)rownum,1L,1L,&uc,&status) ; break ; case TLOGICAL : case TSBYTE : valStream >> c ; fits_write_col(fptr,typecode,colnum,(long)rownum,1L,1L,&c,&status) ; break ; case TSTRING : fits_write_col(fptr,typecode,colnum,(long)rownum,1L,1L,&value,&status) ; break ; case TUSHORT : valStream >> us ; fits_write_col(fptr,typecode,colnum,(long)rownum,1L,1L,&us,&status) ; break ; case TSHORT : valStream >> s ; fits_write_col(fptr,typecode,colnum,(long)rownum,1L,1L,&s,&status) ; break ; case TUINT : valStream >> ui ; fits_write_col(fptr,typecode,colnum,(long)rownum,1L,1L,&ui,&status) ; break ; case TINT : valStream >> i ; fits_write_col(fptr,typecode,colnum,(long)rownum,1L,1L,&i,&status) ; break ; case TULONG : valStream >> ul ; fits_write_col(fptr,typecode,colnum,(long)rownum,1L,1L,&ul,&status) ; break ; case TLONG : valStream >> l ; fits_write_col(fptr,typecode,colnum,(long)rownum,1L,1L,&l,&status) ; break ; case TFLOAT : valStream >> f ; fits_write_col(fptr,typecode,colnum,(long)rownum,1L,1L,&f,&status) ; break ; case TLONGLONG : valStream >> ll ; fits_write_col(fptr,typecode,colnum,(long)rownum,1L,1L,&ll,&status) ; break ; case TDOUBLE : valStream >> d ; fits_write_col(fptr,typecode,colnum,(long)rownum,1L,1L,&d,&status) ; break ; case TCOMPLEX : #if 0 valStream >> cf ; #else valStream >> cf.re >> cf.im ; #endif fits_write_col(fptr,typecode,colnum,(long)rownum,1L,1L,&cf,&status) ; break ; case TDBLCOMPLEX : #if 0 valStream >> cd ; #else #endif fits_write_col(fptr,typecode,colnum,(long)rownum,1L,1L,&cd,&status) ; break ; } } } ; // Split the infile such that the lines understood by the standard cftsio templae // parser go into 'tplfile', and those with the three brackets into the 'setfile' static void splitfile(char *infile, FILE * tpl, FILE * sets,regex_t * pregset, regex_t * preginc) { FILE *in = fopen(infile,"r") ; if ( in ) { char inpline[MAX_CANON] ; while( fgets(inpline,MAX_CANON,in) ) { regmatch_t pmatchinc[2] ; if( regexec(pregset,inpline,0,0,0) == 0 ) { //fputs(inpline,sets) ; fprintf(sets,"%s",inpline) ; } else if ( regexec(preginc,inpline,2,pmatchinc,0) == 0 ) // an include line that includes another file { char newinfile[PATH_MAX+1] ; strncpy(newinfile,inpline+pmatchinc[1].rm_so,pmatchinc[1].rm_eo-pmatchinc[1].rm_so) ; newinfile[pmatchinc[1].rm_eo-pmatchinc[1].rm_so]='\0' ; splitfile(newinfile,tpl,sets,pregset,preginc) ; // recursive call } else fputs(inpline,tpl) ; } fclose(in) ; } else { perror(0) ; cerr << "Cannot open |" << infile << "| ...skipped\n" ; } } static void splitfile(const char *infile, char *& tplfile, char *& setfile) { // a regexp compliation of the [HDU][col mycol][row] syntax regex_t pregset; regex_t preginc; int status ; status = regcomp(&pregset, "^[[:space:]]*\\[[a-zA-Z0-9_]\\{1,\\}\\][[:space:]]*\\[col .\\{1,\\}\\].*", REG_ICASE) ; if( status ) { char errbuf[132] ; regerror(status,&pregset,errbuf,132) ; cerr << __FILE__ << " " << __LINE__ << " internal error " << errbuf << endl ; } status = regcomp(&preginc, "[[:space:]]*\\\\include[[:space:]]*[\"']*\\([^[:space:]\"']\\{1,\\}\\)[\"']*", REG_ICASE) ; if( status ) { char errbuf[132] ; regerror(status,&preginc,errbuf,132) ; cerr << __FILE__ << " " << __LINE__ << " internal error " << errbuf << endl ; } tplfile = new char[17] ; setfile = new char[17] ; strcpy(tplfile,"Ascii2FitsXXXXXX") ; strcpy(setfile,"Ascii2FitsXXXXXX") ; mkstemp(tplfile) ; mkstemp(setfile) ; FILE *tpl = fopen(tplfile,"w") ; FILE *sets = fopen(setfile,"w") ; FILE *in = fopen(infile,"r") ; char inpline[MAX_CANON] ; while( fgets(inpline,MAX_CANON,in) ) { regmatch_t pmatchinc[2] ; if( regexec(&pregset,inpline,0,0,0) == 0 ) // a line that sets a value in the table { //fputs(inpline,sets) ; fprintf(sets,"%s",inpline) ; } else if ( regexec(&preginc,inpline,2,pmatchinc,0) == 0 ) // an include line that includes another file { char newinfile[PATH_MAX+1] ; strncpy(newinfile,inpline+pmatchinc[1].rm_so,pmatchinc[1].rm_eo-pmatchinc[1].rm_so) ; newinfile[pmatchinc[1].rm_eo-pmatchinc[1].rm_so]='\0' ; splitfile(newinfile,tpl,sets,&pregset,&preginc) ; // recursive call } else fputs(inpline,tpl) ; } fclose(in) ; fclose(sets) ; fclose(tpl) ; #ifdef DEBUG cerr << __LINE__ << " " << tplfile << " " << setfile << endl ; #endif regfree(&pregset) ; } /** */ int main(int argc, char *argv[]) { /* behave like dfits of the eclipse library ? */ bool dfits = false ; /* if dfits compatible, only the PHDU, number 1, shown by default */ int dfitsx = 1 ; /* behave like dtfits of the eclipse library ? */ bool dtfits = false ; /* if dtfits compatible, include headers by default */ bool dtfitsBare = false ; /* if dtfits compatible, column separator is the vertical bar by default */ char dtfitsSep = '|' ; /* the getopt(3) character */ char oc ; while ( ( oc=getopt(argc,argv,"px:ts:d")) != EOF) { switch(oc) { case 'p': dfits = true; break ; case 't': dtfits = true; break ; case 'd': dtfitsBare = true; break ; case 'x': dfitsx = atoi(optarg) ; break ; case 's': dtfitsSep = optarg[0] ; break ; case '?': cerr << "Invalid command line option " << optopt << " ignored" << endl ; usage() ; } } if( argv[0][0] == 'A') // invoked as "Ascii2Fits" { char * tplfname, * sfname ; // split the input file into two files, one 'tplfnamae' with the usual template file // definitions of header keywords and table formats, the other one with the assignements to // table elements. splitfile(argv[1],tplfname,sfname) ; // create the FITS file with the standard (nul values) CFITSIO tplfile(tplfname) ; // remove the temporary files that have been created in splitfile() and remove // the temporary storage for their name character strings that has been allocated there. unlink(tplfname) ; free(tplfname) ; // Use the file with the assignments... tplfile.assign(sfname) ; tplfile.tostdout() ; // remove the temporary files that have been created in splitfile() and remove // the temporary storage for their name character strings that has been allocated there. unlink(sfname) ; free(sfname) ; } else { /* Invoked as Fits2Ascii . Loop over input files. */ for(int i=optind; i < argc ; i++) { fitsfile *fpt ; int status =0 ; fits_open_file(&fpt,argv[i],READONLY,&status) ; if( status) { cerr <<"Cannot open " << argv[i] << endl ; } else { CFITSIO ffile(fpt) ; ffile.asci(dfits,dfitsx,dtfits,dtfitsBare,dtfitsSep) ; /* implicit fits_close_file as ffile goes out of scope * here.. */ } /* in dtfits compatibility mode, handle only one file */ if( dtfits) break ; } } return 0 ; }