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 
fits_parse_card(FILE * out,int kpos,char * card,char * kname,kwdtyp * ktype,char * kvalue,char * kcomm)7 int fits_parse_card(FILE *out,		/* output file pointer */
8                     int  kpos,          /* keyposition starting from 1 */
9 		    char *card,  	/* key card */
10 		    char *kname,	/* key name */
11 		    kwdtyp *ktype,	/* key type */
12 		    char *kvalue,	/* key value */
13 		    char *kcomm		/* comment */
14                    )
15 /* Ref: Defininition of the Flexible Image Transport System(FITS),
16 	Sec. 5.1 and 5.2.
17 */
18 {
19     char vind[3];
20     char *p;
21     char **pt;
22     int i;
23     char temp1[FLEN_CARD];
24     unsigned long stat = 0;
25 
26     *kname = '\0';
27     *kvalue = '\0';
28     *kcomm = '\0';
29     *ktype =  UNKNOWN;
30 
31     if(strlen(card) > FLEN_CARD-1 ) {
32 	strncpy(temp1,card,20);
33 	temp1[21]='\0';
34 	sprintf(errmes,"card %s is > 80.",card);
35 	wrterr(out,errmes,1);
36 	return 1;
37     }
38     card[FLEN_CARD-1] = '\0';
39 
40     /* get the kname */
41     strncpy(kname, card, 8);
42     kname[8] = '\0';
43 
44     /* take out the trailing space */
45     i = 7;
46     p = &kname[7];
47     while(isspace((int)*p) && i >= 0) {*p = '\0'; p--; i--;}
48 
49     /* Whether the keyword name is left justified */
50     i = 0;
51     p = &kname[0];
52     while(isspace((int)*p) && *p != '\0' ) {  p++; i++;}
53     if( i < 8 && i > 0) {
54         sprintf(errmes,"Keyword #%d: Name %s is not left justified.",
55            kpos,kname);
56 	wrterr(out,errmes,1);
57     }
58     /* Whether the characters in keyword name are valid */
59     while(*p != '\0' ){
60 	if((*p < 'A'  ||  *p > 'Z')&&
61 	   (*p < '0'  ||  *p > '9')&&
62 	   (*p != '-' &&  *p  != '_') ) {
63 	    sprintf(errmes,
64 "Keyword #%d: Name \"%s\" contains char \"%c\" which is not letter, digit, \"-\", and \"_\".",kpos,kname,*p);
65 	    wrterr(out,errmes,1);
66 	    break;
67         }
68 	p++; i++;
69     }
70 
71     /* COMMENT, HISTORY, HIERARCH and "" keywords */
72     if( !strcmp(kname,"COMMENT") ||
73         !strcmp(kname,"HISTORY") ||
74         !strcmp(kname,"HIERARCH") ||
75         !strcmp(kname,"CONTINUE") ||
76         !strcmp(kname,"")   ){
77 
78         *ktype =  COM_KEY;
79 
80         p = &card[8];
81         strcpy(kcomm, p);
82         kcomm[FLEN_COMMENT-1] = '\0';
83         for( ; *p != '\0'; p++) {
84 	    if(!isprint((int)*p)) {
85 		sprintf(errmes,
86                 "Keyword #%d, %s: String contains non-text characters.",
87 		    kpos,kname);
88                 wrterr(out,errmes,1);
89 		return 1;
90 	    }
91         }
92 	p = kname;
93         while(!isspace((int)*p)&& *p != '\0')p++;
94 	*p = '\0';
95         return 0;
96     }
97 
98     /* End Keyword: 9-80 shall be filled with ASCII blanks \x20 */
99     if( !strcmp(kname,"END") ){
100         *ktype =  COM_KEY;
101         if(card[3] == '\0') return 0;
102         for( p = &card[8]; *p != '\0'; p++) {
103             if(*p != '\x20' ){
104 		wrterr(out,"END keyword contains non-blank characters.",1);
105 		return 1;
106             }
107         }
108 	kname[3] = '\0';
109 	return 0;
110     }
111 
112 
113     /* check for value indicator */
114     p = &card[8];
115     strncpy(vind,p,2);
116     vind[2] = '\0';
117     if(strcmp(vind,"= ") && strcmp(vind,"=") ){
118         /* no value indicator, so this is a commentary keyword */
119        *ktype =  COM_KEY;
120         strcpy(kcomm, p);
121         kcomm[FLEN_COMMENT-1] = '\0';
122         for( ; *p != '\0'; p++) {
123 	    if(!isprint((int)*p)) {
124 		sprintf(errmes,
125                 "Keyword #%d, %s: String contains non-text characters.",
126 		    kpos,kname);
127                 wrterr(out,errmes,1);
128 		return 1;
129 	    }
130         }
131 	p = kname;
132         while(!isspace((int)*p)&& *p != '\0')p++;
133 	*p = '\0';
134         return 0;
135     }
136 
137     p = &card[10];
138     while (isspace((int)*p) && *p != '\0')  p++;
139     pt = &p;
140     switch (*p) {
141 	case '\'': 	/* string */
142 	    get_str(pt, kvalue,&stat);
143 	    *ktype = STR_KEY;
144             p = *pt;
145 	    if(*p != '\0') get_comm(pt,kcomm,&stat);
146 	    break;
147 	case 'T': case 'F':	 	/*logical */
148 	    get_log(pt, kvalue, &stat);
149 	    *ktype = LOG_KEY;
150             p = *pt;
151 	    if(*p != '\0') get_comm(pt,kcomm,&stat);
152 	    break;
153 	case '+': case '-': case '.':	/* number */
154 	case '0': case '1': case '2':
155 	case '3': case '4': case '5':
156 	case '6': case '7': case '8':
157 	case '9':
158 	    get_num(pt, kvalue, ktype, &stat);
159             p = *pt;
160 	    if(*p != '\0') get_comm(pt,kcomm,&stat);
161 	    break;
162 	case '(':			/* complex number */
163 	    get_cmp(pt, kvalue, ktype, &stat);
164             p = *pt;
165 	    if(*p != '\0') get_comm(pt,kcomm,&stat);
166 	    break;
167 	case '/':			/* comment */
168 	    if(*p != '\0') get_comm(pt,kcomm,&stat);
169             *ktype = UNKNOWN;
170             break;
171         default:
172             get_unknown(pt,kvalue,ktype,&stat);
173             p = *pt;
174 	    if(*p != '\0') get_comm(pt,kcomm,&stat);
175     }
176     /* take out the trailing blanks for non-string keys */
177     if(*ktype != STR_KEY) {
178         i = strlen(kvalue);
179         p = &kvalue[i-1];
180         while(isspace((int)*p) && i >0) {
181             *p = '\0';
182             p--; i--;
183         }
184         if(i == 0 && isspace((int)*p))*p = '\0';
185     }
186     pr_kval_err(out,kpos,kname,kvalue,stat);
187     if(stat != 0) return 1;
188     return 0;
189 }
190 
191 /* parse And test the string keys */
get_str(char ** pt,char * kvalue,unsigned long * stat)192 void get_str(char **pt,     		/* card string from character 11*/
193 	    char *kvalue,		/* key value string */
194 	    unsigned long *stat		/* error number */
195 	   )
196 {
197     char *pi;
198     char prev;		/* previous char */
199     int nchar = 0;
200     char *p;
201 
202     p = *pt;
203     pi = p;
204     p++;
205     prev = 'a';
206     while(*p != '\0') {
207         if( !isprint((int)*p) )*stat |= BAD_STR;
208 	if(prev == '\'' && *p != '\'') break;
209 	if(prev == '\'' && *p == '\'') {    /* skip the '' */
210 	    p++;
211 	    prev = 'a';
212         }
213 	else {
214             prev = *p;
215             p++;
216         }
217     }
218     p--;
219     if(*p != '\'') *stat |= NO_TRAIL_QUOTE;
220     pi++;
221     nchar = p - pi ;     /* excluding the ' */
222     strncpy(kvalue,pi,nchar);
223     *(kvalue+nchar) = '\0';
224     pi = kvalue + (nchar -1) ;
225     while(isspace((int)*pi)){ *pi = '\0'; pi--;} /* delete the trailing space */
226     p++;				  /* skip the  ' */
227     while(isspace((int)*p) && *p != '\0')  p++;
228     *pt = p;
229     return;
230 }
231 
232 /* parse and test the logical keys */
get_log(char ** pt,char * kvalue,unsigned long * stat)233 void get_log(char **pt,     		/* card string */
234 	    char *kvalue,		/* key value string */
235 	    unsigned long *stat		/* error number */
236 	   )
237 {
238     char *p;
239 
240     p = *pt;
241     *kvalue = *p;
242     kvalue[1] = '\0';
243     p++;
244     while(isspace((int)*p)) p++;
245     if(*p != '/' && *p != '\0') *stat |= BAD_LOGICAL;
246     *pt = p;
247     return;
248 }
249 
250 /* parse and test the numerical keys */
get_num(char ** pt,char * kvalue,kwdtyp * ktype,unsigned long * stat)251 void get_num(char **pt,     		/* card string */
252 	    char *kvalue,		/* comment string */
253 	    kwdtyp *ktype,
254 	    unsigned long *stat		/* error number */
255 	   )
256 {
257     char *pi;
258     int set_deci = 0;
259     int set_expo = 0;
260     int set_sign = 0;
261     int nchar;
262     char *p;
263 
264     p = *pt;
265     pi = p;
266     *ktype = INT_KEY;
267 
268     if( *p != '+' && *p != '-' && !isdigit((int)*p) &&*p != '.') {
269         *stat |= BAD_NUM;
270 	return;
271     }
272     if(*p == '.') {
273 	*ktype = FLT_KEY;
274 	set_deci = 1;
275     }
276     if(*p == '+'|| *p == '-') {
277 	set_sign = 1;
278     }
279     p++;
280     while(!isspace((int)*p) && *p != '\0' && *p != '/') {
281         if( *p == '.' && !set_deci ){
282 	    set_deci = 1;
283 	    *ktype = FLT_KEY;
284 	    p++;
285 	    continue;
286         }
287         if( (*p == 'd'|| *p == 'e') && !set_expo) {
288             set_expo = 1;
289 	    *ktype = FLT_KEY;
290 	    p++;
291 	    if(*p == '+' || *p == '-') p++;
292             *stat |= LOWCASE_EXPO;
293 	    continue;
294         }
295         if( (*p == 'D'|| *p == 'E') && !set_expo) {
296             set_expo = 1;
297 	    *ktype = FLT_KEY;
298 	    p++;
299 	    if(*p == '+' || *p == '-') p++;
300 	    continue;
301         }
302 	if(!isdigit((int)*p)) *stat |= BAD_NUM;
303 	p++;
304     }
305     nchar = p - pi;
306     strncpy(kvalue,pi,nchar);
307     *(kvalue+nchar) = '\0';
308     while(isspace((int)*p) && *p != '\0')  p++;
309     *pt = p;
310     return;
311 }
312 
313 /* parse and test the complex keys */
get_cmp(char ** pt,char * kvalue,kwdtyp * ktype,unsigned long * stat)314 void get_cmp(char **pt,     		/* card string */
315 	    char *kvalue,		/* comment string */
316 	    kwdtyp *ktype,
317 	    unsigned long *stat		/* error number */
318 	   )
319 {
320     char *p;
321     char **pp;
322     char *pr_beg;			/* end of real part */
323     char *pr_end=0;			/* end of real part */
324     char *pi_beg;			/* beginning of the imaginay part */
325     char *pi_end=0;			/* end of real part */
326     int  nchar;
327     int set_comm = 0;
328     int set_paren = 0;
329 
330     unsigned long tr  = 0;
331     unsigned long ti = 0;
332     kwdtyp rtype, itype;
333     char temp[FLEN_CARD];
334     char card[FLEN_CARD];
335 
336 
337     strcpy(card,*pt);			/* save the original */
338     card[FLEN_CARD-1] = '\0';
339 
340     *ktype = CMI_KEY;			/* default: integer complex */
341     p = card + 1;
342     pr_beg = p;
343 
344     temp[0] = '\0';
345     while(*p != '\0' && *p != '/') {
346 	if(*p == ')') {
347 	    set_paren = 1;
348 	    pi_end = p;
349 	    p++;
350 	    break;
351         }
352 	if(!set_comm && *p == ',') {
353 	    set_comm = 1;
354 	    pr_end = p;
355 	    pi_beg = p+1;
356         }
357         else if(*p == ',') {
358 	    *stat |= TOO_MANY_COMMA;
359         }
360 	p++;
361     }
362     if(!set_comm) *stat |= NO_COMMA;
363     if(!set_paren) {
364 	*stat |= NO_TRAIL_PAREN;
365 	pi_end = p;
366 	pi_end--;
367 	while(isspace((int)*pi_end))pi_end--;
368 	pi_end++;
369     }
370 
371     nchar = pi_end - card ;
372     strncpy(kvalue,card,nchar);
373     *(kvalue+nchar) = '\0';
374     while(isspace((int)*p)&& *p != '\0')  p++;
375     *pt = *pt + (p - card);
376 
377     /* analyse the real and imagine part */
378     *pr_end = '\0';
379     *pi_end = '\0';
380     while(isspace((int)*pr_beg) && *pr_beg != '\0')  pr_beg++;
381     while(isspace((int)*pi_beg) && *pi_beg != '\0')  pi_beg++;
382     temp[0] = '\0';
383     pp = &pr_beg;
384     get_num(pp, temp, &rtype, &tr);
385     if(tr)*stat |= BAD_REAL;
386     temp[0] = '\0';
387     pp = &pi_beg;
388     get_num(pp, temp, &itype, &ti);
389     if(ti)*stat |= BAD_IMG;
390     if(rtype == FLT_KEY || itype == FLT_KEY) *ktype = CMF_KEY;
391     return;
392 }
393 
394 /* parse and test the comment keys */
get_comm(char ** pt,char * kcomm,unsigned long * stat)395 void get_comm(char **pt,     		/* card string */
396 	    char *kcomm,		/* comment string */
397 	    unsigned long *stat		/* error number */
398 	   )
399 {
400     char *pi;
401     int nchar = 0;
402     char *p;
403 
404     p = *pt;
405     pi = p;
406     if(*p != '/')  {
407       *stat |= NO_START_SLASH;
408     }
409     p++;
410     while(*p != '\0') {
411         if(!isprint((int)*p) ) *stat |=  BAD_COMMENT;
412         p++;
413     }
414     nchar = p - pi;
415     strncpy(kcomm,pi,nchar);
416     *(kcomm+nchar) = '\0';
417     return;
418 }
419 
420 /* parsing the unknown keyword */
get_unknown(char ** pt,char * kvalue,kwdtyp * ktype,unsigned long * stat)421 void get_unknown(char **pt,     		/* card string */
422 	    char *kvalue,		/* comment string */
423 	    kwdtyp *ktype,
424 	    unsigned long *stat		/* error number */
425 	   )
426 {
427      char *p;
428      char *p1;
429      char temp[FLEN_CARD];
430 
431      p = *pt;
432      strcpy(temp,*pt);
433      p1 = temp;
434      while(*p != '\0' && *p != '/') { p++; p1++;}
435      *p1 = '\0';
436      p1 = temp;
437      *pt = p;
438 
439      strcpy(kvalue, p1);
440      *ktype = UNKNOWN;
441      *stat |= UNKNOWN_TYPE;
442      return ;
443 }
444 /* routine to print out the error of keyword value/comment */
pr_kval_err(FILE * out,int kpos,char * kname,char * kval,unsigned long errnum)445 void pr_kval_err(FILE *out,		/* output  FILE */
446                  int  kpos,          /* keyposition starting from 1 */
447                 char *kname,		/* keyword name */
448                 char *kval,		/* keyword value */
449 		unsigned long errnum	/* error number */
450                )
451 {
452     if(errnum == 0) return;
453     if(errnum & BAD_STR) {
454 	sprintf(errmes,
455         "Keyword #%d, %s: String \"%s\"  contains non-text characters.",
456          kpos,kname,kval);
457 	wrterr(out,errmes,1);
458     }
459     if(errnum & NO_TRAIL_QUOTE) {
460 	sprintf(errmes,
461   "Keyword #%d, %s: The closing \"\'\" is missing in the string." ,
462          kpos,kname);
463 	wrterr(out,errmes,1);
464     }
465     if(errnum & BAD_LOGICAL) {
466 	sprintf(errmes,"Keyword #%d, %s: Bad logical value \"%s\".",
467          kpos,kname,kval);
468 	 wrterr(out,errmes,1);
469     }
470     if(errnum & BAD_NUM) {
471 	sprintf(errmes,"Keyword #%d, %s: Bad numerical value \"%s\".",
472          kpos,kname,kval);
473 	wrterr(out,errmes,1);
474     }
475     if(errnum & LOWCASE_EXPO) {
476 	sprintf(errmes,
477 "Keyword #%d, %s: lower-case exponent d or e is illegal in value %s.",
478          kpos,kname,kval);
479 	wrterr(out,errmes,1);
480     }
481     if(errnum & NO_TRAIL_PAREN) {
482 	sprintf(errmes,
483    "Keyword #%d, %s: Complex value \"%s\" misses closing \")\".",
484          kpos,kname, kval);
485 	wrterr(out,errmes,1);
486     }
487     if(errnum & NO_COMMA) {
488 	sprintf(errmes,
489            "keyword #%d, %s : Complex value \"%s\" misses \",\".",
490             kpos,kname,kval);
491 	wrterr(out,errmes,1);
492     }
493     if(errnum & TOO_MANY_COMMA) {
494 	sprintf(errmes,
495        "Keyword #%d, %s: Too many \",\" are in the complex value \"%s\".",
496          kpos,kname,kval);
497 	wrterr(out,errmes,1);
498     }
499     if(errnum & BAD_REAL) {
500 	sprintf(errmes,
501         "Keyword #%d, %s: Real part of complex value \"%s\" is  bad.",
502          kpos,kname,kval);
503 	wrterr(out,errmes,1);
504     }
505     if(errnum & BAD_IMG) {
506 	sprintf(errmes,
507         "Keyword #%d, %s: Imagine part of complex value \"%s\" is bad.",
508         kpos,kname,kval);
509 	wrterr(out,errmes,1);
510     }
511     if(errnum & NO_START_SLASH) {
512 	sprintf(errmes,
513     "Keyword #%d, %s: Value and Comment not separated by a \"/\".",
514          kpos,kname);
515 	wrterr(out,errmes,1);
516     }
517     if(errnum & BAD_COMMENT) {
518 	sprintf(errmes,
519    "Keyword #%d, %s: Comment contains non-text characters.",
520          kpos,kname);
521 	wrterr(out,errmes,1);
522     }
523 
524     if(errnum & UNKNOWN_TYPE) {
525       if (*kval != 0) {  /* don't report null keywords as an error */
526 	sprintf(errmes,
527    "Keyword #%d, %s: Type of value \"%s\" is unknown.",
528          kpos,kname,kval);
529 	wrterr(out,errmes,1);
530       }
531     }
532     return ;
533 }
534 
check_str(FitsKey * pkey,FILE * out)535     int check_str(FitsKey* pkey, FILE *out)
536 {
537     if(pkey->ktype == UNKNOWN && *(pkey->kvalue) == 0) {
538         sprintf(errmes,"Keyword #%d, %s has a null value; expected a string.",
539         pkey->kindex,pkey->kname);
540         wrterr(out,errmes,1);
541         return 0;
542     } else if(pkey->ktype != STR_KEY) {
543         sprintf(errmes,"Keyword #%d, %s: \"%s\" is not a string.",
544         pkey->kindex,pkey->kname, pkey->kvalue);
545         wrterr(out,errmes,1);
546         return 0;
547     }
548     return 1;
549 }
550 
check_int(FitsKey * pkey,FILE * out)551     int check_int(FitsKey* pkey, FILE *out)
552 {
553     if(pkey->ktype == UNKNOWN && *(pkey->kvalue) == 0) {
554         sprintf(errmes,"Keyword #%d, %s has a null value; expected an integer.",
555         pkey->kindex,pkey->kname);
556         wrterr(out,errmes,1);
557         return 0;
558     } else if(pkey->ktype != INT_KEY) {
559         sprintf(errmes,"Keyword #%d, %s: value = %s is not an integer.",
560         pkey->kindex,pkey->kname, pkey->kvalue);
561 	if(pkey->ktype == STR_KEY)
562 	   strcat(errmes," The value is entered as a string. ");
563         wrterr(out,errmes,1);
564         return 0;
565     }
566     return 1;
567 }
check_flt(FitsKey * pkey,FILE * out)568     int check_flt(FitsKey* pkey, FILE *out)
569 {
570     if(pkey->ktype == UNKNOWN && *(pkey->kvalue) == 0) {
571         sprintf(errmes,"Keyword #%d, %s has a null value; expected a float.",
572         pkey->kindex,pkey->kname);
573         wrterr(out,errmes,1);
574         return 0;
575     } else if(pkey->ktype != INT_KEY && pkey->ktype != FLT_KEY) {
576         sprintf(errmes,
577         "Keyword #%d, %s: value = %s is not a floating point number.",
578         pkey->kindex,pkey->kname, pkey->kvalue);
579 	if(pkey->ktype == STR_KEY)
580 	   strcat(errmes," The value is entered as a string. ");
581         wrterr(out,errmes,1);
582         return 0;
583     }
584     return 1;
585 }
586 
check_cmi(FitsKey * pkey,FILE * out)587     int check_cmi(FitsKey* pkey, FILE *out)
588 {
589     if(pkey->ktype != CMI_KEY ) {
590         sprintf(errmes,
591           "Keyword #%d, %s: value = %s is not a integer complex number.",
592         pkey->kindex,pkey->kname, pkey->kvalue);
593 	if(pkey->ktype == STR_KEY)
594 	   strcat(errmes," The value is entered as a string. ");
595         wrterr(out,errmes,1);
596         return 0;
597     }
598     return 1;
599 }
600 
check_cmf(FitsKey * pkey,FILE * out)601     int check_cmf(FitsKey* pkey, FILE *out)
602 {
603     if(pkey->ktype != CMI_KEY && pkey->ktype != CMF_KEY) {
604         sprintf(errmes,
605            "Keyword #%d, %s: value = %s is not a floating point complex number.",
606         pkey->kindex,pkey->kname, pkey->kvalue);
607 	if(pkey->ktype == STR_KEY)
608 	   strcat(errmes," The value is entered as a string. ");
609         wrterr(out,errmes,1);
610         return 0;
611     }
612     return 1;
613 }
check_log(FitsKey * pkey,FILE * out)614     int check_log(FitsKey* pkey, FILE *out)
615 {
616     if(pkey->ktype != LOG_KEY ) {
617         sprintf(errmes,
618             "Keyword #%d, %s: value = %s is not a logical constant.",
619         pkey->kindex,pkey->kname, pkey->kvalue);
620 	if(pkey->ktype == STR_KEY)
621 	   strcat(errmes," The value is entered as a string. ");
622         wrterr(out,errmes,1);
623         return 0;
624     }
625     return 1;
626 }
check_fixed_int(char * card,FILE * out)627     int check_fixed_int(char* card, FILE *out)
628 {
629     char *cptr;
630 
631     /* fixed format integer must be right justified in columns 11-30 */
632 
633     cptr = &card[10];
634 
635     while (*cptr == ' ')cptr++;  /* skip leading spaces */
636 
637     if (*cptr == '-')
638         cptr++;  /* skip leading minus sign */
639     else if (*cptr == '+')
640         cptr++;  /* skip leading plus sign */
641 
642     while (isdigit((int) *cptr))cptr++;  /* skip digits */
643 
644     /* should be pointing to column 31 of the card */
645 
646     if ((cptr - card)  != 30) {
647         sprintf(errmes,
648             "%.8s mandatory keyword is not in integer fixed format:",
649         card);
650         wrterr(out,errmes,1);
651         print_fmt(out,card,13);
652         print_fmt(out,"          -------------------^",13);
653 
654         return 0;
655     }
656     return 1;
657 }
check_fixed_log(char * card,FILE * out)658     int check_fixed_log(char* card, FILE *out)
659 {
660     char *cptr;
661 
662     /* fixed format logical must have T or F in column 30 */
663 
664     cptr = &card[10];
665 
666     while (*cptr == ' ')cptr++;  /* skip leading spaces */
667 
668     if (*cptr != 'T' && *cptr != 'F') {
669         sprintf(errmes,
670             "%.8s mandatory keyword does not have T or F logical value.",
671         card);
672         wrterr(out,errmes,1);
673         return 0;
674     }
675 
676     /* should be pointing to column 31 of the card */
677 
678     if ((cptr - card)  != 29) {
679         sprintf(errmes,
680             "%.8s mandatory keyword is not in logical fixed format:",
681         card);
682         wrterr(out,errmes,1);
683         print_fmt(out,card,13);
684         print_fmt(out,"          -------------------^",13);
685 
686         return 0;
687     }
688     return 1;
689 }
check_fixed_str(char * card,FILE * out)690     int check_fixed_str(char* card, FILE *out)
691 {
692     char *cptr;
693 
694     /* fixed format string must have quotes in columns 11 and >= 20 */
695     /* This only applys to the XTENSION and TFORMn keywords. */
696 
697     cptr = &card[10];
698 
699     if (*cptr != '\'' ) {
700         sprintf(errmes,
701             "%.8s mandatory string keyword does not start in col 11.",
702         card);
703         wrterr(out,errmes,1);
704         print_fmt(out,card,13);
705           print_fmt(out,"          ^--------^",13);
706         return 0;
707     }
708 
709     cptr++;
710 
711     while (*cptr != '\'') {
712 
713         if (*cptr == '\0') {
714           sprintf(errmes,
715             "%.8s mandatory string keyword missing closing quote character:",
716           card);
717           wrterr(out,errmes,1);
718           print_fmt(out,card,13);
719           return 0;
720         }
721         cptr++;
722     }
723 
724     if ((cptr - card)  < 19) {
725         sprintf(errmes,
726             "%.8s mandatory string keyword ends before column 20.",
727         card);
728         wrterr(out,errmes,1);
729         print_fmt(out,card,13);
730         print_fmt(out,"          ^--------^",13);
731 
732         return 0;
733     }
734 
735     return 1;
736 }
737