1 /*
2   This file is part of "fitsverify" and was imported from:
3     http://heasarc.gsfc.nasa.gov/docs/software/ftools/fitsverify/
4  */
5 #include "fverify.h"
6 
7 /*
8 the following are only needed if one calls wcslib
9 #include <wcslib/wcshdr.h>
10 #include <wcslib/wcsfix.h>
11 #include <wcslib/wcs.h>
12 #include <wcslib/getwcstab.h>
13 */
14 
15 static char **cards;		/* array to store the keywords  */
16 static int ncards;		/* total number of the keywords */
17 static char **tmpkwds;          /* An  string array holding the keyword name.
18 			          It is sorted in alphabetical ascending order
19 				  and not includes the keywords before
20 				  the first non-reserved keyword and END
21 				  keyword. */
22 
23 static char **ttype;
24 static char **tform;
25 static char **tunit;
26 
27 static  char temp[80];
28 static  char *ptemp;		/* it always pointed to the address of
29                                    temp */
30 static char snull[] = "";
31 static int curhdu;			/* current HDU index */
32 static int curtype;			/* current HDU type  */
33 
34 /******************************************************************************
35 * Function
36 *      verify_fits
37 *
38 * DESCRIPTION:
39 *      Verify individual fits file.
40 *
41 *******************************************************************************/
42 /* routine to verify individual fitsfile */
verify_fits(char * infile,FILE * out)43 void verify_fits(char *infile, FILE *out)
44 {
45     char rootnam[FLEN_FILENAME] = "";   /* Input Fits file root name */
46     fitsfile *infits;                   /* input fits file pointer */
47     FitsHdu fitshdu;                    /* hdu information */
48     int hdutype;
49     int status = 0;
50     int i;
51     int len;
52     char *p;
53     char *pfile;
54     char xtension[80];
55 
56     /* take out the leading and trailing space and skip the empty line*/
57     p = infile;
58     while(isspace((int)*p) )p++;
59     len = strlen(p);
60     pfile = p;
61     p += (len -1);
62     for (i = len - 1; i >= 0 && isspace((int)*p); i--) {*p = '\0'; p--;}
63     if(!strlen(pfile)) return;
64 
65 #ifndef WEBTOOL
66     wrtout(out," ");
67     sprintf(comm,"File: %s",pfile);
68     wrtout(out,comm);
69 #endif
70 
71     totalhdu = 0;
72 
73     /* discard the extension, rowfilter... */
74     if(ffrtnm(pfile, rootnam, &status)) {
75         wrtserr(out,"",&status,2);
76         leave_early(out);
77         return;
78     }
79 
80     if(fits_open_file(&infits, rootnam, READONLY, &status)) {
81         wrtserr(out,"",&status,2);
82         leave_early(out);
83         return;
84     }
85 
86     /* get the total hdus */
87     if(fits_get_num_hdus(infits, &totalhdu, &status)) {
88         wrtserr(out,"",&status,2);
89         leave_early(out);
90         return;
91     }
92 
93     /* initialize the report */
94     init_report(out,rootnam);
95     /*------------------  Hdu Loop --------------------------------*/
96     for (i = 1; i <= totalhdu; i++) {
97         /* move to the right hdu and do the CFITSIO test */
98         hdutype = -1;
99         if(fits_movabs_hdu(infits,i, &hdutype, &status) ) {
100             print_title(out,i, hdutype);
101             wrtferr(out,"",&status,2);
102             set_hdubasic(i,hdutype);
103             break;
104         }
105 
106         if (i != 1 && hdutype == IMAGE_HDU) {
107            /* test if this is a tile compressed image in a binary table */
108            fits_read_key(infits, TSTRING, "XTENSION", xtension, NULL, &status);
109            if (!strcmp(xtension, "BINTABLE") )
110                print_title(out,i, BINARY_TBL);
111 	   else
112 	       print_title(out,i, hdutype);
113         }
114         else
115                print_title(out,i, hdutype);
116 
117         init_hdu(infits,out,i,hdutype,
118             &fitshdu);                          /* initialize fitshdu  */
119 
120         test_hdu(infits,out,&fitshdu);          /* test hdu header */
121 
122         if(testdata)
123             test_data(infits,out,&fitshdu);
124 
125         close_err(out);                         /* end of error report */
126 
127         if(prhead)
128             print_header(out);
129         if(prstat)
130             print_summary(infits,out,&fitshdu);
131         close_hdu(&fitshdu);                    /* clear the fitshdu  */
132     }
133     /* test the end of file  */
134     test_end(infits,out);
135 
136     /*------------------ Closing  --------------------------------*/
137     /* closing the report*/
138     close_report(out);
139 
140     /* close the input fitsfile  */
141     fits_close_file(infits, &status);
142 }
143 
leave_early(FILE * out)144 void leave_early (FILE* out)
145 {
146     sprintf(comm,"**** Abort Verification: Fatal Error. ****");
147     wrtout(out,comm);
148 
149     /* write the total number of errors and warnings to parfile*/
150     update_parfile(1,0);
151 }
152 
close_err(FILE * out)153 void close_err(FILE* out)
154 {
155     int merr, mwrn;
156     num_err_wrn(&merr, &mwrn);
157     if(merr || mwrn ) wrtout(out," ");
158     return;
159 }
160 
161 
162 /*************************************************************
163 *
164 *      init_hdu
165 *
166 *   Initialize the FitsHdu, HduName and ttype, tform, tunit if
167 * the hdu is a table.
168 *
169 *
170 *************************************************************/
init_hdu(fitsfile * infits,FILE * out,int hdunum,int hdutype,FitsHdu * hduptr)171 void init_hdu(fitsfile *infits, 	/* input fits file   */
172 	     FILE*	out,	/* output ascii file */
173 	     int     hdunum,	/* hdu index 	     */
174 	     int     hdutype,	/* hdutype	     */
175              FitsHdu *hduptr
176             )
177 {
178 
179     int morekeys;
180     int i,j,k,m,n;
181     int status = 0;
182     FitsKey ** kwds;
183     char *p = 0;
184     int numusrkey;
185     LONGLONG lv,lu=0L;
186 
187 
188     FitsKey tmpkey;
189 
190     hduptr->hdunum = hdunum;
191     hduptr->hdutype = hdutype;
192 
193     /* curhdu and curtype are shared with print_title */
194     curhdu = hdunum; /* set the current hdu number */
195     curtype = hdutype; /* set the current hdu number */
196 
197     /* check the null character in the header.(only the first one will
198        be recorded */
199     lv = 0;
200     lv = fits_null_check(infits, &status);
201     if (lv > 0) {
202         m = (lv - 1)/80 + 1;
203         n = lv - (m - 1) * 80;
204         sprintf(errmes,
205           "Byte #%d in Card#%d is a null(\\0).",n,m);
206         wrterr(out,errmes,1);
207         status = 0;
208     } else {
209         if (status) {
210 	    wrtserr(out,"",&status,1);
211             status = 0;
212         }
213     }
214 
215     /* get the total number of keywords */
216     hduptr->nkeys = 0;
217     morekeys = 0;
218     if(fits_get_hdrspace(infits, &(hduptr->nkeys), &morekeys, &status))
219         wrtferr(out,"",&status,1);
220     (hduptr->nkeys)++; 	/* include END keyword */
221 
222 
223     /* read all the keywords  */
224     ncards = hduptr->nkeys;
225     cards = (char **)malloc(sizeof(char *) * ncards );
226     for (i=0; i <  ncards; i++) {
227         cards[i] = (char *)malloc(sizeof(char )* FLEN_CARD );
228     }
229     for (i=1; i <= ncards; i++) {
230         if(fits_read_record(infits, i, cards[i-1], &status))
231 	    wrtferr(out,"",&status,1);
232     }
233 
234     /* Parse the XTENSION/SIMPLEX  keyword */
235     fits_parse_card(out, 1, cards[0], tmpkey.kname,
236         &(tmpkey.ktype), tmpkey.kvalue,comm);
237     if( *(tmpkey.kvalue) == ' ') {
238          sprintf(errmes,
239      "Keyword #1, %s \"%s\" should not have leading space.",
240                  tmpkey.kname,tmpkey.kvalue);
241          wrterr(out,errmes,1);
242     }
243     if(hdunum == 1) { /* SIMPLE should be logical T */
244         if(strcmp(tmpkey.kname,"SIMPLE"))
245             wrterr(out, "The 1st keyword of a primary array is not SIMPLE.",1);
246         if( !check_log(&tmpkey,out)|| strcmp(tmpkey.kvalue,"T"))
247 	    wrtwrn(out,
248     "SIMPLE != T indicates file may not conform to the FITS Standard.",0);
249 
250         check_fixed_log(cards[0], out);
251     }
252     else {
253         if(strcmp(tmpkey.kname,"XTENSION"))
254             wrterr(out, "The 1st keyword of a extension is not XTENSION.",1);
255 	check_str(&tmpkey,out);
256 
257         check_fixed_str(cards[0], out);
258 
259         /* Get the original string */
260         p = cards[0];
261         p +=10;
262         while (*p == ' ') p++;
263         p++;   /* skip the  quote */
264 	if( strncmp(p,"TABLE   ",8)  &&
265 	    strncmp(p,"BINTABLE",8)  &&
266 	    strncmp(p,"A3DTABLE",8)  &&
267 	    strncmp(p,"IUEIMAGE",8)  &&
268 	    strncmp(p,"FOREIGN ",8)  &&
269 	    strncmp(p,"DUMP    ",8)  &&
270 	    strncmp(p,"IMAGE   ",8)  )   {
271             sprintf(errmes, "Unregistered XTENSION value \"%8.8s\".",p);
272             wrterr(out,errmes,1);
273         }
274         else {
275             if  (p[8] != '\'') {
276                 sprintf(errmes,
277          "Extra \'%c\' follows the XTENSION value \"%8.8s\".",p[8],p);
278                 wrterr(out,errmes,1);
279             }
280         }
281 
282         /* test if this is a tile compressed image, stored in a binary table */
283         /* If so then test the extension as binary table rather than an image */
284 
285         if (!strncmp(p,"BINTABLE",8) && hduptr->hdutype == IMAGE_HDU) {
286           hduptr->hdutype = BINARY_TBL;
287           hduptr->istilecompressed = 1;
288         } else {
289           hduptr->istilecompressed = 0;
290         }
291     }
292 
293 
294     /* read the BITPIX keywords */
295     if(fits_read_key(infits, TINT, "BITPIX", &(hduptr->bitpix), NULL, &status))
296          wrtferr(out,"",&status,2);
297     check_fixed_int(cards[1], out);
298 
299     /* Read and Parse the NAXIS */
300     hduptr->naxis = 0;
301     if(fits_read_key(infits, TINT, "NAXIS", &(hduptr->naxis), NULL, &status))
302          wrtferr(out,"",&status,2);
303     check_fixed_int(cards[2], out);
304 
305     if(hduptr->naxis!=0)
306 	 hduptr->naxes = (LONGLONG *)malloc(hduptr->naxis*sizeof(LONGLONG));
307     for (i = 0; i < hduptr->naxis; i++) hduptr->naxes[i] = -1;
308 
309     /* Parse the keywords NAXISn */
310     for (j = 3; j < 3 + hduptr->naxis; j++){
311         fits_parse_card(out, 1+j,cards[j], tmpkey.kname,
312 	    &(tmpkey.ktype), tmpkey.kvalue,comm);
313         p = tmpkey.kname+5;
314 	if(!isdigit((int) *p))continue;
315 #if (USE_LL_SUFFIX == 1)
316         if(check_int(&tmpkey,out)) lu = strtoll(tmpkey.kvalue,NULL,10);
317 #else
318 	if(check_int(&tmpkey,out)) lu = strtol(tmpkey.kvalue,NULL,10);
319 #endif
320         lv = strtol(p,NULL,10);
321         if(lv > hduptr->naxis && lv <= 0) {
322             sprintf(errmes,
323                   "Keyword #%d, %s is not allowed (with n > NAXIS = %d).",
324                    tmpkey.kindex,tmpkey.kname,hduptr->naxis);
325             wrterr(out,errmes,1);
326         }
327         else {
328              if(hduptr->naxes[lv-1] == -1) {
329                  hduptr->naxes[lv-1] = lu;
330              }
331              else {
332                  sprintf(errmes, "Keyword #%d, %s is duplicated.",
333                    tmpkey.kindex,tmpkey.kname);
334                  wrterr(out,errmes,1);
335              }
336         }
337 
338         check_fixed_int(cards[j], out);
339     }
340 
341     /* check all the NAXISn are there */
342     for (j = 0; j < hduptr->naxis; j++) {
343          if(hduptr->naxes[j] == -1) {
344              sprintf(errmes,
345             "Keyword NAXIS%d is not present or is out of order.", j+1);
346              wrterr(out,errmes,2);
347          }
348     }
349 
350     /* get the column number */
351     hduptr->ncols = 1;
352     if(hduptr->hdutype == ASCII_TBL || hduptr->hdutype == BINARY_TBL) {
353         /* get the total number of columns  */
354         if(fits_get_num_cols(infits, &(hduptr->ncols),&status))
355             wrtferr(out,"",&status,2);
356     }
357 
358     /* parse the keywords after NAXISn and prepare the array for
359        sorting. We only check the keywords after the NAXISn */
360     n = hduptr->nkeys - 4 - hduptr->naxis ;   /* excluding the SIMPLE/XTENSION,
361 						 BITPIX, NAXIS, NAXISn
362 						 and END */
363     hduptr->kwds = (FitsKey **)malloc(sizeof(FitsKey *)*n);
364     for (i= 0; i < n; i++)
365         hduptr->kwds[i] = (FitsKey *)malloc(sizeof(FitsKey));
366     kwds = hduptr->kwds;
367     k = 3 + hduptr->naxis;  /* index of first keyword following NAXISn. */
368     m = hduptr->nkeys - 1;     /* last key  */
369     i = 0;
370     hduptr->use_longstr = 0;
371     for (j = k ; j < m; j++) {
372         kwds[i]->kindex = j+1;  	/* record number */
373 	kwds[i]->goodkey=1;
374 	if(fits_parse_card(out,1+j,cards[j], kwds[i]->kname,
375 		     &(kwds[i]->ktype), kwds[i]->kvalue,comm))
376 		     kwds[i]->goodkey=0;
377 
378 	if (kwds[i]->ktype == UNKNOWN && *(kwds[i]->kvalue) == 0)
379 	{
380 	    sprintf(errmes,
381                "Keyword #%d, %s has a null value.",
382                 j+1,kwds[i]->kname);
383             wrtwrn(out,errmes,0);
384 	}
385 
386         /* only count the non-commentary keywords */
387 	if (!strcmp(kwds[i]->kname,"CONTINUE")) {
388             hduptr->use_longstr = 1;
389         }
390         if( strcmp(kwds[i]->kname,"COMMENT") &&
391 	    strcmp(kwds[i]->kname,"HISTORY") &&
392 	    strcmp(kwds[i]->kname,"HIERARCH") &&
393 	    strcmp(kwds[i]->kname,"CONTINUE") &&
394             strcmp(kwds[i]->kname,"") ) i++;
395     }
396     numusrkey = i;
397     hduptr->tkeys = i;
398 
399     /* parse the END key */
400     fits_parse_card(out,m+1,cards[hduptr->nkeys-1],
401          tmpkey.kname,&(tmpkey.ktype),tmpkey.kvalue,comm) ;
402 
403     /* sort the keyword in the ascending order of kname field*/
404     qsort(kwds, numusrkey, sizeof(FitsKey *), compkey);
405 
406     /* store addresses of sorted keyword names in a working
407        array */
408     tmpkwds = (char **)malloc(sizeof(char*) * numusrkey);
409     for (i=0; i < numusrkey; i++)  tmpkwds[i] = kwds[i]->kname;
410 
411     /* Initialize  the PCOUNT, GCOUNT and heap values */
412     hduptr->pcount = -99;
413     hduptr->gcount = -99;
414     hduptr->heap = -99;
415 
416     /* set the random group flag (will be determined later) */
417     hduptr->isgroup = 0;
418 
419     /* allocate memory for datamax and datamin (will determined later)*/
420     if(hduptr->ncols > 0) {
421         hduptr->datamax = (char **)calloc(hduptr->ncols, sizeof(char *));
422         hduptr->datamin = (char **)calloc(hduptr->ncols, sizeof(char *));
423         hduptr->tnull   = (char **)calloc(hduptr->ncols, sizeof(char *));
424         for (i = 0; i < hduptr->ncols; i++) {
425 	    hduptr->datamax[i] = (char *)calloc(13,sizeof(char));
426 	    hduptr->datamin[i] = (char *)calloc(13,sizeof(char));
427 	    hduptr->tnull[i]   = (char *)calloc(12,sizeof(char));
428 	}
429     }
430 
431 
432     /* initialize  the extension  name and version */
433     strcpy(hduptr->extname,"");
434     hduptr->extver = -999;
435 
436 
437     return;
438 }
439 
440 /*************************************************************
441 *
442 *      test_hdu
443 *
444 *   Test the  HDU header
445 *    This includes many tests of WCS keywords
446 *
447 *************************************************************/
test_hdu(fitsfile * infits,FILE * out,FitsHdu * hduptr)448 void test_hdu(fitsfile *infits, 	/* input fits file   */
449 	     FILE	*out,	/* output ascii file */
450              FitsHdu *hduptr
451             )
452 
453 {
454     int status = 0;
455     FitsKey **kwds;
456     int numusrkey;
457     int hdunum;
458     char *p, *p2, *pname = 0;
459     int i,j,k,m,n, wcsaxes = 0, taxes;
460     int wcsaxesExists = 0, wcsaxesvalue = 0, wcsaxespos = 0, wcskeypos = 1000000000;
461     FitsKey *pkey;
462     int crota2_exists = 0, matrix_exists[2] = {0,0};
463     double dvalue;
464 
465     /* floating WCS keywords  */
466     char *cfltkeys[] = {"CRPIX", "CRVAL","CDELT","CROTA",
467                         "CRDER","CSYER", "PV"};
468     int ncfltkeys = 7;
469     int keynum[] = {0,0,0,0,0,0,0}, nmax = 0;
470 
471     /* floating non-indexed WCS keywords  */
472     char *cfltnkeys[] = {"RESTFRQ", "RESTFREQ", "RESTWAV",
473 			"OBSGEO-X", "OBSGEO-Y", "OBSGEO-Z",
474 			"VELOSYS", "ZSOURCE", "VELANGL",
475 			"LONPOLE", "LATPOLE"};
476     int ncfltnkeys = 11;
477 
478     /* floating WCS keywords w/ underscore  */
479     char *cflt_keys[] = {"PC","CD"};
480     int ncflt_keys = 2;
481 
482     /* string WCS keywords  */
483     char *cstrkeys[] = {"CTYPE", "CUNIT", "PS", "CNAME" };
484     int ncstrkeys = 4;
485 
486      /* string RADESYS keywords with list of allowed values  */
487     char *rastrkeys[] = {"RADESYS", "RADECSYS" };
488     int nrastrkeys = 2;
489 
490      /* string spectral ref frame keywords with list of allowed values  */
491     char *specstrkeys[] = {"SPECSYS", "SSYSOBS", "SSYSSRC" };
492     int nspecstrkeys = 3;
493 
494 
495     numusrkey = hduptr->tkeys;
496     kwds = hduptr->kwds;
497 
498     /* find the extension  name and version */
499     strcpy(temp,"EXTNAME");
500     ptemp = temp;
501     key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n);
502     if(k> -1 ) {
503          if(kwds[k]->ktype == STR_KEY)
504               strcpy(hduptr->extname,kwds[k]->kvalue);
505     }
506 
507     strcpy(temp,"EXTVER");
508     ptemp = temp;
509     key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n);
510     if(k> -1 ) {
511          if(kwds[k]->ktype == INT_KEY)
512                hduptr->extver = (int) strtol(kwds[k]->kvalue,NULL,10);
513     }
514 
515     /* set the HduName structure */
516     hdunum = hduptr->hdunum;
517     set_hduname(hdunum,hduptr->hdutype,hduptr->extname, hduptr->extver);
518 
519     if(hduptr->hdunum == 1) {
520         test_prm(infits,out,hduptr);
521     }
522     else {
523         /* test the keywords specific to the hdutype*/
524         switch (hduptr->hdutype) {
525 	    case IMAGE_HDU:
526                 test_img_ext(infits,out,hduptr);
527                 break;
528 	    case ASCII_TBL:
529                 test_asc_ext(infits,out,hduptr);
530                 break;
531 	    case BINARY_TBL:
532                 test_bin_ext(infits,out,hduptr);
533                 break;
534             default:
535 	        break;
536         }
537     }
538     /* test the general keywords */
539     test_header(infits,out,hduptr);
540 
541     /* test if CROTA2 exists; if so, then PCi_j must not exist */
542     strcpy(temp,"CROTA2");
543     ptemp = temp;
544     key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n);
545     if (n == 1) {
546         pkey = hduptr->kwds[k];
547         crota2_exists = pkey->kindex;
548     }
549 
550     strcpy(temp,"WCSAXES");
551     ptemp = temp;
552 
553     /* first find the primary WCSAXES value, if it exists */
554     key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n);
555     if (k >= 0) {
556         j = k;
557         if (check_int(kwds[j],out)) {
558             pkey = hduptr->kwds[j];
559 	    wcsaxesvalue = (int) strtol(pkey->kvalue,NULL,10);
560             nmax = wcsaxesvalue;
561         }
562     }
563 
564     /* Check and find max value of the WCSAXESa keywords */
565     /* Use the max value when checking the range of the indexed WCS keywords. */
566     /* This is a less rigorous test than if one were to test the range of the */
567     /* keywords for each of the alternate WCS systems (A - Z) against the */
568     /* corresponding WCSAXESa keyword.  */
569     key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n);
570 
571     for (j = k; j< n + k ; j++){
572 	if (check_int(kwds[j],out)) {
573             pkey = hduptr->kwds[j];
574 	    taxes = (int) strtol(pkey->kvalue,NULL,10);
575             if (taxes > wcsaxes) wcsaxes = taxes;
576             wcsaxesExists = 1;
577 
578 	    /* store highest index of any wcsaxes keyword */
579 	    /*  (they must appear before other WCS keywords) */
580 	    if (pkey->kindex > wcsaxespos) wcsaxespos = pkey->kindex;
581 	}
582     }
583 
584     /* test datatype of reserved indexed floating point WCS keywords */
585     for (i = 0; i < ncfltkeys; i++) {
586         strcpy(temp,cfltkeys[i]);
587     	ptemp = temp;
588     	key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n);
589         if(k < 0) continue;
590 
591         for (j = k; j < k+n; j++) {
592             pkey = hduptr->kwds[j];
593 
594 	    p = kwds[j]->kname;
595 	    p += strlen(temp);
596             if(!isdigit((int)*p)) continue;
597 
598 	    if (!check_flt(pkey,out) )continue;
599 
600 	    if (i == 2 ) {  /* test that CDELTi != 0 */
601 		dvalue = strtod(pkey->kvalue, NULL);
602 		if (dvalue == 0.) {
603 		    sprintf( errmes,
604             "Keyword #%d, %s: must have non-zero value.",
605                    pkey->kindex,pkey->kname);
606                    wrterr(out,errmes,1);
607 		}
608 	    }
609 
610 	    if (i == 4 || i == 5 ) {  /* test that CRDERi and CSYSERi are non-negative */
611 		dvalue = strtod(pkey->kvalue, NULL);
612 		if (dvalue < 0.) {
613 		    sprintf( errmes,
614             "Keyword #%d, %s: must have non-negative value: %s",
615                    pkey->kindex,pkey->kname,pkey->kvalue);
616                    wrterr(out,errmes,1);
617 		}
618 	    }
619 
620             m = (int)strtol(p,&p2,10);
621             if (wcsaxesExists) {     /* WCSAXES keyword exists */
622 
623               if (m < 1 || m > wcsaxes) {
624                  sprintf( errmes,
625             "Keyword #%d, %s: index %d is not in range 1-%d (WCSAXES).",
626                    pkey->kindex,pkey->kname,m,wcsaxes);
627                    wrterr(out,errmes,1);
628               }
629 
630             } else {
631 
632                 if (m < 1 || m > hduptr->naxis) {
633                   sprintf( errmes,
634                   "Keyword #%d, %s: index %d is not in range 1-%d (NAXIS).",
635                    pkey->kindex,pkey->kname,m,hduptr->naxis);
636                    wrtwrn(out,errmes,0);
637                 }
638             }
639 
640             /* count the number of each keyword */
641 	    if (*p2 == 0) {  /* only test the primary set of WCS keywords */
642         	keynum[i] = keynum[i] + 1;
643 		if (m > nmax) nmax = m;
644             }
645 
646 	    /* store lowest index of any wcs keyword */
647 	    if (pkey->kindex < wcskeypos) {
648 	        wcskeypos = pkey->kindex;
649 		pname = pkey->kname;
650 	    }
651         }
652     }
653 
654     if (wcsaxesvalue == 0) {  /* limit value of nmax to the legal maximum */
655         if (nmax > hduptr->naxis)
656 	    nmax = hduptr->naxis;
657     } else {
658         if (nmax > wcsaxesvalue)
659 	    nmax = wcsaxesvalue;
660     }
661 
662     if (keynum[0] < nmax) { /* test number of CRPIXi keywords */
663              sprintf( errmes,
664             "Some CRPIXi keywords appear to be missing; expected %d.",nmax);
665              wrtwrn(out,errmes,0);
666     }
667     if (keynum[1] < nmax) { /* test number of CRVALi keywords */
668              sprintf( errmes,
669             "Some CRVALi keywords appear to be missing; expected %d.",nmax);
670              wrtwrn(out,errmes,0);
671     }
672 
673     /* test datatype of reserved non-indexed floating point WCS keywords */
674     for (i = 0; i < ncfltnkeys; i++) {
675         strcpy(temp,cfltnkeys[i]);
676     	ptemp = temp;
677     	key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n);
678 
679         if(k < 0) continue;
680 
681         for (j = k; j < k+n; j++) {
682             pkey = hduptr->kwds[j];
683 
684 	    if (!check_flt(pkey,out) )continue;
685         }
686     }
687 
688     /* test datatype of reserved indexed floating point WCS keywords with "_" */
689     for (i = 0; i < ncflt_keys; i++) {
690         strcpy(temp,cflt_keys[i]);
691     	ptemp = temp;
692     	key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n);
693         if(k < 0) continue;
694 
695         for (j = k; j < k+n; j++) {
696             pkey = hduptr->kwds[j];
697 
698 	    p = kwds[j]->kname;
699 	    p += strlen(temp);
700             if(!isdigit((int)*p)) continue;
701 
702 	    p2 = strchr(p, '_');   /* 2 digits must be separated by a '_' */
703 	    if (!p2) continue;
704 
705 	    if (!check_flt(pkey,out) )continue;
706 
707             *p2 = '\0';   /* terminate string at the '_' */
708 
709             /* test the first digit */
710             m = (int)strtol(p,NULL,10);
711             *p2 = '_';   /* replace the '_' */
712 
713             if (wcsaxesExists) {     /* WCSAXES keyword exists */
714 
715               if (m < 1 || m > wcsaxes) {
716                  sprintf( errmes,
717             "Keyword #%d, %s: 1st index %d is not in range 1-%d (WCSAXES).",
718                    pkey->kindex,pkey->kname,m,wcsaxes);
719                    wrterr(out,errmes,1);
720               }
721 
722             } else {
723 
724               if (m < 1 || m > hduptr->naxis) {
725                 sprintf( errmes,
726             "Keyword #%d, %s: 1st index %d is not in range 1-%d (NAXIS).",
727                    pkey->kindex,pkey->kname,m,hduptr->naxis);
728                    wrtwrn(out,errmes,0);
729               }
730 
731             }
732 
733             /* test the second digit */
734             p = p2 + 1;
735             m = (int)strtol(p,&p2,10);
736 
737             if (wcsaxesExists) {     /* WCSAXES keyword exists */
738 
739               if (m < 1 || m > wcsaxes) {
740                  sprintf( errmes,
741             "Keyword #%d, %s: 2nd index %d is not in range 1-%d (WCSAXES).",
742                    pkey->kindex,pkey->kname,m,wcsaxes);
743                    wrterr(out,errmes,1);
744               }
745 
746             } else {
747 
748                 if (m < 1 || m > hduptr->naxis) {
749                 sprintf( errmes,
750                 "Keyword #%d, %s: 2nd index %d is not in range 1-%d (NAXIS).",
751                    pkey->kindex,pkey->kname,m,hduptr->naxis);
752                    wrtwrn(out,errmes,0);
753                 }
754             }
755 
756 	    if (*p2 == 0) { /* no alternate suffix on the PC or CD name */
757 	       matrix_exists[i] = pkey->kindex;
758 	    }
759 
760 	    /* store lowest index of any wcs keyword */
761 	    if (pkey->kindex < wcskeypos) {
762 	        wcskeypos = pkey->kindex;
763 		pname = pkey->kname;
764 	    }
765         }
766     }
767 
768     if (matrix_exists[0] > 0 && matrix_exists[1] > 0 ) {
769        sprintf( errmes,
770             "Keywords PCi_j (#%d) and CDi_j (#%d) are mutually exclusive.",
771                    matrix_exists[0],matrix_exists[1]);
772                    wrterr(out,errmes,1);
773     }
774 
775     if (matrix_exists[0] > 0 && crota2_exists > 0 ) {
776        sprintf( errmes,
777             "Keywords PCi_j (#%d) and CROTA2 (#%d) are mutually exclusive.",
778                    matrix_exists[0],crota2_exists);
779                    wrterr(out,errmes,1);
780     }
781 
782     /* test datatype of reserved indexed string WCS keywords */
783     for (i = 0; i < ncstrkeys; i++) {
784         strcpy(temp,cstrkeys[i]);
785     	ptemp = temp;
786         keynum[i] = 0;
787     	key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n);
788 
789         if(k < 0) continue;
790 
791         for (j = k; j < k+n; j++) {
792             pkey = hduptr->kwds[j];
793 
794 	    p = kwds[j]->kname;
795 	    p += strlen(temp);
796             if(!isdigit((int)*p)) continue;
797 
798 	    if (!check_str(pkey,out) )continue;
799 
800             m = (int)strtol(p,&p2,10);
801 
802             if (wcsaxesExists) {     /* WCSAXES keyword exists */
803 
804               if (m < 1 || m > wcsaxes) {
805                  sprintf( errmes,
806             "Keyword #%d, %s: index %d is not in range 1-%d (WCSAXES).",
807                    pkey->kindex,pkey->kname,m,wcsaxes);
808                    wrterr(out,errmes,1);
809               }
810 
811             } else {
812 
813                 if (m < 1 || m > hduptr->naxis) {
814                    sprintf( errmes,
815                    "Keyword #%d, %s: index %d is not in range 1-%d (NAXIS).",
816                    pkey->kindex,pkey->kname,m,hduptr->naxis);
817                    wrtwrn(out,errmes,0);
818                 }
819 
820             }
821 
822 	    if (*p2 == 0) {  /* only test the primary set of WCS keywords */
823         	keynum[i] = keynum[i] + 1;
824             }
825 
826 	    /* store lowest index of any wcs keyword */
827 	    if (pkey->kindex < wcskeypos) {
828 	        wcskeypos = pkey->kindex;
829 		pname = pkey->kname;
830 	    }
831         }
832     }
833 
834     if (keynum[0] < nmax) {
835              sprintf( errmes,
836             "Some CTYPEi keywords appear to be missing; expected %d.",nmax);
837              wrtwrn(out,errmes,0);
838     }
839 
840     if (wcskeypos < wcsaxespos) {
841              sprintf( errmes,
842             "WCSAXES keyword #%d appears after other WCS keyword %s #%d",
843 	       wcsaxespos, pname, wcskeypos);
844              wrterr(out,errmes,1);
845     }
846 
847     /* test datatype and value of reserved RADECSYS WCS keywords */
848     for (i = 0; i < nrastrkeys; i++) {
849         strcpy(temp,rastrkeys[i]);
850     	ptemp = temp;
851         keynum[i] = 0;
852     	key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n);
853 
854         if(k < 0) continue;
855 
856         for (j = k; j < k+n; j++) {
857             pkey = hduptr->kwds[j];
858 
859 	    p = kwds[j]->kname;
860 	    p += strlen(temp);
861 
862 	    if (!check_str(pkey,out) )continue;
863 
864             if (strcmp(pkey->kvalue, "ICRS") && strcmp(pkey->kvalue, "FK5") &&
865 	        strcmp(pkey->kvalue, "FK4") && strcmp(pkey->kvalue, "FK4-NO-E") &&
866 		strcmp(pkey->kvalue, "GAPPT")) {
867                    sprintf( errmes,
868                    "Keyword #%d, %s has non-allowed value: %s",
869                    pkey->kindex,pkey->kname,pkey->kvalue);
870                    wrtwrn(out,errmes,0);
871 	    }
872 
873         }
874     }
875 
876     /* test datatype and value of reserved spectral ref frame WCS keywords */
877     for (i = 0; i < nspecstrkeys; i++) {
878         strcpy(temp,specstrkeys[i]);
879     	ptemp = temp;
880         keynum[i] = 0;
881     	key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n);
882 
883         if(k < 0) continue;
884 
885         for (j = k; j < k+n; j++) {
886             pkey = hduptr->kwds[j];
887 
888 	    p = kwds[j]->kname;
889 	    p += strlen(temp);
890 
891 	    if (!check_str(pkey,out) )continue;
892 
893             if (strcmp(pkey->kvalue, "TOPOCENT") && strcmp(pkey->kvalue, "GEOCENTR") &&
894 	        strcmp(pkey->kvalue, "BARYCENT") && strcmp(pkey->kvalue, "HELIOCEN") &&
895 	        strcmp(pkey->kvalue, "LSRK") && strcmp(pkey->kvalue, "LSRD") &&
896 	        strcmp(pkey->kvalue, "GALACTOC") && strcmp(pkey->kvalue, "LOCALGRP") &&
897 	        strcmp(pkey->kvalue, "CMBDIPOL") && strcmp(pkey->kvalue, "SOURCE")) {
898                    sprintf( errmes,
899                    "Keyword #%d, %s has non-allowed value: %s",
900                    pkey->kindex,pkey->kname,pkey->kvalue);
901                    wrtwrn(out,errmes,0);
902 	    }
903 
904         }
905     }
906 
907     /* test the fill area */
908     if(testfill) {
909 	if(ffchfl(infits,&status)) {
910 	    wrterr(out,
911           "The header fill area is not totally filled with blanks.",1);
912         }
913     }
914     return ;
915 }
916 
917 
918 /*************************************************************
919 *
920 *      test_prm
921 *
922 *   Test the primary array header
923 *
924 *
925 *************************************************************/
test_prm(fitsfile * infits,FILE * out,FitsHdu * hduptr)926 void test_prm(fitsfile *infits, 	/* input fits file   */
927 	     FILE*	out,	/* output ascii file */
928              FitsHdu *hduptr    /* hdu information structure */
929             )
930 
931 {
932     int i,j,k,n;
933     FitsKey *pkey;
934     FitsKey **kwds;
935     int numusrkey;
936     char *p;
937 
938     char *exlkey[] = {"XTENSION"};
939     int nexlkey = 1;
940 
941     kwds = hduptr->kwds;
942     numusrkey = hduptr->tkeys;
943 
944     /* The SIMPLE, BITPIX, NAXIS, and NAXISn keywords  have been
945        checked in CFITSIO */
946 
947     /* excluded keywords cannot be used. */
948     for (i = 0; i < nexlkey; i++) {
949         strcpy(temp,exlkey[i]);
950         ptemp = temp;
951         key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n);
952         if( n > 0) {
953             pkey = hduptr->kwds[k];
954 	    sprintf(errmes,
955                "Keyword #%d, %s is not allowed in a primary array.",
956                 pkey->kindex,exlkey[i]);
957             wrterr(out,errmes,1);
958         }
959     }
960 
961     /* Check if Random Groups file */
962     strcpy(temp,"GROUPS");
963     ptemp = temp;
964     key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n);
965     if(k > -1){
966         pkey = hduptr->kwds[k];
967 	if(*(pkey->kvalue) == 'T' && hduptr->naxis > 0 && hduptr->naxes[0]==0) {
968           hduptr->isgroup = 1;
969 
970           check_fixed_log(cards[pkey->kindex - 1], out);
971         }
972     }
973 
974     /* check the position of the EXTEND  */
975 
976 /*  the EXTEND keyword is no longer required if the file contains extensions */
977 
978     if (hduptr->isgroup == 0) {
979        strcpy(temp,"EXTEND");
980        ptemp = temp;
981        key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n);
982        if( k > 0) {
983            pkey = hduptr->kwds[k];
984 
985 	   if(check_log(pkey,out) && *(pkey->kvalue)!='T' && totalhdu > 1) {
986 	      sprintf(errmes,"There are extensions but EXTEND = F.");
987               wrterr(out,errmes,1);
988            }
989        }
990     }
991 
992     /* Check PCOUNT and GCOUNT  keyword */
993     strcpy(temp,"PCOUNT");
994     ptemp = temp;
995     key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n);
996     if(k > -1) {
997         pkey = hduptr->kwds[k];
998         /* Primary array cannot have PCOUNT */
999 	if (!hduptr->isgroup ){
1000 	    sprintf(errmes,
1001            " Keyword #%d, %s is not allowed in a primary array.",
1002             pkey->kindex,pkey->kname);
1003             wrterr(out,errmes,1);
1004         }
1005         else {
1006 	    if(check_int(pkey,out))
1007 	        hduptr->pcount = (int) strtol(pkey->kvalue,NULL,10);
1008 
1009             check_fixed_int(cards[pkey->kindex - 1], out);
1010         }
1011     }
1012 
1013     strcpy(temp,"GCOUNT");
1014     ptemp = temp;
1015     key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n);
1016     if(k > -1) {
1017         pkey = hduptr->kwds[k];
1018         /* Primary array cannot have GCOUNT */
1019 	if (!hduptr->isgroup ){
1020 	    sprintf(errmes,
1021            " Keyword #%d, %s is not allowed in a primary array.",
1022             pkey->kindex,pkey->kname);
1023             wrterr(out,errmes,1);
1024         }
1025         else {
1026 	    if(check_int(pkey,out))
1027 	        hduptr->gcount = (int) strtol(pkey->kvalue,NULL,10);
1028 
1029             check_fixed_int(cards[pkey->kindex - 1], out);
1030         }
1031     }
1032 
1033     strcpy(temp,"BLOCKED");
1034     ptemp = temp;
1035     key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n);
1036     if(k > -1) {
1037          pkey = hduptr->kwds[k];
1038          sprintf(errmes,
1039             "Keyword #%d, %s is deprecated.",
1040              pkey->kindex, pkey->kname);
1041          wrtwrn(out,errmes,0);
1042 	 check_log(pkey,out);
1043 
1044 /*  no longer required
1045          if(pkey->kindex > 36) {
1046                   sprintf(errmes,
1047                    "Keyword #%d, BLOCKED, appears beyond keyword 36.",
1048                     pkey->kindex);
1049                   wrterr(out,errmes,1);
1050          }
1051 */
1052 
1053     }
1054 
1055     /*  Check PSCALn keywords (only in Random Groups) */
1056     strcpy(temp,"PSCAL");
1057     ptemp = temp;
1058     key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n);
1059     for (j = k; j< k + n ; j++){
1060 	p = kwds[j]->kname;
1061 	p += 5;
1062         if(!isdigit((int)*p)) continue;
1063 
1064         if (!(hduptr->isgroup)) {
1065             sprintf(errmes,"Keyword #%d, %s ",
1066             kwds[j]->kindex,kwds[j]->kname);
1067             strcat(errmes,
1068               "is only allowed in Random Groups structures.");
1069             wrterr(out,errmes,1);
1070             continue;
1071         }
1072 
1073 	if (check_flt(kwds[j],out) && strtod(kwds[j]->kvalue,NULL) == 0.0) {
1074             sprintf(errmes,"Keyword #%d, %s: ",
1075             kwds[j]->kindex,kwds[j]->kname);
1076             strcat(errmes,
1077               "The scaling factor is zero.");
1078             wrtwrn(out,errmes,0);
1079         }
1080 
1081 	i = (int) strtol(p,NULL,10) -1 ;
1082         if(i< 0 || i >= hduptr->gcount) {
1083             sprintf(errmes,
1084       "Keyword #%d, %s: invalid index %d (> GCOUNT = %d).",
1085             kwds[j]->kindex,kwds[j]->kname,i+1,hduptr->gcount);
1086             wrterr(out,errmes,1);
1087             continue;
1088         }
1089 
1090     }
1091 
1092     /*  Check PZEROn keywords (only in Random Groups) */
1093     strcpy(temp,"PZERO");
1094     ptemp = temp;
1095     key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n);
1096     for (j = k; j< k + n ; j++){
1097 	p = kwds[j]->kname;
1098 	p += 5;
1099         if(!isdigit((int)*p)) continue;
1100 
1101         if (!(hduptr->isgroup)) {
1102             sprintf(errmes,"Keyword #%d, %s ",
1103             kwds[j]->kindex,kwds[j]->kname);
1104             strcat(errmes,
1105               "is only allowed in Random Groups structures.");
1106             wrterr(out,errmes,1);
1107             continue;
1108         }
1109 
1110 	check_flt(kwds[j],out);
1111 	i = (int) strtol(p,NULL,10) -1 ;
1112         if(i< 0 || i >= hduptr->gcount) {
1113             sprintf(errmes,
1114       "Keyword #%d, %s: invalid index %d (> GCOUNT = %d).",
1115             kwds[j]->kindex,kwds[j]->kname,i+1,hduptr->gcount);
1116             wrterr(out,errmes,1);
1117             continue;
1118         }
1119     }
1120 
1121     /*  Check PTYPEn keywords (only in Random Groups) */
1122     strcpy(temp,"PTYPE");
1123     ptemp = temp;
1124     key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n);
1125     for (j = k; j< k + n ; j++){
1126 	p = kwds[j]->kname;
1127 	p += 5;
1128         if(!isdigit((int)*p)) continue;
1129 
1130         if (!(hduptr->isgroup)) {
1131             sprintf(errmes,"Keyword #%d, %s ",
1132             kwds[j]->kindex,kwds[j]->kname);
1133             strcat(errmes,
1134               "is only allowed in Random Groups structures.");
1135             wrterr(out,errmes,1);
1136             continue;
1137         }
1138 
1139 	check_str(kwds[j],out);
1140 	i = (int) strtol(p,NULL,10) -1 ;
1141         if(i< 0 || i >= hduptr->gcount) {
1142             sprintf(errmes,
1143       "Keyword #%d, %s: invalid index %d (> GCOUNT = %d).",
1144             kwds[j]->kindex,kwds[j]->kname,i+1,hduptr->gcount);
1145             wrterr(out,errmes,1);
1146             continue;
1147         }
1148     }
1149     test_array(infits, out, hduptr);
1150 
1151     return;
1152 }
1153 
1154 /*************************************************************
1155 *
1156 *      test_ext
1157 *
1158 *   Test the extension header
1159 *
1160 *
1161 *************************************************************/
test_ext(fitsfile * infits,FILE * out,FitsHdu * hduptr)1162 void test_ext(fitsfile *infits, 	/* input fits file   */
1163 	     FILE*     out,	/* output ascii file */
1164 	     FitsHdu  *hduptr	/* information about header */
1165             )
1166 {
1167     FitsKey *pkey;
1168     FitsKey **kwds;
1169     int  i,j,k,n;
1170     int numusrkey;
1171     char *exlkey[] = {"SIMPLE","EXTEND", "BLOCKED", };
1172     int nexlkey = 3;
1173     char *exlnkey[] = {"PTYPE","PSCAL", "PZERO", "GROUPS", };
1174     int nexlnkey = 4;
1175     int hdunum;
1176     char *p;
1177 
1178     numusrkey = hduptr->tkeys;
1179     kwds = hduptr->kwds;
1180     hdunum = hduptr->hdunum;
1181 
1182     /* check the duplicate extensions */
1183     for (i = hdunum - 1; i > 0; i--) {
1184         if(test_hduname(hdunum,i)) {
1185             sprintf(comm,
1186 	    "The HDU %d and %d have identical type/name/version",
1187                 hdunum,i);
1188             wrtwrn(out,comm,0);
1189         }
1190     }
1191 
1192     /* check the position of the PCOUNT  */
1193     strcpy(temp,"PCOUNT");
1194     ptemp = temp;
1195     key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n);
1196     if( k < 0) {
1197 	sprintf(errmes,"cannot find the PCOUNT keyword.");
1198         wrterr(out,errmes,1);
1199     }
1200     else {
1201         pkey = hduptr->kwds[k];
1202 	if(check_int(pkey,out))
1203 	    hduptr->pcount = (int) strtol(pkey->kvalue,NULL,10);
1204         if( pkey->kindex != 4 + hduptr->naxis ) {
1205 	     sprintf(errmes,"PCOUNT is not in record %d of the header.",
1206                  hduptr->naxis + 4);
1207              wrterr(out,errmes,1);
1208         }
1209 
1210         check_fixed_int(cards[pkey->kindex - 1], out);
1211     }
1212 
1213     /* check the position of the GCOUNT */
1214     strcpy(temp,"GCOUNT");
1215     ptemp = temp;
1216     key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n);
1217     if( k < 0) {
1218 	sprintf(errmes,"cannot find the GCOUNT keyword.");
1219         wrterr(out,errmes,1);
1220     }
1221     else {
1222         pkey = hduptr->kwds[k];
1223 	if(check_int(pkey,out))
1224 	    hduptr->gcount = (int) strtol(pkey->kvalue,NULL,10);
1225         if( pkey->kindex != 5 + hduptr->naxis ) {
1226 	     sprintf(errmes,"GCOUNT is not in record %d of the header.",
1227                  hduptr->naxis + 5);
1228              wrterr(out,errmes,1);
1229         }
1230 
1231         check_fixed_int(cards[pkey->kindex - 1], out);
1232     }
1233 
1234     for (i = 0; i < nexlkey; i++) {
1235         strcpy(temp,exlkey[i]);
1236     	ptemp = temp;
1237     	key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n);
1238     	if(k > -1) {
1239             pkey = hduptr->kwds[k];
1240             sprintf( errmes,
1241                "Keyword #%d, %s is not allowed in extensions.",
1242                pkey->kindex,pkey->kname);
1243             wrterr(out,errmes,1);
1244         }
1245     }
1246 
1247     for (i = 0; i < nexlnkey; i++) {
1248         strcpy(temp,exlnkey[i]);
1249     	ptemp = temp;
1250     	key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n);
1251     	if(k > -1) {
1252 
1253           for (j = k; j< k + n ; j++){
1254 	    p = kwds[j]->kname;
1255 	    p += 5;
1256             if(!isdigit((int)*p)) continue;
1257 
1258             pkey = hduptr->kwds[j];
1259             sprintf( errmes,
1260                "Keyword #%d, %s is only allowed in Random Groups structures.",
1261                pkey->kindex,pkey->kname);
1262             wrterr(out,errmes,1);
1263           }
1264         }
1265     }
1266 
1267     return;
1268 
1269 }
1270 /*************************************************************
1271 *
1272 *      test_img_ext
1273 *
1274 *   Test the image extension header
1275 *
1276 *
1277 *************************************************************/
test_img_ext(fitsfile * infits,FILE * out,FitsHdu * hduptr)1278 void test_img_ext(fitsfile *infits, 	/* input fits file   */
1279 	     FILE*     out,	/* output ascii file */
1280 	     FitsHdu  *hduptr	/* information about header */
1281             )
1282 {
1283     int numusrkey;
1284 
1285     numusrkey = hduptr->tkeys;
1286 
1287     test_ext(infits,out,hduptr);
1288 
1289     /* The XTENSION, BITPIX, NAXIS, and NAXISn keywords  have been
1290        checked in CFITSIO */
1291 
1292     if(hduptr->pcount != 0 && hduptr->pcount != -99){
1293         sprintf(errmes,
1294            "Illegal pcount value %d for image ext.",hduptr->pcount);
1295         wrterr(out,errmes,1);
1296     }
1297 
1298     if(hduptr->gcount !=1 && hduptr->gcount != -99){
1299         sprintf(errmes,
1300            "Illegal gcount value %d for image ext.",hduptr->gcount);
1301         wrterr(out,errmes,1);
1302     }
1303 
1304     test_array(infits, out, hduptr);
1305 
1306     return ;
1307 }
1308 
1309 /*************************************************************
1310 *
1311 *      test_array
1312 *
1313 *   Test the keywords which are used by both the primary array
1314 * and image Extension.
1315 *
1316 *
1317 *************************************************************/
test_array(fitsfile * infits,FILE * out,FitsHdu * hduptr)1318 void test_array(fitsfile *infits, 	/* input fits file   */
1319 	     FILE*     out,	/* output ascii file */
1320 	     FitsHdu  *hduptr	/* information about header */
1321             )
1322 {
1323     int numusrkey;
1324     FitsKey **kwds;
1325     char *p;
1326     int i,j,k,n;
1327     FitsKey *pkey;
1328 
1329     /* excluded non-indexed keywords  */
1330     char *exlkeys[] = {"TFIELDS","THEAP"};
1331     int nexlkeys = 2;
1332 
1333     /* excluded indexed keywords */
1334     char *exlnkeys[] = {"TBCOL", "TFORM",
1335                       "TSCAL", "TZERO","TNULL",
1336                       "TTYPE", "TUNIT","TDISP","TDIM",
1337                       "TCTYP","TCUNI","TCRVL","TCDLT","TCRPX","TCROT"};
1338     int nexlnkeys = 15;
1339 
1340     /* non-indexed floating keywords  (excluding BSCALE) */
1341     char *fltkeys[] = {"BZERO","DATAMAX","DATAMIN"};
1342     int nfltkeys = 3;
1343 
1344     /* non-indexed string keywords */
1345     char *strkeys[] = {"BUNIT"};
1346     int nstrkeys = 1;
1347 
1348     numusrkey = hduptr->tkeys;
1349     kwds = hduptr->kwds;
1350 
1351     /*  Check BLANK, BSCALE keywords */
1352     strcpy(temp,"BLANK");
1353     ptemp = temp;
1354     key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n);
1355     if( k >= 0) {
1356 	check_int(kwds[k],out);
1357         if(hduptr->bitpix < 0) {
1358             sprintf(errmes,
1359           "Keyword #%d, %s must not be used with floating point data (BITPIX = %d).",
1360                kwds[k]->kindex,kwds[k]->kname, hduptr->bitpix);
1361             wrterr(out,errmes,2);
1362         }
1363     }
1364 
1365     strcpy(temp,"BSCALE");
1366     ptemp = temp;
1367     key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n);
1368     if( k >= 0) {
1369 	if(check_flt(kwds[k],out) && strtod(kwds[k]->kvalue,NULL) == 0.0) {
1370                 sprintf(errmes,"Keyword #%d, %s: The scaling factor is 0.",
1371                 kwds[k]->kindex,kwds[k]->kname);
1372                 wrtwrn(out,errmes,0);
1373         }
1374     }
1375 
1376     /* search for excluded, non-indexed keywords */
1377     for (i = 0; i < nexlkeys; i++) {
1378         strcpy(temp,exlkeys[i]);
1379     	ptemp = temp;
1380     	key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n);
1381         if(k < 0) continue;
1382         for (j = k; j < k+n; j++) {
1383             pkey = hduptr->kwds[j];
1384             sprintf( errmes,
1385                "Keyword #%d, %s is not allowed in the array HDU.",
1386                pkey->kindex,pkey->kname);
1387             wrterr(out,errmes,1);
1388         }
1389     }
1390 
1391     /* search for excluded, indexed keywords */
1392     for (i = 0; i < nexlnkeys; i++) {
1393         strcpy(temp,exlnkeys[i]);
1394     	ptemp = temp;
1395     	key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n);
1396         if(k < 0) continue;
1397         for (j = k; j < k+n; j++) {
1398             pkey = hduptr->kwds[j];
1399 
1400 	    p = kwds[j]->kname;
1401 	    p += strlen(temp);
1402             if(!isdigit((int)*p)) continue;
1403 
1404             sprintf( errmes,
1405                "Keyword #%d, %s is not allowed in the array HDU.",
1406                pkey->kindex,pkey->kname);
1407             wrterr(out,errmes,1);
1408         }
1409     }
1410 
1411     /* test datatype of reserved non-indexed floating point keywords */
1412     for (i = 0; i < nfltkeys; i++) {
1413         strcpy(temp,fltkeys[i]);
1414     	ptemp = temp;
1415     	key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n);
1416         if(k < 0) continue;
1417         for (j = k; j < k+n; j++) {
1418             pkey = hduptr->kwds[j];
1419 	    if (!check_flt(pkey,out)) continue;
1420         }
1421     }
1422 
1423     /* test datatype of reserved non-indexed string keywords */
1424     for (i = 0; i < nstrkeys; i++) {
1425         strcpy(temp,strkeys[i]);
1426     	ptemp = temp;
1427     	key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n);
1428         if(k < 0) continue;
1429         for (j = k; j < k+n; j++) {
1430             pkey = hduptr->kwds[j];
1431 	    check_str(pkey,out);
1432         }
1433     }
1434 
1435     return;
1436 }
1437 
1438 /*************************************************************
1439 *
1440 *      test_img_wcs
1441 *
1442 *   Test the image WCS keywords
1443 *
1444 *
1445 *************************************************************/
1446 
1447 /*
1448 void test_img_wcs(fitsfile *infits,
1449 	     FILE*     out,
1450 	     FitsHdu  *hduptr
1451             )
1452 {
1453 
1454     int nkeyrec, nreject, nwcs, status = 0;
1455     int *stat = 0, ii;
1456     char *header;
1457     struct wcsprm *wcs;
1458 */
1459 
1460 /* NOTE: WCSLIB currently doesn't provide very much diagnostic information
1461   about possible problems with the WCS keywords so for now, comment out this
1462   routine.
1463 */
1464 
1465     /* use WCSLIB to look for inconsistencies in the WCS keywords */
1466 
1467     /* Read in the FITS header, excluding COMMENT and HISTORY keyrecords. */
1468 /*
1469     if (fits_hdr2str(infits, 1, NULL, 0, &header, &nkeyrec, &status)) {
1470         sprintf(errmes,
1471            "test_img_ext failed to read header keywords into array %d", status);
1472         wrterr(out,errmes,1);
1473 	return;
1474     }
1475 */
1476     /* Interpret the WCS keywords. */
1477 
1478 /*
1479     if ((status = wcsbth(header, nkeyrec, WCSHDR_all, -2, 0, 0, &nreject, &nwcs,
1480                        &wcs))) {
1481         sprintf(errmes,
1482            "test_img_ext: wcsbth ERROR %d: %s.", status, wcshdr_errmsg[status]);
1483         wrterr(out,errmes,1);
1484 
1485         free(header);
1486 	return;
1487     }
1488 
1489     free(header);
1490 
1491     if (wcs) {
1492         if (nwcs == 1) {
1493            sprintf(errmes,
1494                " Found 1 World Coordinate System (WCS).");
1495         } else {
1496            sprintf(errmes,
1497                " Found %d World Coordinate Systems (WCS).", nwcs);
1498         }
1499         wrtout(out,errmes);
1500     }
1501 */
1502     /* Translate non-standard WCS keyvalues and look for inconsistencies */
1503 
1504 /* this doesn't provide any useful checks
1505     stat = malloc(NWCSFIX * sizeof(int));
1506 
1507     if ((status = wcsfix(7, 0, wcs, stat))) {
1508       for (ii = 0; ii < NWCSFIX; ii++) {
1509         if (stat[ii] > 0) {
1510            sprintf(errmes, "wcsfix ERROR %d: %s.", stat[ii],
1511                    wcsfix_errmsg[stat[ii]]);
1512            wrtwrn(out,errmes,0);
1513 
1514         }
1515       }
1516     }
1517 
1518     if ((status = wcsset(wcs))) {
1519       sprintf(errmes,
1520          "wcsset ERROR %d %s.", status, wcs_errmsg[status]);
1521       wrtwrn(out,errmes,0);
1522     }
1523 */
1524 
1525 /*
1526     status = wcsvfree(&nwcs, &wcs);
1527 
1528     return;
1529 }
1530 */
1531 
1532 /*************************************************************
1533 *
1534 *      test_tbl
1535 *
1536 *   Test the table extension header and fill the tform, ttype,
1537 *   tunit.
1538 *
1539 *
1540 *************************************************************/
test_tbl(fitsfile * infits,FILE * out,FitsHdu * hduptr)1541 void test_tbl(fitsfile *infits, 	/* input fits file   */
1542 	     FILE*     out,	/* output ascii file */
1543 	     FitsHdu  *hduptr	/* information about header */
1544             )
1545 
1546 {
1547     FitsKey *pkey;
1548     FitsKey **kwds;
1549     char *p;
1550     char *q;
1551     int m,n,i,j,k;
1552     long w,d,e;
1553     long lm;
1554     int mcol;
1555 
1556     /* excluded, non-index keywords (allowed in tile-compressed images) */
1557     char*  exlkey[] = {"BSCALE","BZERO", "BUNIT", "BLANK", "DATAMAX",
1558                        "DATAMIN" };
1559     int nexlkey = 6;
1560 
1561     /* floating WCS keywords  */
1562     char *cfltkeys[] = {"TCRVL","TCDLT","TCRPX","TCROT" };
1563     int ncfltkeys = 4;
1564 
1565     /* string WCS keywords  */
1566     char *cstrkeys[] = {"TCTYP","TCUNI" };
1567     int ncstrkeys = 2
1568 ;
1569     int numusrkey;
1570 
1571     numusrkey = hduptr->tkeys;
1572     mcol = hduptr->ncols;
1573     kwds = hduptr->kwds;
1574 
1575     if(mcol <= 0) goto OTHERKEY;
1576     /* set the ttype, ttform, tunit for tables */
1577     ttype =  (char **)calloc(mcol, sizeof(char *));
1578     tform =  (char **)calloc(mcol, sizeof(char *));
1579     tunit =  (char **)calloc(mcol, sizeof(char *));
1580     for (i=0; i< mcol; i++) {
1581        ttype[i] = snull;
1582        tform[i] = snull;
1583        tunit[i] = snull;
1584     }
1585 
1586     strcpy(temp,"TFIELDS");
1587     ptemp = temp;
1588     key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n);
1589     if( k >= 0) {
1590         pkey = hduptr->kwds[k];
1591         check_fixed_int(cards[pkey->kindex - 1], out);
1592     }
1593 
1594     strcpy(temp,"TTYPE");
1595     ptemp = temp;
1596     key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n);
1597     for (j = k; j< k+n ; j++){
1598         pkey = hduptr->kwds[j];
1599         p = pkey->kname;
1600         p += 5;
1601         if(!isdigit((int)*p)) continue;
1602 
1603 	check_str(pkey,out);
1604         i = (int) strtol(p,NULL,10) -1 ;
1605         if(i>= 0 && i < mcol) {
1606             ttype[i] = pkey->kvalue;
1607         }
1608         else {
1609             sprintf(errmes,
1610       "Keyword #%d, %s: invalid index %d (> TFIELD = %d).",
1611             pkey->kindex,pkey->kname,i+1,mcol);
1612             wrterr(out,errmes,2);
1613         }
1614     }
1615 
1616     strcpy(temp,"TFORM");
1617     ptemp = temp;
1618     key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n);
1619     for (j = k; j< k + n ; j++){
1620         pkey = hduptr->kwds[j];
1621         p = pkey->kname;
1622         p += 5;
1623         if(!isdigit((int)*p)) continue;
1624 
1625 	check_str(pkey,out);
1626 
1627 /*  TFORMn keyword no longer required to be padded to at least 8 characters
1628         check_fixed_str(cards[pkey->kindex - 1], out);
1629 */
1630 
1631         if(*(pkey->kvalue) == ' ') {
1632             sprintf(errmes,"Keyword #%d, %s: TFORM=\"%s\" ",
1633             pkey->kindex,pkey->kname, pkey->kvalue);
1634             strcat(errmes,
1635                 "should not have leading space.");
1636             wrterr(out,errmes,1);
1637         }
1638 
1639         i = (int) strtol(p,NULL,10) -1 ;
1640         if(i>= 0 && i < mcol) {
1641             tform[i] = pkey->kvalue;
1642         }
1643         else {
1644             sprintf(errmes,
1645       "Keyword #%d, %s: invalid index %d (> TFIELD = %d).",
1646             pkey->kindex,pkey->kname,i+1,mcol);
1647             wrterr(out,errmes,2);
1648         }
1649 
1650         p = pkey->kvalue;
1651         while(*p != ' ' && *p != '\0') {
1652             if( !isdigit((int)*p) && !isupper((int)*p) && *p != '.' && *p != ')'
1653                 && *p != '(' ) {
1654                 sprintf(errmes,
1655 "Keyword #%d, %s: The value %s has character %c which is not uppercase letter.",
1656                 pkey->kindex,pkey->kname,pkey->kvalue,*p);
1657                 wrterr(out,errmes,1);
1658             }
1659 
1660             p++;
1661         }
1662     }
1663 
1664     strcpy(temp,"TUNIT");
1665     ptemp = temp;
1666     key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n);
1667     for (j = k; j< k + n ; j++){
1668         pkey = hduptr->kwds[j];
1669         p = pkey->kname;
1670         p += 5;
1671         if(!isdigit((int)*p)) continue;
1672 
1673 	check_str(pkey,out);
1674         i = (int) strtol(p,NULL,10) -1 ;
1675         if(i>= 0 && i < mcol) {
1676             tunit[i] = pkey->kvalue;
1677         }
1678         else {
1679             sprintf(errmes,
1680       "Keyword #%d, %s: invalid index %d (> TFIELD = %d).",
1681             pkey->kindex,pkey->kname,i+1,mcol);
1682             wrterr(out,errmes,1);
1683         }
1684     }
1685 
1686     /*  Check TDISPn keywords */
1687     strcpy(temp,"TDISP");
1688     ptemp = temp;
1689     key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n);
1690     for (j = k; j< k + n ; j++){
1691 	p = kwds[j]->kname;
1692 	p += 5;
1693         if(!isdigit((int)*p)) continue;
1694 
1695         if (*(kwds[j]->kvalue) == '\0') continue;  /* ignore blank string */
1696 	check_str(kwds[j],out);
1697         if(*(kwds[j]->kvalue) == ' ') {
1698             sprintf(errmes,"Keyword #%d, %s: TDISP=\"%s\" ",
1699                 kwds[j]->kindex,kwds[j]->kname,kwds[j]->kvalue);
1700             strcat(errmes,
1701                     "should not have leading space.");
1702             wrterr(out,errmes,1);
1703         }
1704 
1705 
1706 	i = (int) strtol(p,NULL,10) -1 ;
1707         if(i< 0 || i >= mcol ) {
1708             sprintf(errmes,
1709       "Keyword #%d, %s: invalid index %d (> TFIELD = %d).",
1710             kwds[j]->kindex,kwds[j]->kname,i+1,mcol);
1711             wrterr(out,errmes,1);
1712             continue;
1713         }
1714         p = kwds[j]->kvalue;
1715         switch (*p) {
1716             case 'A':
1717                  p++;
1718 		 w = 0;
1719                  w = strtol(p,NULL,10);
1720                  if( !w || w == LONG_MAX || w == LONG_MIN) {
1721                      sprintf(errmes,
1722                        "Keyword #%d, %s: invalid format \"%s\".",
1723                        kwds[j]->kindex,kwds[j]->kname, kwds[j]->kvalue);
1724                      wrterr(out,errmes,1);
1725                  }
1726                  if(strchr(tform[i],'A') == NULL ){
1727                      sprintf(errmes,
1728         "Keyword #%d, %s:  Format \"%s\" cannot be used for TFORM \"%s\".",
1729         kwds[j]->kindex,kwds[j]->kname, kwds[j]->kvalue, tform[i]);
1730                      wrterr(out,errmes,1);
1731                  }
1732                  break;
1733             case 'L':
1734                  p++;
1735 		 w = 0;
1736                  w = strtol(p,NULL,10);
1737                  if(!w || w == LONG_MAX || w == LONG_MIN) {
1738                      sprintf(errmes,
1739                        "Keyword #%d, %s: invalid format \"%s\".",
1740                        kwds[j]->kindex,kwds[j]->kname, kwds[j]->kvalue);
1741                      wrterr(out,errmes,1);
1742                  }
1743                  if(strchr(tform[i],'L') == NULL ){
1744                      sprintf(errmes,
1745         "Keyword #%d, %s:  Format %s cannot be used for TFORM \"%s\".",
1746         kwds[j]->kindex,kwds[j]->kname, kwds[j]->kvalue, tform[i]);
1747                      wrterr(out,errmes,1);
1748                  }
1749                  break;
1750             case 'I': case 'B': case 'O': case 'Z':
1751                  p++;
1752 		 w = 0;
1753                  w = strtol(p,NULL,10);
1754                  if((q = strchr(p,'.')) != NULL) {
1755 		     p = q;
1756                      p++;
1757                      lm = strtol(p,NULL,10);
1758                  }
1759                  else {
1760                     lm = -1;    /* no minimum digit field */
1761                  }
1762                  if(!w || w == LONG_MAX || w == LONG_MIN  ||
1763                     lm == LONG_MAX || lm == LONG_MIN  || w < lm ) {
1764                      sprintf(errmes,
1765                        "Keyword #%d, %s: invalid format \"%s\".",
1766                        kwds[j]->kindex,kwds[j]->kname, kwds[j]->kvalue);
1767                      wrterr(out,errmes,1);
1768                  }
1769                  if(strchr(tform[i],'I') == NULL &&
1770                     strchr(tform[i],'J') == NULL &&
1771                     strchr(tform[i],'K') == NULL &&
1772                     strchr(tform[i],'B') == NULL &&
1773                     strchr(tform[i],'X') == NULL   ){
1774                      sprintf(errmes,
1775         "Keyword #%d, %s:  Format \"%s\" cannot be used for TFORM \"%s\".",
1776         kwds[j]->kindex,kwds[j]->kname, kwds[j]->kvalue, tform[i]);
1777                      wrterr(out,errmes,1);
1778                  }
1779                  break;
1780             case 'F':
1781                  p++;
1782 		 d = -1;
1783 		 w = 0;
1784                  w = strtol(p,NULL,10);
1785                  if((q = strchr(p,'.')) != NULL) {
1786 		     p = q;
1787                      p++;
1788                      d = strtol(p,NULL,10);
1789                  }
1790                  if(!w || w == LONG_MAX || w == LONG_MIN  ||
1791                     d == -1 || d == LONG_MAX || d == LONG_MIN  || w < d+1 ) {
1792                      sprintf(errmes,
1793                        "Keyword #%d, %s: invalid format \"%s\".",
1794                        kwds[j]->kindex,kwds[j]->kname, kwds[j]->kvalue);
1795                      wrterr(out,errmes,1);
1796                  }
1797                  if(strchr(tform[i],'E') == NULL &&
1798                     strchr(tform[i],'F') == NULL &&
1799                     strchr(tform[i],'C') == NULL &&
1800                     strchr(tform[i],'D') == NULL &&
1801                     strchr(tform[i],'M') == NULL &&
1802                     strchr(tform[i],'I') == NULL &&
1803                     strchr(tform[i],'J') == NULL &&
1804                     strchr(tform[i],'B') == NULL &&
1805                     strchr(tform[i],'X') == NULL  ){
1806                      sprintf(errmes,
1807         "Keyword #%d, %s:  Format \"%s\" cannot be used for TFORM \"%s\".",
1808         kwds[j]->kindex,kwds[j]->kname, kwds[j]->kvalue, tform[i]);
1809                      wrterr(out,errmes,1);
1810                  }
1811                  break;
1812             case 'E': case 'D':
1813                  p++;
1814 		 w = 0;
1815                  e = 0;
1816 		 d = 0;
1817                  if(*p == 'N' || *p == 'S') { p++; e = 2;}
1818                  w = strtol(p,NULL,10);
1819                  if((q = strchr(p,'.')) != NULL) {
1820 		     p = q;
1821                      p++;
1822                      d = strtol(p,NULL,10);
1823                  }
1824                  if((q = strchr(p,'E')) != NULL) {
1825 		     p = q;
1826                      p++;
1827                      e = strtol(p,NULL,10);
1828                  }
1829 		 else {
1830                      e = 2;
1831                  }
1832                  if(!w || w == LONG_MAX || w == LONG_MIN  ||
1833                     !d || d == LONG_MAX || d == LONG_MIN  ||
1834                     !e || e == LONG_MAX || e == LONG_MIN  ||
1835                     w < d+e+3) {
1836                      sprintf(errmes,
1837                        "Keyword #%d, %s: invalid format \"%s\".",
1838                        kwds[j]->kindex,kwds[j]->kname, kwds[j]->kvalue);
1839                      wrterr(out,errmes,1);
1840                  }
1841                  if(strchr(tform[i],'E') == NULL &&
1842                     strchr(tform[i],'F') == NULL &&
1843                     strchr(tform[i],'C') == NULL &&
1844                     strchr(tform[i],'D') == NULL &&
1845                     strchr(tform[i],'M') == NULL &&
1846                     strchr(tform[i],'I') == NULL &&
1847                     strchr(tform[i],'J') == NULL &&
1848                     strchr(tform[i],'B') == NULL &&
1849                     strchr(tform[i],'X') == NULL  ){
1850                      sprintf(errmes,
1851         "Keyword #%d, %s:  Format \"%s\" cannot be used for TFORM \"%s\".",
1852         kwds[j]->kindex,kwds[j]->kname, kwds[j]->kvalue, tform[i]);
1853                      wrterr(out,errmes,1);
1854                  }
1855                  break;
1856             case 'G':
1857                  p++;
1858                  e = 0;
1859 		 d = 0;
1860 		 w = 0;
1861                  w = strtol(p,NULL,10);
1862                  if((q = strchr(p,'.')) != NULL) {
1863 		     p = q;
1864                      p++;
1865                      d = strtol(p,NULL,10);
1866                  }
1867                  if((q = strchr(p,'E')) != NULL) {
1868 		     p = q;
1869                      p++;
1870                      e = strtol(p,NULL,10);
1871                  }
1872 		 else {
1873                      e = 2;
1874                  }
1875                  if(!w || w == LONG_MAX || w == LONG_MIN  ||
1876                     !d || d == LONG_MAX || d == LONG_MIN  ||
1877                     !e || e == LONG_MAX || e == LONG_MIN  ){
1878                      sprintf(errmes,
1879                        "Keyword #%d, %s: invalid format \"%s\".",
1880                        kwds[j]->kindex,kwds[j]->kname, kwds[j]->kvalue);
1881                      wrterr(out,errmes,1);
1882                  }
1883                  break;
1884              default:
1885                  sprintf(errmes,
1886                    "Keyword #%d, %s: invalid format \"%s\".",
1887                    kwds[j]->kindex,kwds[j]->kname, kwds[j]->kvalue);
1888                  wrterr(out,errmes,1);
1889                  break;
1890         }
1891     }
1892 
1893 OTHERKEY:
1894     if (!(hduptr->istilecompressed) ) {
1895       /* tile compressed images can have these keywords */
1896       for (i = 0; i < nexlkey; i++) {
1897         strcpy(temp,exlkey[i]);
1898     	ptemp = temp;
1899     	key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n);
1900     	if(k > -1) {
1901             pkey = hduptr->kwds[k];
1902             sprintf( errmes,
1903                "Keyword #%d, %s is not allowed in the Bin/ASCII table.",
1904                pkey->kindex,pkey->kname);
1905             wrterr(out,errmes,1);
1906         }
1907       }
1908 
1909       /* search for excluded indexed keywords */
1910 
1911 /* these WCS keywords are all allowed (changed July 2010)
1912       for (i = 0; i < nexlkeys; i++) {
1913         strcpy(temp,exlkeys[i]);
1914     	ptemp = temp;
1915     	key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n);
1916         if(k < 0) continue;
1917         for (j = k; j < k+n; j++) {
1918             pkey = hduptr->kwds[j];
1919 
1920 	    p = kwds[j]->kname;
1921 	    p += strlen(temp);
1922             if(!isdigit((int)*p)) continue;
1923 
1924             sprintf( errmes,
1925                "Keyword #%d, %s is not allowed in the Bin/ASCII table.",
1926                pkey->kindex,pkey->kname);
1927             wrterr(out,errmes,1);
1928         }
1929       }
1930 */
1931     }
1932 
1933     /* test datatype of reserved indexed floating point WCS keywords */
1934     for (i = 0; i < ncfltkeys; i++) {
1935         strcpy(temp,cfltkeys[i]);
1936     	ptemp = temp;
1937     	key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n);
1938         if(k < 0) continue;
1939 
1940         for (j = k; j < k+n; j++) {
1941             pkey = hduptr->kwds[j];
1942 
1943 	    p = kwds[j]->kname;
1944 	    p += strlen(temp);
1945             if(!isdigit((int)*p)) continue;
1946 
1947 	    if (!check_flt(pkey,out) )continue;
1948 
1949             m = (int)strtol(p,NULL,10);
1950             if (m < 1 || m > mcol) {
1951                 sprintf( errmes,
1952             "Keyword #%d, %s: index %d is not in range 1-%d (TFIELD).",
1953                    pkey->kindex,pkey->kname,m,mcol);
1954                    wrterr(out,errmes,1);
1955             }
1956         }
1957     }
1958 
1959     /* test datatype of reserved indexed string WCS keywords */
1960     for (i = 0; i < ncstrkeys; i++) {
1961         strcpy(temp,cstrkeys[i]);
1962     	ptemp = temp;
1963     	key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n);
1964         if(k < 0) continue;
1965 
1966         for (j = k; j < k+n; j++) {
1967             pkey = hduptr->kwds[j];
1968 
1969 	    p = kwds[j]->kname;
1970 	    p += strlen(temp);
1971             if(!isdigit((int)*p)) continue;
1972 
1973 	    if (!check_str(pkey,out) )continue;
1974 
1975             m = (int)strtol(p,NULL,10);
1976             if (m < 1 || m > mcol) {
1977                 sprintf( errmes,
1978             "Keyword #%d, %s: index %d is not in range 1-%d (TFIELD).",
1979                    pkey->kindex,pkey->kname,m,mcol);
1980                    wrterr(out,errmes,1);
1981             }
1982 
1983         }
1984     }
1985     return;
1986 }
1987 
1988 /*************************************************************
1989 *
1990 *      test_asc_ext
1991 *
1992 *   Test the ascii table extension header
1993 *
1994 *
1995 *************************************************************/
test_asc_ext(fitsfile * infits,FILE * out,FitsHdu * hduptr)1996 void test_asc_ext(fitsfile *infits, 	/* input fits file   */
1997 	     FILE*     out,	/* output ascii file */
1998 	     FitsHdu  *hduptr	/* information about header */
1999             )
2000 {
2001     int numusrkey;
2002     FitsKey **kwds;
2003     FitsKey *pkey;
2004     char *p;
2005     int i,j,k;
2006     int n;
2007     int mcol;
2008 
2009     numusrkey = hduptr->tkeys;
2010     kwds = hduptr->kwds;
2011     mcol = hduptr->ncols;
2012 
2013     /* The XTENSION, BITPIX, NAXIS, NAXISn, TFIELDS, PCOUNT, GCOUNT, TFORMn,
2014        TBCOLn, TTYPEn keywords  have been checked in CFITSIO */
2015 
2016     /* General extension */
2017     test_ext(infits,out,hduptr);
2018 
2019     /* general table */
2020     test_tbl(infits,out,hduptr);
2021 
2022     /* Check TBCOLn */
2023     strcpy(temp,"TBCOL");
2024     ptemp = temp;
2025     key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n);
2026     for (j = k; j< k + n ; j++){
2027         pkey = hduptr->kwds[j];
2028         p = pkey->kname;
2029         p += 5;
2030         if(!isdigit((int)*p)) continue;
2031 
2032         check_int(pkey,out);
2033 
2034         i = (int) strtol(p,NULL,10) ;
2035         if(i< 0 || i > mcol) {
2036             sprintf(errmes,
2037       "Keyword #%d, %s: invalid index %d (> TFIELD = %d).",
2038             pkey->kindex,pkey->kname,i,mcol);
2039             wrterr(out,errmes,1);
2040         }
2041         else {
2042             check_fixed_int(cards[pkey->kindex - 1], out);
2043         }
2044     }
2045 
2046     /*  Check TNULLn, TSCALn, and TZEORn keywords */
2047     strcpy(temp,"TNULL");
2048     ptemp = temp;
2049     key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n);
2050     for (j = k; j< k + n ; j++){
2051 	p = kwds[j]->kname;
2052 	p += 5;
2053         if(!isdigit((int)*p)) continue;
2054         i = (int) strtol(p,NULL,10) -1;
2055         if(i< 0 || i >= mcol) {
2056             sprintf(errmes,
2057       "Keyword #%d, %s: invalid index %d (> TFIELD = %d).",
2058            kwds[j]->kindex,kwds[j]->kname,i+1,mcol);
2059             wrterr(out,errmes,1);
2060         }
2061 	check_str(kwds[j],out);
2062     }
2063 
2064     strcpy(temp,"TSCAL");
2065     ptemp = temp;
2066     key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n);
2067     for (j = k; j< k + n ; j++){
2068 	p = kwds[j]->kname;
2069 	p += 5;
2070         if(!isdigit((int)*p)) continue;
2071         i = (int) strtol(p,NULL,10) -1 ;
2072 	if(check_flt(kwds[j],out)){
2073             if(strtod(kwds[j]->kvalue,NULL) == 0.0) {
2074                 sprintf(errmes,"Keyword #%d, %s: Scaling factor is zero.",
2075                 kwds[j]->kindex,kwds[j]->kname);
2076                 wrtwrn(out,errmes,0);
2077             }
2078         }
2079         if(i< 0 || i >= mcol) {
2080             sprintf(errmes,
2081       "Keyword #%d, %s: invalid index %d (> TFIELD = %d).",
2082             kwds[j]->kindex,kwds[j]->kname,i+1,mcol);
2083             wrterr(out,errmes,1);
2084             continue;
2085         }
2086         if(strchr(tform[i],'A') != NULL) {
2087             sprintf(errmes,
2088               "Keyword #%d, %s may not be used for the A-format fields.",
2089             kwds[j]->kindex,kwds[j]->kname);
2090             wrterr(out,errmes,1);
2091         }
2092     }
2093 
2094     strcpy(temp,"TZERO");
2095     ptemp = temp;
2096     key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n);
2097     for (j = k; j< k + n ; j++){
2098 	p = kwds[j]->kname;
2099 	p += 5;
2100         if(!isdigit((int)*p)) continue;
2101 	check_flt(kwds[j],out);
2102 	i = (int) strtol(p,NULL,10) -1 ;
2103         if(i< 0 || i >= mcol) {
2104             sprintf(errmes,
2105       "Keyword #%d, %s: invalid index %d (> TFIELD = %d).",
2106             kwds[j]->kindex,kwds[j]->kname,i+1,mcol);
2107             wrterr(out,errmes,1);
2108             continue;
2109         }
2110         if(strchr(tform[i],'A') != NULL) {
2111             sprintf(errmes,
2112               "Keyword #%d, %s may not be used for the A-format fields.",
2113             kwds[j]->kindex,kwds[j]->kname);
2114             wrterr(out,errmes,1);
2115         }
2116     }
2117 
2118     strcpy(temp,"TDIM");
2119     ptemp = temp;
2120     key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n);
2121     for (j = k; j< k + n ; j++){
2122 	p = kwds[j]->kname;
2123 	p += 4;
2124         if(!isdigit((int)*p)) continue;
2125 
2126         pkey = hduptr->kwds[j];
2127         sprintf( errmes,
2128            "Keyword #%d, %s is not allowed in the ASCII table.",
2129            pkey->kindex,pkey->kname);
2130         wrterr(out,errmes,1);
2131     }
2132 
2133     strcpy(temp,"THEAP");
2134     ptemp = temp;
2135     key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n);
2136     if (k > -1) {
2137         pkey = hduptr->kwds[k];
2138         sprintf( errmes,
2139            "Keyword #%d, %s is not allowed in the ASCII table.",
2140            pkey->kindex,pkey->kname);
2141         wrterr(out,errmes,1);
2142     }
2143 
2144 
2145     /* check whether the column name is unique  */
2146     test_colnam(out, hduptr);
2147     return ;
2148 }
2149 
2150 
2151 /*************************************************************
2152 *
2153 *      test_bin_ext
2154 *
2155 *   Test the binary table extension header
2156 *
2157 *
2158 *************************************************************/
test_bin_ext(fitsfile * infits,FILE * out,FitsHdu * hduptr)2159 void test_bin_ext(fitsfile *infits, 	/* input fits file   */
2160 	     FILE*     out,	/* output ascii file */
2161 	     FitsHdu  *hduptr	/* information about header */
2162             )
2163 {
2164     FitsKey *pkey;
2165     int i,j,k,n;
2166     long l;
2167     int status = 0;
2168     char *p;
2169 
2170     int ntdim;
2171     long tdim[10];
2172     int repeat, width;
2173     FitsKey **kwds;
2174     int numusrkey;
2175     int mcol, vla, datatype;
2176 
2177     /* The indexed keywords excluded from ascii table */
2178     char *exlkeys[] = { "TBCOL"};
2179     int nexlkeys = 1;
2180 
2181     kwds = hduptr->kwds;
2182     numusrkey = hduptr->tkeys;
2183     mcol = hduptr->ncols;
2184 
2185     /* General extension */
2186     test_ext(infits,out,hduptr);
2187 
2188     /* General table */
2189     test_tbl(infits,out,hduptr);
2190 
2191     /* The XTENSION, BITPIX, NAXIS, NAXISn, TFIELDS, PCOUNT, GCOUNT, TFORMn,
2192        TTYPEn keywords  have been checked in CFITSIO */
2193 
2194     /*  Check TNULLn keywords */
2195     strcpy(temp,"TNULL");
2196     ptemp = temp;
2197     key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n);
2198     for (j = k; j< k + n ; j++){
2199 	p = kwds[j]->kname;
2200 	p += 5;
2201         if(!isdigit((int)*p)) continue;
2202 	check_int(kwds[j],out);
2203 	i = (int) strtol(p,NULL,10) -1 ;
2204         if(i< 0 || i >= mcol) {
2205             sprintf(errmes,
2206       "Keyword #%d, %s: invalid index %d (> TFIELD = %d).",
2207            kwds[j]->kindex,kwds[j]->kname,i+1,mcol);
2208             wrterr(out,errmes,1);
2209             continue;
2210         }
2211         if(strchr(tform[i],'B') == NULL &&
2212            strchr(tform[i],'I') == NULL &&
2213            strchr(tform[i],'J') == NULL &&
2214            strchr(tform[i],'K') == NULL ) {
2215             sprintf(errmes,
2216      "Keyword #%d, %s is used for the column with format \"%s \".",
2217             kwds[j]->kindex,kwds[j]->kname,tform[i]);
2218             wrterr(out,errmes,2);
2219         }
2220         l = strtol(kwds[j]->kvalue,NULL,10);
2221         if(strchr(tform[i],'B') != NULL && (
2222             l < 0 || l > 255) ) {
2223             sprintf(errmes,"Keyword #%d, %s: The value %ld",
2224             kwds[j]->kindex,kwds[j]->kname, l);
2225             strcat(errmes, " is not in the range of datatype B.");
2226             wrtwrn(out,errmes,0);
2227         }
2228         l = strtol(kwds[j]->kvalue,NULL,10);
2229         if(strchr(tform[i],'I') != NULL && (
2230             l < -32768 || l > 32767) ) {
2231             sprintf(errmes,"Keyword #%d, %s: The value %ld",
2232             kwds[j]->kindex,kwds[j]->kname, l);
2233             strcat(errmes, " is not in the range of datatype I ");
2234             wrtwrn(out,errmes,0);
2235         }
2236     }
2237 
2238     /*  Check TSCALn keywords */
2239     strcpy(temp,"TSCAL");
2240     ptemp = temp;
2241     key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n);
2242     for (j = k; j< k + n ; j++){
2243 	p = kwds[j]->kname;
2244 	p += 5;
2245         if(!isdigit((int)*p)) continue;
2246 	if (check_flt(kwds[j],out) && strtod(kwds[j]->kvalue,NULL) == 0.0) {
2247             sprintf(errmes,"Keyword #%d, %s:",
2248             kwds[j]->kindex,kwds[j]->kname);
2249             strcat(errmes,
2250               "The scaling factor is zero.");
2251             wrtwrn(out,errmes,0);
2252         }
2253 	i = (int) strtol(p,NULL,10) -1 ;
2254         if(i< 0 || i >= mcol) {
2255             sprintf(errmes,
2256       "Keyword #%d, %s: invalid index %d (> TFIELD = %d).",
2257             kwds[j]->kindex,kwds[j]->kname,i+1,mcol);
2258             wrterr(out,errmes,1);
2259             continue;
2260         }
2261         if(strchr(tform[i],'A') != NULL ||
2262            strchr(tform[i],'L') != NULL ||
2263            strchr(tform[i],'X') != NULL ) {
2264             sprintf(errmes,
2265          "Keyword #%d, %s is used in A, L, or X column. ",
2266             kwds[j]->kindex,kwds[j]->kname);
2267             wrterr(out,errmes,1);
2268         }
2269     }
2270 
2271     /*  Check TZEROn keywords */
2272     strcpy(temp,"TZERO");
2273     ptemp = temp;
2274     key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n);
2275     for (j = k; j< k + n ; j++){
2276 	p = kwds[j]->kname;
2277 	p += 5;
2278         if(!isdigit((int)*p)) continue;
2279 	check_flt(kwds[j],out);
2280 	i = (int) strtol(p,NULL,10) -1 ;
2281         if(i< 0 || i >= mcol) {
2282             sprintf(errmes,
2283       "Keyword #%d, %s: invalid index %d (> TFIELD = %d).",
2284             kwds[j]->kindex,kwds[j]->kname,i+1,mcol);
2285             wrterr(out,errmes,1);
2286             continue;
2287         }
2288         if(strchr(tform[i],'A') != NULL &&
2289            strchr(tform[i],'L') != NULL &&
2290            strchr(tform[i],'X') != NULL ) {
2291             sprintf(errmes,
2292                 "Keyword #%d, %s is used in A, L, or X column. ",
2293             kwds[j]->kindex,kwds[j]->kname);
2294             wrterr(out,errmes,1);
2295         }
2296     }
2297 
2298     /* Check THEAP keyword */
2299     hduptr->heap = (hduptr->naxes[0]) * (hduptr->naxes[1]);
2300     strcpy(temp,"THEAP");
2301     key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n);
2302     if(k > -1) {
2303          if(check_int(kwds[k],out))
2304              hduptr->heap = (int) strtol(hduptr->kwds[k]->kvalue,NULL,10);
2305          if(!hduptr->pcount) {
2306             sprintf( errmes,
2307                "Pcount is zero, but keyword THEAP is present at record #%d). ",
2308 	        kwds[k]->kindex);
2309                 wrterr(out,errmes,1);
2310          }
2311     }
2312 
2313     /* if PCOUNT != 0, test that there is at least 1 variable length array column */
2314     vla = 0;
2315     if(hduptr->pcount) {
2316         for (i=0; i< mcol; i++){
2317             if(fits_get_coltype(infits, i+1, &datatype, NULL, NULL, &status)){
2318                sprintf(errmes,"Column #%d: ",i);
2319  	       wrtferr(out,errmes, &status,2);
2320             }
2321             if (datatype < 0) {
2322 	      vla = 1;
2323 	      break;
2324 	    }
2325 	}
2326 
2327 	if (vla == 0) {
2328 	    sprintf(errmes,
2329 	    "PCOUNT = %ld, but there are no variable-length array columns.",
2330 	   (long) hduptr->pcount);
2331             wrtwrn(out,errmes,0);
2332 	}
2333     }
2334 
2335 
2336     /* Check TDIMn  keywords */
2337     strcpy(temp,"TDIM");
2338     key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n);
2339     for (j = k; j< k + n ; j++){
2340         pkey = kwds[j];
2341 	p = pkey->kname;
2342 	p += 4;
2343         if(!isdigit((int)*p)) continue;
2344 	check_str(kwds[j],out);
2345         if(*(pkey->kvalue) == ' ') {
2346             sprintf(errmes,"Keyword #%d, %s: TDIM=\"%s\" ",
2347                 pkey->kindex,pkey->kname,pkey->kvalue);
2348             strcat(errmes,
2349                     "should not have leading space.");
2350             wrterr(out,errmes,1);
2351             continue;
2352         }
2353 	i = (int) strtol(p,NULL,10) -1 ;
2354         if(i< 0 || i >= mcol) {
2355             sprintf(errmes,
2356       "Keyword #%d, %s: invalid index %d (> TFIELD = %d).",
2357             kwds[j]->kindex,kwds[j]->kname,i+1,mcol);
2358             wrterr(out,errmes,1);
2359             continue;
2360         }
2361 	if(fits_decode_tdim(infits,pkey->kvalue,i+1,10,&ntdim,tdim, &status)){
2362            sprintf(errmes,"Keyword #%d, %s: ",
2363                 kwds[j]->kindex,kwds[j]->kname);
2364 	    wrtferr(out,errmes,&status,1);
2365         }
2366     }
2367 
2368     /* check the local convension "rAw"*/
2369     for (i = 0; i < hduptr->ncols; i++) {
2370 	if((p = strchr(tform[i],'A'))==NULL) continue;
2371         repeat = (int) strtol(tform[i],NULL,10);
2372         p++;
2373 	if(!isdigit((int)*p))continue;
2374 	width = (int)strtol(p,NULL,10);
2375 	if(repeat%width != 0)  {
2376 	    sprintf(errmes,
2377 	 "TFORM %s of column %d: repeat %d is not the multiple of the width %d",
2378 	    tform[i], i+1, repeat, width);
2379             wrtwrn(out,errmes,0);
2380         }
2381     }
2382 
2383     for (i = 0; i < nexlkeys; i++) {
2384         strcpy(temp,exlkeys[i]);
2385     	ptemp = temp;
2386     	key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n);
2387         if(k < 0) continue;
2388         for (j = k; j < k+n; j++) {
2389             pkey = hduptr->kwds[j];
2390 
2391 	    p = kwds[j]->kname;
2392 	    p += strlen(temp);
2393             if(!isdigit((int)*p)) continue;
2394 
2395             sprintf( errmes,
2396                "Keyword #%d, %s is not allowed in the Binary table.",
2397                pkey->kindex,pkey->kname);
2398             wrterr(out,errmes,1);
2399         }
2400     }
2401 
2402     /* check whether the column name is unique */
2403     test_colnam(out, hduptr);
2404     return ;
2405 }
2406 
2407 /*************************************************************
2408 *
2409 *      test_header
2410 *
2411 *   Test the general keywords that can be in any header
2412 *
2413 *
2414 *************************************************************/
test_header(fitsfile * infits,FILE * out,FitsHdu * hduptr)2415 void test_header(
2416 	     fitsfile *infits, 	/* input fits file   */
2417 	     FILE*     out,	/* output ascii file */
2418 	     FitsHdu  *hduptr	/* information about header  */
2419 )
2420 {
2421     /* common mandatory  keywords */
2422     char *mandkey[] = {"SIMPLE", "BITPIX", "NAXIS",
2423                        "XTENSION",  "END"};  /* not including NAXIS */
2424     int nmandkey = 5;
2425 
2426 
2427     /* string keywords */
2428     char *strkey[] = {"EXTNAME", "ORIGIN", "AUTHOR","CREATOR","REFERENC","TELESCOP",
2429         "INSTRUME", "OBSERVER", "OBJECT"};
2430     int nstrkey = 9;
2431 
2432     /* int keywords  */
2433     char *intkey[] = {"EXTVER", "EXTLEVEL"};
2434     int nintkey = 2;
2435 
2436     /* floating keywords  */
2437     char *fltkey[] = {"EQUINOX", "MJD-OBS", "MJD-AVG"};
2438     int nfltkey = 3;
2439 
2440     FitsKey** kwds;		/* FitsKey structure array */
2441     int numusrkey;
2442 
2443     int i,j,k,n;
2444     long lv;
2445     char* pt;
2446     char **pp;
2447     int status = 0;
2448     int yr, mn, dy, hr, min;	/* time */
2449     double sec;
2450     int yy;
2451 
2452     kwds = hduptr->kwds;
2453     numusrkey = hduptr->tkeys;
2454 
2455 /* Check the mandatory keywords */
2456     for (i = 0; i < nmandkey; i++) {
2457 	 pp = &(mandkey[i]);
2458          key_match(tmpkwds,numusrkey,pp,1,&k,&n);
2459          if(k > -1) {
2460              for ( j = k; j < k + n; j++) {
2461                 sprintf(errmes,
2462       "Keyword #%d, %s is duplicated or out of order.",
2463                 kwds[j]->kindex,kwds[j]->kname);
2464              wrterr(out,errmes,1);
2465              }
2466          }
2467     }
2468 
2469     /* check the NAXIS index keyword */
2470     strcpy(temp,"NAXIS");
2471     ptemp = temp;
2472     key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n);
2473     for ( j = k; j < k + n; j++) {
2474         pt = kwds[j]->kname+5;
2475         lv = strtol(pt,NULL,10);
2476         if(lv > 0 ){
2477             if(kwds[j]->kindex != 3 + lv) {
2478                 sprintf(errmes,
2479                 "Keyword #%d, %s is duplicated or out of order.",
2480                 kwds[j]->kindex,kwds[j]->kname);
2481                 wrterr(out,errmes,1);
2482             }
2483             if(lv > hduptr->naxis) {
2484                 sprintf(errmes,
2485                   "Keyword #%d, %s is not allowed (with n > NAXIS =%d).",
2486                    kwds[j]->kindex,kwds[j]->kname,hduptr->naxis);
2487                 wrterr(out,errmes,1);
2488             }
2489         }
2490     }
2491 
2492     /* Check the deprecated keywords */
2493     strcpy(temp,"EPOCH");
2494     ptemp = temp;
2495     key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n);
2496     if(k > -1) {
2497          sprintf(errmes,
2498             "Keyword #%d, %s is deprecated. Use EQUINOX instead.",
2499              kwds[k]->kindex, kwds[k]->kname);
2500          wrtwrn(out,errmes,0);
2501 	 check_flt(kwds[k],out);
2502     }
2503 
2504 
2505     /* Check the DATExxxx keyword */
2506     strcpy(temp,"DATE");
2507     ptemp = temp;
2508     key_match(tmpkwds,numusrkey,&ptemp,0,&k,&n);
2509     for (j = k; j< n + k ; j++){
2510        check_str(kwds[j],out);
2511        if(fits_str2time(kwds[j]->kvalue, &yr, &mn, &dy, &hr, &min,
2512           &sec, &status)){
2513            sprintf(errmes,"Keyword #%d, %s: ", kwds[j]->kindex,kwds[j]->kname);
2514            wrtserr(out,errmes,&status,1);
2515         }
2516         if( (pt = strchr(kwds[j]->kvalue,'/'))!=NULL) {
2517                pt +=4;
2518                yy = (int) strtol(pt,NULL,10);
2519                if(0 <= yy && yy <=10) {
2520                sprintf(errmes,
2521                   "Keyword #%d, %s %s intends to mean year 20%-2.2d?",
2522                    kwds[j]->kindex, kwds[j]->kname, kwds[j]->kvalue, yy);
2523                    wrtwrn(out,errmes,0);
2524 	       }
2525         }
2526     }
2527 
2528     /* Check the reserved string keywords */
2529     for (i = 0; i < nstrkey; i++) {
2530         strcpy(temp,strkey[i]);
2531     	ptemp = temp;
2532     	key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n);
2533     	if(k > -1) check_str(kwds[k],out);
2534     }
2535 
2536     /* Check the reserved int keywords */
2537     for (i = 0; i < nintkey; i++) {
2538         strcpy(temp,intkey[i]);
2539     	ptemp = temp;
2540     	key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n);
2541     	if(k > -1) check_int(kwds[k],out);
2542     }
2543 
2544     /* Check  reserved floating  keywords */
2545     for (i = 0; i < nfltkey; i++) {
2546         strcpy(temp,fltkey[i]);
2547         ptemp = temp;
2548         key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n);
2549     	if(k > -1) check_flt(kwds[k],out);
2550     }
2551 
2552     /* Check the duplication of the keywords */
2553     for (i = 0; i < numusrkey-1; i++) {
2554        if(!strcmp(tmpkwds[i],tmpkwds[i+1])) {
2555            sprintf(errmes,
2556      "Keyword %s is duplicated in card #%d and card #%d.",
2557             kwds[i]->kname, kwds[i]->kindex, kwds[i+1]->kindex);
2558           wrtwrn(out,errmes,0);
2559        }
2560     }
2561 
2562     /* check the long string convention */
2563     if (hduptr->use_longstr == 1) {
2564         strcpy(temp,"LONGSTRN");
2565         ptemp = temp;
2566         key_match(tmpkwds,numusrkey,&ptemp,1,&k,&n);
2567         if(k <= -1) {
2568             sprintf(errmes,
2569 "The OGIP long string keyword convention is used without the recommended LONGSTRN keyword. ");
2570           wrtwrn(out,errmes,1);
2571         }
2572     }
2573 
2574 /*  disabled this routine because it doesn't perform an useful tests
2575     test_img_wcs(infits, out, hduptr);
2576 
2577 */
2578     return;
2579 }
2580 
2581 
2582 /*************************************************************
2583 *
2584 *      key_match
2585 *
2586 *   find the keywords whose name match the pattern. The keywords
2587 *   name is stored in a sorted array.
2588 *
2589 *
2590 *************************************************************/
key_match(char ** strs,int nstr,char ** pattern,int exact,int * ikey,int * mkey)2591 void key_match(char **strs,  	/* fits keyname  array */
2592              int nstr,		/* total number of keys */
2593              char **pattern,	/* wanted pattern  */
2594              int exact,		/* exact matching or pattern matching
2595                                    exact = 1: exact matching.
2596                                    exact = 0: pattern matching.
2597                                    Any keywords with "patten"* is included
2598                                 */
2599 
2600              int *ikey,		/* The element number of first key
2601                                    Return -99 if not found */
2602              int *mkey		/* total number of key matched
2603                                    return -999 if not found */
2604             )
2605 {
2606      char **p;
2607      char **pi;
2608      int i;
2609      int (*fnpt)(const void *, const void *);
2610      *mkey = -999;
2611      *ikey = -99;
2612      if(exact)
2613 	 fnpt = compstre;
2614      else
2615          fnpt = compstrp;
2616      p = (char **)bsearch(pattern, strs, nstr,sizeof(char *), fnpt);
2617      if(p) {
2618         *mkey = 1;
2619         *ikey = p - strs;
2620 	pi = p;
2621 	i = *ikey - 1;
2622 	p--;
2623         while(i > 0 && !fnpt(pattern, p)) {*mkey += 1; *ikey =i; i--; p--;}
2624 	p = pi;
2625 	i = *ikey + *mkey;
2626         p++;
2627         while(i < nstr && !fnpt(pattern, p) ) {*mkey += 1; i++; p++;}
2628      }
2629      return;
2630 }
2631 
2632 
2633 /*************************************************************
2634 *
2635 *      test_colnam
2636 *
2637 *   Test the whether the column name is unique.
2638 *
2639 *
2640 *************************************************************/
test_colnam(FILE * out,FitsHdu * hduptr)2641 void test_colnam(FILE *out,
2642 		FitsHdu *hduptr)
2643 {
2644     int i,n;
2645     char *p, *q;
2646     ColName **cols;
2647     char **ttypecopy;
2648 
2649     n = hduptr->ncols;
2650 
2651     if(n <= 0) return;
2652     /* make a local working copy of ttype */
2653     ttypecopy = (char **)malloc(n*sizeof(char *));
2654     for (i = 0; i < n; i++) {
2655         ttypecopy[i] = (char *)malloc(FLEN_VALUE*sizeof(char));
2656         strcpy(ttypecopy[i],ttype[i]);
2657     }
2658 
2659     /* check whether there are any other non ASCII-text characters
2660       (FITS standard R14). Also "uppercase" the working copies. */
2661     for (i = 0; i < n; i++) {
2662         p = ttype[i];
2663         q = ttypecopy[i];
2664         if(!strlen(p)) {
2665             sprintf(errmes,
2666             "Column #%d has no name (No TTYPE%d keyword).",i+1, i+1);
2667             wrtwrn(out,errmes,0);
2668             continue;
2669         }
2670 
2671 
2672 /*      disable this check (it was only a warning)
2673         if( (*p  > 'z' || *p < 'a') && (*p > 'Z' || *p <'A')
2674                 && (*p > '9' || *p < '0') ) {
2675             sprintf(errmes,"Column #%d: Name \"%s\" does not begin with a letter or a digit.",i+1,ttype[i]);
2676             wrtwrn(out,errmes,1);
2677         }
2678 */
2679         while(*p != '\0') {
2680             if(    (*p > 'z' || *p < 'a') && (*p > 'Z' || *p < 'A')
2681                 && (*p > '9' || *p < '0') && (*p != '_')) {
2682             sprintf(errmes,
2683       "Column #%d: Name \"%s\" contains character \'%c\' other than letters, digits, and \"_\".",
2684             i+1,ttype[i],*p);
2685             wrtwrn(out,errmes,0);
2686             }
2687             if(*p <= 'z' || *p >= 'a') *q = toupper(*p);
2688             p++; q++;
2689         }
2690     }
2691 
2692     cols = (ColName **)calloc(n, sizeof(ColName *));
2693     for (i=0; i < n; i++) {
2694         cols[i] = (ColName *)malloc(sizeof(ColName));
2695 	cols[i]->name = ttypecopy[i];
2696 	cols[i]->index = i+1;
2697     }
2698 
2699     /* sort the column name in the ascending order of name field*/
2700     qsort(cols, n, sizeof(ColName *), compcol);
2701 
2702     /* Check the duplication of the column name */
2703     for (i = 0; i < n-1; i++) {
2704         if(!strlen(cols[i]->name)) continue;
2705 
2706 /*      disable this warning
2707         if(!strncmp(cols[i]->name,cols[i+1]->name,16)) {
2708             sprintf(errmes,
2709      "Columns #%d, %s and #%d, %s are not unique within first 16 characters(case insensitive).",
2710             cols[i]->index,   ttype[(cols[i]->index-1)],
2711             cols[i+1]->index, ttype[(cols[i+1]->index-1)]);
2712           wrtwrn(out,errmes,1);
2713         }
2714 */
2715 
2716         if(!strcmp(cols[i]->name,cols[i+1]->name)) {
2717             sprintf(errmes,
2718      "Columns #%d, %s and #%d, %s are not unique (case insensitive).",
2719             cols[i]->index,   ttype[(cols[i]->index-1)],
2720             cols[i+1]->index, ttype[(cols[i+1]->index-1)]);
2721           wrtwrn(out,errmes,0);
2722         }
2723     }
2724     for (i = 0; i < n; i++) { free(cols[i]); free(ttypecopy[i]);}
2725     free(cols); free(ttypecopy);
2726     return;
2727 }
2728 
2729 /*************************************************************
2730 *
2731 *     parse_vtform
2732 *
2733 *   Parse the tform of the variable length vector.
2734 *
2735 *
2736 *************************************************************/
parse_vtform(fitsfile * infits,FILE * out,FitsHdu * hduptr,int colnum,int * datacode,long * maxlen)2737 void   parse_vtform(fitsfile *infits,
2738 		FILE *out,
2739                 FitsHdu *hduptr,
2740 		int colnum,		/* column number */
2741 		int* datacode,		/* data code */
2742 		long* maxlen		/* maximum length of the vector */
2743                )
2744 {
2745     int i = 0;
2746     int status = 0;
2747     char *p;
2748 
2749 
2750     *maxlen = -1;
2751     strcpy(temp,tform[colnum-1]);
2752     p = temp;
2753 
2754     if(isdigit((int)*p)) sscanf(ptemp,"%d",&i);
2755     if(i > 1) {
2756         sprintf(errmes,"Illegal repeat value for value %s of TFORM%d.",
2757 	   tform[colnum-1], colnum);
2758         wrterr(out,errmes,1);
2759     }
2760     while(isdigit((int)*p))p++;
2761 
2762     if( (*p != 'P') && (*p != 'Q') ) {
2763         sprintf(errmes,
2764 	  "TFORM%d is not for the variable length array: %s.",
2765         colnum, tform[colnum-1]);
2766         wrterr(out,errmes,1);
2767     }
2768 
2769     fits_get_coltype(infits,colnum, datacode, NULL, NULL, &status);
2770     status = 0;
2771     p += 2;
2772     if(*p != '(') return;
2773     p++;
2774     if(!isdigit((int)*p)) {
2775        sprintf(errmes, "Bad value of TFORM%d: %s.",colnum,tform[colnum-1]);
2776        wrterr(out,errmes,1);
2777     }
2778     sscanf(p,"%ld",maxlen);
2779     while(isdigit((int)*p))p++;
2780     if(*p != ')') {
2781        sprintf(errmes, "Bad value of TFORM%d: %s.",colnum,tform[colnum-1]);
2782        wrterr(out,errmes,1);
2783     }
2784     return;
2785 }
2786 
2787 /*************************************************************
2788 *
2789 *      print_title
2790 *
2791 *  Print the title of the HDU.
2792 *  when verbose < 2, called by wrterr and wrtwrn.
2793 *
2794 *************************************************************/
print_title(FILE * out,int hdunum,int hdutype)2795 void print_title(FILE* out, int hdunum, int hdutype)
2796 {
2797     static char hdutitle[64];
2798     static int oldhdu = 0;
2799 
2800     /* print out the title */
2801     curhdu = hdunum;
2802     curtype = hdutype;
2803 
2804     if(oldhdu == curhdu) return; /* Do not print it twice */
2805     if(curhdu == 1){
2806 	        sprintf(hdutitle," HDU %d: Primary Array ", curhdu);
2807     }
2808     else {
2809         switch (curtype) {
2810 	    case IMAGE_HDU:
2811 		sprintf(hdutitle," HDU %d: Image Exten. ", curhdu);
2812                 break;
2813 	    case ASCII_TBL:
2814 		sprintf(hdutitle," HDU %d: ASCII Table ", curhdu);
2815                 break;
2816 	    case BINARY_TBL:
2817 		sprintf(hdutitle," HDU %d: BINARY Table ", curhdu);
2818                 break;
2819             default:
2820 		sprintf(hdutitle," HDU %d: Unknown Ext. ", curhdu);
2821                 break;
2822         }
2823     }
2824     wrtsep(out,'=',hdutitle,60);
2825     wrtout(out," ");
2826     oldhdu = curhdu;
2827     if(curhdu == totalhdu) oldhdu = 0;  /* reset the old hdu at the last hdu */
2828     return;
2829 }
2830 
2831 /*************************************************************
2832 *
2833 *      print_header
2834 *
2835 *  Print the header of the HDU.
2836 *
2837 *************************************************************/
print_header(FILE * out)2838 void print_header(FILE* out)
2839 {
2840     char htemp[100];
2841     int i;
2842     for (i=1; i <= ncards; i++)  {
2843         sprintf(htemp,"%4d | %s",i,cards[i-1]);
2844 	wrtout(out, htemp);
2845     }
2846     wrtout(out," ");
2847     return;
2848 }
2849 
2850 /*************************************************************
2851 *
2852 *      print_summary
2853 *
2854 *  Print out the summary of this hdu.
2855 *
2856 **************************************************************/
print_summary(fitsfile * infits,FILE * out,FitsHdu * hduptr)2857 void print_summary(fitsfile *infits, 	/* input fits file   */
2858 	     FILE*	out,		/* output ascii file */
2859              FitsHdu *hduptr
2860             )
2861 {
2862 
2863     int i = 0;
2864     char extver[10];
2865     char extnv[FLEN_VALUE];
2866     long npix;
2867     int hdutype;
2868 
2869     /* get the error number and wrn number */
2870     set_hduerr(hduptr->hdunum);
2871 
2872     hdutype = hduptr->hdutype;
2873     sprintf(comm," %d header keywords", hduptr->nkeys);
2874     wrtout(out,comm);
2875     wrtout(out," ");
2876     if(hdutype == ASCII_TBL || hdutype== BINARY_TBL) {
2877         sprintf(extnv, "%s",hduptr->extname);
2878         if (hduptr->extver!=-999) {
2879             sprintf(extver,"(%d)",hduptr->extver);
2880             strcat(extnv,extver);
2881         }
2882 
2883 #if (USE_LL_SUFFIX == 1)
2884         sprintf(comm," %s  (%d columns x %lld rows)", extnv, hduptr->ncols,
2885            hduptr->naxes[1]);
2886 #else
2887         sprintf(comm," %s  (%d columns x %ld rows)", extnv, hduptr->ncols,
2888            hduptr->naxes[1]);
2889 #endif
2890         wrtout(out,comm);
2891         if(hduptr->ncols) {
2892            wrtout(out," ");
2893            sprintf(comm, " Col# Name (Units)       Format");
2894            wrtout(out,comm);
2895 	}
2896         for ( i = 0; i < hduptr->ncols; i++) {
2897            if(strlen(tunit[i]))
2898                sprintf(extnv,"%s (%s)",ttype[i],tunit[i]);
2899            else
2900                sprintf(extnv,"%s",ttype[i]);
2901  	   sprintf(comm," %3d %-20.20s %-10.10s",
2902               i+1, extnv, tform[i]);
2903 	   wrtout(out,comm);
2904         }
2905     }
2906     else if(hdutype == IMAGE_HDU && hduptr->isgroup) {
2907 
2908             sprintf(comm, " %d Random Groups, ",hduptr->gcount);
2909 
2910             switch(hduptr->bitpix) {
2911             	case BYTE_IMG:
2912                	    strcpy(temp," 8-bit integer pixels, ");
2913                	    break;
2914                 case SHORT_IMG:
2915                    strcpy(temp," 16-bit integer pixels, ");
2916                    break;
2917                 case USHORT_IMG:
2918                    strcpy(temp," 16-bit unsigned integer pixels, ");
2919                    break;
2920                 case LONG_IMG:
2921                    strcpy(temp," 32-bit integer pixels, ");
2922                    break;
2923                 case LONGLONG_IMG:
2924                    strcpy(temp," 64-bit long integer pixels, ");
2925                    break;
2926                 case ULONG_IMG:
2927                    strcpy(temp," 32-bit unsigned integer pixels, ");
2928                    break;
2929                 case FLOAT_IMG:
2930                    strcpy(temp," 32-bit floating point pixels, ");
2931                    break;
2932                 case DOUBLE_IMG:
2933                    strcpy(temp," 64-bit double precision pixels, ");
2934                    break;
2935                 default:
2936                    strcpy(temp," unknown datatype, ");
2937                    break;
2938             }
2939 	    strcat(comm,temp);
2940 
2941             sprintf(temp," %d axes ",hduptr->naxis);
2942 	    strcat(comm,temp);
2943 
2944 #if (USE_LL_SUFFIX == 1)
2945 	    sprintf(temp, "(%lld",hduptr->naxes[0]);
2946 #else
2947 	    sprintf(temp, "(%ld",hduptr->naxes[0]);
2948 #endif
2949 	    strcat(comm,temp);
2950 
2951 	    npix = hduptr->naxes[0];
2952 	    for ( i = 1; i < hduptr->naxis; i++){
2953 	       npix *= hduptr->naxes[i];
2954 #if (USE_LL_SUFFIX == 1)
2955 	       sprintf(temp, " x %lld",hduptr->naxes[i]);
2956 #else
2957 	       sprintf(temp, " x %ld",hduptr->naxes[i]);
2958 #endif
2959 	       strcat(comm,temp);
2960             }
2961 	    strcat(comm,"), ");
2962             wrtout(out,comm);
2963     }
2964     else if(hdutype == IMAGE_HDU) {
2965         if(hduptr->naxis > 0) {
2966 
2967 	    if(hduptr->hdunum == 1) {
2968                 strcpy(extnv,"");
2969             } else {
2970                 sprintf(extnv, "%s",hduptr->extname);
2971                 if (hduptr->extver!=-999) {
2972                    sprintf(extver," (%d)",hduptr->extver);
2973                    strcat(extnv,extver);
2974                 }
2975             }
2976 	    strcpy(comm,extnv);
2977 
2978             switch(hduptr->bitpix) {
2979             	case BYTE_IMG:
2980                	    strcpy(temp," 8-bit integer pixels, ");
2981                	    break;
2982                 case SHORT_IMG:
2983                    strcpy(temp," 16-bit integer pixels, ");
2984                    break;
2985                 case USHORT_IMG:
2986                    strcpy(temp," 16-bit unsigned integer pixels, ");
2987                    break;
2988                 case LONG_IMG:
2989                    strcpy(temp," 32-bit integer pixels, ");
2990                    break;
2991                 case LONGLONG_IMG:
2992                    strcpy(temp," 64-bit long integer pixels, ");
2993                    break;
2994                 case ULONG_IMG:
2995                    strcpy(temp," 32-bit unsigned integer pixels, ");
2996                    break;
2997                 case FLOAT_IMG:
2998                    strcpy(temp," 32-bit floating point pixels, ");
2999                    break;
3000                 case DOUBLE_IMG:
3001                    strcpy(temp," 64-bit double precision pixels, ");
3002                    break;
3003                 default:
3004                    strcpy(temp," unknown datatype, ");
3005                    break;
3006             }
3007 	    strcat(comm,temp);
3008 
3009             sprintf(temp," %d axes ",hduptr->naxis);
3010 	    strcat(comm,temp);
3011 
3012 #if (USE_LL_SUFFIX == 1)
3013 	    sprintf(temp, "(%lld",hduptr->naxes[0]);
3014 #else
3015 	    sprintf(temp, "(%ld",hduptr->naxes[0]);
3016 #endif
3017 	    strcat(comm,temp);
3018 
3019 	    npix = hduptr->naxes[0];
3020 	    for ( i = 1; i < hduptr->naxis; i++){
3021 	       npix *= hduptr->naxes[i];
3022 #if (USE_LL_SUFFIX == 1)
3023 	       sprintf(temp, " x %lld",hduptr->naxes[i]);
3024 #else
3025 	       sprintf(temp, " x %ld",hduptr->naxes[i]);
3026 #endif
3027 	       strcat(comm,temp);
3028             }
3029 	    strcat(comm,"), ");
3030             wrtout(out,comm);
3031         }
3032         else{
3033             sprintf(comm," Null data array; NAXIS = 0 ");
3034             wrtout(out,comm);
3035         }
3036     }
3037     wrtout(out," ");
3038     return;
3039 }
3040 
3041 /*************************************************************
3042 *
3043 *      close_hdu
3044 *
3045 *  Free the memory allocated to the FitsHdu structure and
3046 *  other temporary  spaces.
3047 *
3048 **************************************************************/
close_hdu(FitsHdu * hduptr)3049 void close_hdu( FitsHdu *hduptr )
3050 {
3051     int i;
3052     int n;
3053     /* free  memories */
3054     for (i=0; i <  ncards; i++)  free(cards[i]);
3055 
3056     n = hduptr->nkeys - 4 - hduptr->naxis ;   /* excluding the SIMPLE,
3057 						 BITPIX, NAXIS, NAXISn
3058 						 and END */
3059     for (i=0; i <  n; i++)  free(hduptr->kwds[i]);
3060 
3061     for (i=0; i <  hduptr->ncols; i++) {
3062 	free(hduptr->datamin[i]);
3063 	free(hduptr->datamax[i]);
3064 	free(hduptr->tnull[i]);
3065     }
3066     if(hduptr->hdutype == ASCII_TBL && hduptr->hdutype == BINARY_TBL){
3067 	if(hduptr->ncols > 0)free(ttype);
3068 	if(hduptr->ncols > 0)free(tunit);
3069 	if(hduptr->ncols > 0)free(tform);
3070     }
3071     if(hduptr->naxis) free(hduptr->naxes);
3072     if(hduptr->ncols > 0)free(hduptr->datamax);
3073     if(hduptr->ncols > 0)free(hduptr->datamin);
3074     if(hduptr->ncols > 0)free(hduptr->tnull);
3075     free(hduptr->kwds);
3076     free(cards);
3077     free(tmpkwds);
3078     return;
3079 }
3080