fitsverify-4.22/0000755000220700000360000000000014453545447012446 5ustar birbylheafitsverify-4.22/fvrf_head.c0000644000220700000360000030332714427522442014535 0ustar birbylhea#include "fverify.h" /* the following are only needed if one calls wcslib #include #include #include #include */ static char **cards; /* array to store the keywords */ static int ncards; /* total number of the keywords */ static char **tmpkwds; /* String array holding the keyword name. It is sorted in alphabetical ascending order and does not include the keywords before the first non-reserved keyword and END keyword. */ static char **ttype; static char **tform; static char **tunit; static char temp[80]; static char *ptemp; /* it always pointed to the address of temp */ static char snull[] = ""; static int curhdu; /* current HDU index */ static int curtype; /* current HDU type */ /****************************************************************************** * Function * verify_fits * * DESCRIPTION: * Verify individual fits file. * *******************************************************************************/ /* routine to verify individual fitsfile */ int verify_fits(char *infile, FILE *out) { char rootnam[FLEN_FILENAME] = ""; /* Input Fits file root name */ fitsfile *infits; /* input fits file pointer */ FitsHdu fitshdu; /* hdu information */ int hdutype; int status = 0; int i; int len; char *p; char *pfile; char xtension[80]; /* take out the leading and trailing space and skip the empty line*/ p = infile; while(isspace((int)*p) )p++; len = strlen(p); pfile = p; p += (len -1); for (i = len - 1; i >= 0 && isspace((int)*p); i--) {*p = '\0'; p--;} if(!strlen(pfile)) return status; #ifndef WEBTOOL wrtout(out," "); sprintf(comm,"File: %s",pfile); wrtout(out,comm); #endif totalhdu = 0; #ifndef STANDALONE /* discard the extension, rowfilter... */ if(ffrtnm(pfile, rootnam, &status)) { wrtserr(out,"",&status,2); leave_early(out); status = 1; return status; } if(fits_open_file(&infits, rootnam, READONLY, &status)) { wrtserr(out,"",&status,2); leave_early(out); status = 1; return status; } #else if(fits_open_diskfile(&infits, pfile, READONLY, &status)) { wrtserr(out,"",&status,2); leave_early(out); status = 1; return status; } #endif /* get the total hdus */ if(fits_get_num_hdus(infits, &totalhdu, &status)) { wrtserr(out,"",&status,2); leave_early(out); status = 1; return status; } /* initialize the report */ init_report(out,rootnam); /*------------------ Hdu Loop --------------------------------*/ for (i = 1; i <= totalhdu; i++) { /* move to the right hdu and do the CFITSIO test */ hdutype = -1; if(fits_movabs_hdu(infits,i, &hdutype, &status) ) { print_title(out,i, hdutype); wrtferr(out,"",&status,2); set_hdubasic(i,hdutype); break; } if (i != 1 && hdutype == IMAGE_HDU) { /* test if this is a tile compressed image in a binary table */ fits_read_key(infits, TSTRING, "XTENSION", xtension, NULL, &status); if (!strcmp(xtension, "BINTABLE") ) print_title(out,i, BINARY_TBL); else print_title(out,i, hdutype); } else print_title(out,i, hdutype); init_hdu(infits,out,i,hdutype, &fitshdu); /* initialize fitshdu */ test_hdu(infits,out,&fitshdu); /* test hdu header */ if(testdata) test_data(infits,out,&fitshdu); close_err(out); /* end of error report */ if(prhead) print_header(out); if(prstat) print_summary(infits,out,&fitshdu); close_hdu(&fitshdu); /* clear the fitshdu */ } /* test the end of file */ test_end(infits,out); /*------------------ Closing --------------------------------*/ /* closing the report*/ close_report(out); /* close the input fitsfile */ fits_close_file(infits, &status); return status; } void leave_early (FILE* out) { sprintf(comm,"**** Abort Verification: Fatal Error. ****"); wrtout(out,comm); /* write the total number of errors and warnings to parfile*/ update_parfile(1,0); } void close_err(FILE* out) { int merr, mwrn; num_err_wrn(&merr, &mwrn); if(merr || mwrn ) wrtout(out," "); return; } /************************************************************* * * init_hdu * * Initialize the FitsHdu, HduName and ttype, tform, tunit if * the hdu is a table. * * *************************************************************/ void init_hdu(fitsfile *infits, /* input fits file */ FILE* out, /* output ascii file */ int hdunum, /* hdu index */ int hdutype, /* hdutype */ FitsHdu *hduptr ) { int morekeys; int i,j,k,m,n; int status = 0; FitsKey ** kwds; char *p = 0; int numusrkey; LONGLONG lv,lu=0L; FitsKey tmpkey; hduptr->hdunum = hdunum; hduptr->hdutype = hdutype; /* curhdu and curtype are shared with print_title */ curhdu = hdunum; /* set the current hdu number */ curtype = hdutype; /* set the current hdu number */ /* check the null character in the header.(only the first one will be recorded */ lv = 0; lv = fits_null_check(infits, &status); if (lv > 0) { m = (lv - 1)/80 + 1; n = lv - (m - 1) * 80; sprintf(errmes, "Byte #%d in Card#%d is a null(\\0).",n,m); wrterr(out,errmes,1); status = 0; } else { if (status) { wrtserr(out,"",&status,1); status = 0; } } /* get the total number of keywords */ hduptr->nkeys = 0; morekeys = 0; if(fits_get_hdrspace(infits, &(hduptr->nkeys), &morekeys, &status)) wrtferr(out,"",&status,1); (hduptr->nkeys)++; /* include END keyword */ /* read all the keywords */ ncards = hduptr->nkeys; cards = (char **)malloc(sizeof(char *) * ncards ); for (i=0; i < ncards; i++) { cards[i] = (char *)malloc(sizeof(char )* FLEN_CARD ); } for (i=1; i <= ncards; i++) { if(fits_read_record(infits, i, cards[i-1], &status)) wrtferr(out,"",&status,1); } /* if there were blank cards prior to the END card, then make a fake END card, because CFITSIO blocks us from reading the real END card */ if (strncmp(cards[ncards-1], "END ", 8)) { strcpy(cards[ncards-1],"END "); } /* Parse the XTENSION/SIMPLEX keyword */ fits_parse_card(out, 1, cards[0], tmpkey.kname, &(tmpkey.ktype), tmpkey.kvalue,comm); if( *(tmpkey.kvalue) == ' ') { sprintf(errmes, "Keyword #1, %s \"%s\" should not have leading space.", tmpkey.kname,tmpkey.kvalue); wrterr(out,errmes,1); } if(hdunum == 1) { /* SIMPLE should be logical T */ if(strcmp(tmpkey.kname,"SIMPLE")) wrterr(out, "The 1st keyword of a primary array is not SIMPLE.",1); if( !check_log(&tmpkey,out)|| strcmp(tmpkey.kvalue,"T")) wrtwrn(out, "SIMPLE != T indicates file may not conform to the FITS Standard.",0); check_fixed_log(cards[0], out); } else { if(strcmp(tmpkey.kname,"XTENSION")) wrterr(out, "The 1st keyword of a extension is not XTENSION.",1); check_str(&tmpkey,out); check_fixed_str(cards[0], out); /* Get the original string */ p = cards[0]; p +=10; while (*p == ' ') p++; p++; /* skip the quote */ if( strncmp(p,"TABLE ",8) && strncmp(p,"BINTABLE",8) && strncmp(p,"A3DTABLE",8) && strncmp(p,"IUEIMAGE",8) && strncmp(p,"FOREIGN ",8) && strncmp(p,"DUMP ",8) && strncmp(p,"IMAGE ",8) ) { sprintf(errmes, "Unregistered XTENSION value \"%8.8s\".",p); wrterr(out,errmes,1); } else { if (p[8] != '\'') { sprintf(errmes, "Extra \'%c\' follows the XTENSION value \"%8.8s\".",p[8],p); wrterr(out,errmes,1); } } /* test if this is a tile compressed image, stored in a binary table */ /* If so then test the extension as binary table rather than an image */ if (!strncmp(p,"BINTABLE",8) && hduptr->hdutype == IMAGE_HDU) { hduptr->hdutype = BINARY_TBL; hduptr->istilecompressed = 1; } else { hduptr->istilecompressed = 0; } } /* read the BITPIX keywords */ if(fits_read_key(infits, TINT, "BITPIX", &(hduptr->bitpix), NULL, &status)) wrtferr(out,"",&status,2); check_fixed_int(cards[1], out); /* Read and Parse the NAXIS */ hduptr->naxis = 0; if(fits_read_key(infits, TINT, "NAXIS", &(hduptr->naxis), NULL, &status)) wrtferr(out,"",&status,2); check_fixed_int(cards[2], out); if(hduptr->naxis!=0) hduptr->naxes = (LONGLONG *)malloc(hduptr->naxis*sizeof(LONGLONG)); for (i = 0; i < hduptr->naxis; i++) hduptr->naxes[i] = -1; /* Parse the keywords NAXISn */ for (j = 3; j < 3 + hduptr->naxis; j++){ fits_parse_card(out, 1+j,cards[j], tmpkey.kname, &(tmpkey.ktype), tmpkey.kvalue,comm); p = tmpkey.kname+5; if(!isdigit((int) *p))continue; #if (USE_LL_SUFFIX == 1) if(check_int(&tmpkey,out)) lu = strtoll(tmpkey.kvalue,NULL,10); #else if(check_int(&tmpkey,out)) lu = strtol(tmpkey.kvalue,NULL,10); #endif lv = strtol(p,NULL,10); if(lv > hduptr->naxis && lv <= 0) { sprintf(errmes, "Keyword #%d, %s is not allowed (with n > NAXIS = %d).", tmpkey.kindex,tmpkey.kname,hduptr->naxis); wrterr(out,errmes,1); } else { if(hduptr->naxes[lv-1] == -1) { hduptr->naxes[lv-1] = lu; } else { sprintf(errmes, "Keyword #%d, %s is duplicated.", tmpkey.kindex,tmpkey.kname); wrterr(out,errmes,1); } } check_fixed_int(cards[j], out); } /* check all the NAXISn are there */ for (j = 0; j < hduptr->naxis; j++) { if(hduptr->naxes[j] == -1) { sprintf(errmes, "Keyword NAXIS%d is not present or is out of order.", j+1); wrterr(out,errmes,2); } } /* get the column number */ hduptr->ncols = 1; if(hduptr->hdutype == ASCII_TBL || hduptr->hdutype == BINARY_TBL) { /* get the total number of columns */ if(fits_get_num_cols(infits, &(hduptr->ncols),&status)) wrtferr(out,"",&status,2); } /* parse the keywords after NAXISn and prepare the array for sorting. We only check the keywords after the NAXISn */ n = hduptr->nkeys - 4 - hduptr->naxis ; /* excluding the SIMPLE/XTENSION, BITPIX, NAXIS, NAXISn and END */ hduptr->kwds = (FitsKey **)malloc(sizeof(FitsKey *)*n); for (i= 0; i < n; i++) hduptr->kwds[i] = (FitsKey *)malloc(sizeof(FitsKey)); kwds = hduptr->kwds; k = 3 + hduptr->naxis; /* index of first keyword following NAXISn. */ m = hduptr->nkeys - 1; /* last key */ i = 0; hduptr->use_longstr = 0; for (j = k ; j < m; j++) { kwds[i]->kindex = j+1; /* record number */ kwds[i]->goodkey=1; if(fits_parse_card(out,1+j,cards[j], kwds[i]->kname, &(kwds[i]->ktype), kwds[i]->kvalue,comm)) kwds[i]->goodkey=0; if (kwds[i]->ktype == UNKNOWN && *(kwds[i]->kvalue) == 0) { sprintf(errmes, "Keyword #%d, %s has a null value.", j+1,kwds[i]->kname); wrtwrn(out,errmes,0); } /* only count the non-commentary keywords */ if (!strcmp(kwds[i]->kname,"CONTINUE")) { hduptr->use_longstr = 1; } if( strcmp(kwds[i]->kname,"COMMENT") && strcmp(kwds[i]->kname,"HISTORY") && (strcmp(kwds[i]->kname,"HIERARCH") || testhierarch) && strcmp(kwds[i]->kname,"CONTINUE") && strcmp(kwds[i]->kname,"") ) i++; } numusrkey = i; hduptr->tkeys = i; /* parse the END key */ fits_parse_card(out,m+1,cards[hduptr->nkeys-1], tmpkey.kname,&(tmpkey.ktype),tmpkey.kvalue,comm) ; /* sort the keyword in the ascending order of kname field*/ qsort(kwds, numusrkey, sizeof(FitsKey *), compkey); /* store addresses of sorted keyword names in a working array */ tmpkwds = (char **)malloc(sizeof(char*) * numusrkey); for (i=0; i < numusrkey; i++) tmpkwds[i] = kwds[i]->kname; /* Initialize the PCOUNT, GCOUNT and heap values */ hduptr->pcount = -99; hduptr->gcount = -99; hduptr->heap = -99; /* set the random group flag (will be determined later) */ hduptr->isgroup = 0; /* allocate memory for datamax and datamin (will determined later)*/ if(hduptr->ncols > 0) { hduptr->datamax = (char **)calloc(hduptr->ncols, sizeof(char *)); hduptr->datamin = (char **)calloc(hduptr->ncols, sizeof(char *)); hduptr->tnull = (char **)calloc(hduptr->ncols, sizeof(char *)); for (i = 0; i < hduptr->ncols; i++) { hduptr->datamax[i] = (char *)calloc(13,sizeof(char)); hduptr->datamin[i] = (char *)calloc(13,sizeof(char)); hduptr->tnull[i] = (char *)calloc(12,sizeof(char)); } } /* initialize the extension name and version */ strcpy(hduptr->extname,""); hduptr->extver = -999; return; } /************************************************************* * * test_hdu * * Test the HDU header * This includes many tests of WCS keywords * *************************************************************/ void test_hdu(fitsfile *infits, /* input fits file */ FILE *out, /* output ascii file */ FitsHdu *hduptr ) { int status = 0; FitsKey **kwds; int numusrkey; int hdunum; char *p, *p2, *pname = 0; int i,j,k,m,n, wcsaxes = 0; int taxes; int wcsaxesExists = 0, wcsaxesvalue = 0, wcsaxespos = 0, wcskeypos = 1000000000; FitsKey *pkey; int crota2_exists = 0, matrix_exists[2] = {0,0}; double dvalue; int primary_naxis = 0; /* floating WCS keywords */ char *cfltkeys[] = {"CRPIX", "CRVAL","CDELT","CROTA", "CRDER","CSYER", "PV"}; int ncfltkeys = 7; int keynum[] = {0,0,0,0,0,0,0}, nmax = 0; /* floating non-indexed WCS keywords */ char *cfltnkeys[] = {"RESTFRQ", "RESTFREQ", "RESTWAV", "OBSGEO-X", "OBSGEO-Y", "OBSGEO-Z", "VELOSYS", "ZSOURCE", "VELANGL", "LONPOLE", "LATPOLE"}; int ncfltnkeys = 11; /* floating WCS keywords w/ underscore */ char *cflt_keys[] = {"PC","CD"}; int ncflt_keys = 2; /* string WCS keywords */ char *cstrkeys[] = {"CTYPE", "CUNIT", "PS", "CNAME" }; int ncstrkeys = 4; /* string RADESYS keywords with list of allowed values */ char *rastrkeys[] = {"RADESYS", "RADECSYS" }; int nrastrkeys = 2; /* string spectral ref frame keywords with list of allowed values */ char *specstrkeys[] = {"SPECSYS", "SSYSOBS", "SSYSSRC" }; int nspecstrkeys = 3; numusrkey = hduptr->tkeys; kwds = hduptr->kwds; /* find the extension name and version */ strcpy(temp,"EXTNAME"); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n); if(k> -1 ) { if(kwds[k]->ktype == STR_KEY) strcpy(hduptr->extname,kwds[k]->kvalue); } strcpy(temp,"EXTVER"); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n); if(k> -1 ) { if(kwds[k]->ktype == INT_KEY) hduptr->extver = (int) strtol(kwds[k]->kvalue,NULL,10); } /* set the HduName structure */ hdunum = hduptr->hdunum; set_hduname(hdunum,hduptr->hdutype,hduptr->extname, hduptr->extver); if(hduptr->hdunum == 1) { test_prm(infits,out,hduptr); primary_naxis = hduptr->naxis; } else { /* test the keywords specific to the hdutype*/ switch (hduptr->hdutype) { case IMAGE_HDU: test_img_ext(infits,out,hduptr); break; case ASCII_TBL: test_asc_ext(infits,out,hduptr); break; case BINARY_TBL: test_bin_ext(infits,out,hduptr); break; default: break; } } /* test the general keywords */ test_header(infits,out,hduptr); /* Check INHERIT keyword; must not be used if primary contains data */ strcpy(temp,"INHERIT"); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n); if(k > -1) { if(primary_naxis != 0) { sprintf(errmes, "Keyword #%d, %s cannot be used if the primary array contains data (NAXIS != 0).", kwds[k]->kindex, kwds[k]->kname); wrtwrn(out,errmes,0); } check_log(kwds[k],out); } /* test if CROTA2 exists; if so, then PCi_j must not exist */ strcpy(temp,"CROTA2"); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n); if (n == 1) { pkey = hduptr->kwds[k]; crota2_exists = pkey->kindex; } strcpy(temp,"WCSAXES"); ptemp = temp; /* first find the primary WCSAXES value, if it exists */ key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n); if (k >= 0) { j = k; if (check_int(kwds[j],out)) { pkey = hduptr->kwds[j]; wcsaxesvalue = (int) strtol(pkey->kvalue,NULL,10); nmax = wcsaxesvalue; if (wcsaxesvalue > wcsaxes) wcsaxes = wcsaxesvalue; wcsaxesExists = 1; /* store index of the wcsaxes keyword */ /* (it must appear before other WCS keywords) */ if (pkey->kindex > wcsaxespos) wcsaxespos = pkey->kindex; } } /* Check and find max value of the WCSAXESa keywords */ /* Use the max value when checking the range of the indexed WCS keywords. */ /* This is a less rigorous test than if one were to test the range of the */ /* keywords for each of the alternate WCS systems (A - Z) against the */ /* corresponding WCSAXESa keyword. */ key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n); for (j = k; j< n + k ; j++){ if (check_int(kwds[j],out)) { pkey = hduptr->kwds[j]; taxes = (int) strtol(pkey->kvalue,NULL,10); if (taxes > wcsaxes) wcsaxes = taxes; wcsaxesExists = 1; /* store highest index of any wcsaxes keyword */ /* (they must appear before other WCS keywords) */ /* Removed this check on 6/28/2012. See discussion on FITSBITS related to this requirement. The sense of this dicussion is that it is not required that every WCSAXESa keyword appear before ANY OTHER WCS keyword. In principle, each WCSAXESa keyword should appear before any other WCS keyword within the SAME alternate system, but this does not really provide any benefit to software that needs to parse the WCS keywords. Since it would be somewhat tedious to make this test, we will not not worry about the placement of the WCSAXESa keywords. */ /* if (pkey->kindex > wcsaxespos) wcsaxespos = pkey->kindex; */ } } /* test datatype of reserved indexed floating point WCS keywords */ for (i = 0; i < ncfltkeys; i++) { strcpy(temp,cfltkeys[i]); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n); if(k < 0) continue; for (j = k; j < k+n; j++) { pkey = hduptr->kwds[j]; p = kwds[j]->kname; p += strlen(temp); if(!isdigit((int)*p)) continue; if (!check_flt(pkey,out) )continue; if (i == 2 ) { /* test that CDELTi != 0 */ dvalue = strtod(pkey->kvalue, NULL); if (dvalue == 0.) { sprintf( errmes, "Keyword #%d, %s: must have non-zero value.", pkey->kindex,pkey->kname); wrterr(out,errmes,1); } } if (i == 4 || i == 5 ) { /* test that CRDERi and CSYSERi are non-negative */ dvalue = strtod(pkey->kvalue, NULL); if (dvalue < 0.) { sprintf( errmes, "Keyword #%d, %s: must have non-negative value: %s", pkey->kindex,pkey->kname,pkey->kvalue); wrterr(out,errmes,1); } } m = (int)strtol(p,&p2,10); if (wcsaxesExists) { /* WCSAXES keyword exists */ if (m < 1 || m > wcsaxes) { sprintf( errmes, "Keyword #%d, %s: index %d is not in range 1-%d (WCSAXES).", pkey->kindex,pkey->kname,m,wcsaxes); wrterr(out,errmes,1); } } else { if (m < 1 || m > hduptr->naxis) { sprintf( errmes, "Keyword #%d, %s: index %d is not in range 1-%d (NAXIS).", pkey->kindex,pkey->kname,m,hduptr->naxis); wrtwrn(out,errmes,0); } } /* count the number of each keyword */ if (*p2 == 0) { /* only test the primary set of WCS keywords */ keynum[i] = keynum[i] + 1; if (m > nmax) nmax = m; } /* store lowest index of any wcs keyword */ if (pkey->kindex < wcskeypos) { wcskeypos = pkey->kindex; pname = pkey->kname; } } } if (wcsaxesvalue == 0) { /* limit value of nmax to the legal maximum */ if (nmax > hduptr->naxis) nmax = hduptr->naxis; } else { if (nmax > wcsaxesvalue) nmax = wcsaxesvalue; } if (keynum[0] < nmax) { /* test number of CRPIXi keywords */ sprintf( errmes, "Some CRPIXi keywords appear to be missing; expected %d.",nmax); wrtwrn(out,errmes,0); } if (keynum[1] < nmax) { /* test number of CRVALi keywords */ sprintf( errmes, "Some CRVALi keywords appear to be missing; expected %d.",nmax); wrtwrn(out,errmes,0); } /* test datatype of reserved non-indexed floating point WCS keywords */ for (i = 0; i < ncfltnkeys; i++) { strcpy(temp,cfltnkeys[i]); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n); if(k < 0) continue; for (j = k; j < k+n; j++) { pkey = hduptr->kwds[j]; if (!check_flt(pkey,out) )continue; } } /* test datatype of reserved indexed floating point WCS keywords with "_" */ for (i = 0; i < ncflt_keys; i++) { strcpy(temp,cflt_keys[i]); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n); if(k < 0) continue; for (j = k; j < k+n; j++) { pkey = hduptr->kwds[j]; p = kwds[j]->kname; p += strlen(temp); if(!isdigit((int)*p)) continue; p2 = strchr(p, '_'); /* 2 digits must be separated by a '_' */ if (!p2) continue; if (!check_flt(pkey,out) )continue; *p2 = '\0'; /* terminate string at the '_' */ /* test the first digit */ m = (int)strtol(p,NULL,10); *p2 = '_'; /* replace the '_' */ if (wcsaxesExists) { /* WCSAXES keyword exists */ if (m < 1 || m > wcsaxes) { sprintf( errmes, "Keyword #%d, %s: 1st index %d is not in range 1-%d (WCSAXES).", pkey->kindex,pkey->kname,m,wcsaxes); wrterr(out,errmes,1); } } else { if (m < 1 || m > hduptr->naxis) { sprintf( errmes, "Keyword #%d, %s: 1st index %d is not in range 1-%d (NAXIS).", pkey->kindex,pkey->kname,m,hduptr->naxis); wrtwrn(out,errmes,0); } } /* test the second digit */ p = p2 + 1; m = (int)strtol(p,&p2,10); if (wcsaxesExists) { /* WCSAXES keyword exists */ if (m < 1 || m > wcsaxes) { sprintf( errmes, "Keyword #%d, %s: 2nd index %d is not in range 1-%d (WCSAXES).", pkey->kindex,pkey->kname,m,wcsaxes); wrterr(out,errmes,1); } } else { if (m < 1 || m > hduptr->naxis) { sprintf( errmes, "Keyword #%d, %s: 2nd index %d is not in range 1-%d (NAXIS).", pkey->kindex,pkey->kname,m,hduptr->naxis); wrtwrn(out,errmes,0); } } if (*p2 == 0) { /* no alternate suffix on the PC or CD name */ matrix_exists[i] = pkey->kindex; } /* store lowest index of any wcs keyword */ if (pkey->kindex < wcskeypos) { wcskeypos = pkey->kindex; pname = pkey->kname; } } } if (matrix_exists[0] > 0 && matrix_exists[1] > 0 ) { sprintf( errmes, "Keywords PCi_j (#%d) and CDi_j (#%d) are mutually exclusive.", matrix_exists[0],matrix_exists[1]); wrterr(out,errmes,1); } if (matrix_exists[0] > 0 && crota2_exists > 0 ) { sprintf( errmes, "Keywords PCi_j (#%d) and CROTA2 (#%d) are mutually exclusive.", matrix_exists[0],crota2_exists); wrterr(out,errmes,1); } /* test datatype of reserved indexed string WCS keywords */ for (i = 0; i < ncstrkeys; i++) { strcpy(temp,cstrkeys[i]); ptemp = temp; keynum[i] = 0; key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n); if(k < 0) continue; for (j = k; j < k+n; j++) { pkey = hduptr->kwds[j]; p = kwds[j]->kname; p += strlen(temp); if(!isdigit((int)*p)) continue; if (!check_str(pkey,out) )continue; m = (int)strtol(p,&p2,10); if (wcsaxesExists) { /* WCSAXES keyword exists */ if (m < 1 || m > wcsaxes) { sprintf( errmes, "Keyword #%d, %s: index %d is not in range 1-%d (WCSAXES).", pkey->kindex,pkey->kname,m,wcsaxes); wrterr(out,errmes,1); } } else { if (m < 1 || m > hduptr->naxis) { sprintf( errmes, "Keyword #%d, %s: index %d is not in range 1-%d (NAXIS).", pkey->kindex,pkey->kname,m,hduptr->naxis); wrtwrn(out,errmes,0); } } if (*p2 == 0) { /* only test the primary set of WCS keywords */ keynum[i] = keynum[i] + 1; } /* store lowest index of any wcs keyword */ if (pkey->kindex < wcskeypos) { wcskeypos = pkey->kindex; pname = pkey->kname; } } } if (keynum[0] < nmax) { sprintf( errmes, "Some CTYPEi keywords appear to be missing; expected %d.",nmax); wrtwrn(out,errmes,0); } if (wcskeypos < wcsaxespos) { sprintf( errmes, "WCSAXES keyword #%d appears after other WCS keyword %s #%d", wcsaxespos, pname, wcskeypos); wrterr(out,errmes,1); } /* test datatype and value of reserved RADECSYS WCS keywords */ for (i = 0; i < nrastrkeys; i++) { strcpy(temp,rastrkeys[i]); ptemp = temp; keynum[i] = 0; key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n); if(k < 0) continue; for (j = k; j < k+n; j++) { pkey = hduptr->kwds[j]; p = kwds[j]->kname; p += strlen(temp); if (!check_str(pkey,out) )continue; if (strcmp(pkey->kvalue, "ICRS") && strcmp(pkey->kvalue, "FK5") && strcmp(pkey->kvalue, "FK4") && strcmp(pkey->kvalue, "FK4-NO-E") && strcmp(pkey->kvalue, "GAPPT")) { sprintf( errmes, "Keyword #%d, %s has non-allowed value: %s", pkey->kindex,pkey->kname,pkey->kvalue); wrtwrn(out,errmes,0); } } } /* test datatype and value of reserved spectral ref frame WCS keywords */ for (i = 0; i < nspecstrkeys; i++) { strcpy(temp,specstrkeys[i]); ptemp = temp; keynum[i] = 0; key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n); if(k < 0) continue; for (j = k; j < k+n; j++) { pkey = hduptr->kwds[j]; p = kwds[j]->kname; p += strlen(temp); if (!check_str(pkey,out) )continue; if (strcmp(pkey->kvalue, "TOPOCENT") && strcmp(pkey->kvalue, "GEOCENTR") && strcmp(pkey->kvalue, "BARYCENT") && strcmp(pkey->kvalue, "HELIOCEN") && strcmp(pkey->kvalue, "LSRK") && strcmp(pkey->kvalue, "LSRD") && strcmp(pkey->kvalue, "GALACTOC") && strcmp(pkey->kvalue, "LOCALGRP") && strcmp(pkey->kvalue, "CMBDIPOL") && strcmp(pkey->kvalue, "SOURCE")) { sprintf( errmes, "Keyword #%d, %s has non-allowed value: %s", pkey->kindex,pkey->kname,pkey->kvalue); wrtwrn(out,errmes,0); } } } /* test the fill area */ if(testfill) { if(ffchfl(infits,&status)) { wrterr(out, "The header fill area is not totally filled with blanks.",1); } } return ; } /************************************************************* * * test_prm * * Test the primary array header * * *************************************************************/ void test_prm(fitsfile *infits, /* input fits file */ FILE* out, /* output ascii file */ FitsHdu *hduptr /* hdu information structure */ ) { int i,j,k,n; FitsKey *pkey; FitsKey **kwds; int numusrkey; char *p; char *exlkey[] = {"XTENSION", "INHERIT"}; int nexlkey = 1; kwds = hduptr->kwds; numusrkey = hduptr->tkeys; /* The SIMPLE, BITPIX, NAXIS, and NAXISn keywords have been checked in CFITSIO */ /* excluded keywords cannot be used. */ for (i = 0; i < nexlkey; i++) { strcpy(temp,exlkey[i]); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n); if( n > 0) { pkey = hduptr->kwds[k]; sprintf(errmes, "Keyword #%d, %s is not allowed in a primary array.", pkey->kindex,exlkey[i]); wrterr(out,errmes,1); } } /* Check if Random Groups file */ strcpy(temp,"GROUPS"); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n); if(k > -1){ pkey = hduptr->kwds[k]; if(*(pkey->kvalue) == 'T' && hduptr->naxis > 0 && hduptr->naxes[0]==0) { hduptr->isgroup = 1; check_fixed_log(cards[pkey->kindex - 1], out); } } /* check the position of the EXTEND */ /* the EXTEND keyword is no longer required if the file contains extensions */ if (hduptr->isgroup == 0) { strcpy(temp,"EXTEND"); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n); if( k > 0) { pkey = hduptr->kwds[k]; if(check_log(pkey,out) && *(pkey->kvalue)!='T' && totalhdu > 1) { sprintf(errmes,"There are extensions but EXTEND = F."); wrterr(out,errmes,1); } } } /* Check PCOUNT and GCOUNT keyword */ strcpy(temp,"PCOUNT"); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n); if(k > -1) { pkey = hduptr->kwds[k]; /* Primary array cannot have PCOUNT */ if (!hduptr->isgroup ){ sprintf(errmes, " Keyword #%d, %s is not allowed in a primary array.", pkey->kindex,pkey->kname); wrterr(out,errmes,1); } else { if(check_int(pkey,out)) hduptr->pcount = (LONGLONG) atof(pkey->kvalue); check_fixed_int(cards[pkey->kindex - 1], out); } } strcpy(temp,"GCOUNT"); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n); if(k > -1) { pkey = hduptr->kwds[k]; /* Primary array cannot have GCOUNT */ if (!hduptr->isgroup ){ sprintf(errmes, " Keyword #%d, %s is not allowed in a primary array.", pkey->kindex,pkey->kname); wrterr(out,errmes,1); } else { if(check_int(pkey,out)) hduptr->gcount = (int) strtol(pkey->kvalue,NULL,10); check_fixed_int(cards[pkey->kindex - 1], out); } } strcpy(temp,"BLOCKED"); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n); if(k > -1) { pkey = hduptr->kwds[k]; sprintf(errmes, "Keyword #%d, %s is deprecated.", pkey->kindex, pkey->kname); wrtwrn(out,errmes,0); check_log(pkey,out); /* no longer required if(pkey->kindex > 36) { sprintf(errmes, "Keyword #%d, BLOCKED, appears beyond keyword 36.", pkey->kindex); wrterr(out,errmes,1); } */ } /* Check PSCALn keywords (only in Random Groups) */ strcpy(temp,"PSCAL"); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n); for (j = k; j< k + n ; j++){ p = kwds[j]->kname; p += 5; if(!isdigit((int)*p)) continue; if (!(hduptr->isgroup)) { sprintf(errmes,"Keyword #%d, %s ", kwds[j]->kindex,kwds[j]->kname); strcat(errmes, "is only allowed in Random Groups structures."); wrterr(out,errmes,1); continue; } if (check_flt(kwds[j],out) && strtod(kwds[j]->kvalue,NULL) == 0.0) { sprintf(errmes,"Keyword #%d, %s: ", kwds[j]->kindex,kwds[j]->kname); strcat(errmes, "The scaling factor is zero."); wrtwrn(out,errmes,0); } i = (int) strtol(p,NULL,10) -1 ; if(i< 0 || i >= hduptr->gcount) { sprintf(errmes, "Keyword #%d, %s: invalid index %d (> GCOUNT = %d).", kwds[j]->kindex,kwds[j]->kname,i+1,hduptr->gcount); wrterr(out,errmes,1); continue; } } /* Check PZEROn keywords (only in Random Groups) */ strcpy(temp,"PZERO"); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n); for (j = k; j< k + n ; j++){ p = kwds[j]->kname; p += 5; if(!isdigit((int)*p)) continue; if (!(hduptr->isgroup)) { sprintf(errmes,"Keyword #%d, %s ", kwds[j]->kindex,kwds[j]->kname); strcat(errmes, "is only allowed in Random Groups structures."); wrterr(out,errmes,1); continue; } check_flt(kwds[j],out); i = (int) strtol(p,NULL,10) -1 ; if(i< 0 || i >= hduptr->gcount) { sprintf(errmes, "Keyword #%d, %s: invalid index %d (> GCOUNT = %d).", kwds[j]->kindex,kwds[j]->kname,i+1,hduptr->gcount); wrterr(out,errmes,1); continue; } } /* Check PTYPEn keywords (only in Random Groups) */ strcpy(temp,"PTYPE"); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n); for (j = k; j< k + n ; j++){ p = kwds[j]->kname; p += 5; if(!isdigit((int)*p)) continue; if (!(hduptr->isgroup)) { sprintf(errmes,"Keyword #%d, %s ", kwds[j]->kindex,kwds[j]->kname); strcat(errmes, "is only allowed in Random Groups structures."); wrterr(out,errmes,1); continue; } check_str(kwds[j],out); i = (int) strtol(p,NULL,10) -1 ; if(i< 0 || i >= hduptr->gcount) { sprintf(errmes, "Keyword #%d, %s: invalid index %d (> GCOUNT = %d).", kwds[j]->kindex,kwds[j]->kname,i+1,hduptr->gcount); wrterr(out,errmes,1); continue; } } test_array(infits, out, hduptr); return; } /************************************************************* * * test_ext * * Test the extension header * * *************************************************************/ void test_ext(fitsfile *infits, /* input fits file */ FILE* out, /* output ascii file */ FitsHdu *hduptr /* information about header */ ) { FitsKey *pkey; FitsKey **kwds; int i,j,k,n; int numusrkey; char *exlkey[] = {"SIMPLE","EXTEND", "BLOCKED", }; int nexlkey = 3; char *exlnkey[] = {"PTYPE","PSCAL", "PZERO", "GROUPS", }; int nexlnkey = 4; int hdunum; char *p; numusrkey = hduptr->tkeys; kwds = hduptr->kwds; hdunum = hduptr->hdunum; /* check the duplicate extensions */ for (i = hdunum - 1; i > 0; i--) { if(test_hduname(hdunum,i)) { sprintf(comm, "The HDU %d and %d have identical type/name/version", hdunum,i); wrtwrn(out,comm,0); } } /* check the position of the PCOUNT */ strcpy(temp,"PCOUNT"); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n); if( k < 0) { sprintf(errmes,"cannot find the PCOUNT keyword."); wrterr(out,errmes,1); } else { pkey = hduptr->kwds[k]; if(check_int(pkey,out)) hduptr->pcount = (LONGLONG) atof(pkey->kvalue); if( pkey->kindex != 4 + hduptr->naxis ) { sprintf(errmes,"PCOUNT is not in record %d of the header.", hduptr->naxis + 4); wrterr(out,errmes,1); } check_fixed_int(cards[pkey->kindex - 1], out); } /* check the position of the GCOUNT */ strcpy(temp,"GCOUNT"); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n); if( k < 0) { sprintf(errmes,"cannot find the GCOUNT keyword."); wrterr(out,errmes,1); } else { pkey = hduptr->kwds[k]; if(check_int(pkey,out)) hduptr->gcount = (int) strtol(pkey->kvalue,NULL,10); if( pkey->kindex != 5 + hduptr->naxis ) { sprintf(errmes,"GCOUNT is not in record %d of the header.", hduptr->naxis + 5); wrterr(out,errmes,1); } check_fixed_int(cards[pkey->kindex - 1], out); } for (i = 0; i < nexlkey; i++) { strcpy(temp,exlkey[i]); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n); if(k > -1) { pkey = hduptr->kwds[k]; sprintf( errmes, "Keyword #%d, %s is not allowed in extensions.", pkey->kindex,pkey->kname); wrterr(out,errmes,1); } } for (i = 0; i < nexlnkey; i++) { strcpy(temp,exlnkey[i]); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n); if(k > -1) { for (j = k; j< k + n ; j++){ p = kwds[j]->kname; p += 5; if(!isdigit((int)*p)) continue; pkey = hduptr->kwds[j]; sprintf( errmes, "Keyword #%d, %s is only allowed in Random Groups structures.", pkey->kindex,pkey->kname); wrterr(out,errmes,1); } } } return; } /************************************************************* * * test_img_ext * * Test the image extension header * * *************************************************************/ void test_img_ext(fitsfile *infits, /* input fits file */ FILE* out, /* output ascii file */ FitsHdu *hduptr /* information about header */ ) { test_ext(infits,out,hduptr); /* The XTENSION, BITPIX, NAXIS, and NAXISn keywords have been checked in CFITSIO */ if(hduptr->pcount != 0 && hduptr->pcount != -99){ sprintf(errmes, "Illegal pcount value %ld for image ext.",(long) hduptr->pcount); wrterr(out,errmes,1); } if(hduptr->gcount !=1 && hduptr->gcount != -99){ sprintf(errmes, "Illegal gcount value %d for image ext.",hduptr->gcount); wrterr(out,errmes,1); } test_array(infits, out, hduptr); return ; } /************************************************************* * * test_array * * Test the keywords which are used by both the primary array * and image Extension. * * *************************************************************/ void test_array(fitsfile *infits, /* input fits file */ FILE* out, /* output ascii file */ FitsHdu *hduptr /* information about header */ ) { int numusrkey; FitsKey **kwds; char *p; int i,j,k,n; FitsKey *pkey; /* excluded non-indexed keywords */ char *exlkeys[] = {"TFIELDS","THEAP"}; int nexlkeys = 2; /* excluded indexed keywords */ char *exlnkeys[] = {"TBCOL", "TFORM", "TSCAL", "TZERO","TNULL", "TTYPE", "TUNIT","TDISP","TDIM", "TCTYP","TCUNI","TCRVL","TCDLT","TCRPX","TCROT"}; int nexlnkeys = 15; /* non-indexed floating keywords (excluding BSCALE) */ char *fltkeys[] = {"BZERO","DATAMAX","DATAMIN"}; int nfltkeys = 3; /* non-indexed string keywords */ char *strkeys[] = {"BUNIT"}; int nstrkeys = 1; numusrkey = hduptr->tkeys; kwds = hduptr->kwds; /* Check BLANK, BSCALE keywords */ strcpy(temp,"BLANK"); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n); if( k >= 0) { check_int(kwds[k],out); if(hduptr->bitpix < 0) { sprintf(errmes, "Keyword #%d, %s must not be used with floating point data (BITPIX = %d).", kwds[k]->kindex,kwds[k]->kname, hduptr->bitpix); wrterr(out,errmes,2); } } strcpy(temp,"BSCALE"); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n); if( k >= 0) { if(check_flt(kwds[k],out) && strtod(kwds[k]->kvalue,NULL) == 0.0) { sprintf(errmes,"Keyword #%d, %s: The scaling factor is 0.", kwds[k]->kindex,kwds[k]->kname); wrtwrn(out,errmes,0); } } /* search for excluded, non-indexed keywords */ for (i = 0; i < nexlkeys; i++) { strcpy(temp,exlkeys[i]); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n); if(k < 0) continue; for (j = k; j < k+n; j++) { pkey = hduptr->kwds[j]; sprintf( errmes, "Keyword #%d, %s is not allowed in the array HDU.", pkey->kindex,pkey->kname); wrterr(out,errmes,1); } } /* search for excluded, indexed keywords */ for (i = 0; i < nexlnkeys; i++) { strcpy(temp,exlnkeys[i]); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n); if(k < 0) continue; for (j = k; j < k+n; j++) { pkey = hduptr->kwds[j]; p = kwds[j]->kname; p += strlen(temp); if(!isdigit((int)*p)) continue; sprintf( errmes, "Keyword #%d, %s is not allowed in the array HDU.", pkey->kindex,pkey->kname); wrterr(out,errmes,1); } } /* test datatype of reserved non-indexed floating point keywords */ for (i = 0; i < nfltkeys; i++) { strcpy(temp,fltkeys[i]); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n); if(k < 0) continue; for (j = k; j < k+n; j++) { pkey = hduptr->kwds[j]; if (!check_flt(pkey,out)) continue; } } /* test datatype of reserved non-indexed string keywords */ for (i = 0; i < nstrkeys; i++) { strcpy(temp,strkeys[i]); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n); if(k < 0) continue; for (j = k; j < k+n; j++) { pkey = hduptr->kwds[j]; check_str(pkey,out); } } return; } /************************************************************* * * test_img_wcs * * Test the image WCS keywords * * *************************************************************/ /* void test_img_wcs(fitsfile *infits, FILE* out, FitsHdu *hduptr ) { int nkeyrec, nreject, nwcs, status = 0; int *stat = 0, ii; char *header; struct wcsprm *wcs; */ /* NOTE: WCSLIB currently doesn't provide very much diagnostic information about possible problems with the WCS keywords so for now, comment out this routine. */ /* use WCSLIB to look for inconsistencies in the WCS keywords */ /* Read in the FITS header, excluding COMMENT and HISTORY keyrecords. */ /* if (fits_hdr2str(infits, 1, NULL, 0, &header, &nkeyrec, &status)) { sprintf(errmes, "test_img_ext failed to read header keywords into array %d", status); wrterr(out,errmes,1); return; } */ /* Interpret the WCS keywords. */ /* if ((status = wcsbth(header, nkeyrec, WCSHDR_all, -2, 0, 0, &nreject, &nwcs, &wcs))) { sprintf(errmes, "test_img_ext: wcsbth ERROR %d: %s.", status, wcshdr_errmsg[status]); wrterr(out,errmes,1); free(header); return; } free(header); if (wcs) { if (nwcs == 1) { sprintf(errmes, " Found 1 World Coordinate System (WCS)."); } else { sprintf(errmes, " Found %d World Coordinate Systems (WCS).", nwcs); } wrtout(out,errmes); } */ /* Translate non-standard WCS keyvalues and look for inconsistencies */ /* this doesn't provide any useful checks stat = malloc(NWCSFIX * sizeof(int)); if ((status = wcsfix(7, 0, wcs, stat))) { for (ii = 0; ii < NWCSFIX; ii++) { if (stat[ii] > 0) { sprintf(errmes, "wcsfix ERROR %d: %s.", stat[ii], wcsfix_errmsg[stat[ii]]); wrtwrn(out,errmes,0); } } } if ((status = wcsset(wcs))) { sprintf(errmes, "wcsset ERROR %d %s.", status, wcs_errmsg[status]); wrtwrn(out,errmes,0); } */ /* status = wcsvfree(&nwcs, &wcs); return; } */ /************************************************************* * * test_tbl * * Test the table extension header and fill the tform, ttype, * tunit. * * *************************************************************/ void test_tbl(fitsfile *infits, /* input fits file */ FILE* out, /* output ascii file */ FitsHdu *hduptr /* information about header */ ) { FitsKey *pkey; FitsKey **kwds; char *p; char *q; int m,n,i,j,k; long w,d,e; long lm; int mcol; /* excluded, non-index keywords (allowed in tile-compressed images) */ char* exlkey[] = {"BSCALE","BZERO", "BUNIT", "BLANK", "DATAMAX", "DATAMIN" }; int nexlkey = 6; /* floating WCS keywords */ char *cfltkeys[] = {"TCRVL","TCDLT","TCRPX","TCROT" }; int ncfltkeys = 4; /* string WCS keywords */ char *cstrkeys[] = {"TCTYP","TCUNI" }; int ncstrkeys = 2 ; int numusrkey; numusrkey = hduptr->tkeys; mcol = hduptr->ncols; kwds = hduptr->kwds; if(mcol <= 0) goto OTHERKEY; /* set the ttype, ttform, tunit for tables */ ttype = (char **)calloc(mcol, sizeof(char *)); tform = (char **)calloc(mcol, sizeof(char *)); tunit = (char **)calloc(mcol, sizeof(char *)); for (i=0; i< mcol; i++) { ttype[i] = snull; tform[i] = snull; tunit[i] = snull; } strcpy(temp,"TFIELDS"); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n); if( k >= 0) { pkey = hduptr->kwds[k]; check_fixed_int(cards[pkey->kindex - 1], out); } strcpy(temp,"TTYPE"); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n); for (j = k; j< k+n ; j++){ pkey = hduptr->kwds[j]; p = pkey->kname; p += 5; if(!isdigit((int)*p)) continue; check_str(pkey,out); i = (int) strtol(p,NULL,10) -1 ; if(i>= 0 && i < mcol) { ttype[i] = pkey->kvalue; } else { sprintf(errmes, "Keyword #%d, %s: invalid index %d (> TFIELD = %d).", pkey->kindex,pkey->kname,i+1,mcol); wrterr(out,errmes,2); } } strcpy(temp,"TFORM"); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n); for (j = k; j< k + n ; j++){ pkey = hduptr->kwds[j]; p = pkey->kname; p += 5; if(!isdigit((int)*p)) continue; check_str(pkey,out); /* TFORMn keyword no longer required to be padded to at least 8 characters check_fixed_str(cards[pkey->kindex - 1], out); */ if(*(pkey->kvalue) == ' ') { sprintf(errmes,"Keyword #%d, %s: TFORM=\"%s\" ", pkey->kindex,pkey->kname, pkey->kvalue); strcat(errmes, "should not have leading space."); wrterr(out,errmes,1); } i = (int) strtol(p,NULL,10) -1 ; if(i>= 0 && i < mcol) { tform[i] = pkey->kvalue; } else { sprintf(errmes, "Keyword #%d, %s: invalid index %d (> TFIELD = %d).", pkey->kindex,pkey->kname,i+1,mcol); wrterr(out,errmes,2); } p = pkey->kvalue; while(*p != ' ' && *p != '\0') { if( !isdigit((int)*p) && !isupper((int)*p) && *p != '.' && *p != ')' && *p != '(' ) { sprintf(errmes, "Keyword #%d, %s: The value %s has character %c which is not uppercase letter.", pkey->kindex,pkey->kname,pkey->kvalue,*p); wrterr(out,errmes,1); } p++; } } strcpy(temp,"TUNIT"); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n); for (j = k; j< k + n ; j++){ pkey = hduptr->kwds[j]; p = pkey->kname; p += 5; if(!isdigit((int)*p)) continue; check_str(pkey,out); i = (int) strtol(p,NULL,10) -1 ; if(i>= 0 && i < mcol) { tunit[i] = pkey->kvalue; } else { sprintf(errmes, "Keyword #%d, %s: invalid index %d (> TFIELD = %d).", pkey->kindex,pkey->kname,i+1,mcol); wrterr(out,errmes,1); } } /* Check TDISPn keywords */ strcpy(temp,"TDISP"); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n); for (j = k; j< k + n ; j++){ p = kwds[j]->kname; p += 5; if(!isdigit((int)*p)) continue; if (*(kwds[j]->kvalue) == '\0') continue; /* ignore blank string */ check_str(kwds[j],out); if(*(kwds[j]->kvalue) == ' ') { sprintf(errmes,"Keyword #%d, %s: TDISP=\"%s\" ", kwds[j]->kindex,kwds[j]->kname,kwds[j]->kvalue); strcat(errmes, "should not have leading space."); wrterr(out,errmes,1); } i = (int) strtol(p,NULL,10) -1 ; if(i< 0 || i >= mcol ) { sprintf(errmes, "Keyword #%d, %s: invalid index %d (> TFIELD = %d).", kwds[j]->kindex,kwds[j]->kname,i+1,mcol); wrterr(out,errmes,1); continue; } p = kwds[j]->kvalue; switch (*p) { case 'A': p++; w = 0; w = strtol(p,NULL,10); if( !w || w == LONG_MAX || w == LONG_MIN) { sprintf(errmes, "Keyword #%d, %s: invalid format \"%s\".", kwds[j]->kindex,kwds[j]->kname, kwds[j]->kvalue); wrterr(out,errmes,1); } if(strchr(tform[i],'A') == NULL ){ sprintf(errmes, "Keyword #%d, %s: Format \"%s\" cannot be used for TFORM \"%s\".", kwds[j]->kindex,kwds[j]->kname, kwds[j]->kvalue, tform[i]); wrterr(out,errmes,1); } break; case 'L': p++; w = 0; w = strtol(p,NULL,10); if(!w || w == LONG_MAX || w == LONG_MIN) { sprintf(errmes, "Keyword #%d, %s: invalid format \"%s\".", kwds[j]->kindex,kwds[j]->kname, kwds[j]->kvalue); wrterr(out,errmes,1); } if(strchr(tform[i],'L') == NULL ){ sprintf(errmes, "Keyword #%d, %s: Format %s cannot be used for TFORM \"%s\".", kwds[j]->kindex,kwds[j]->kname, kwds[j]->kvalue, tform[i]); wrterr(out,errmes,1); } break; case 'I': case 'B': case 'O': case 'Z': p++; w = 0; w = strtol(p,NULL,10); if((q = strchr(p,'.')) != NULL) { p = q; p++; lm = strtol(p,NULL,10); } else { lm = -1; /* no minimum digit field */ } if(!w || w == LONG_MAX || w == LONG_MIN || lm == LONG_MAX || lm == LONG_MIN || w < lm ) { sprintf(errmes, "Keyword #%d, %s: invalid format \"%s\".", kwds[j]->kindex,kwds[j]->kname, kwds[j]->kvalue); wrterr(out,errmes,1); } if(strchr(tform[i],'I') == NULL && strchr(tform[i],'J') == NULL && strchr(tform[i],'K') == NULL && strchr(tform[i],'B') == NULL && strchr(tform[i],'X') == NULL ){ sprintf(errmes, "Keyword #%d, %s: Format \"%s\" cannot be used for TFORM \"%s\".", kwds[j]->kindex,kwds[j]->kname, kwds[j]->kvalue, tform[i]); wrterr(out,errmes,1); } break; case 'F': p++; d = -1; w = 0; w = strtol(p,NULL,10); if((q = strchr(p,'.')) != NULL) { p = q; p++; d = strtol(p,NULL,10); } if(!w || w == LONG_MAX || w == LONG_MIN || d == -1 || d == LONG_MAX || d == LONG_MIN || w < d+1 ) { sprintf(errmes, "Keyword #%d, %s: invalid format \"%s\".", kwds[j]->kindex,kwds[j]->kname, kwds[j]->kvalue); wrterr(out,errmes,1); } if(strchr(tform[i],'E') == NULL && strchr(tform[i],'F') == NULL && strchr(tform[i],'C') == NULL && strchr(tform[i],'D') == NULL && strchr(tform[i],'M') == NULL && strchr(tform[i],'I') == NULL && strchr(tform[i],'J') == NULL && strchr(tform[i],'K') == NULL && strchr(tform[i],'B') == NULL && strchr(tform[i],'X') == NULL ){ sprintf(errmes, "Keyword #%d, %s: Format \"%s\" cannot be used for TFORM \"%s\".", kwds[j]->kindex,kwds[j]->kname, kwds[j]->kvalue, tform[i]); wrterr(out,errmes,1); } break; case 'E': case 'D': p++; w = 0; e = 0; d = 0; if(*p == 'N' || *p == 'S') { p++; e = 2;} w = strtol(p,NULL,10); if((q = strchr(p,'.')) != NULL) { p = q; p++; d = strtol(p,NULL,10); } if((q = strchr(p,'E')) != NULL) { p = q; p++; e = strtol(p,NULL,10); } else { e = 2; } if(!w || w == LONG_MAX || w == LONG_MIN || !d || d == LONG_MAX || d == LONG_MIN || !e || e == LONG_MAX || e == LONG_MIN || w < d+e+3) { sprintf(errmes, "Keyword #%d, %s: invalid format \"%s\".", kwds[j]->kindex,kwds[j]->kname, kwds[j]->kvalue); wrterr(out,errmes,1); } if(strchr(tform[i],'E') == NULL && strchr(tform[i],'F') == NULL && strchr(tform[i],'C') == NULL && strchr(tform[i],'D') == NULL && strchr(tform[i],'M') == NULL && strchr(tform[i],'I') == NULL && strchr(tform[i],'J') == NULL && strchr(tform[i],'K') == NULL && strchr(tform[i],'B') == NULL && strchr(tform[i],'X') == NULL ){ sprintf(errmes, "Keyword #%d, %s: Format \"%s\" cannot be used for TFORM \"%s\".", kwds[j]->kindex,kwds[j]->kname, kwds[j]->kvalue, tform[i]); wrterr(out,errmes,1); } break; case 'G': p++; e = 0; d = 0; w = 0; w = strtol(p,NULL,10); if((q = strchr(p,'.')) != NULL) { p = q; p++; d = strtol(p,NULL,10); } if((q = strchr(p,'E')) != NULL) { p = q; p++; e = strtol(p,NULL,10); } else { e = 2; } if(!w || w == LONG_MAX || w == LONG_MIN || !d || d == LONG_MAX || d == LONG_MIN || !e || e == LONG_MAX || e == LONG_MIN ){ sprintf(errmes, "Keyword #%d, %s: invalid format \"%s\".", kwds[j]->kindex,kwds[j]->kname, kwds[j]->kvalue); wrterr(out,errmes,1); } break; default: sprintf(errmes, "Keyword #%d, %s: invalid format \"%s\".", kwds[j]->kindex,kwds[j]->kname, kwds[j]->kvalue); wrterr(out,errmes,1); break; } } OTHERKEY: if (!(hduptr->istilecompressed) ) { /* tile compressed images can have these keywords */ for (i = 0; i < nexlkey; i++) { strcpy(temp,exlkey[i]); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n); if(k > -1) { pkey = hduptr->kwds[k]; sprintf( errmes, "Keyword #%d, %s is not allowed in the Bin/ASCII table.", pkey->kindex,pkey->kname); wrterr(out,errmes,1); } } /* search for excluded indexed keywords */ /* these WCS keywords are all allowed (changed July 2010) for (i = 0; i < nexlkeys; i++) { strcpy(temp,exlkeys[i]); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n); if(k < 0) continue; for (j = k; j < k+n; j++) { pkey = hduptr->kwds[j]; p = kwds[j]->kname; p += strlen(temp); if(!isdigit((int)*p)) continue; sprintf( errmes, "Keyword #%d, %s is not allowed in the Bin/ASCII table.", pkey->kindex,pkey->kname); wrterr(out,errmes,1); } } */ } /* test datatype of reserved indexed floating point WCS keywords */ for (i = 0; i < ncfltkeys; i++) { strcpy(temp,cfltkeys[i]); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n); if(k < 0) continue; for (j = k; j < k+n; j++) { pkey = hduptr->kwds[j]; p = kwds[j]->kname; p += strlen(temp); if(!isdigit((int)*p)) continue; if (!check_flt(pkey,out) )continue; m = (int)strtol(p,NULL,10); if (m < 1 || m > mcol) { sprintf( errmes, "Keyword #%d, %s: index %d is not in range 1-%d (TFIELD).", pkey->kindex,pkey->kname,m,mcol); wrterr(out,errmes,1); } } } /* test datatype of reserved indexed string WCS keywords */ for (i = 0; i < ncstrkeys; i++) { strcpy(temp,cstrkeys[i]); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n); if(k < 0) continue; for (j = k; j < k+n; j++) { pkey = hduptr->kwds[j]; p = kwds[j]->kname; p += strlen(temp); if(!isdigit((int)*p)) continue; if (!check_str(pkey,out) )continue; m = (int)strtol(p,NULL,10); if (m < 1 || m > mcol) { sprintf( errmes, "Keyword #%d, %s: index %d is not in range 1-%d (TFIELD).", pkey->kindex,pkey->kname,m,mcol); wrterr(out,errmes,1); } } } return; } /************************************************************* * * test_asc_ext * * Test the ascii table extension header * * *************************************************************/ void test_asc_ext(fitsfile *infits, /* input fits file */ FILE* out, /* output ascii file */ FitsHdu *hduptr /* information about header */ ) { int numusrkey; FitsKey **kwds; FitsKey *pkey; char *p; int i,j,k; int n; int mcol; numusrkey = hduptr->tkeys; kwds = hduptr->kwds; mcol = hduptr->ncols; /* The XTENSION, BITPIX, NAXIS, NAXISn, TFIELDS, PCOUNT, GCOUNT, TFORMn, TBCOLn, TTYPEn keywords have been checked in CFITSIO */ /* General extension */ test_ext(infits,out,hduptr); /* general table */ test_tbl(infits,out,hduptr); /* Check TBCOLn */ strcpy(temp,"TBCOL"); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n); for (j = k; j< k + n ; j++){ pkey = hduptr->kwds[j]; p = pkey->kname; p += 5; if(!isdigit((int)*p)) continue; check_int(pkey,out); i = (int) strtol(p,NULL,10) ; if(i< 0 || i > mcol) { sprintf(errmes, "Keyword #%d, %s: invalid index %d (> TFIELD = %d).", pkey->kindex,pkey->kname,i,mcol); wrterr(out,errmes,1); } else { check_fixed_int(cards[pkey->kindex - 1], out); } } /* Check TNULLn, TSCALn, and TZEORn keywords */ strcpy(temp,"TNULL"); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n); for (j = k; j< k + n ; j++){ p = kwds[j]->kname; p += 5; if(!isdigit((int)*p)) continue; i = (int) strtol(p,NULL,10) -1; if(i< 0 || i >= mcol) { sprintf(errmes, "Keyword #%d, %s: invalid index %d (> TFIELD = %d).", kwds[j]->kindex,kwds[j]->kname,i+1,mcol); wrterr(out,errmes,1); } check_str(kwds[j],out); } strcpy(temp,"TSCAL"); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n); for (j = k; j< k + n ; j++){ p = kwds[j]->kname; p += 5; if(!isdigit((int)*p)) continue; i = (int) strtol(p,NULL,10) -1 ; if(check_flt(kwds[j],out)){ if(strtod(kwds[j]->kvalue,NULL) == 0.0) { sprintf(errmes,"Keyword #%d, %s: Scaling factor is zero.", kwds[j]->kindex,kwds[j]->kname); wrtwrn(out,errmes,0); } } if(i< 0 || i >= mcol) { sprintf(errmes, "Keyword #%d, %s: invalid index %d (> TFIELD = %d).", kwds[j]->kindex,kwds[j]->kname,i+1,mcol); wrterr(out,errmes,1); continue; } if(strchr(tform[i],'A') != NULL) { sprintf(errmes, "Keyword #%d, %s may not be used for the A-format fields.", kwds[j]->kindex,kwds[j]->kname); wrterr(out,errmes,1); } } strcpy(temp,"TZERO"); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n); for (j = k; j< k + n ; j++){ p = kwds[j]->kname; p += 5; if(!isdigit((int)*p)) continue; check_flt(kwds[j],out); i = (int) strtol(p,NULL,10) -1 ; if(i< 0 || i >= mcol) { sprintf(errmes, "Keyword #%d, %s: invalid index %d (> TFIELD = %d).", kwds[j]->kindex,kwds[j]->kname,i+1,mcol); wrterr(out,errmes,1); continue; } if(strchr(tform[i],'A') != NULL) { sprintf(errmes, "Keyword #%d, %s may not be used for the A-format fields.", kwds[j]->kindex,kwds[j]->kname); wrterr(out,errmes,1); } } strcpy(temp,"TDIM"); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n); for (j = k; j< k + n ; j++){ p = kwds[j]->kname; p += 4; if(!isdigit((int)*p)) continue; pkey = hduptr->kwds[j]; sprintf( errmes, "Keyword #%d, %s is not allowed in the ASCII table.", pkey->kindex,pkey->kname); wrterr(out,errmes,1); } strcpy(temp,"THEAP"); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n); if (k > -1) { pkey = hduptr->kwds[k]; sprintf( errmes, "Keyword #%d, %s is not allowed in the ASCII table.", pkey->kindex,pkey->kname); wrterr(out,errmes,1); } /* check whether the column name is unique */ test_colnam(out, hduptr); return ; } /************************************************************* * * test_bin_ext * * Test the binary table extension header * * *************************************************************/ void test_bin_ext(fitsfile *infits, /* input fits file */ FILE* out, /* output ascii file */ FitsHdu *hduptr /* information about header */ ) { FitsKey *pkey; int i,j,k,n; long l; int status = 0; char *p; int ntdim; long tdim[10]; int repeat, width; FitsKey **kwds; int numusrkey; int mcol, vla, datatype; /* The indexed keywords excluded from ascii table */ char *exlkeys[] = { "TBCOL"}; int nexlkeys = 1; kwds = hduptr->kwds; numusrkey = hduptr->tkeys; mcol = hduptr->ncols; /* General extension */ test_ext(infits,out,hduptr); /* General table */ test_tbl(infits,out,hduptr); /* The XTENSION, BITPIX, NAXIS, NAXISn, TFIELDS, PCOUNT, GCOUNT, TFORMn, TTYPEn keywords have been checked in CFITSIO */ /* Check TNULLn keywords */ strcpy(temp,"TNULL"); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n); for (j = k; j< k + n ; j++){ p = kwds[j]->kname; p += 5; if(!isdigit((int)*p)) continue; check_int(kwds[j],out); i = (int) strtol(p,NULL,10) -1 ; if(i< 0 || i >= mcol) { sprintf(errmes, "Keyword #%d, %s: invalid index %d (> TFIELD = %d).", kwds[j]->kindex,kwds[j]->kname,i+1,mcol); wrterr(out,errmes,1); continue; } if(strchr(tform[i],'B') == NULL && strchr(tform[i],'I') == NULL && strchr(tform[i],'J') == NULL && strchr(tform[i],'K') == NULL ) { sprintf(errmes, "Keyword #%d, %s is used for the column with format \"%s \".", kwds[j]->kindex,kwds[j]->kname,tform[i]); wrterr(out,errmes,2); } l = strtol(kwds[j]->kvalue,NULL,10); if(strchr(tform[i],'B') != NULL && ( l < 0 || l > 255) ) { sprintf(errmes,"Keyword #%d, %s: The value %ld", kwds[j]->kindex,kwds[j]->kname, l); strcat(errmes, " is not in the range of datatype B."); wrtwrn(out,errmes,0); } l = strtol(kwds[j]->kvalue,NULL,10); if(strchr(tform[i],'I') != NULL && ( l < -32768 || l > 32767) ) { sprintf(errmes,"Keyword #%d, %s: The value %ld", kwds[j]->kindex,kwds[j]->kname, l); strcat(errmes, " is not in the range of datatype I "); wrtwrn(out,errmes,0); } } /* Check TSCALn keywords */ strcpy(temp,"TSCAL"); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n); for (j = k; j< k + n ; j++){ p = kwds[j]->kname; p += 5; if(!isdigit((int)*p)) continue; if (check_flt(kwds[j],out) && strtod(kwds[j]->kvalue,NULL) == 0.0) { sprintf(errmes,"Keyword #%d, %s:", kwds[j]->kindex,kwds[j]->kname); strcat(errmes, "The scaling factor is zero."); wrtwrn(out,errmes,0); } i = (int) strtol(p,NULL,10) -1 ; if(i< 0 || i >= mcol) { sprintf(errmes, "Keyword #%d, %s: invalid index %d (> TFIELD = %d).", kwds[j]->kindex,kwds[j]->kname,i+1,mcol); wrterr(out,errmes,1); continue; } if(strchr(tform[i],'A') != NULL || strchr(tform[i],'L') != NULL || strchr(tform[i],'X') != NULL ) { sprintf(errmes, "Keyword #%d, %s is used in A, L, or X column. ", kwds[j]->kindex,kwds[j]->kname); wrterr(out,errmes,1); } } /* Check TZEROn keywords */ strcpy(temp,"TZERO"); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n); for (j = k; j< k + n ; j++){ p = kwds[j]->kname; p += 5; if(!isdigit((int)*p)) continue; check_flt(kwds[j],out); i = (int) strtol(p,NULL,10) -1 ; if(i< 0 || i >= mcol) { sprintf(errmes, "Keyword #%d, %s: invalid index %d (> TFIELD = %d).", kwds[j]->kindex,kwds[j]->kname,i+1,mcol); wrterr(out,errmes,1); continue; } if(strchr(tform[i],'A') != NULL && strchr(tform[i],'L') != NULL && strchr(tform[i],'X') != NULL ) { sprintf(errmes, "Keyword #%d, %s is used in A, L, or X column. ", kwds[j]->kindex,kwds[j]->kname); wrterr(out,errmes,1); } } /* Check THEAP keyword */ hduptr->heap = (hduptr->naxes[0]) * (hduptr->naxes[1]); strcpy(temp,"THEAP"); key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n); if(k > -1) { if(check_int(kwds[k],out)) hduptr->heap = (int) strtol(hduptr->kwds[k]->kvalue,NULL,10); if(!hduptr->pcount) { sprintf( errmes, "Pcount is zero, but keyword THEAP is present at record #%d). ", kwds[k]->kindex); wrterr(out,errmes,1); } } /* if PCOUNT != 0, test that there is at least 1 variable length array column */ vla = 0; if(hduptr->pcount) { for (i=0; i< mcol; i++){ if(fits_get_coltype(infits, i+1, &datatype, NULL, NULL, &status)){ sprintf(errmes,"Column #%d: ",i); wrtferr(out,errmes, &status,2); } if (datatype < 0) { vla = 1; break; } } if (vla == 0) { sprintf(errmes, "PCOUNT = %ld, but there are no variable-length array columns.", (long) hduptr->pcount); wrtwrn(out,errmes,0); } } /* Check TDIMn keywords */ strcpy(temp,"TDIM"); key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n); for (j = k; j< k + n ; j++){ pkey = kwds[j]; p = pkey->kname; p += 4; if(!isdigit((int)*p)) continue; check_str(kwds[j],out); if(*(pkey->kvalue) == ' ') { sprintf(errmes,"Keyword #%d, %s: TDIM=\"%s\" ", pkey->kindex,pkey->kname,pkey->kvalue); strcat(errmes, "should not have leading space."); wrterr(out,errmes,1); continue; } i = (int) strtol(p,NULL,10) -1 ; if(i< 0 || i >= mcol) { sprintf(errmes, "Keyword #%d, %s: invalid index %d (> TFIELD = %d).", kwds[j]->kindex,kwds[j]->kname,i+1,mcol); wrterr(out,errmes,1); continue; } if(fits_decode_tdim(infits,pkey->kvalue,i+1,10,&ntdim,tdim, &status)){ sprintf(errmes,"Keyword #%d, %s: ", kwds[j]->kindex,kwds[j]->kname); wrtferr(out,errmes,&status,1); } } /* check the local convension "rAw"*/ for (i = 0; i < hduptr->ncols; i++) { if((p = strchr(tform[i],'A'))==NULL) continue; repeat = (int) strtol(tform[i],NULL,10); p++; if(!isdigit((int)*p))continue; width = (int)strtol(p,NULL,10); if(repeat%width != 0) { sprintf(errmes, "TFORM %s of column %d: repeat %d is not the multiple of the width %d", tform[i], i+1, repeat, width); wrtwrn(out,errmes,0); } } for (i = 0; i < nexlkeys; i++) { strcpy(temp,exlkeys[i]); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n); if(k < 0) continue; for (j = k; j < k+n; j++) { pkey = hduptr->kwds[j]; p = kwds[j]->kname; p += strlen(temp); if(!isdigit((int)*p)) continue; sprintf( errmes, "Keyword #%d, %s is not allowed in the Binary table.", pkey->kindex,pkey->kname); wrterr(out,errmes,1); } } /* check whether the column name is unique */ test_colnam(out, hduptr); return ; } /************************************************************* * * test_header * * Test the general keywords that can be in any header * * *************************************************************/ void test_header( fitsfile *infits, /* input fits file */ FILE* out, /* output ascii file */ FitsHdu *hduptr /* information about header */ ) { /* common mandatory keywords */ char *mandkey[] = {"SIMPLE", "BITPIX", "NAXIS", "XTENSION", "END"}; /* not including NAXIS */ int nmandkey = 5; /* string keywords */ char *strkey[] = {"EXTNAME", "ORIGIN", "AUTHOR","CREATOR","REFERENC","TELESCOP", "INSTRUME", "OBSERVER", "OBJECT"}; int nstrkey = 9; /* int keywords */ char *intkey[] = {"EXTVER", "EXTLEVEL"}; int nintkey = 2; /* floating keywords */ char *fltkey[] = {"EQUINOX", "MJD-OBS", "MJD-AVG"}; int nfltkey = 3; FitsKey** kwds; /* FitsKey structure array */ int numusrkey; int i,j,k,n,ii,jj; long lv; unsigned long stat = 0; char* pt; char* p1; char* p2; char **pp; char* equals; char vtemp[72]; int status = 0; int yr, mn, dy, hr, min; /* time */ double sec; int yy; kwdtyp ktype; kwds = hduptr->kwds; numusrkey = hduptr->tkeys; /* Check the mandatory keywords */ for (i = 0; i < nmandkey; i++) { pp = &(mandkey[i]); key_match(tmpkwds,numusrkey,pp,1,&k,&n); if(k > -1) { for ( j = k; j < k + n; j++) { sprintf(errmes, "Keyword #%d, %s is duplicated or out of order.", kwds[j]->kindex,kwds[j]->kname); wrterr(out,errmes,1); } } } /* check the NAXIS index keyword */ strcpy(temp,"NAXIS"); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n); for ( j = k; j < k + n; j++) { pt = kwds[j]->kname+5; lv = strtol(pt,NULL,10); if(lv > 0 ){ if(kwds[j]->kindex != 3 + lv) { sprintf(errmes, "Keyword #%d, %s is duplicated or out of order.", kwds[j]->kindex,kwds[j]->kname); wrterr(out,errmes,1); } if(lv > hduptr->naxis) { sprintf(errmes, "Keyword #%d, %s is not allowed (with n > NAXIS =%d).", kwds[j]->kindex,kwds[j]->kname,hduptr->naxis); wrterr(out,errmes,1); } } } /* Check the deprecated keywords */ strcpy(temp,"EPOCH"); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n); if(k > -1) { sprintf(errmes, "Keyword #%d, %s is deprecated. Use EQUINOX instead.", kwds[k]->kindex, kwds[k]->kname); wrtwrn(out,errmes,0); check_flt(kwds[k],out); } /* Check the DATExxxx keyword */ strcpy(temp,"DATE"); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n); for (j = k; j< n + k ; j++){ check_str(kwds[j],out); if(fits_str2time(kwds[j]->kvalue, &yr, &mn, &dy, &hr, &min, &sec, &status)){ sprintf(errmes,"Keyword #%d, %s: ", kwds[j]->kindex,kwds[j]->kname); wrtserr(out,errmes,&status,1); } if( (pt = strchr(kwds[j]->kvalue,'/'))!=NULL) { pt +=4; yy = (int) strtol(pt,NULL,10); if(0 <= yy && yy <=10) { sprintf(errmes, "Keyword #%d, %s %s intends to mean year 20%-2.2d?", kwds[j]->kindex, kwds[j]->kname, kwds[j]->kvalue, yy); wrtwrn(out,errmes,0); } } } /* Check the reserved string keywords */ for (i = 0; i < nstrkey; i++) { strcpy(temp,strkey[i]); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n); if(k > -1) check_str(kwds[k],out); } /* Check the reserved int keywords */ for (i = 0; i < nintkey; i++) { strcpy(temp,intkey[i]); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n); if(k > -1) check_int(kwds[k],out); } /* Check reserved floating keywords */ for (i = 0; i < nfltkey; i++) { strcpy(temp,fltkey[i]); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n); if(k > -1) check_flt(kwds[k],out); } /* Check the duplication of the keywords */ for (i = 0; i < numusrkey-1; i++) { if(!strcmp(tmpkwds[i],tmpkwds[i+1])) { if (strcmp(kwds[i]->kname,"HIERARCH")) { sprintf(errmes, "Keyword %s is duplicated in card #%d and card #%d.", kwds[i]->kname, kwds[i]->kindex, kwds[i+1]->kindex); wrtwrn(out,errmes,0); } } } /* check the long string convention */ if (hduptr->use_longstr == 1) { strcpy(temp,"LONGSTRN"); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n); if(k <= -1) { sprintf(errmes, "The OGIP long string keyword convention is used without the recommended LONGSTRN keyword. "); wrtwrn(out,errmes,1); } } /* Check the HIERARCH keywords */ if (testhierarch) { strcpy(temp,"HIERARCH"); ptemp = temp; key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n); for (j = k; j< n + k ; j++){ i = (kwds[j]->kindex)-1; /* index number of the keyword */ /* Must have a space character following "HIERARCH" */ if (*(cards[i] + 8) != ' ') { sprintf(errmes, "Keyword #%d: does not have a space character in byte 9: %66s", i+1,cards[i]); wrterr(out,errmes,1); } /* Whether the characters in HIERARCH token names are valid */ pt = cards[i]; while(*pt != '\0' ){ ii = 0; if (*pt == '=' ) /* look for the required "=" sign */ break; if((*pt < 'A' || *pt > 'Z')&& (*pt < '0' || *pt > '9')&& (*pt != '-' && *pt != '_' && *pt != ' ') ) { sprintf(errmes, "Keyword #%d: token contains illegal char \"%c\" (only A-Z,0-9,-,_): %66s", i+1,*pt,cards[i]); wrterr(out,errmes,1); break; } pt++; ii++; } if (*pt == '\0') { /* the "=" is not present on the card */ sprintf(errmes, "Keyword #%d: does not contain the \"=\" value indicator char: %66s", i+1, cards[i]); wrterr(out,errmes,1); } else if (*pt == '=') { /* now check that the keyword has a legal value */ pt++; while (isspace((int)*pt) && *pt != '\0') pt++; switch (*pt) { case '\'': /* string */ get_str(&pt, vtemp,&stat); break; case 'T': case 'F': /*logical */ get_log(&pt, vtemp, &stat); break; case '+': case '-': case '.': /* number */ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': get_num(&pt, vtemp, &ktype, &stat); break; case '(': /* complex number */ get_cmp(&pt, vtemp, &ktype, &stat); break; case '/': /* comment */ break; default: get_unknown(&pt,vtemp,&ktype,&stat); } pr_kval_err(out,i+1,"HIERARCH",vtemp,stat); stat = 0; /* reset error status for next time */ } /* end of keyword value test */ } /* end of test of individual HIERARCH keywords */ /* now test for any duplicate HIERARCH keywords */ for (j = k; j< n + k -1 ; j++) { /* loop over all the HIERARCH keywords except the last */ i = (kwds[j]->kindex)-1; /* index number of the keyword */ equals = strchr(cards[i], '='); if (equals) { for (jj = j+1; jj< n + k ; jj++) { /* loop over any other HIERARCH keywords */ ii = (kwds[jj]->kindex)-1; /* index number of the keyword */ equals = strchr(cards[i], '='); if (equals) { /* compare names char by char, ignoring extra spaces */ p1 = cards[i] + 8; /*start at the end of the HIERARCH name */ p2 = cards[ii] + 8; while (*p1 == *p2) { /* chars are the same in both */ if (*p1 == ' ') { /* this is a space char */ /* skip over non-significant spaces in both name, then continue testing next chars */ while (*p1 == ' ') p1++; while (*p2 == ' ') p2++; } else if (*p1 == '=' ) { /* found '=' in both keywords */ sprintf(errmes, "HIERARCH keyword name is duplicated in cards #%d and card #%d: %66s", i+1, ii+1, cards[i]); wrtwrn(out,errmes,0); p1++; /* do this to prevent duplicate warning message, below */ break; } else { p1++; p2++; } } /* end of identical chars test */ /* chars are not identical */ /* test for special case where one is a '=' and other non-significant spaces followed by '=' */ /* first, skip over spaces in either name */ while (*p1 == ' ') p1++; while (*p2 == ' ') p2++; if (*p1 == '=' && *p2 == '=') { /* if we got here, then the names are the same except for non-significant spacing differences */ sprintf(errmes, "HIERARCH keyword name is duplicated in cards #%d and card #%d: %66s", i+1, ii+1, cards[i]); wrtwrn(out,errmes,0); break; } else { /* these HIERARCH keywords do not have idential tokens */ break; } } /* end of if second HIERARCH keyword has a '=' */ } /* end of loop over other HIERARCH keywords */ } /* end of if first HIERARCH keyword has a '=' */ } /* end of loop over all HIERARCH keywords */ } /* disabled this routine because it doesn't perform an useful tests test_img_wcs(infits, out, hduptr); */ return; } /************************************************************* * * key_match * * find the keywords whose name match the pattern. The keywords * name is stored in a sorted array. * * *************************************************************/ void key_match(char **strs, /* fits keyname array */ int nstr, /* total number of keys */ char **pattern, /* wanted pattern */ int exact, /* exact matching or pattern matching exact = 1: exact matching. exact = 0: pattern matching. Any keywords with "patten"* is included */ int *ikey, /* The element number of first key Return -99 if not found */ int *mkey /* total number of key matched return -999 if not found */ ) { char **p; char **pi; int i; int (*fnpt)(const void *, const void *); *mkey = -999; *ikey = -99; if(exact) fnpt = compstre; else fnpt = compstrp; p = (char **)bsearch(pattern, strs, nstr,sizeof(char *), fnpt); if(p) { *mkey = 1; *ikey = p - strs; pi = p; i = *ikey - 1; p--; while(i > 0 && !fnpt(pattern, p)) {*mkey += 1; *ikey =i; i--; p--;} p = pi; i = *ikey + *mkey; p++; while(i < nstr && !fnpt(pattern, p) ) {*mkey += 1; i++; p++;} } return; } /************************************************************* * * test_colnam * * Test the whether the column name is unique. * * *************************************************************/ void test_colnam(FILE *out, FitsHdu *hduptr) { int i,n; char *p, *q; ColName **cols; char **ttypecopy; n = hduptr->ncols; if(n <= 0) return; /* make a local working copy of ttype */ ttypecopy = (char **)malloc(n*sizeof(char *)); for (i = 0; i < n; i++) { ttypecopy[i] = (char *)malloc(FLEN_VALUE*sizeof(char)); strcpy(ttypecopy[i],ttype[i]); } /* check whether there are any other non ASCII-text characters (FITS standard R14). Also "uppercase" the working copies. */ for (i = 0; i < n; i++) { p = ttype[i]; q = ttypecopy[i]; if(!strlen(p)) { sprintf(errmes, "Column #%d has no name (No TTYPE%d keyword).",i+1, i+1); wrtwrn(out,errmes,0); continue; } /* disable this check (it was only a warning) if( (*p > 'z' || *p < 'a') && (*p > 'Z' || *p <'A') && (*p > '9' || *p < '0') ) { sprintf(errmes,"Column #%d: Name \"%s\" does not begin with a letter or a digit.",i+1,ttype[i]); wrtwrn(out,errmes,1); } */ while(*p != '\0') { if ((*p > 'z' || *p < 'a') && (*p > 'Z' || *p < 'A') && (*p > '9' || *p < '0') && (*p != '_')) { if (*p == '&') { sprintf(errmes, "Column #%d: Reserved column name keyword (TTYPE%d) may use an illegal CONTINUE (\'%c\')", i+1,i+1,*p); wrtwrn(out,errmes,0); } else { sprintf(errmes, "Column #%d: Name \"%s\" contains character \'%c\' other than letters, digits, and \"_\".", i+1,ttype[i],*p); wrtwrn(out,errmes,0); } } if(*p <= 'z' || *p >= 'a') *q = toupper(*p); p++; q++; } } cols = (ColName **)calloc(n, sizeof(ColName *)); for (i=0; i < n; i++) { cols[i] = (ColName *)malloc(sizeof(ColName)); cols[i]->name = ttypecopy[i]; cols[i]->index = i+1; } /* sort the column name in the ascending order of name field*/ qsort(cols, n, sizeof(ColName *), compcol); /* Check the duplication of the column name */ for (i = 0; i < n-1; i++) { if(!strlen(cols[i]->name)) continue; /* disable this warning if(!strncmp(cols[i]->name,cols[i+1]->name,16)) { sprintf(errmes, "Columns #%d, %s and #%d, %s are not unique within first 16 characters(case insensitive).", cols[i]->index, ttype[(cols[i]->index-1)], cols[i+1]->index, ttype[(cols[i+1]->index-1)]); wrtwrn(out,errmes,1); } */ if(!strcmp(cols[i]->name,cols[i+1]->name)) { sprintf(errmes, "Columns #%d, %s and #%d, %s are not unique (case insensitive).", cols[i]->index, ttype[(cols[i]->index-1)], cols[i+1]->index, ttype[(cols[i+1]->index-1)]); wrtwrn(out,errmes,0); } } for (i = 0; i < n; i++) { free(cols[i]); free(ttypecopy[i]);} free(cols); free(ttypecopy); return; } /************************************************************* * * parse_vtform * * Parse the tform of the variable length vector. * * *************************************************************/ void parse_vtform(fitsfile *infits, FILE *out, FitsHdu *hduptr, int colnum, /* column number */ int* datacode, /* data code */ long* maxlen, /* maximum length of the vector */ int* isQFormat /* true if var col is 'Q' format */ ) { int i = 0; int status = 0; char *p; *maxlen = -1; strcpy(temp,tform[colnum-1]); p = temp; if(isdigit((int)*p)) sscanf(ptemp,"%d",&i); if(i > 1) { sprintf(errmes,"Illegal repeat value for value %s of TFORM%d.", tform[colnum-1], colnum); wrterr(out,errmes,1); } while(isdigit((int)*p))p++; if( (*p != 'P') && (*p != 'Q') ) { sprintf(errmes, "TFORM%d is not for the variable length array: %s.", colnum, tform[colnum-1]); wrterr(out,errmes,1); } *isQFormat = (*p == 'Q') ? 1 : 0; fits_get_coltype(infits,colnum, datacode, NULL, NULL, &status); status = 0; p += 2; if(*p != '(') return; p++; if(!isdigit((int)*p)) { sprintf(errmes, "Bad value of TFORM%d: %s.",colnum,tform[colnum-1]); wrterr(out,errmes,1); } sscanf(p,"%ld",maxlen); while(isdigit((int)*p))p++; if(*p != ')') { sprintf(errmes, "Bad value of TFORM%d: %s.",colnum,tform[colnum-1]); wrterr(out,errmes,1); } return; } /************************************************************* * * print_title * * Print the title of the HDU. * when verbose < 2, called by wrterr and wrtwrn. * *************************************************************/ void print_title(FILE* out, int hdunum, int hdutype) { static char hdutitle[64]; static int oldhdu = 0; /* print out the title */ curhdu = hdunum; curtype = hdutype; if(oldhdu == curhdu) return; /* Do not print it twice */ if(curhdu == 1){ sprintf(hdutitle," HDU %d: Primary Array ", curhdu); } else { switch (curtype) { case IMAGE_HDU: sprintf(hdutitle," HDU %d: Image Exten. ", curhdu); break; case ASCII_TBL: sprintf(hdutitle," HDU %d: ASCII Table ", curhdu); break; case BINARY_TBL: sprintf(hdutitle," HDU %d: BINARY Table ", curhdu); break; default: sprintf(hdutitle," HDU %d: Unknown Ext. ", curhdu); break; } } wrtsep(out,'=',hdutitle,60); wrtout(out," "); oldhdu = curhdu; if(curhdu == totalhdu) oldhdu = 0; /* reset the old hdu at the last hdu */ return; } /************************************************************* * * print_header * * Print the header of the HDU. * *************************************************************/ void print_header(FILE* out) { char htemp[100]; int i; for (i=1; i <= ncards; i++) { sprintf(htemp,"%4d | %s",i,cards[i-1]); wrtout(out, htemp); } wrtout(out," "); return; } /************************************************************* * * print_summary * * Print out the summary of this hdu. * **************************************************************/ void print_summary(fitsfile *infits, /* input fits file */ FILE* out, /* output ascii file */ FitsHdu *hduptr ) { int i = 0; char extver[10]; char extnv[FLEN_VALUE]; long npix; int hdutype; /* get the error number and wrn number */ set_hduerr(hduptr->hdunum); hdutype = hduptr->hdutype; sprintf(comm," %d header keywords", hduptr->nkeys); wrtout(out,comm); wrtout(out," "); if(hdutype == ASCII_TBL || hdutype== BINARY_TBL) { sprintf(extnv, "%s",hduptr->extname); if (hduptr->extver!=-999) { sprintf(extver,"(%d)",hduptr->extver); strcat(extnv,extver); } #if (USE_LL_SUFFIX == 1) sprintf(comm," %s (%d columns x %lld rows)", extnv, hduptr->ncols, hduptr->naxes[1]); #else sprintf(comm," %s (%d columns x %ld rows)", extnv, hduptr->ncols, hduptr->naxes[1]); #endif wrtout(out,comm); if(hduptr->ncols) { wrtout(out," "); sprintf(comm, " Col# Name (Units) Format"); wrtout(out,comm); } for ( i = 0; i < hduptr->ncols; i++) { if(strlen(tunit[i])) sprintf(extnv,"%s (%s)",ttype[i],tunit[i]); else sprintf(extnv,"%s",ttype[i]); sprintf(comm," %3d %-20.20s %-10.10s", i+1, extnv, tform[i]); wrtout(out,comm); } } else if(hdutype == IMAGE_HDU && hduptr->isgroup) { sprintf(comm, " %d Random Groups, ",hduptr->gcount); switch(hduptr->bitpix) { case BYTE_IMG: strcpy(temp," 8-bit integer pixels, "); break; case SHORT_IMG: strcpy(temp," 16-bit integer pixels, "); break; case USHORT_IMG: strcpy(temp," 16-bit unsigned integer pixels, "); break; case LONG_IMG: strcpy(temp," 32-bit integer pixels, "); break; case LONGLONG_IMG: strcpy(temp," 64-bit long integer pixels, "); break; case ULONG_IMG: strcpy(temp," 32-bit unsigned integer pixels, "); break; case FLOAT_IMG: strcpy(temp," 32-bit floating point pixels, "); break; case DOUBLE_IMG: strcpy(temp," 64-bit double precision pixels, "); break; default: strcpy(temp," unknown datatype, "); break; } strcat(comm,temp); sprintf(temp," %d axes ",hduptr->naxis); strcat(comm,temp); #if (USE_LL_SUFFIX == 1) sprintf(temp, "(%lld",hduptr->naxes[0]); #else sprintf(temp, "(%ld",hduptr->naxes[0]); #endif strcat(comm,temp); npix = hduptr->naxes[0]; for ( i = 1; i < hduptr->naxis; i++){ npix *= hduptr->naxes[i]; #if (USE_LL_SUFFIX == 1) sprintf(temp, " x %lld",hduptr->naxes[i]); #else sprintf(temp, " x %ld",hduptr->naxes[i]); #endif strcat(comm,temp); } strcat(comm,"), "); wrtout(out,comm); } else if(hdutype == IMAGE_HDU) { if(hduptr->naxis > 0) { if(hduptr->hdunum == 1) { strcpy(extnv,""); } else { sprintf(extnv, "%s",hduptr->extname); if (hduptr->extver!=-999) { sprintf(extver," (%d)",hduptr->extver); strcat(extnv,extver); } } strcpy(comm,extnv); switch(hduptr->bitpix) { case BYTE_IMG: strcpy(temp," 8-bit integer pixels, "); break; case SHORT_IMG: strcpy(temp," 16-bit integer pixels, "); break; case USHORT_IMG: strcpy(temp," 16-bit unsigned integer pixels, "); break; case LONG_IMG: strcpy(temp," 32-bit integer pixels, "); break; case LONGLONG_IMG: strcpy(temp," 64-bit long integer pixels, "); break; case ULONG_IMG: strcpy(temp," 32-bit unsigned integer pixels, "); break; case FLOAT_IMG: strcpy(temp," 32-bit floating point pixels, "); break; case DOUBLE_IMG: strcpy(temp," 64-bit double precision pixels, "); break; default: strcpy(temp," unknown datatype, "); break; } strcat(comm,temp); sprintf(temp," %d axes ",hduptr->naxis); strcat(comm,temp); #if (USE_LL_SUFFIX == 1) sprintf(temp, "(%lld",hduptr->naxes[0]); #else sprintf(temp, "(%ld",hduptr->naxes[0]); #endif strcat(comm,temp); npix = hduptr->naxes[0]; for ( i = 1; i < hduptr->naxis; i++){ npix *= hduptr->naxes[i]; #if (USE_LL_SUFFIX == 1) sprintf(temp, " x %lld",hduptr->naxes[i]); #else sprintf(temp, " x %ld",hduptr->naxes[i]); #endif strcat(comm,temp); } strcat(comm,"), "); wrtout(out,comm); } else{ sprintf(comm," Null data array; NAXIS = 0 "); wrtout(out,comm); } } wrtout(out," "); return; } /************************************************************* * * close_hdu * * Free the memory allocated to the FitsHdu structure and * other temporary spaces. * **************************************************************/ void close_hdu( FitsHdu *hduptr ) { int i; int n; /* free memories */ for (i=0; i < ncards; i++) free(cards[i]); n = hduptr->nkeys - 4 - hduptr->naxis ; /* excluding the SIMPLE, BITPIX, NAXIS, NAXISn and END */ for (i=0; i < n; i++) free(hduptr->kwds[i]); for (i=0; i < hduptr->ncols; i++) { free(hduptr->datamin[i]); free(hduptr->datamax[i]); free(hduptr->tnull[i]); } if(hduptr->hdutype == ASCII_TBL && hduptr->hdutype == BINARY_TBL){ if(hduptr->ncols > 0)free(ttype); if(hduptr->ncols > 0)free(tunit); if(hduptr->ncols > 0)free(tform); } if(hduptr->naxis) free(hduptr->naxes); if(hduptr->ncols > 0)free(hduptr->datamax); if(hduptr->ncols > 0)free(hduptr->datamin); if(hduptr->ncols > 0)free(hduptr->tnull); free(hduptr->kwds); free(cards); free(tmpkwds); return; } fitsverify-4.22/License.txt0000664000220700007640000000260213133202264015550 0ustar birbywwwgroupCopyright (Unpublished--all rights reserved under the copyright laws of the United States), U.S. Government as represented by the Administrator of the National Aeronautics and Space Administration. No copyright is claimed in the United States under Title 17, U.S. Code. Permission to freely use, copy, modify, and distribute this software and its documentation without fee is hereby granted, provided that this copyright notice and disclaimer of warranty appears in all copies. DISCLAIMER: THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT SHALL NASA BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, CONTRACT, TORT , OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. fitsverify-4.22/fvrf_data.c0000644000220700000360000006653414357326015014553 0ustar birbylhea#include "fverify.h" typedef struct { int nnum; int ncmp; int nfloat; int *indatatyp; double *datamax; double *datamin; double *tnull; unsigned char *mask; /* for bit X column only */ int ntxt; FitsHdu *hduptr; FILE* out; }UserIter; /************************************************************* * * test_data * * Test the HDU data * * This routine reads every row and column of ASCII tables to * verify that the values have the correct format. * * This routine checks the following types of columns in binary tables: * * Logical L - value must be T, F or zero * Bit nX - if n != a multiple of 8, then check that fill bits = 0 * String A - must contain ascii text, or zero * * It is impossible to write an invalid value to the other types of * columns in binary tables (B, I, J, K, E, D, C and M) so these * columns are not read. * * Since it is impossible to write an invalid value in a FITS image, * this routine does not read the image pixels. * *************************************************************/ void test_data(fitsfile *infits, /* input fits file */ FILE *out, /* output ascii file */ FitsHdu *hduptr /* fits hdu pointer */ ) { iteratorCol *iter_col=0; int ncols; int nnum = 0; int *numlist; /* the list of the column whose data type is numerical(scalar and complex) */ int nfloat = 0; int *floatlist; /* the list of the floating point columns in ASCII table */ int ncmp = 0; int *cmplist; /* the list of the column whose data type is numerical(scalar and complex) */ int ntxt = 0; int *txtlist; /* the list of column whose data type is string, logical, bit or complex */ int niter = 0; /* total columns read into the literator function */ int ndesc = 0; int *desclist; /* the list of column which is the descriptor of the variable length array. */ int *isVarQFormat; /* Format type for each of the ndesc variable-length columns: 0 = type 'P', 1 = type 'Q' */ long rows_per_loop = 0, offset; UserIter usrdata; int datatype; long repeat; long totalrows; LONGLONG length; LONGLONG toffset; long *maxlen; int icol; char *cdata; double *ndata; int *idata; int *maxminflag; int *dflag; char lnull = 2; int anynul; long rlength; long bytelength; long maxmax; int i = 0; int j = 0; long jl = 0; long k = 0; int status = 0; char errtmp[80]; int* perbyte; LONGLONG naxis2; int largeVarLengthWarned = 0; int largeVarOffsetWarned = 0; if(testcsum) test_checksum(infits,out); if(testfill) { test_agap(infits,out,hduptr); /* test the bytes between the ascii table columns. */ if(ffcdfl(infits, &status)) { wrtferr(out,"checking data fill: ", &status, 1); status = 0; } } if(hduptr->hdutype != ASCII_TBL && hduptr->hdutype != BINARY_TBL ) return; ncols = hduptr->ncols; if(ncols <= 0) return; ffgkyjj(infits, "NAXIS2", &naxis2, NULL, &status); if (naxis2 > 2147483647) { wrtout(out, "Cannot test data in tables with more than 2**31 (2147483647) rows."); return; } /* separate the numerical, complex, text and the variable length vector columns */ numlist =(int*)malloc(ncols * sizeof(int)); floatlist =(int*)malloc(ncols * sizeof(int)); cmplist =(int*)malloc(ncols * sizeof(int)); txtlist =(int*)malloc(ncols * sizeof(int)); desclist =(int*)malloc(ncols * sizeof(int)); if(hduptr->hdutype == ASCII_TBL) { /*read every column of an ASCII table */ rows_per_loop = 0; for (i=0; i< ncols; i++){ if(fits_get_coltype(infits, i+1, &datatype, NULL, NULL, &status)){ sprintf(errmes,"Column #%d: ",i); wrtferr(out,errmes, &status,2); } if ( datatype != TSTRING ) { numlist[nnum] = i+1; nnum++; if (datatype > TLONG) { /* floating point number column */ floatlist[nfloat] = i + 1; nfloat++; } } else { txtlist[ntxt] = i+1; ntxt++; } } } else if (hduptr->hdutype == BINARY_TBL) { /* only check Bit, Logical and String columns in Binary tables */ rows_per_loop = 0; for (i=0; i< ncols; i++){ if(fits_get_coltype(infits, i+1, &datatype, &repeat, NULL, &status)){ sprintf(errmes,"Column #%d: ",i); wrtferr(out,errmes, &status,2); } if(datatype < 0) { /* variable length column */ desclist[ndesc] = i+1; ndesc++; } else if(datatype == TBIT && (repeat%8) ) { /* bit column that does not have a multiple of 8 bits */ numlist[nnum] = i+1; nnum++; } else if( (datatype == TLOGICAL) || (datatype == TSTRING ) ) { txtlist[ntxt] = i+1; ntxt++; } /* ignore all other types of columns (B I J K E D C and M ) */ } } /* Use Iterator to read the columns that are not variable length arrays */ /* columns from 1 to nnum are scalar numerical columns. columns from nnum+1 to nnum+ncmp are complex columns. columns from nnum+ncmp are text columns */ niter = nnum + ncmp + ntxt + nfloat; if(niter)iter_col = (iteratorCol *) malloc (sizeof(iteratorCol)*niter); for (i=0; i< nnum; i++){ fits_iter_set_by_num(&iter_col[i], infits, numlist[i], TDOUBLE, InputCol); } for (i=0; i< ncmp; i++){ j = nnum + i; fits_iter_set_by_num(&iter_col[j], infits, cmplist[i], TDBLCOMPLEX, InputCol); } for (i=0; i< ntxt; i++){ j = nnum + ncmp + i; fits_iter_set_by_num(&iter_col[j], infits, txtlist[i], 0, InputCol); } for (i=0; i< nfloat; i++){ j = nnum + ncmp + ntxt + i; fits_iter_set_by_num(&iter_col[j], infits, floatlist[i], TSTRING, InputCol); } offset = 0; usrdata.nnum = nnum; usrdata.ncmp = ncmp; if (nnum > 0 || ncmp > 0) { usrdata.datamax = (double *)calloc((nnum+ncmp), sizeof(double)); usrdata.datamin = (double *)calloc((nnum+ncmp), sizeof(double)); } usrdata.tnull = (double *)calloc(ncols, sizeof(double)); usrdata.ntxt = ntxt; usrdata.hduptr = hduptr; usrdata.out = out; usrdata.nfloat = nfloat; /* get the mask for the bit X column for column other than the X, it always 255 for Column nX, it will be 000...111, where # of 0 is n%8, # of 1 is 8 - n%8. */ if(nnum > 0) usrdata.mask = (unsigned char *)calloc(nnum,sizeof( unsigned char)); if(nnum > 0) usrdata.indatatyp = (int *)calloc(nnum,sizeof( int)); for (i=0; i< nnum; i++){ j = fits_iter_get_colnum(&(iter_col[i])); if(fits_get_coltype(infits, j, &datatype, &repeat, NULL, &status)){ sprintf(errmes,"Column #%d: ",i); wrtferr(out,errmes, &status,2); } usrdata.indatatyp[i] = datatype; usrdata.mask[i] = 255; if(datatype == TBIT) { repeat = repeat%8; usrdata.mask[i] = (usrdata.mask[i])>>repeat; if(!repeat) usrdata.mask[i] = 0; } } if(niter > 0) { if(fits_iterate_data(niter, iter_col, offset,rows_per_loop, iterdata, &usrdata,&status)){ wrtserr(out,"When Reading data, ",&status,2); } } if(niter>0) free(iter_col); free(numlist); free(floatlist); free(cmplist); free(txtlist); if(nnum > 0) free(usrdata.mask); if(nnum > 0) free(usrdata.indatatyp); if(nnum > 0 || ncmp > 0) { free(usrdata.datamax); free(usrdata.datamin); } free(usrdata.tnull); if(!ndesc ) { goto data_end; } /* ------------read the variable length vectors -------------------*/ usrdata.datamax = (double *)calloc(ndesc, sizeof(double)); usrdata.datamin = (double *)calloc(ndesc, sizeof(double)); usrdata.tnull = (double *)calloc(ndesc, sizeof(double)); maxminflag = (int *) calloc(ndesc , sizeof(int)); maxlen = (long *) calloc(ndesc , sizeof(long)); dflag = (int *) calloc(ndesc , sizeof(int)); perbyte = (int *) calloc(ndesc , sizeof(int)); isVarQFormat = (int *) calloc(ndesc , sizeof(int)); fits_get_num_rows(infits,&totalrows,&status); status = 0; /* this routine now only reads and test BIT, LOGICAL, and STRING columns */ /* There is no point in reading the other columns because the other datatypes */ /* have no possible invalid values. */ for (i = 0; i < ndesc; i++) { icol = desclist[i]; parse_vtform(infits,out,hduptr,icol,&datatype,&maxlen[i],&isVarQFormat[i]); dflag[i] = 4; switch (datatype) { case -TBIT: dflag[i] = 1; perbyte[i] = -8; break; case -TBYTE: perbyte[i] = 1; break; case -TLOGICAL: dflag[i] = 3; perbyte[i] = 1; break; case -TSTRING: dflag[i] = 0; perbyte[i] = 1; break; case -TSHORT: perbyte[i] = 2; break; case -TLONG: perbyte[i] = 4; break; case -TFLOAT: perbyte[i] = 4; break; case -TDOUBLE: perbyte[i] = 8; break; case -TCOMPLEX: dflag[i] = 2; perbyte[i] = 8; break; case -TDBLCOMPLEX: dflag[i] = 2; perbyte[i] = 16; break; default: break; } } maxmax = maxlen[0]; for (i = 1; i < ndesc; i++) { if(maxmax < maxlen[i]) maxmax = maxlen[i]; } if(maxmax < 0) maxmax = 100; ndata = (double *)malloc(2*maxmax*sizeof(double)); cdata = (char *)malloc((maxmax+1) *sizeof(char)); idata = (int *)malloc(maxmax *sizeof(int)); for (jl = 1; jl <= totalrows; jl++) { for (i = 0; i < ndesc; i++) { icol = desclist[i]; /* read and check the descriptor length and offset values */ if(fits_read_descriptll(infits, icol ,jl,&length, &toffset, &status)){ sprintf(errtmp,"Row #%ld Col.#%d: ",jl,icol); wrtferr(out,errtmp,&status,2); } if (!isVarQFormat[i]) { if (!largeVarLengthWarned && length > 2147483647) { strcpy(errmes,"Var row length exceeds maximum 32-bit signed int. "); sprintf(errtmp,"First detected for Row #%ld Column #%d",jl,icol); strcat(errmes,errtmp); wrtwrn(out,errmes,0); largeVarLengthWarned = 1; } if (!largeVarOffsetWarned && toffset > 2147483647) { strcpy(errmes,"Heap offset for var length row exceeds maximum 32-bit signed int. "); sprintf(errtmp,"First detected for Row #%ld Column #%d",jl,icol); strcat(errmes,errtmp); wrtwrn(out,errmes,0); largeVarOffsetWarned = 1; } } if(length > maxlen[i] && maxlen[i] > -1 ) { sprintf(errmes, "Descriptor of Column #%d at Row %ld: ", icol, jl); sprintf(errtmp,"nelem(%ld) > maxlen(%ld) given by TFORM%d.", (long) length,maxlen[i],icol); strcat(errmes,errtmp); wrterr(out,errmes,1); } if( perbyte[i] < 0) bytelength = length/8; else bytelength = length*perbyte[i]; if(toffset + bytelength > hduptr->pcount ) { sprintf(errmes, "Descriptor of Column #%d at Row %ld: ", icol, jl); sprintf(errtmp, " offset of first element(%ld) + nelem(%ld)", (long) toffset, (long) length); strcat(errmes,errtmp); if(perbyte[i] < 0) sprintf(errtmp, "/8 > total heap area = %ld.", (long) hduptr->pcount); else sprintf(errtmp, "*%d > total heap area = %ld.", perbyte[i], (long) hduptr->pcount); strcat(errmes,errtmp); wrterr(out,errmes,2); } if(!length) continue; /* skip the 0 length array */ /* now check the values in BIT, LOGICAL, and String columns */ rlength = length; if(length > maxmax) rlength = maxmax; if(dflag[i] == 1) { /* read BIT column */ anynul = 0; /* NOT YET IMPLEMENTED: This code should test that the fill bits that pad out the last byte are all zero. Currently this test is applied to fixed length logical arrays, but has not yet been done for the variable length logical array case. It is probably safe to assume that not many FITS files will contain variable length Logical columns, to adding this test is not a high priority. if(fits_read_col(infits, TDOUBLE, icol , jl, 1, nelem, &nullval, ndata, &anynul, &status)) { wrtferr(out,"",&status,2); } */ } else if(dflag[i] == 0) { /* read String column */ if(fits_read_col(infits, TSTRING, icol, jl, 1, rlength, NULL, &cdata, &anynul, &status)) { sprintf(errtmp,"Row #%ld Col.#%d: ",jl,icol); wrtferr(out,errtmp,&status,2); } else { j = 0; while (cdata[j] != 0) { if ((cdata[j] > 126) || (cdata[j] < 32) ) { sprintf(errmes, "String in row #%ld, and column #%d contains non-ASCII text.", jl,icol); wrterr(out,errmes,1); strcpy(errmes, " (This error is reported only once; other rows may have errors)."); print_fmt(out,errmes,13); break; } j++; } } } else if(dflag[i] == 3) { /* read Logical column */ if(fits_read_col(infits, TLOGICAL, icol, jl, 1, rlength, &lnull, cdata, &anynul, &status)) { sprintf(errtmp,"Row #%ld Col.#%d: ",jl,icol); wrtferr(out,errtmp,&status,2); } else { for (k = 0; k < rlength; k++) { if (cdata[k] > 2) { sprintf(errmes, "Logical value in row #%ld, column #%d not equal to 'T', 'F', or 0", jl, icol); wrterr(out,errmes,1); strcpy(errmes, " (This error is reported only once; other rows may have errors)."); print_fmt(out,errmes,13); break; } } } } } } free(ndata); free(cdata); free(idata); free(usrdata.datamax); free(usrdata.datamin); free(usrdata.tnull); free(maxminflag); free(maxlen); free(dflag); free(perbyte); free(isVarQFormat); data_end: free(desclist); for ( i = 0; i< ncols; i++) { (hduptr->datamax[i])[12] = '\0'; (hduptr->datamin[i])[12] = '\0'; (hduptr->tnull[i])[11] = '\0'; } return; } /***********************************************************************/ /* iterator work function */ int iterdata(long totaln, long offset, long firstn, long nrows, int narray, iteratorCol *iter_col, void *usrdata ) { static UserIter *usrpt; /* static FitsHdu *hdupt; */ static int nnum; static int ntxt; static int ncmp; static int nfloat; static int *flag_minmax = 0; /* define the initial min and max value */ static long *repeat; static int *datatype; static int find_badbit = 0; static int find_baddot = 0; static int find_badspace = 0; static int find_badchar = 0; static int find_badlog = 0; double *data; unsigned char *ldata; char **cdata; unsigned char *ucdata; char *floatvalue; /* bit column working space */ static unsigned char bdata; int i; long j,k,l; long nelem; if(firstn == 1 ) { /* first time for this table, so initialize */ usrpt = (UserIter *)usrdata; /* hdupt= usrpt->hduptr; */ nnum = usrpt->nnum; ncmp = usrpt->ncmp; ntxt = usrpt->ntxt; nfloat = usrpt->nfloat; flag_minmax = (int *)calloc(nnum+ncmp, sizeof(int)); repeat = (long *)calloc(narray,sizeof(long)); datatype = (int *)calloc(narray,sizeof(int)); for (i=0; i < narray; i++) { repeat[i] = fits_iter_get_repeat(&(iter_col[i])); datatype[i] = fits_iter_get_datatype(&(iter_col[i])); } find_badbit = 0; find_baddot = 0; find_badspace = 0; find_badchar = 0; find_badlog = 0; } /* columns from 1 to nnum are scalar numerical columns. columns from nnum+1 to nnum+ncmp are complex columns. (not used any more) columns from nnum+ncmp are text columns */ /* deal with the numerical column */ for (i=0; i < nnum+ncmp; i++) { data = (double *) fits_iter_get_array(&(iter_col[i])); j = 1; nelem = nrows * repeat[i]; if(i >= nnum) nelem = 2 * nrows *repeat[i]; if(nelem == 0) continue; find_badbit = 0; /* check for the bit jurisfication */ if(!find_badbit && usrpt->indatatyp[i] == TBIT ) { for (k = 0; k < nrows; k++) { j = (k+1)*repeat[i]; bdata = (unsigned char)data[j]; if( bdata & usrpt->mask[i] ) { sprintf(errmes, "Row #%ld, and Column #%d: X vector ", firstn+k, fits_iter_get_colnum(&(iter_col[i]))); for (l = 1; l<= repeat[i]; l++) { sprintf(comm, "0x%02x ", (unsigned char) data[k*repeat[i]+l]); strcat(errmes,comm); } strcat(errmes,"is not left justified."); wrterr(usrpt->out,errmes,2); strcpy(errmes, " (Other rows may have errors)."); print_fmt(usrpt->out,errmes,13); find_badbit = 1; break; } } } } /* deal with character and logical columns */ for (i = nnum + ncmp; i < nnum + ncmp + ntxt; i++) { if(datatype[i] == TSTRING ) { /* character */ nelem = nrows; if(nelem == 0) continue; cdata = (char **) fits_iter_get_array(&(iter_col[i])); find_badchar = 0; /* test for illegal ASCII text characters > 126 or < 32 */ if (!find_badchar) { for (k = 0; k < nrows; k++) { ucdata = (unsigned char *)cdata[k+1]; j = 0; while (ucdata[j] != 0) { if ((ucdata[j] > 126) || (ucdata[j] < 32)) { sprintf(errmes, "String in row #%ld, column #%d contains non-ASCII text.", firstn+k, fits_iter_get_colnum(&(iter_col[i]))); wrterr(usrpt->out,errmes,1); strcpy(errmes, " (Other rows may have errors)."); print_fmt(usrpt->out,errmes,13); find_badchar = 1; break; } j++; } } } } else { /* logical value */ nelem = nrows * repeat[i]; if(nelem == 0) continue; ldata = (unsigned char *) fits_iter_get_array(&(iter_col[i])); /* test for illegal logical column values */ /* The first element in the array gives the value that is used to represent nulls */ if (!find_badlog) { for(j = 1; j <= nrows * repeat[i]; j++) { if (ldata[j] > 2) { sprintf(errmes, "Logical value in row #%ld, column #%d not equal to 'T', 'F', or 0", (firstn+j - 2)/repeat[i] +1, fits_iter_get_colnum(&(iter_col[i]))); wrterr(usrpt->out,errmes,1); strcpy(errmes, " (Other rows may have similar errors)."); print_fmt(usrpt->out,errmes,13); find_badlog = 1; break; } } } } } for (i = nnum + ncmp +ntxt; i < nnum + ncmp + ntxt + nfloat; i++) { nelem = nrows; if(nelem == 0) continue; cdata = (char **) fits_iter_get_array(&(iter_col[i])); find_baddot = 0; find_badspace = 0; /* test for missing (implicit) decimal point in floating point numbers */ if (!find_baddot) { for (k = 0; k < nrows; k++) { floatvalue = (char *)cdata[k+1]; if (strcmp(cdata[0], floatvalue) && !strchr(floatvalue, '.') ) { while (*floatvalue == ' ') /* skip leading spaces */ floatvalue++; if (strlen(floatvalue)) { /* ignore completely blank fields */ sprintf(errmes, "Number in row #%ld, column #%d has no decimal point:", firstn+k, fits_iter_get_colnum(&(iter_col[i]))); wrterr(usrpt->out,errmes,1); strcpy(errmes, floatvalue); strcat(errmes, " (Other rows may have similar errors)."); print_fmt(usrpt->out,errmes,13); find_baddot = 1; break; } } } } if (!find_badspace) { for (k = 0; k < nrows; k++) { floatvalue = (char *)cdata[k+1]; if (strcmp(cdata[0], floatvalue) ) { /* not a null value? */ while (*floatvalue == ' ') /* skip leading spaces */ floatvalue++; l = strlen(floatvalue) - 1; while (l > 0 && floatvalue[l] == ' ') { /* remove trailing spaces */ floatvalue[l] = '\0'; l--; } if (strchr(floatvalue, ' ') ) { sprintf(errmes, "Number in row #%ld, column #%d has embedded space:", firstn+k, fits_iter_get_colnum(&(iter_col[i]))); wrterr(usrpt->out,errmes,1); strcpy(errmes, floatvalue); strcat(errmes, " (Other rows may have similar errors)."); print_fmt(usrpt->out,errmes,13); find_badspace = 1; break; } } } } } if(firstn + nrows - 1 == totaln) { free(flag_minmax); free(datatype); free(repeat); } return 0; } /************************************************************* * * test_agap * * Test the bytes between the ASCII table column. * * *************************************************************/ void test_agap(fitsfile *infits, /* input fits file */ FILE *out, /* output ascii file */ FitsHdu *hduptr /* fits hdu pointer */ ) { int ncols; LONGLONG nrows; long irows; LONGLONG rowlen; unsigned char *data; int *temp; unsigned char *p; LONGLONG i, j; int k, m, t; long firstrow = 1; long ntodo; long nerr = 0; int status = 0; char keyname[9]; char tform[FLEN_VALUE], comment[256]; int typecode, decimals; long width, tbcol; nerr = 0; if(hduptr->hdutype != ASCII_TBL) return; ncols = hduptr->ncols; fits_get_num_rowsll(infits,&nrows,&status); status = 0; fits_get_rowsize(infits, &irows, &status); status = 0; rowlen = hduptr->naxes[0]; data = (unsigned char*)malloc(rowlen*sizeof(unsigned char)*irows); /* Create a template row with data fields filled with 1s. Used below - different ASCII rules apply within data columns vs. between data columns. */ temp = (int*)malloc(rowlen * sizeof(int)); for (m = 0; m 0) { if( i > irows) ntodo = irows; else ntodo = i; p = data; if(fits_read_tblbytes(infits,firstrow,1, rowlen*ntodo, data, &status)){ wrtferr(out,"",&status,1); } for (j = 0; j #include #include #include #include #include #include "fitsio.h" #define MAXERRORS 200 #define MAXWRNS 200 static char errmes[256]; static char comm[FLEN_FILENAME+6]; extern int prhead; extern int testdata; extern int testfill; extern int testcsum; extern int totalhdu; /* total number of hdu */ extern int err_report; extern int heasarc_conv; extern int testhierarch; extern int prstat; /******************************** * * * Keywords * * * ********************************/ typedef enum { STR_KEY, /* string key */ LOG_KEY, /* Logical key */ INT_KEY, /* Integer key */ FLT_KEY, /* Float key */ CMI_KEY, /* Complex integer key */ CMF_KEY, /* Complex float key */ COM_KEY, /* history, comment, " ", and end */ UNKNOWN /* Unknown types */ } kwdtyp; /* error number masks of the keyword test */ #define BAD_STR 0X0001 #define NO_TRAIL_QUOTE 0X0002 #define BAD_NUM 0X0004 #define LOWCASE_EXPO 0X0008 #define NO_TRAIL_PAREN 0X0010 #define NO_COMMA 0X0020 #define TOO_MANY_COMMA 0X0040 #define BAD_REAL 0X0080 #define BAD_IMG 0X0100 #define BAD_LOGICAL 0x0200 #define NO_START_SLASH 0X0400 #define BAD_COMMENT 0x0800 #define UNKNOWN_TYPE 0x1000 /* keyword structure */ typedef struct { char kname[FLEN_KEYWORD]; /* fits keyword name */ kwdtyp ktype; /* fits keyword type */ char kvalue[FLEN_VALUE]; /* fits keyword name */ int kindex; /* position at the header */ int goodkey; /* good keyword flag (=1 good)*/ }FitsKey; int fits_parse_card(FILE *out, int pos, char *card, char *kname, kwdtyp *ktype, char *kvalue, char *kcomm); void get_str(char **p, char *kvalue, unsigned long *stat); void get_log(char **p, char *kvalue, unsigned long *stat); void get_num(char **p, char *kvalue, kwdtyp *ktype, unsigned long *stat); void get_cmp(char **p, char *kvalue, kwdtyp *ktype, unsigned long *stat); int check_str(FitsKey* pkey, FILE *out); int check_int(FitsKey* pkey, FILE *out); int check_flt(FitsKey* pkey, FILE *out); int check_cmi(FitsKey* pkey, FILE *out); int check_cmf(FitsKey* pkey, FILE *out); int check_log(FitsKey* pkey, FILE *out); int check_fixed_int(char *card, FILE *out); int check_fixed_log(char *card, FILE *out); int check_fixed_str(char *card, FILE *out); void get_unknown(char **p, char *kvalue, kwdtyp *ktype, unsigned long *stat); void get_comm(char **p, char *kcomm, unsigned long *stat); void pr_kval_err(FILE *out, int pos, char *keyname, char *keyval, unsigned long stat); /******************************** * * * Headers * * * ********************************/ typedef struct { int hdutype; /* hdutype */ int hdunum; /* hdunum */ int isgroup; /* random group flag */ int istilecompressed; /* tile compressed image */ int gcount; /* gcount */ LONGLONG pcount; /* pcount */ int bitpix; /* pix number */ int naxis; /* number of the axis,used for image array*/ LONGLONG *naxes; /* dimension of each axis,used for image array*/ int ncols; /* number of the columns, used for image only*/ char extname[FLEN_VALUE]; /* EXTENSION NAME */ int extver; /* extension version */ char **datamax; /* strings for the maximum of the data in a column */ char **datamin; /* strings for the minimum of the data in a column */ char **tnull; /* number of NULL values */ int nkeys; /* number of keys */ int tkeys; /* total of the keys tested*/ int heap; /* heap */ FitsKey **kwds; /* keywords list starting from the last NAXISn keyword. The array is sorted in the ascending alphabetical order of keyword names. The last keyword END and commentary keywords are excluded. The total number of element, tkey, is nkeys - 4 - naxis - ncomm. */ int use_longstr; /* flag indicates that the long string convention is used */ }FitsHdu; typedef struct { char * name; int index; }ColName; int verify_fits(char *infile, FILE *out); void leave_early (FILE* out); void close_err(FILE* out); void init_hdu(fitsfile *infits, FILE *out, int hdunum, int hdutype, FitsHdu *hduptr); void test_hdu(fitsfile *infits, FILE *out, FitsHdu *hduptr); void test_ext(fitsfile *infits, FILE *out, FitsHdu *hduptr); void test_tbl(fitsfile *infits, FILE *out, FitsHdu *hduptr); void test_array(fitsfile *infits, FILE *out, FitsHdu *hduptr); void test_prm(fitsfile *infits, FILE *out, FitsHdu *hduptr); void test_img_ext(fitsfile *infits, FILE *out, FitsHdu *hduptr); void test_asc_ext(fitsfile *infits, FILE *out, FitsHdu *hduptr); void test_bin_ext(fitsfile *infits, FILE *out, FitsHdu *hduptr); void test_header(fitsfile *infits, FILE *out, FitsHdu *hduptr); void key_match(char **strs, int nstr, char **pattern, int exact, int *ikey, int *mkey); void test_colnam(FILE *out, FitsHdu *hduptr); void parse_vtform(fitsfile *infits, FILE *out, FitsHdu *hduptr, int colnum, int *datacode, long *maxlen, int *isQFormat); void print_title(FILE* out, int hdunum, int hdutype); void print_header(FILE* out); void print_summary(fitsfile *infits, FILE *out, FitsHdu *hduptr); void close_hdu(FitsHdu *hduptr); /******************************** * * * Data * * * ********************************/ void test_data(fitsfile *infits, FILE *out, FitsHdu *hduptr); void test_agap(fitsfile *infits, FILE *out, FitsHdu *hduptr); void test_checksum(fitsfile *infits, FILE *out); int iterdata(long totaln, long offset, long firstn, long nrows, int narrays, iteratorCol *iter_col, void *usrdata); /******************************** * * * Files * * * ********************************/ typedef struct { int hdutype; /* hdutype */ int hdunum; /* hdunum */ char extname[FLEN_VALUE]; /* extension name, used for extension*/ int extver; /* extension version, used for extension */ int errnum; /* number of errors in this hdu */ int wrnno; /* number of warnning in this hdu */ }HduName; int get_total_warn(); int get_total_err(); void init_hduname(); void set_hduname(int hdunum,int hdutype, char* extname,int extver); void set_hduerr(int hdunum); void set_hdubasic(int hdunum,int hdutype); int test_hduname(int hdunum1, int hdunum2); void total_errors (int *totalerr, int * totalwrn); void hdus_summary(FILE *out); void destroy_hduname(); void test_end(fitsfile *infits, FILE *out); void init_report(FILE *out, char *rootnam); void close_report(FILE *out); void update_parfile(int numerr, int numwrn); /******************************** * * * Miscellaneous * * * ********************************/ void print_fmt(FILE *out, char *temp, int nprompt); int wrtout (FILE *out,char *comm); int wrterr (FILE *out,char *comm, int severity); int wrtwrn (FILE *out,char *comm, int heasarc); int wrtferr(FILE *out, char* mess, int *status, int severity); int wrtserr(FILE *out, char* mess, int *status, int severity); void wrtsep (FILE *out,char fill, char *title, int nchar); void num_err_wrn(int *num_err, int *num_wrn); void reset_err_wrn(); int compkey (const void *key1, const void *key2); int compcol (const void *col1, const void *col2); int compcol (const void *col1, const void *col2); int compstrp (const void *str1, const void *str2); int compstre (const void *str1, const void *str2); #endif fitsverify-4.22/fvrf_file.c0000644000220700000360000001672314100567764014560 0ustar birbylhea#include "fverify.h" static HduName **hduname; static int total_err=1; /* initialzed to 1 in case fail to open file */ static int total_warn=0; int get_total_warn() { return (total_warn); } int get_total_err() { return (total_err); } /* Get the total hdu number and allocate the memory for hdu array */ void init_hduname() { int i; /* allocate memories for the hdu structure array */ hduname = (HduName **)malloc(totalhdu*sizeof(HduName *)); for (i=0; i < totalhdu; i++) { hduname[i] = (HduName *)calloc(1, sizeof(HduName)); hduname[i]->hdutype = -1; hduname[i]->errnum = 0; hduname[i]->wrnno = 0; strcpy(hduname[i]->extname,""); hduname[i]->extver = 0; } return; } /* set the hduname memeber hdutype, extname, extver */ void set_hduname( int hdunum, /* hdu number */ int hdutype, /* hdutype */ char* extname, /* extension name */ int extver /* extension version */ ) { int i; i = hdunum - 1; hduname[i]->hdutype = hdutype; if(extname!=NULL) strcpy (hduname[i]->extname,extname); else strcpy(hduname[i]->extname,""); hduname[i]->extver = extver; return; } /* get the total errors and total warnings in this hdu */ void set_hduerr(int hdunum /* hdu number */ ) { int i; i = hdunum - 1; num_err_wrn(&(hduname[i]->errnum), &(hduname[i]->wrnno)); reset_err_wrn(); /* reset the error and warning counter */ return; } /* set the basic information for hduname structure */ void set_hdubasic(int hdunum,int hdutype) { set_hduname(hdunum, hdutype, NULL, 0); set_hduerr(hdunum); return; } /* test to see whether the two extension having the same name */ /* return 1: identical 0: different */ int test_hduname (int hdunum1, /* index of first hdu */ int hdunum2 /* index of second hdu */ ) { HduName *p1; HduName *p2; p1 = hduname[hdunum1-1]; p2 = hduname[hdunum2-1]; if(!strlen(p1->extname) || !strlen(p2->extname)) return 0; if(!strcmp(p1->extname,p2->extname) && p1->hdutype == p2->hdutype && p2->extver == p1->extver && hdunum1 != hdunum2){ return 1; } return 0; } /* Added the error numbers */ void total_errors (int *toterr, int * totwrn) { int i = 0; int ierr, iwrn; *toterr = 0; *totwrn = 0; if (totalhdu == 0) { /* this means the file couldn't be opened */ *toterr = 1; return; } for (i = 0; i < totalhdu; i++) { *toterr += hduname[i]->errnum; *totwrn += hduname[i]->wrnno; } /*check the end of file errors */ num_err_wrn(&ierr, &iwrn); *toterr +=ierr; *totwrn +=iwrn; return; } /* print the extname, exttype, extver, errnum and wrnno in a table */ void hdus_summary(FILE *out) { HduName *p; int i; int ierr, iwrn; char temp[FLEN_VALUE]; char temp1[FLEN_VALUE]; wrtsep(out,'+'," Error Summary ",60); wrtout(out," "); sprintf(comm," HDU# Name (version) Type Warnings Errors"); wrtout(out,comm); sprintf(comm," 1 Primary Array %-4d %-4d ", hduname[0]->wrnno,hduname[0]->errnum); wrtout(out,comm); for (i=2; i <= totalhdu; i++) { p = hduname[i-1]; strcpy(temp,p->extname); if(p->extver && p->extver!= -999) { sprintf(temp1," (%-d)",p->extver); strcat(temp,temp1); } switch(hduname[i-1]->hdutype){ case IMAGE_HDU: sprintf(comm," %-5d %-20s Image Array %-4d %-4d ", i,temp, p->wrnno,p->errnum); wrtout(out,comm); break; case ASCII_TBL: sprintf(comm," %-5d %-20s ASCII Table %-4d %-4d ", i,temp, p->wrnno,p->errnum); wrtout(out,comm); break; case BINARY_TBL: sprintf(comm," %-5d %-20s Binary Table %-4d %-4d ", i,temp, p->wrnno,p->errnum); wrtout(out,comm); break; default: sprintf(comm," %-5d %-20s Unknown HDU %-4d %-4d ", i,temp, p->wrnno,p->errnum); wrtout(out,comm); break; } } /* check the end of file */ num_err_wrn(&ierr, &iwrn); if (iwrn || ierr) { sprintf(comm," End-of-file %-30s %-4d %-4d ", "", iwrn,ierr); wrtout(out,comm); } wrtout(out," "); return; } void destroy_hduname() { int i; for (i=0; i < totalhdu; i++) free(hduname[i]); free(hduname); return; } /* Routine to test the extra bytes at the end of file */ void test_end(fitsfile *infits, FILE *out) { int status = 0; LONGLONG headstart, datastart, dataend; int hdutype; /* check whether there are any HDU left */ fits_movrel_hdu(infits,1, &hdutype, &status); if (!status) { wrtout(out,"< End-of-File >"); sprintf(errmes, "There are extraneous HDU(s) beyond the end of last HDU."); wrterr(out,errmes,2); wrtout(out," "); return; } if (status != END_OF_FILE) { wrtserr(out,"Bad HDU? ",&status,2); return; } status = 0; fits_clear_errmsg(); if(ffghadll(infits, &headstart, &datastart, &dataend, &status)) wrtferr(out, "",&status,1); /* try to move to the last byte of this extension. */ if (ffmbyt(infits, dataend - 1,0,&status)) { sprintf(errmes, "Error trying to read last byte of the file at byte %ld.", (long) dataend); wrterr(out,errmes,2); wrtout(out,"< End-of-File >"); wrtout(out," "); return; } /* try to move to what would be the first byte of the next extension. If successfull, we have a problem... */ ffmbyt(infits, dataend,0,&status); if(status == 0) { wrtout(out,"< End-of-File >"); sprintf(errmes, "File has extra byte(s) after last HDU at byte %ld.", (long) dataend); wrterr(out,errmes,2); wrtout(out," "); } return; } /****************************************************************************** * Function * init_report * * * DESCRIPTION: * Initialize the fverify report * *******************************************************************************/ void init_report(FILE *out, /* output file */ char *rootnam /* input file name */ ) { sprintf(comm,"\n%d Header-Data Units in this file.",totalhdu); wrtout(out,comm); wrtout(out," "); reset_err_wrn(); init_hduname(); } /****************************************************************************** * Function * close_report * * * DESCRIPTION: * Close the fverify report * *******************************************************************************/ void close_report(FILE *out /* output file */ ) { int numerrs = 0; /* number of the errors */ int numwrns = 0; /* number of the warnings */ /* print out a summary of all the hdus */ if(prstat)hdus_summary(out); total_errors (&numerrs, &numwrns); total_warn = numwrns; total_err = numerrs; /* get the total number of errors and warnnings */ sprintf(comm,"**** Verification found %d warning(s) and %d error(s). ****", numwrns, numerrs); wrtout(out,comm); update_parfile(numerrs,numwrns); /* destroy the hdu name */ destroy_hduname(); return ; } fitsverify-4.22/fvrf_key.c0000644000220700000360000004473014100567764014430 0ustar birbylhea#include "fverify.h" int fits_parse_card(FILE *out, /* output file pointer */ int kpos, /* keyposition starting from 1 */ char *card, /* key card */ char *kname, /* key name */ kwdtyp *ktype, /* key type */ char *kvalue, /* key value */ char *kcomm /* comment */ ) /* Ref: Defininition of the Flexible Image Transport System(FITS), Sec. 5.1 and 5.2. */ { char vind[3]; char *p; char **pt; int i; char temp1[FLEN_CARD]; unsigned long stat = 0; *kname = '\0'; *kvalue = '\0'; *kcomm = '\0'; *ktype = UNKNOWN; if(strlen(card) > FLEN_CARD-1 ) { strncpy(temp1,card,20); temp1[21]='\0'; sprintf(errmes,"card %s is > 80.",card); wrterr(out,errmes,1); return 1; } card[FLEN_CARD-1] = '\0'; /* get the kname */ strncpy(kname, card, 8); kname[8] = '\0'; /* take out the trailing space */ i = 7; p = &kname[7]; while(isspace((int)*p) && i >= 0) {*p = '\0'; p--; i--;} /* Whether the keyword name is left justified */ i = 0; p = &kname[0]; while(isspace((int)*p) && *p != '\0' ) { p++; i++;} if( i < 8 && i > 0) { sprintf(errmes,"Keyword #%d: Name %s is not left justified.", kpos,kname); wrterr(out,errmes,1); } /* Whether the characters in keyword name are valid */ while(*p != '\0' ){ if((*p < 'A' || *p > 'Z')&& (*p < '0' || *p > '9')&& (*p != '-' && *p != '_') ) { sprintf(errmes, "Keyword #%d: Name \"%s\" contains char \"%c\" which is not upper case letter, digit, \"-\", or \"_\".",kpos,kname,*p); wrterr(out,errmes,1); break; } p++; i++; } /* COMMENT, HISTORY, HIERARCH and "" keywords */ if( !strcmp(kname,"COMMENT") || !strcmp(kname,"HISTORY") || !strcmp(kname,"HIERARCH") || !strcmp(kname,"CONTINUE") || !strcmp(kname,"") ){ *ktype = COM_KEY; p = &card[8]; strcpy(kcomm, p); kcomm[FLEN_COMMENT-1] = '\0'; for( ; *p != '\0'; p++) { if(!isprint((int)*p)) { sprintf(errmes, "Keyword #%d, %s: String contains non-text characters.", kpos,kname); wrterr(out,errmes,1); return 1; } } p = kname; while(!isspace((int)*p)&& *p != '\0')p++; *p = '\0'; return 0; } /* End Keyword: 9-80 shall be filled with ASCII blanks \x20 */ if( !strcmp(kname,"END") ){ *ktype = COM_KEY; if(card[3] == '\0') return 0; for( p = &card[8]; *p != '\0'; p++) { if(*p != '\x20' ){ wrterr(out,"END keyword contains non-blank characters.",1); return 1; } } kname[3] = '\0'; return 0; } /* check for value indicator */ p = &card[8]; strncpy(vind,p,2); vind[2] = '\0'; if(strcmp(vind,"= ") && strcmp(vind,"=") ){ /* no value indicator, so this is a commentary keyword */ *ktype = COM_KEY; strcpy(kcomm, p); kcomm[FLEN_COMMENT-1] = '\0'; for( ; *p != '\0'; p++) { if(!isprint((int)*p)) { sprintf(errmes, "Keyword #%d, %s: String contains non-text characters.", kpos,kname); wrterr(out,errmes,1); return 1; } } p = kname; while(!isspace((int)*p)&& *p != '\0')p++; *p = '\0'; return 0; } p = &card[10]; while (isspace((int)*p) && *p != '\0') p++; pt = &p; switch (*p) { case '\'': /* string */ get_str(pt, kvalue,&stat); *ktype = STR_KEY; p = *pt; if(*p != '\0') get_comm(pt,kcomm,&stat); break; case 'T': case 'F': /*logical */ get_log(pt, kvalue, &stat); *ktype = LOG_KEY; p = *pt; if(*p != '\0') get_comm(pt,kcomm,&stat); break; case '+': case '-': case '.': /* number */ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': get_num(pt, kvalue, ktype, &stat); p = *pt; if(*p != '\0') get_comm(pt,kcomm,&stat); break; case '(': /* complex number */ get_cmp(pt, kvalue, ktype, &stat); p = *pt; if(*p != '\0') get_comm(pt,kcomm,&stat); break; case '/': /* comment */ if(*p != '\0') get_comm(pt,kcomm,&stat); *ktype = UNKNOWN; break; default: get_unknown(pt,kvalue,ktype,&stat); p = *pt; if(*p != '\0') get_comm(pt,kcomm,&stat); } /* take out the trailing blanks for non-string keys */ if(*ktype != STR_KEY) { i = strlen(kvalue); p = &kvalue[i-1]; while(isspace((int)*p) && i >0) { *p = '\0'; p--; i--; } if(i == 0 && isspace((int)*p))*p = '\0'; } pr_kval_err(out,kpos,kname,kvalue,stat); if(stat != 0) return 1; return 0; } /* parse And test the string keys */ void get_str(char **pt, /* card string from character 11*/ char *kvalue, /* key value string */ unsigned long *stat /* error number */ ) { char *pi; char prev; /* previous char */ int nchar = 0; char *p; p = *pt; pi = p; p++; prev = 'a'; while(*p != '\0') { if( !isprint((int)*p) )*stat |= BAD_STR; if(prev == '\'' && *p != '\'') break; if(prev == '\'' && *p == '\'') { /* skip the '' */ p++; prev = 'a'; } else { prev = *p; p++; } } p--; if(*p != '\'') *stat |= NO_TRAIL_QUOTE; pi++; nchar = p - pi ; /* excluding the ' */ strncpy(kvalue,pi,nchar); *(kvalue+nchar) = '\0'; pi = kvalue + (nchar -1) ; while(isspace((int)*pi)){ *pi = '\0'; pi--;} /* delete the trailing space */ p++; /* skip the ' */ while(isspace((int)*p) && *p != '\0') p++; *pt = p; return; } /* parse and test the logical keys */ void get_log(char **pt, /* card string */ char *kvalue, /* key value string */ unsigned long *stat /* error number */ ) { char *p; p = *pt; *kvalue = *p; kvalue[1] = '\0'; p++; while(isspace((int)*p)) p++; if(*p != '/' && *p != '\0') *stat |= BAD_LOGICAL; *pt = p; return; } /* parse and test the numerical keys */ void get_num(char **pt, /* card string */ char *kvalue, /* comment string */ kwdtyp *ktype, unsigned long *stat /* error number */ ) { char *pi; int set_deci = 0; int set_expo = 0; int nchar; char *p; p = *pt; pi = p; *ktype = INT_KEY; if( *p != '+' && *p != '-' && !isdigit((int)*p) &&*p != '.') { *stat |= BAD_NUM; return; } if(*p == '.') { *ktype = FLT_KEY; set_deci = 1; } p++; while(!isspace((int)*p) && *p != '\0' && *p != '/') { if( *p == '.' && !set_deci ){ set_deci = 1; *ktype = FLT_KEY; p++; continue; } if( (*p == 'd'|| *p == 'e') && !set_expo) { set_expo = 1; *ktype = FLT_KEY; p++; if(*p == '+' || *p == '-') p++; *stat |= LOWCASE_EXPO; continue; } if( (*p == 'D'|| *p == 'E') && !set_expo) { set_expo = 1; *ktype = FLT_KEY; p++; if(*p == '+' || *p == '-') p++; continue; } if(!isdigit((int)*p)) *stat |= BAD_NUM; p++; } nchar = p - pi; strncpy(kvalue,pi,nchar); *(kvalue+nchar) = '\0'; while(isspace((int)*p) && *p != '\0') p++; *pt = p; return; } /* parse and test the complex keys */ void get_cmp(char **pt, /* card string */ char *kvalue, /* comment string */ kwdtyp *ktype, unsigned long *stat /* error number */ ) { char *p; char **pp; char *pr_beg; /* end of real part */ char *pr_end=0; /* end of real part */ char *pi_beg; /* beginning of the imaginay part */ char *pi_end=0; /* end of real part */ int nchar; int set_comm = 0; int set_paren = 0; unsigned long tr = 0; unsigned long ti = 0; kwdtyp rtype, itype; char temp[FLEN_CARD]; char card[FLEN_CARD]; strcpy(card,*pt); /* save the original */ card[FLEN_CARD-1] = '\0'; *ktype = CMI_KEY; /* default: integer complex */ p = card + 1; pr_beg = p; temp[0] = '\0'; while(*p != '\0' && *p != '/') { if(*p == ')') { set_paren = 1; pi_end = p; p++; break; } if(!set_comm && *p == ',') { set_comm = 1; pr_end = p; pi_beg = p+1; } else if(*p == ',') { *stat |= TOO_MANY_COMMA; } p++; } if(!set_comm) *stat |= NO_COMMA; if(!set_paren) { *stat |= NO_TRAIL_PAREN; pi_end = p; pi_end--; while(isspace((int)*pi_end))pi_end--; pi_end++; } nchar = pi_end - card ; strncpy(kvalue,card,nchar); *(kvalue+nchar) = '\0'; while(isspace((int)*p)&& *p != '\0') p++; *pt = *pt + (p - card); /* analyse the real and imagine part */ *pr_end = '\0'; *pi_end = '\0'; while(isspace((int)*pr_beg) && *pr_beg != '\0') pr_beg++; while(isspace((int)*pi_beg) && *pi_beg != '\0') pi_beg++; temp[0] = '\0'; pp = &pr_beg; get_num(pp, temp, &rtype, &tr); if(tr)*stat |= BAD_REAL; temp[0] = '\0'; pp = &pi_beg; get_num(pp, temp, &itype, &ti); if(ti)*stat |= BAD_IMG; if(rtype == FLT_KEY || itype == FLT_KEY) *ktype = CMF_KEY; return; } /* parse and test the comment keys */ void get_comm(char **pt, /* card string */ char *kcomm, /* comment string */ unsigned long *stat /* error number */ ) { char *pi; int nchar = 0; char *p; p = *pt; pi = p; if(*p != '/') { *stat |= NO_START_SLASH; } p++; while(*p != '\0') { if(!isprint((int)*p) ) *stat |= BAD_COMMENT; p++; } nchar = p - pi; strncpy(kcomm,pi,nchar); *(kcomm+nchar) = '\0'; return; } /* parsing the unknown keyword */ void get_unknown(char **pt, /* card string */ char *kvalue, /* comment string */ kwdtyp *ktype, unsigned long *stat /* error number */ ) { char *p; char *p1; char temp[FLEN_CARD]; p = *pt; strcpy(temp,*pt); p1 = temp; while(*p != '\0' && *p != '/') { p++; p1++;} *p1 = '\0'; p1 = temp; *pt = p; strcpy(kvalue, p1); *ktype = UNKNOWN; *stat |= UNKNOWN_TYPE; return ; } /* routine to print out the error of keyword value/comment */ void pr_kval_err(FILE *out, /* output FILE */ int kpos, /* keyposition starting from 1 */ char *kname, /* keyword name */ char *kval, /* keyword value */ unsigned long errnum /* error number */ ) { if(errnum == 0) return; if(errnum & BAD_STR) { sprintf(errmes, "Keyword #%d, %s: String \"%s\" contains non-text characters.", kpos,kname,kval); wrterr(out,errmes,1); } if(errnum & NO_TRAIL_QUOTE) { sprintf(errmes, "Keyword #%d, %s: The closing \"\'\" is missing in the string." , kpos,kname); wrterr(out,errmes,1); } if(errnum & BAD_LOGICAL) { sprintf(errmes,"Keyword #%d, %s: Bad logical value \"%s\".", kpos,kname,kval); wrterr(out,errmes,1); } if(errnum & BAD_NUM) { sprintf(errmes,"Keyword #%d, %s: Bad numerical value \"%s\".", kpos,kname,kval); wrterr(out,errmes,1); } if(errnum & LOWCASE_EXPO) { sprintf(errmes, "Keyword #%d, %s: lower-case exponent d or e is illegal in value %s.", kpos,kname,kval); wrterr(out,errmes,1); } if(errnum & NO_TRAIL_PAREN) { sprintf(errmes, "Keyword #%d, %s: Complex value \"%s\" misses closing \")\".", kpos,kname, kval); wrterr(out,errmes,1); } if(errnum & NO_COMMA) { sprintf(errmes, "keyword #%d, %s : Complex value \"%s\" misses \",\".", kpos,kname,kval); wrterr(out,errmes,1); } if(errnum & TOO_MANY_COMMA) { sprintf(errmes, "Keyword #%d, %s: Too many \",\" are in the complex value \"%s\".", kpos,kname,kval); wrterr(out,errmes,1); } if(errnum & BAD_REAL) { sprintf(errmes, "Keyword #%d, %s: Real part of complex value \"%s\" is bad.", kpos,kname,kval); wrterr(out,errmes,1); } if(errnum & BAD_IMG) { sprintf(errmes, "Keyword #%d, %s: Imagine part of complex value \"%s\" is bad.", kpos,kname,kval); wrterr(out,errmes,1); } if(errnum & NO_START_SLASH) { sprintf(errmes, "Keyword #%d, %s: Value and Comment not separated by a \"/\".", kpos,kname); wrterr(out,errmes,1); } if(errnum & BAD_COMMENT) { sprintf(errmes, "Keyword #%d, %s: Comment contains non-text characters.", kpos,kname); wrterr(out,errmes,1); } if(errnum & UNKNOWN_TYPE) { if (*kval != 0) { /* don't report null keywords as an error */ sprintf(errmes, "Keyword #%d, %s: Type of value \"%s\" is unknown.", kpos,kname,kval); wrterr(out,errmes,1); } } return ; } int check_str(FitsKey* pkey, FILE *out) { if(pkey->ktype == UNKNOWN && *(pkey->kvalue) == 0) { sprintf(errmes,"Keyword #%d, %s has a null value; expected a string.", pkey->kindex,pkey->kname); wrterr(out,errmes,1); return 0; } else if(pkey->ktype != STR_KEY) { sprintf(errmes,"Keyword #%d, %s: \"%s\" is not a string.", pkey->kindex,pkey->kname, pkey->kvalue); wrterr(out,errmes,1); return 0; } return 1; } int check_int(FitsKey* pkey, FILE *out) { if(pkey->ktype == UNKNOWN && *(pkey->kvalue) == 0) { sprintf(errmes,"Keyword #%d, %s has a null value; expected an integer.", pkey->kindex,pkey->kname); wrterr(out,errmes,1); return 0; } else if(pkey->ktype != INT_KEY) { sprintf(errmes,"Keyword #%d, %s: value = %s is not an integer.", pkey->kindex,pkey->kname, pkey->kvalue); if(pkey->ktype == STR_KEY) strcat(errmes," The value is entered as a string. "); wrterr(out,errmes,1); return 0; } return 1; } int check_flt(FitsKey* pkey, FILE *out) { if(pkey->ktype == UNKNOWN && *(pkey->kvalue) == 0) { sprintf(errmes,"Keyword #%d, %s has a null value; expected a float.", pkey->kindex,pkey->kname); wrterr(out,errmes,1); return 0; } else if(pkey->ktype != INT_KEY && pkey->ktype != FLT_KEY) { sprintf(errmes, "Keyword #%d, %s: value = %s is not a floating point number.", pkey->kindex,pkey->kname, pkey->kvalue); if(pkey->ktype == STR_KEY) strcat(errmes," The value is entered as a string. "); wrterr(out,errmes,1); return 0; } return 1; } int check_cmi(FitsKey* pkey, FILE *out) { if(pkey->ktype != CMI_KEY ) { sprintf(errmes, "Keyword #%d, %s: value = %s is not a integer complex number.", pkey->kindex,pkey->kname, pkey->kvalue); if(pkey->ktype == STR_KEY) strcat(errmes," The value is entered as a string. "); wrterr(out,errmes,1); return 0; } return 1; } int check_cmf(FitsKey* pkey, FILE *out) { if(pkey->ktype != CMI_KEY && pkey->ktype != CMF_KEY) { sprintf(errmes, "Keyword #%d, %s: value = %s is not a floating point complex number.", pkey->kindex,pkey->kname, pkey->kvalue); if(pkey->ktype == STR_KEY) strcat(errmes," The value is entered as a string. "); wrterr(out,errmes,1); return 0; } return 1; } int check_log(FitsKey* pkey, FILE *out) { if(pkey->ktype != LOG_KEY ) { sprintf(errmes, "Keyword #%d, %s: value = %s is not a logical constant.", pkey->kindex,pkey->kname, pkey->kvalue); if(pkey->ktype == STR_KEY) strcat(errmes," The value is entered as a string. "); wrterr(out,errmes,1); return 0; } return 1; } int check_fixed_int(char* card, FILE *out) { char *cptr; /* fixed format integer must be right justified in columns 11-30 */ cptr = &card[10]; while (*cptr == ' ')cptr++; /* skip leading spaces */ if (*cptr == '-') cptr++; /* skip leading minus sign */ else if (*cptr == '+') cptr++; /* skip leading plus sign */ while (isdigit((int) *cptr))cptr++; /* skip digits */ /* should be pointing to column 31 of the card */ if ((cptr - card) != 30) { sprintf(errmes, "%.8s mandatory keyword is not in integer fixed format:", card); wrterr(out,errmes,1); print_fmt(out,card,13); print_fmt(out," -------------------^",13); return 0; } return 1; } int check_fixed_log(char* card, FILE *out) { char *cptr; /* fixed format logical must have T or F in column 30 */ cptr = &card[10]; while (*cptr == ' ')cptr++; /* skip leading spaces */ if (*cptr != 'T' && *cptr != 'F') { sprintf(errmes, "%.8s mandatory keyword does not have T or F logical value.", card); wrterr(out,errmes,1); return 0; } /* should be pointing to column 31 of the card */ if ((cptr - card) != 29) { sprintf(errmes, "%.8s mandatory keyword is not in logical fixed format:", card); wrterr(out,errmes,1); print_fmt(out,card,13); print_fmt(out," -------------------^",13); return 0; } return 1; } int check_fixed_str(char* card, FILE *out) { char *cptr; /* fixed format string must have quotes in columns 11 and >= 20 */ /* This only applys to the XTENSION and TFORMn keywords. */ cptr = &card[10]; if (*cptr != '\'' ) { sprintf(errmes, "%.8s mandatory string keyword does not start in col 11.", card); wrterr(out,errmes,1); print_fmt(out,card,13); print_fmt(out," ^--------^",13); return 0; } cptr++; while (*cptr != '\'') { if (*cptr == '\0') { sprintf(errmes, "%.8s mandatory string keyword missing closing quote character:", card); wrterr(out,errmes,1); print_fmt(out,card,13); return 0; } cptr++; } if ((cptr - card) < 19) { sprintf(errmes, "%.8s mandatory string keyword ends before column 20.", card); wrterr(out,errmes,1); print_fmt(out,card,13); print_fmt(out," ^--------^",13); return 0; } return 1; } fitsverify-4.22/fvrf_misc.c0000644000220700000360000002047414100567764014572 0ustar birbylhea/****************************************************************************** * Function * wrtout: print messages in the streams of stdout and out. * wrterr: print erro messages in the streams of stderr and out. * wrtferr: print cfitsio erro messages in the streams of stderr and out. * wrtwrn: print warning messages in the streams of stdout and out. * wrtsep: print seperators. * num_err_wrn: Return the number of errors and warnings. * *******************************************************************************/ #include "fverify.h" static int nwrns = 0; static int nerrs = 0; static char temp[512]; void num_err_wrn(int *num_err, int *num_wrn) { *num_wrn = nwrns; *num_err = nerrs; return; } void reset_err_wrn() { nwrns = 0; nerrs = 0; return; } int wrtout(FILE *out, char *mess) { if(out != NULL )fprintf(out,"%s\n",mess); if(out == stdout) fflush(stdout); return 0; } int wrtwrn(FILE *out, char *mess, int isheasarc) { if(err_report) return 0; /* Don't print the warnings */ if(!heasarc_conv && isheasarc) return 0; /* heasarc warnings but with heasarc convention turns off */ nwrns++; strcpy(temp,"*** Warning: "); strcat(temp,mess); if(isheasarc) strcat(temp," (HEASARC Convention)"); print_fmt(out,temp,13); /* if(nwrns > MAXWRNS ) { fprintf(stderr,"??? Too many Warnings! I give up...\n"); } */ return nwrns; } int wrterr(FILE *out, char *mess, int severity ) { if(severity < err_report) { fits_clear_errmsg(); return 0; } nerrs++; strcpy(temp,"*** Error: "); strcat(temp,mess); if(out != NULL) { if ((out!=stdout) && (out!=stderr)) print_fmt(out,temp,13); /* if ERR2OUT is defined, then error messages will be sent to the stdout stream rather than to stderr */ #ifdef ERR2OUT print_fmt(stdout,temp,13); #else print_fmt(stderr,temp,13); #endif } if(nerrs > MAXERRORS ) { #ifdef ERR2OUT fprintf(stdout,"??? Too many Errors! I give up...\n"); #else fprintf(stderr,"??? Too many Errors! I give up...\n"); #endif close_report(out); exit(1); } fits_clear_errmsg(); return nerrs; } int wrtferr(FILE *out, char* mess, int *status, int severity) /* construct an error message: mess + cfitsio error */ { char ttemp[255]; if(severity < err_report) { fits_clear_errmsg(); return 0; } nerrs++; strcpy(temp,"*** Error: "); strcat(temp,mess); fits_get_errstatus(*status, ttemp); strcat(temp,ttemp); if(out != NULL ) { if ((out!=stdout) && (out!=stderr)) print_fmt(out,temp,13); /* if ERR2OUT is defined, then error messages will be sent to the stdout stream rather than to stderr */ #ifdef ERR2OUT print_fmt(stdout,temp,13); #else print_fmt(stderr,temp,13); #endif } *status = 0; fits_clear_errmsg(); if(nerrs > MAXERRORS ) { #ifdef ERR2OUT fprintf(stdout,"??? Too many Errors! I give up...\n"); #else fprintf(stderr,"??? Too many Errors! I give up...\n"); #endif close_report(out); exit(1); } return nerrs; } int wrtserr(FILE *out, char* mess, int *status, int severity) /* dump the cfitsio stack */ { char* errfmt = " %.67s\n"; int i; char tmp[20][80]; int nstack = 0; if(severity < err_report) { fits_clear_errmsg(); return 0; } nerrs++; strcpy(temp,"*** Error: "); strcat(temp,mess); strcat(temp,"(from CFITSIO error stack:)"); while(nstack < 20) { tmp[nstack][0] = '\0'; i = fits_read_errmsg(tmp[nstack]); if(!i && tmp[nstack][0]=='\0') break; nstack++; } if(out !=NULL) { if ((out!=stdout) && (out!=stderr)) { print_fmt(out,temp,13); for(i=0; i<=nstack; i++) fprintf(out,errfmt,tmp[i]); } #ifdef ERR2OUT print_fmt(stdout,temp,13); for(i=0; i<=nstack; i++) fprintf(stdout,errfmt,tmp[i]); #else print_fmt(stderr,temp,13); for(i=0; i<=nstack; i++) fprintf(stderr,errfmt,tmp[i]); #endif } *status = 0; fits_clear_errmsg(); if(nerrs > MAXERRORS ) { #ifdef ERR2OUT fprintf(stdout,"??? Too many Errors! I give up...\n"); #else fprintf(stderr,"??? Too many Errors! I give up...\n"); #endif close_report(out); exit(1); } return nerrs; } void print_fmt(FILE *out, char *temp, int nprompt) /* Print output of messages in a 80 character record. Continue lines are aligned. */ { char *p; int i,j; int clen; char tmp[81]; static char cont_fmt[80]; static int save_nprompt = 0; if (out == NULL) return; if(nprompt != save_nprompt) { for (i = 0; i < nprompt; i++) cont_fmt[i] = ' '; strcat(cont_fmt,"%.67s\n"); save_nprompt = nprompt; } i = strlen(temp) - 80; if(i <= 0) { fprintf(out,"%.80s\n",temp); } else{ p = temp; clen = 80 -nprompt; strncpy(tmp,p,80); tmp[80] = '\0'; if(isprint((int)*(p+79)) && isprint((int)*(p+80)) && *(p+80) != '\0') { j = 79; while(*(p+j) != ' ' && j > 0) j--; p += j; while( *p == ' ')p++; tmp[j] = '\0'; } else if( *(p+80) == ' ') { j = 80; while( *(p+j) == ' ') j++; p += j; } else { p += 80; } fprintf(out,"%.80s\n",tmp); while(*p != '\0' && i > 0) { strncpy(tmp,p,clen); tmp[clen] = '\0'; i = strlen(p)- clen; if(i > 0 && isprint((int)*(p+clen-1)) && isprint((int)*(p+clen)) && *(p+clen) != '\0') { j = clen; while(*(p+j)!= ' ' && j > 0) j--; p += j; while( *p == ' ')p++; tmp[j] = '\0'; } else if(i> 0 && *(p+clen) == ' ') { j = clen; while( *(p+j) == ' ') j++; p += j; } else if(i> 0) { p+= clen; } fprintf(out,cont_fmt,tmp); } } if(out==stdout) fflush(stdout); return; } void wrtsep(FILE *out,char fill, char *title, int nchar) /* print a line of char fill with string title in the middle */ { int ntitle; char *line; char *p; int first_end; int i = 0; ntitle = strlen(title); if(ntitle > nchar) nchar = ntitle; if(nchar <= 0) return; line = (char *)malloc((nchar+1)*sizeof(char)); p = line; if(ntitle < 1) { for (i=0; i < nchar; i++) {*p = fill; p++;} *p = '\0'; } else { first_end = ( nchar - ntitle)/2; for (i = 0; i < first_end; i++) { *p = fill; p++;} *p = '\0'; strcat(line, title); p += ntitle; for( i = first_end + ntitle; i < nchar; i++) {*p = fill; p++;} *p = '\0'; } if(out != NULL )fprintf(out,"%s\n",line); if(out == stdout )fflush(out); free (line); return ; } /* comparison function for the FitsKey structure array */ int compkey (const void *key1, const void *key2) { char *name1; char *name2; name1 = (*(FitsKey **)key1)->kname; name2 = (*(FitsKey **)key2)->kname; return strncmp(name1,name2,FLEN_KEYWORD); } /* comparison function for the colname structure array */ int compcol (const void *col1, const void *col2) { char *name1; char *name2; name1 = (*(ColName **)col1)->name; name2 = (*(ColName **)col2)->name; return strcmp(name1,name2); } /* comparison function for the string pattern maching*/ int compstrp (const void *str1, const void *str2) { char *p; char *q; p = (char *)(*(char**) str1); q = (char *)(*(char**) str2); while( *q == *p && *q != '\0') { p++; q++; if(*p == '\0') return 0; /* str2 is longer than str1, but matched */ } return (*p - *q); } /* comparison function for the string exact maching*/ int compstre (const void *str1, const void *str2) { char *p; char *q; p = (char *)(*(char**) str1); q = (char *)(*(char**) str2); return strcmp( p, q); } fitsverify-4.22/README0000644000220700000360000001606314100567764013327 0ustar birbylheaThis package contains the source code for the fitsverify FITS file conformance verification program. It is maintained by the HEASARC at NASA/GSFC (http://heasarc.gsfc.nasa.gov). This is a stand-alone version of the fverify task in the FTOOLS package. The CFITSIO library, also available from the HEASARC, is required to compile and build fitsverify. In particular, the fitsio.h, and longnam.h include files are needed to compile the program, which must then be linked with the CFITSIO library itself (i.e., the file libcfitsio.a on unix systems). fitsverify can be built on most unix machines with a command similar to the following: gcc -o fitsverify ftverify.c fvrf_data.c fvrf_file.c fvrf_head.c fvrf_key.c fvrf_misc.c -DSTANDALONE -I/path/to/my/cfitsio -L/path/to/my/cfitsio -lcfitsio -lm -lnsl Where you should substitute "/path/to/my/cfitsio" with the location of the cfitsio header files and library on your system. Note also that the '-lm' and '-lnsl' library directives may not be required on all platforms. Optionally, one may add the -DERR2OUT flag to force all the error messages to go to stdout rather than stderr (usually only useful if the output of fitsverify is being piped to another file or task). To build fitsverify with Visual C++ on Windows PCs, first execute the vcvars32.bat file that is distributed with vcc, unpack the fitverify .zip file, then excute the following command: cl /MD ftverify.c fvrf_data.c fvrf_file.c fvrf_head.c fvrf_key.c fvrf_misc.c -DSTANDALONE /link setargv.obj cfitsio.lib (The "/link setargv.obj" is optional and just enables support for wildcard characters (like *) in the input file names). A help file describing the features of fitsverify can be produced by entering the command 'fitsverify -h'. The help file is reproduced below: ---------------------------------------------------------------- fitsverify -- Verify that the input files conform to the FITS Standard. USAGE: fitsverify filename ... - verify one or more FITS files (may use wildcard characters) or fitsverify @filelist.txt - verify a list of FITS files Optional flags: -l list all header keywords -q quiet; print one-line pass/fail summary per file -e only test for error conditions (ignore warnings) fitsverify exits with a status equal to the number of errors + warnings. EXAMPLES: fitsverify -l m101.fits - produce a detailed verificaton report of a single file, including a keyword listing fitsverify -q *.fits *.fit - verify all files with .fits or .fit extensions, writing a 1-line pass/fail message for each file DESCRIPTION: This task reads one or more input FITS files and verifies that the files conform to the specifications of the FITS Standard, Definition of the Flexible Image Transport System (FITS), Version 3.0, available online at http://fits.gsfc.nasa.gov/. The input filename template may contain wildcard characters, in which case all matching files will be tested. Alternatively, the name of an ASCII text file containing a list of file names, one per line, may be entered preceded by an '@' character. The following error or warning conditions will be reported: ERROR CONDITIONS - Mandatory keyword not present or out of order - Mandatory keyword has wrong datatype or illegal value - END header keyword is not present - Sum of table column widths is inconsistent with NAXIS1 value - BLANK keyword present in image with floating-point datatype - TNULLn keyword present for floating-point binary table column - Bit column has non-zero fill bits or is not left adjusted - ASCII TABLE column contains illegal value inconsistent with TFORMn - Address to a variable length array not within the data heap - Extraneous bytes in the FITS file following the last HDU - Mandatory keyword values not expressed in fixed format - Mandatory keyword duplicated elsewhere in the header - Header contains illegal ASCII character (not ASCII 32 - 126) - Keyword name contains illegal character - Keyword value field has illegal format - Value and comment fields not separated by a slash character - END keyword not filled with blanks in columns 9 - 80 - Reserved keyword with wrong datatype or illegal value - XTENSION keyword in the primary array - Column related keyword (TFIELDS, TTYPEn,TFORMn, etc.) in an image - SIMPLE, EXTEND, or BLOCKED keyword in any extension - BSCALE, BZERO, BUNIT, BLANK, DATAMAX, DATAMIN keywords in a table - Table WCS keywords (TCTYPn, TCRPXn, TCRVLn, etc.) in an image - TDIMn or THEAP keyword in an ASCII table - TBCOLn keyword in a Binary table - THEAP keyword in a binary table that has PCOUNT = 0 - XTENSION, TFORMn, TDISPn or TDIMn value contains leading space(s) - WCSAXES keyword appears after other WCS keywords - Index of any WCS keyword (CRPIXn, CRVALn, etc.) greater than value of WCSAXES - Index of any table column descriptor keyword (TTYPEn, TFORMn, etc.) greater than value of TFIELDS - TSCALn or TZEROn present for an ASCII, logical, or Bit column - TDISPn value is inconsistent with the column datatype - Length of a variable length array greater than the maximum length as given by the TFORMn keyword - ASCII table floating-point column value does not have decimal point(*) - ASCII table numeric column value has embedded space character - Logical column contains illegal value not equal to 'T', 'F', or 0 - Character string column contains non-ASCII text character - Header fill bytes not all blanks - Data fill bytes not all blanks in ASCII tables or all zeros in any other type of HDU - Gaps between defined ASCII table columns contain characters with ASCII value > 127 WARNING CONDITIONS - SIMPLE = F - Presence of deprecated keywords BLOCKED or EPOCH - 2 HDUs have identical EXTNAME, EXTVER, and EXTLEVEL values - BSCALE or TSCALn value = 0. - BLANK OR TNULLn value exceeds the legal range - TFORMn has 'rAw' format and r is not a multiple of w - DATE = 'dd/mm/yy' and yy is less than 10 (Y2K problem?) - Index of any WCS keyword (CRPIXn, CRVALn, etc.) greater than value of NAXIS, if the WCSAXES keyword is not present - Duplicated keyword (except COMMENT, HISTORY, blank, etc.) - Column name (TTYPEn) does not exist or contains characters other than letter, digit and underscore - Calculated checksum inconsistent with CHECKSUM or DATASUM keyword - Row length or heap offset greater than signed int max for 'P' format variable length columns. This is the stand alone version of the FTOOLS 'fverify' program. It is maintained by the HEASARC at NASA/GSFC. Any comments about this program should be submitted to http://heasarc.gsfc.nasa.gov/cgi-bin/ftoolshelp fitsverify-4.22/fitsverify.c0000644000220700000360000002603614100567764015006 0ustar birbylhea#include #include #include "fverify.h" /* prototypes for PIL interface routines, that are not actually needed for this standalone version of fverify */ #define PIL_LINESIZE 1024 int PILGetFname(char *parname, char *filename); int PILGetString(char *parname, char *stringname); int PILGetBool(char *parname, int *intvalue); int PILPutInt(char *parname, int intvalue); /* This file contains the main fverify routine, and dummy version of various other headas system routines. This is used for the stand alone version of fverify. */ int main(int argc, char *argv[]) { int status = 0, invalid = 0, ii, file1 = 0; char *filename, errormode[2] = {"w"}; if (argc == 2 && !strcmp(argv[1],"-h")) { printf("fitsverify -- Verify that the input files conform to the FITS Standard.\n"); printf("\n"); printf("USAGE: fitsverify filename ... - verify one or more FITS files\n"); printf(" (may use wildcard characters)\n"); printf(" or fitsverify @filelist.txt - verify a list of FITS files\n"); printf(" \n"); printf(" Optional flags:\n"); printf(" -H test ESO HIERARCH keywords\n"); printf(" -l list all header keywords\n"); printf(" -q quiet; print one-line pass/fail summary per file\n"); printf(" -e only test for error conditions (ignore warnings)\n"); printf(" \n"); printf(" fitsverify exits with a status equal to the number of errors + warnings.\n"); printf(" \n"); printf("EXAMPLES:\n"); printf(" fitsverify -l m101.fits - produce a detailed verificaton report of\n"); printf(" a single file, including a keyword listing\n"); printf(" fitsverify -q *.fits *.fit - verify all files with .fits or .fit\n"); printf(" extensions, writing a 1-line pass/fail\n"); printf(" message for each file\n"); printf(" \n"); printf("DESCRIPTION:\n"); printf(" \n"); printf(" This task reads one or more input FITS files and verifies that the\n"); printf(" files conform to the specifications of the FITS Standard, Definition\n"); printf(" of the Flexible Image Transport System (FITS), Version 3.0, available\n"); printf(" online at http://fits.gsfc.nasa.gov/. The input filename template may\n"); printf(" contain wildcard characters, in which case all matching files will be \n"); printf(" tested. Alternatively, the name of an ASCII text file containing a list\n"); printf(" of file names, one per line, may be entered preceded by an '@' character.\n"); printf(" The following error or warning conditions will be reported:\n"); printf(" \n"); printf(" ERROR CONDITIONS\n"); printf(" \n"); printf(" - Mandatory keyword not present or out of order\n"); printf(" - Mandatory keyword has wrong datatype or illegal value\n"); printf(" - END header keyword is not present\n"); printf(" - Sum of table column widths is inconsistent with NAXIS1 value\n"); printf(" - BLANK keyword present in image with floating-point datatype\n"); printf(" - TNULLn keyword present for floating-point binary table column\n"); printf(" - Bit column has non-zero fill bits or is not left adjusted \n"); printf(" - ASCII TABLE column contains illegal value inconsistent with TFORMn\n"); printf(" - Address to a variable length array not within the data heap \n"); printf(" - Extraneous bytes in the FITS file following the last HDU \n"); printf(" - Mandatory keyword values not expressed in fixed format\n"); printf(" - Mandatory keyword duplicated elsewhere in the header\n"); printf(" - Header contains illegal ASCII character (not ASCII 32 - 126)\n"); printf(" - Keyword name contains illegal character\n"); printf(" - Keyword value field has illegal format\n"); printf(" - Value and comment fields not separated by a slash character\n"); printf(" - END keyword not filled with blanks in columns 9 - 80\n"); printf(" - Reserved keyword with wrong datatype or illegal value\n"); printf(" - XTENSION keyword in the primary array\n"); printf(" - Column related keyword (TFIELDS, TTYPEn,TFORMn, etc.) in an image\n"); printf(" - SIMPLE, EXTEND, or BLOCKED keyword in any extension\n"); printf(" - BSCALE, BZERO, BUNIT, BLANK, DATAMAX, DATAMIN keywords in a table\n"); printf(" - Table WCS keywords (TCTYPn, TCRPXn, TCRVLn, etc.) in an image\n"); printf(" - TDIMn or THEAP keyword in an ASCII table \n"); printf(" - TBCOLn keyword in a Binary table\n"); printf(" - THEAP keyword in a binary table that has PCOUNT = 0 \n"); printf(" - XTENSION, TFORMn, TDISPn or TDIMn value contains leading space(s)\n"); printf(" - WCSAXES keyword appears after other WCS keywords\n"); printf(" - Index of any WCS keyword (CRPIXn, CRVALn, etc.) greater than \n"); printf(" value of WCSAXES\n"); printf(" - Index of any table column descriptor keyword (TTYPEn, TFORMn,\n"); printf(" etc.) greater than value of TFIELDS\n"); printf(" - TSCALn or TZEROn present for an ASCII, logical, or Bit column\n"); printf(" - TDISPn value is inconsistent with the column datatype \n"); printf(" - Length of a variable length array greater than the maximum \n"); printf(" length as given by the TFORMn keyword\n"); printf(" - ASCII table floating-point column value does not have decimal point(*)\n"); printf(" - ASCII table numeric column value has embedded space character\n"); printf(" - Logical column contains illegal value not equal to 'T', 'F', or 0\n"); printf(" - Character string column contains non-ASCII text character\n"); printf(" - Header fill bytes not all blanks\n"); printf(" - Data fill bytes not all blanks in ASCII tables or all zeros \n"); printf(" in any other type of HDU \n"); printf(" - Gaps between defined ASCII table columns contain characters with\n"); printf(" ASCII value > 127\n"); printf(" \n"); printf(" WARNING CONDITIONS\n"); printf(" \n"); printf(" - SIMPLE = F\n"); printf(" - Presence of deprecated keywords BLOCKED or EPOCH\n"); printf(" - 2 HDUs have identical EXTNAME, EXTVER, and EXTLEVEL values\n"); printf(" - BSCALE or TSCALn value = 0.\n"); printf(" - BLANK OR TNULLn value exceeds the legal range\n"); printf(" - TFORMn has 'rAw' format and r is not a multiple of w\n"); printf(" - DATE = 'dd/mm/yy' and yy is less than 10 (Y2K problem?)\n"); printf(" - Index of any WCS keyword (CRPIXn, CRVALn, etc.) greater than\n"); printf(" value of NAXIS, if the WCSAXES keyword is not present\n"); printf(" - Duplicated keyword (except COMMENT, HISTORY, blank, etc.)\n"); printf(" - Column name (TTYPEn) does not exist or contains characters \n"); printf(" other than letter, digit and underscore\n"); printf(" - Calculated checksum inconsistent with CHECKSUM or DATASUM keyword\n"); printf(" \n"); printf(" This is the stand alone version of the FTOOLS 'fverify' program. It is\n"); printf(" maintained by the HEASARC at NASA/GSFC. Any comments about this program\n"); printf(" should be submitted to http://heasarc.gsfc.nasa.gov/cgi-bin/ftoolshelp\n"); return(0); } prhead = 0; /* don't print header by default */ prstat = 1; /* print HDU summary by default */ testhierarch = 0; /* do not test ESO HIERARCH keywords by default */ /* check for flags on the command line */ for (ii = 1; ii < argc; ii++) { if ((*argv[ii] != '-') || !strcmp(argv[ii],"-") ){ file1 = ii; break; } if (!strcmp(argv[ii],"-l")) { prhead = 1; } else if (!strcmp(argv[ii],"-H")) { testhierarch = 1; } else if (!strcmp(argv[ii],"-e")) { strcpy(errormode,"e"); } else if (!strcmp(argv[ii],"-q")) { prstat = 0; } else { invalid = 1; } } if (invalid || argc == 1 || file1 == 0) { /* invalid input, so print brief help message */ printf("\n"); printf("fitsverify - test if the input file(s) conform to the FITS format.\n"); printf("\n"); printf("Usage: fitsverify filename ... or fitsverify @filelist.txt\n"); printf("\n"); printf(" where 'filename' is a filename template (with optional wildcards), and\n"); printf(" 'filelist.txt' is an ASCII text file with a list of\n"); printf(" FITS file names, one per line.\n"); printf("\n"); printf(" Optional flags:\n"); printf(" -H test ESO HIERARCH keywords\n"); printf(" -l list all header keywords\n"); printf(" -q quiet; print one-line pass/fail summary per file\n"); printf(" -e only test for error conditions; don't issue warnings\n"); printf("\n"); printf("Help: fitsverify -h\n"); return(0); } /* call work function to verify that infile conforms to the FITS standard and write report to the output file. */ for (ii = file1; ii < argc; ii++) { status = ftverify_work( argv[ii], /* name of file to verify */ "STDOUT", /* write report to this stream */ prhead, /* print listing of header keywords? */ prstat, /* print detailed summary report */ errormode, /* report errors only, or errors and warnings */ 1, /* test the data */ 1, /* test checksum, if checksum keywords are present */ 1, /* test data fill areas (should contain all zeros */ 0, /* do not test for conformance with HEASARC convensions */ /* that are not required by the FITS Standard */ testhierarch); /* test format of ESO HIERARCH keywords? */ if (status) return(status); } if ( (totalerr + totalwrn) > 255) return(255); else return(totalerr + totalwrn); } /*------------------------------------------------------------------ The following are all dummy stub routines for functions that are only needed when ftverify is built in the HEADAS environment. --------------------------------------------------------------------*/ int PILGetFname(char *parname, char *filename) { return(0); } int PILGetString(char *parname, char *stringname) { return(0); } int PILGetBool(char *parname, int *intvalue) { return(0); } int PILPutInt(char *parname, int intvalue) { return(0); } void set_toolname(char *taskname); void set_toolname(char *taskname) { return; } void set_toolversion(char *taskname); void set_toolversion(char *taskname) { return; } void get_toolname(char *taskname); void get_toolname(char *taskname) { strcpy(taskname, "fitsverify"); return; } void get_toolversion(char *taskvers); void get_toolversion(char *taskvers) { strcpy(taskvers, "4.20"); return; } void headas_clobberfile(char *filename); void headas_clobberfile(char *filename) { return; } void HD_ERROR_THROW(char msg[256], int status); void HD_ERROR_THROW(char msg[256], int status) { return; } fitsverify-4.22/ftverify.c0000644000220700000360000003720114100567764014446 0ustar birbylhea#include "fverify.h" #ifndef STANDALONE #include "pil.h" #include "headas.h" #include "headas_error.h" #endif #define MAXMSG 256 /* HISTORY ------- The original fverify.f Fortran program was written by William Pence in 1994. Ning Gan rewrote fverify in C in 1998, and continued to make enhancements throughout 1999 and 2000. Ziqin Pan adapted fverify to build in the new HEADAS environment in 2002, renaming it to ftverify. William Pence made additional enhancements, and rationalized the code so that fverify and ftverify share many of the same source files in January 2003 * Detailed modification History * * MODIFICATION HISTORY: * 1998-08-24 Ning Gan, v3.0.0 * Beta version: xverify v1.0 * 1998-12-18 Ning Gan, v3.0.1 * Beta version: xverify v1.1 * 1999-02-18 Ning Gan, v3.0.2 * Beta version: xverify v1.2 * Added more checks for keywords. * 1999-03-04 Ning Gan, v3.0.3 * Added a feature of multiple input files. * 1999-05-19 Ning Gan, v3.0.5 * Wrote numwrns and numerrs to the par file. * If the # of errors exceeds the MAXERRORS, * quit and wrote the summary. * Took out the limits on warnings. * 1999-06-03 Ning Gan, v3.0.6 * Wrote the version number of underlying * cfitsio. * 1999-06-07 Ning Gan, v3.0.7 * Improve the error handling. If there are * errors on opening fitsfile, the program set * numerr to 1 and quit. * 1999-06-30 Ning Gan, v3.0.8 * Improve the layout of the output. * 1999-08-25 Ning Gan, v3.0.9 * Always write errors to stderr. * Added ffnchk * Took out the checks of rejecting the * TDISP like I2.0 and the column name * startingnerror with a digit. * 1999-10-25 Ning Gan, v3.1.0 * The TDISP can take format I4. * Beutified the CFISIO error stack output * The numerrs and numwrns are the accumulated * number of errors and warnings if multiple * FITS file are tested in on fverify session. * Checked the X Column is left justified. * 1999-12-12 Ning Gan, v3.1.1 * Added the basiconly and heasarc parameters. * 1999-12-20 Ning Gan, v3.1.2 * Added the parameters of errreport and prstat, * removed the parameters of basiconly, erronly and * errpluswrn. * 1999-12-29 Ning Gan, v3.1.3 * fixed a bug on solaris * 2000-05-03 Ning Gan, v3.1.4 * Skip the blank column names in column name * tests. * 2000-06-09 Ning Gan, v3.1.5 * Fixed the memory problem(The bug will crash * 2000-09-26 Ning Gan, v3.1.6 * Fixed the TDISP format bug (not accept * format such as E15.5E3). * 2002-09-30 Ziqin Pan converted fverify to ftverify for HEADAS environ. * 2003-01-09 W Pence v4.0 * Added support for the new WCSAXES keyword * Added support for random groups * several small changes to the output report format * * 2004-06-21 W Pence fixed reporting error when prstat=no and when * opening a nonexistent or non-FITS file. * Also fixed elusive memory allocation error. * * 2009-06-08 W Pence v4.15 * updates to comply with V3.0 of the FITS Standard * 2010-07-26 W Pence v4.16 * Updates to WCS keyword checks, plus other V3.0 issues. * Also check for non-zero heap if binary table has no * variable length array columns. * 2013-08-12 W Pence v4.17 * Ignore blank keywords preceding the END keyword. * Support (partially at least) files with PCOUNT > 2GB. * 2016-04-13 B Irby v4.18 * Change verify_fits from void to int; check return * status for abort conditions and set nerrs (as it * is not set by close_report) in this case for the * one-line file summary. * 2018-Jan/May B Irby v4.19 * Put webtool-only variable declarations inside an ifdef. * Silenced warnings about implicit function declarations when * building standalone fitsverify. Moved conditional include * of fitsverify.c to be after the function prototypes. * 2019-03-15 W Pence v4.20 * Added 'testhierarch' parameter to test that HIERARCH * keywords conform to the ESO convention. */ #define TOOLSUB ftverify /* headas_main() requires that TOOLSUB be defined first */ long totalerr, totalwrn; /* Function Prototypes */ int ftverify (void); int ftverify_getpar (char *infile, char *outfile,int * prehead, int* prstat, char* errreport, int* testdata, int* testcsum, int* testfill, int* heasarc_conv, int* testhierarch); int ftverify_work (char *infile, char *outfile, int prehead, int prstat, char* errreport, int testdata, int testcsum, int testfill, int heasarc_conv, int testhierarch); #ifdef STANDALONE #include "fitsverify.c" #else #include "headas_main.c" #endif int err_report=0; int prhead=0; int prstat=1; int testdata=1; int testcsum=1; int testfill=1; int heasarc_conv=1; int testhierarch=0; int totalhdu=0; /*---------------------------------------------------------------------------*/ int ftverify (void) { /* Read a FITS file and verify that it conforms to the FITS standard */ char infile[PIL_LINESIZE],outfile[PIL_LINESIZE]; int status; char errreport[PIL_LINESIZE]; static char taskname[80] = "ftverify"; static char version[8] = "4.20"; /* Register taskname and version. */ set_toolname(taskname); set_toolversion(version); /* get input parameters */ status = ftverify_getpar(infile, outfile,&prhead,&prstat,errreport, &testdata,&testcsum,&testfill,&heasarc_conv,&testhierarch); /* call work function to verify that infile conforms to the FITS standard and write report to the output file */ if (!status) status = ftverify_work(infile, outfile,prhead,prstat,errreport, testdata,testcsum,testfill,heasarc_conv,testhierarch); return(status); } /*---------------------------------------------------------------------------*/ int ftverify_getpar( char *infile, /* O - Input file name (Fits) */ char *outfile, /* O - Output file name (ASCII) */ int * prhead, int * prstat, char * errreport, int * testdata, int * testcsum, int * testfill, int * heasarc_conv, int * testhierarch) /* read input parameters for the ftverify task from the .par file */ { int status; char msg[MAXMSG]; if ((status = PILGetString("infile", infile))) { sprintf(msg, "Error reading the 'infile' parameter."); HD_ERROR_THROW(msg,status); } else if ((status = PILGetString("outfile", outfile))) { sprintf(msg, "Error reading the 'outfile' parameter."); HD_ERROR_THROW(msg,status); } else if ((status = PILGetBool("prhead", prhead))) { sprintf(msg, "Error reading the 'prhead' parameter."); HD_ERROR_THROW(msg,status); } else if ((status = PILGetBool("prstat", prstat))) { sprintf(msg, "Error reading the 'prstat' parameter."); HD_ERROR_THROW(msg,status); } else if ((status = PILGetString("errreport", errreport))) { sprintf(msg, "Error reading the 'errreport' parameter."); HD_ERROR_THROW(msg,status); } else if ((status = PILGetBool("testdata", testdata))) { sprintf(msg, "Error reading the 'testdata' parameter."); HD_ERROR_THROW(msg,status); } else if ((status = PILGetBool("tchksum", testcsum))) { sprintf(msg, "Error reading the 'tchksum' parameter."); HD_ERROR_THROW(msg,status); } else if ((status = PILGetBool("testfill", testfill))) { sprintf(msg, "Error reading the 'testfill' parameter."); HD_ERROR_THROW(msg,status); } else if ((status = PILGetBool("heasarc", heasarc_conv))) { sprintf(msg, "Error reading the 'heasarc' parameter."); HD_ERROR_THROW(msg,status); } else if ((status = PILGetBool("hierarch", testhierarch))) { sprintf(msg, "Error reading the 'hierarch' parameter."); HD_ERROR_THROW(msg,status); } return(status); } /*---------------------------------------------------------------------------*/ int ftverify_work( char *infile, /* I - Input file name (Fits) */ char *outfile, /* I - Output file name (ASCII) */ int prehead, int prstat, char * errreport, int testdata, int testcsum, int testfill, int heasarc_conv, int testhierarch) /* call work function to verify that infile conforms to the FITS standard and write report to the output file */ { #ifdef WEBTOOL FILE *runfile = 0; int runnum; char runchars[30]; #endif FILE *outfptr = 0; FILE *list=0; int status = 0, vfstatus = 0, filestatus; char * p; char task[80]; char tversion[80]; float fversion; int i, nerrs, nwarns; char msg[MAXMSG]; /* determine 'Severe error", "Error", or "Warning" report level */ if( *errreport == 's' || *errreport == 'S') err_report = 2; if( *errreport == 'e' || *errreport == 'E') err_report = 1; p = infile; if (*p == '@') { p++; if( (list = fopen(p,"r")) == NULL ) { fprintf(stderr,"Cannot open the list file: %s.",p); leave_early(NULL); return (FILE_NOT_OPENED); } } headas_clobberfile(outfile); /* delete existing file if clobber=YES */ p = outfile; /* test if writing output log to a disk file */ if(prstat && strlen(p) && strcmp(p, "STDOUT") && strcmp(p, "STDERR") && (outfptr = fopen(p,"r") ) != NULL ) { sprintf(msg,"Clobber is not set. Cannot overwrite the file%s",p); status = FILE_NOT_CREATED; HD_ERROR_THROW(msg,status); leave_early(NULL); fclose(outfptr); return (status); } if(prstat && (!strlen(p) || !strcmp(p, "STDOUT"))) { outfptr = stdout; } else if(prstat && (!strlen(p) || !strcmp(p, "STDERR"))) { outfptr = stderr; } else if (!prstat) { outfptr=NULL; } else if( (outfptr = fopen(p,"w") ) == NULL) { fprintf(stderr,"Error open output file %s. Using stdout instead.", outfile); outfptr = stdout; } #ifdef WEBTOOL /* try opening and incrementing the file containing cumulative # of runs */ runfile=fopen("/tmp.shared/fits/tmpverify/counter.fitsverify","r+"); /* runfile=fopen("counter.fitsverify","r+"); */ if (runfile) { fgets(runchars,20,runfile); runnum=atoi(runchars); runnum++; sprintf(comm," Run Number %d",runnum); wrtout(outfptr,comm); sprintf(runchars, "%d", runnum); fflush(runfile); rewind(runfile); fputs(runchars, runfile); } #endif wrtout(outfptr," "); fits_get_version(&fversion); get_toolname(task); get_toolversion(tversion); sprintf(comm,"%s %s (CFITSIO V%.3f)",task,tversion,fversion); wrtsep(outfptr,' ',comm,60); for(i = 0; comm[i]!='\0'; i++) comm[i] = '-'; wrtsep(outfptr,' ',comm,60); wrtout(outfptr," "); switch (err_report) { case 2: sprintf(comm, "Caution: Only checking for the most severe FITS format errors."); wrtout(outfptr,comm); break; case 1: break; case 0: break; } if(heasarc_conv) { sprintf(comm, "HEASARC conventions are being checked."); wrtout(outfptr,comm); } if(testhierarch) { sprintf(comm, "ESO HIERARCH keywords are being checked."); wrtout(outfptr,comm); } /* process each file */ if (list == NULL) { vfstatus = verify_fits(infile,outfptr); if (outfptr == NULL) { /* print one-line file summary */ /* verify_fits returns a non-zero status for catastrophic * file I/O problems (an abort), and in this case total_err * is not updated via close_report(), so we need to set * nerrs accordingly for the one-line file summary. */ if (vfstatus) nerrs = 1; else nerrs = get_total_err(); nwarns = get_total_warn(); filestatus = ((nerrs+nwarns)>0) ? 1 : 0; if (filestatus) { if (err_report) printf("verification FAILED: %-20s, %d errors\n", infile, nerrs); else printf("verification FAILED: %-20s, %d warnings and %d errors\n", infile, nwarns, nerrs); } else printf("verification OK: %-20s\n", infile); } } else { while((p = fgets(infile, FLEN_FILENAME, list))!= NULL) { vfstatus = verify_fits(infile,outfptr); if (outfptr == NULL) { /* print one-line file summary */ /* verify_fits returns a non-zero status for catastrophic * file I/O problems (an abort), and in this case total_err * is not updated via close_report(), so we need to set * nerrs accordingly for the one-line file summary. */ if (vfstatus) nerrs = 1; else nerrs = get_total_err(); nwarns = get_total_warn(); filestatus = ((nerrs+nwarns) >0) ? 1 : 0; if (filestatus) { if (err_report) printf("verification FAILED: %-20s, %d errors\n", infile, nerrs); else printf("verification FAILED: %-20s, %d warnings and %d errors\n", infile, nwarns, nerrs); } else printf("verification OK: %-20s\n", infile); } for (i = 1; i < 3; i++) wrtout(outfptr," "); } fclose(list); } /* close the output file */ if (outfptr != stdout && outfptr != NULL) fclose(outfptr); return(status); } /****************************************************************************** * Function * update_parfile * * * DESCRIPTION: * Update the numerrs and numwrns parameters in the parfile. * *******************************************************************************/ void update_parfile(int nerr, int nwrn) { int status = 0; char parname[32]; totalerr += (long )nerr; totalwrn += (long )nwrn; /* write the total accumulated total warnings and errors to the parfile */ strcpy(parname, "numwrns"); status=PILPutInt(parname, totalwrn); if(status) { fprintf(stderr,"Error to update the numwrns keyword.\n"); status = 0; } strcpy(parname, "numerrs"); status=PILPutInt(parname, totalerr); if(status) { fprintf(stderr,"Error to update the numerrs keyword.\n"); status = 0; } }