1 /*  This file, getcols.c, contains routines that read data elements from   */
2 /*  a FITS image or table, with a character string datatype.               */
3 
4 /*  The FITSIO software was written by William Pence at the High Energy    */
5 /*  Astrophysic Science Archive Research Center (HEASARC) at the NASA      */
6 /*  Goddard Space Flight Center.                                           */
7 
8 #include <stdlib.h>
9 #include <string.h>
10 /* stddef.h is apparently needed to define size_t */
11 #include <stddef.h>
12 #include <ctype.h>
13 #include "fitsio2.h"
14 /*--------------------------------------------------------------------------*/
ffgcvs(fitsfile * fptr,int colnum,LONGLONG firstrow,LONGLONG firstelem,LONGLONG nelem,char * nulval,char ** array,int * anynul,int * status)15 int ffgcvs( fitsfile *fptr,   /* I - FITS file pointer                       */
16             int  colnum,      /* I - number of column to read (1 = 1st col)  */
17             LONGLONG  firstrow,   /* I - first row to read (1 = 1st row)         */
18             LONGLONG  firstelem,  /* I - first vector element to read (1 = 1st)  */
19             LONGLONG  nelem,      /* I - number of strings to read               */
20             char *nulval,     /* I - string for null pixels                  */
21             char **array,     /* O - array of values that are read           */
22             int  *anynul,     /* O - set to 1 if any values are null; else 0 */
23             int  *status)     /* IO - error status                           */
24 /*
25   Read an array of string values from a column in the current FITS HDU.
26   Any undefined pixels will be set equal to the value of 'nulval' unless
27   nulval = null in which case no checks for undefined pixels will be made.
28 */
29 {
30     char cdummy[2];
31 
32     ffgcls(fptr, colnum, firstrow, firstelem, nelem, 1, nulval,
33            array, cdummy, anynul, status);
34     return(*status);
35 }
36 /*--------------------------------------------------------------------------*/
ffgcfs(fitsfile * fptr,int colnum,LONGLONG firstrow,LONGLONG firstelem,LONGLONG nelem,char ** array,char * nularray,int * anynul,int * status)37 int ffgcfs( fitsfile *fptr,   /* I - FITS file pointer                       */
38             int  colnum,      /* I - number of column to read (1 = 1st col) */
39             LONGLONG  firstrow,   /* I - first row to read (1 = 1st row)        */
40             LONGLONG  firstelem,  /* I - first vector element to read (1 = 1st) */
41             LONGLONG  nelem,      /* I - number of strings to read              */
42             char **array,     /* O - array of values that are read           */
43             char *nularray,   /* O - array of flags = 1 if nultyp = 2        */
44             int  *anynul,     /* O - set to 1 if any values are null; else 0 */
45             int  *status)     /* IO - error status                           */
46 /*
47   Read an array of string values from a column in the current FITS HDU.
48   Nularray will be set = 1 if the corresponding array pixel is undefined,
49   otherwise nularray will = 0.
50 */
51 {
52     char dummy[2];
53 
54     ffgcls(fptr, colnum, firstrow, firstelem, nelem, 2, dummy,
55            array, nularray, anynul, status);
56     return(*status);
57 }
58 /*--------------------------------------------------------------------------*/
ffgcls(fitsfile * fptr,int colnum,LONGLONG firstrow,LONGLONG firstelem,LONGLONG nelem,int nultyp,char * nulval,char ** array,char * nularray,int * anynul,int * status)59 int ffgcls( fitsfile *fptr,   /* I - FITS file pointer                       */
60             int  colnum,      /* I - number of column to read (1 = 1st col) */
61             LONGLONG  firstrow,   /* I - first row to read (1 = 1st row)        */
62             LONGLONG  firstelem,  /* I - first vector element to read (1 = 1st) */
63             LONGLONG  nelem,      /* I - number of strings to read              */
64             int   nultyp,     /* I - null value handling code:               */
65                               /*     1: set undefined pixels = nulval        */
66                               /*     2: set nularray=1 for undefined pixels  */
67             char  *nulval,    /* I - value for null pixels if nultyp = 1     */
68             char **array,     /* O - array of values that are read           */
69             char *nularray,   /* O - array of flags = 1 if nultyp = 2        */
70             int  *anynul,     /* O - set to 1 if any values are null; else 0 */
71             int  *status)     /* IO - error status                           */
72 /*
73   Read an array of string values from a column in the current FITS HDU.
74   Returns a formated string value, regardless of the datatype of the column
75 */
76 {
77     int tcode, hdutype, tstatus, scaled, intcol, dwidth, nulwidth, ll, dlen;
78     int equivtype;
79     long ii, jj;
80     tcolumn *colptr;
81     char message[FLEN_ERRMSG], *carray, keyname[FLEN_KEYWORD];
82     char cform[20], dispfmt[20], tmpstr[400], *flgarray, tmpnull[80];
83     unsigned char byteval;
84     float *earray;
85     double *darray, tscale = 1.0;
86     LONGLONG *llarray;
87     ULONGLONG *ullarray;
88 
89     if (*status > 0 || nelem == 0)  /* inherit input status value if > 0 */
90         return(*status);
91 
92     /* reset position to the correct HDU if necessary */
93     if (fptr->HDUposition != (fptr->Fptr)->curhdu)
94         ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
95 
96     /* rescan header if data structure is undefined */
97     else if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
98         if ( ffrdef(fptr, status) > 0)
99             return(*status);
100 
101     if (colnum < 1 || colnum > (fptr->Fptr)->tfield)
102     {
103         snprintf(message, FLEN_ERRMSG,"Specified column number is out of range: %d",
104                 colnum);
105         ffpmsg(message);
106         return(*status = BAD_COL_NUM);
107     }
108 
109     /* get equivalent dataype of column (only needed for TLONGLONG columns) */
110     ffeqtyll(fptr, colnum, &equivtype, NULL, NULL, status);
111     if (equivtype < 0) equivtype = abs(equivtype);
112 
113     colptr  = (fptr->Fptr)->tableptr;   /* point to first column */
114     colptr += (colnum - 1);     /* offset to correct column structure */
115     tcode = abs(colptr->tdatatype);
116 
117     if (tcode == TSTRING)
118     {
119       /* simply call the string column reading routine */
120       ffgcls2(fptr, colnum, firstrow, firstelem, nelem, nultyp, nulval,
121            array, nularray, anynul, status);
122     }
123     else if (tcode == TLOGICAL)
124     {
125       /* allocate memory for the array of logical values */
126       carray = (char *) malloc((size_t) nelem);
127 
128       /*  call the logical column reading routine */
129       ffgcll(fptr, colnum, firstrow, firstelem, nelem, nultyp, *nulval,
130            carray, nularray, anynul, status);
131 
132       if (*status <= 0)
133       {
134          /* convert logical values to "T", "F", or "N" (Null) */
135          for (ii = 0; ii < nelem; ii++)
136          {
137            if (carray[ii] == 1)
138               strcpy(array[ii], "T");
139            else if (carray[ii] == 0)
140               strcpy(array[ii], "F");
141            else  /* undefined values = 2 */
142               strcpy(array[ii],"N");
143          }
144       }
145 
146       free(carray);  /* free the memory */
147     }
148     else if (tcode == TCOMPLEX)
149     {
150       /* allocate memory for the array of double values */
151       earray = (float *) calloc((size_t) (nelem * 2), sizeof(float) );
152 
153       ffgcle(fptr, colnum, firstrow, (firstelem - 1) * 2 + 1, nelem * 2,
154         1, 1, FLOATNULLVALUE, earray, nularray, anynul, status);
155 
156       if (*status <= 0)
157       {
158 
159          /* determine the format for the output strings */
160 
161          ffgcdw(fptr, colnum, &dwidth, status);
162          dwidth = (dwidth - 3) / 2;
163 
164          /* use the TDISPn keyword if it exists */
165          ffkeyn("TDISP", colnum, keyname, status);
166          tstatus = 0;
167          cform[0] = '\0';
168 
169          if (ffgkys(fptr, keyname, dispfmt, NULL, &tstatus) == 0)
170          {
171              /* convert the Fortran style format to a C style format */
172              ffcdsp(dispfmt, cform);
173          }
174 
175          if (!cform[0])
176              strcpy(cform, "%14.6E");
177 
178          /* write the formated string for each value:  "(real,imag)" */
179          jj = 0;
180          for (ii = 0; ii < nelem; ii++)
181          {
182            strcpy(array[ii], "(");
183 
184            /* test for null value */
185            if (earray[jj] == FLOATNULLVALUE)
186            {
187              strcpy(tmpstr, "NULL");
188              if (nultyp == 2)
189                 nularray[ii] = 1;
190            }
191            else
192              snprintf(tmpstr, 400,cform, earray[jj]);
193 
194            strncat(array[ii], tmpstr, dwidth);
195            strcat(array[ii], ",");
196            jj++;
197 
198            /* test for null value */
199            if (earray[jj] == FLOATNULLVALUE)
200            {
201              strcpy(tmpstr, "NULL");
202              if (nultyp == 2)
203                 nularray[ii] = 1;
204            }
205            else
206              snprintf(tmpstr, 400,cform, earray[jj]);
207 
208            strncat(array[ii], tmpstr, dwidth);
209            strcat(array[ii], ")");
210            jj++;
211          }
212       }
213 
214       free(earray);  /* free the memory */
215     }
216     else if (tcode == TDBLCOMPLEX)
217     {
218       /* allocate memory for the array of double values */
219       darray = (double *) calloc((size_t) (nelem * 2), sizeof(double) );
220 
221       ffgcld(fptr, colnum, firstrow, (firstelem - 1) * 2 + 1, nelem * 2,
222         1, 1, DOUBLENULLVALUE, darray, nularray, anynul, status);
223 
224       if (*status <= 0)
225       {
226          /* determine the format for the output strings */
227 
228          ffgcdw(fptr, colnum, &dwidth, status);
229          dwidth = (dwidth - 3) / 2;
230 
231          /* use the TDISPn keyword if it exists */
232          ffkeyn("TDISP", colnum, keyname, status);
233          tstatus = 0;
234          cform[0] = '\0';
235 
236          if (ffgkys(fptr, keyname, dispfmt, NULL, &tstatus) == 0)
237          {
238              /* convert the Fortran style format to a C style format */
239              ffcdsp(dispfmt, cform);
240          }
241 
242          if (!cform[0])
243             strcpy(cform, "%23.15E");
244 
245          /* write the formated string for each value:  "(real,imag)" */
246          jj = 0;
247          for (ii = 0; ii < nelem; ii++)
248          {
249            strcpy(array[ii], "(");
250 
251            /* test for null value */
252            if (darray[jj] == DOUBLENULLVALUE)
253            {
254              strcpy(tmpstr, "NULL");
255              if (nultyp == 2)
256                 nularray[ii] = 1;
257            }
258            else
259              snprintf(tmpstr, 400,cform, darray[jj]);
260 
261            strncat(array[ii], tmpstr, dwidth);
262            strcat(array[ii], ",");
263            jj++;
264 
265            /* test for null value */
266            if (darray[jj] == DOUBLENULLVALUE)
267            {
268              strcpy(tmpstr, "NULL");
269              if (nultyp == 2)
270                 nularray[ii] = 1;
271            }
272            else
273              snprintf(tmpstr, 400,cform, darray[jj]);
274 
275            strncat(array[ii], tmpstr, dwidth);
276            strcat(array[ii], ")");
277            jj++;
278          }
279       }
280 
281       free(darray);  /* free the memory */
282     }
283     else if (tcode == TLONGLONG && equivtype == TLONGLONG)
284     {
285       /* allocate memory for the array of LONGLONG values */
286       llarray = (LONGLONG *) calloc((size_t) nelem, sizeof(LONGLONG) );
287       flgarray = (char *) calloc((size_t) nelem, sizeof(char) );
288       dwidth = 20;  /* max width of displayed long long integer value */
289 
290       if (ffgcfjj(fptr, colnum, firstrow, firstelem, nelem,
291             llarray, flgarray, anynul, status) > 0)
292       {
293          free(flgarray);
294          free(llarray);
295          return(*status);
296       }
297 
298       /* write the formated string for each value */
299       if (nulval) {
300           strncpy(tmpnull, nulval,79);
301           tmpnull[79]='\0'; /* In case len(nulval) >= 79 */
302           nulwidth = strlen(tmpnull);
303       } else {
304           strcpy(tmpnull, " ");
305           nulwidth = 1;
306       }
307 
308       for (ii = 0; ii < nelem; ii++)
309       {
310            if ( flgarray[ii] )
311            {
312               *array[ii] = '\0';
313               if (dwidth < nulwidth)
314                   strncat(array[ii], tmpnull, dwidth);
315               else
316                   sprintf(array[ii],"%*s",dwidth,tmpnull);
317 
318               if (nultyp == 2)
319 	          nularray[ii] = 1;
320            }
321            else
322            {
323 
324 #if defined(_MSC_VER)
325     /* Microsoft Visual C++ 6.0 uses '%I64d' syntax  for 8-byte integers */
326         snprintf(tmpstr, 400,"%20I64d", llarray[ii]);
327 #elif (USE_LL_SUFFIX == 1)
328         snprintf(tmpstr, 400,"%20lld", llarray[ii]);
329 #else
330         snprintf(tmpstr, 400,"%20ld", llarray[ii]);
331 #endif
332               *array[ii] = '\0';
333               strncat(array[ii], tmpstr, 20);
334            }
335       }
336 
337       free(flgarray);
338       free(llarray);  /* free the memory */
339 
340     }
341     else if (tcode == TLONGLONG && equivtype == TULONGLONG)
342     {
343       /* allocate memory for the array of ULONGLONG values */
344       ullarray = (ULONGLONG *) calloc((size_t) nelem, sizeof(ULONGLONG) );
345       flgarray = (char *) calloc((size_t) nelem, sizeof(char) );
346       dwidth = 20;  /* max width of displayed unsigned long long integer value */
347 
348       if (ffgcfujj(fptr, colnum, firstrow, firstelem, nelem,
349             ullarray, flgarray, anynul, status) > 0)
350       {
351          free(flgarray);
352          free(ullarray);
353          return(*status);
354       }
355 
356       /* write the formated string for each value */
357       if (nulval) {
358           strncpy(tmpnull, nulval, 79);
359           tmpnull[79]='\0'; /* In case len(nulval) >= 79 */
360           nulwidth = strlen(tmpnull);
361       } else {
362           strcpy(tmpnull, " ");
363           nulwidth = 1;
364       }
365 
366       for (ii = 0; ii < nelem; ii++)
367       {
368            if ( flgarray[ii] )
369            {
370               *array[ii] = '\0';
371               if (dwidth < nulwidth)
372                   strncat(array[ii], tmpnull, dwidth);
373               else
374                   sprintf(array[ii],"%*s",dwidth,tmpnull);
375 
376               if (nultyp == 2)
377 	          nularray[ii] = 1;
378            }
379            else
380            {
381 
382 #if defined(_MSC_VER)
383     /* Microsoft Visual C++ 6.0 uses '%I64d' syntax  for 8-byte integers */
384         snprintf(tmpstr, 400, "%20I64u", ullarray[ii]);
385 #elif (USE_LL_SUFFIX == 1)
386         snprintf(tmpstr, 400, "%20llu", ullarray[ii]);
387 #else
388         snprintf(tmpstr, 400, "%20lu", ullarray[ii]);
389 #endif
390               *array[ii] = '\0';
391               strncat(array[ii], tmpstr, 20);
392            }
393       }
394 
395       free(flgarray);
396       free(ullarray);  /* free the memory */
397 
398     }
399     else
400     {
401       /* allocate memory for the array of double values */
402       darray = (double *) calloc((size_t) nelem, sizeof(double) );
403 
404       /* read all other numeric type columns as doubles */
405       if (ffgcld(fptr, colnum, firstrow, firstelem, nelem, 1, nultyp,
406            DOUBLENULLVALUE, darray, nularray, anynul, status) > 0)
407       {
408          free(darray);
409          return(*status);
410       }
411 
412       /* determine the format for the output strings */
413 
414       ffgcdw(fptr, colnum, &dwidth, status);
415 
416       /* check if  column is scaled */
417       ffkeyn("TSCAL", colnum, keyname, status);
418       tstatus = 0;
419       scaled = 0;
420       if (ffgkyd(fptr, keyname, &tscale, NULL, &tstatus) == 0)
421       {
422             if (tscale != 1.0)
423                 scaled = 1;    /* yes, this is a scaled column */
424       }
425 
426       intcol = 0;
427       if (tcode <= TLONG && !scaled)
428              intcol = 1;   /* this is an unscaled integer column */
429 
430       /* use the TDISPn keyword if it exists */
431       ffkeyn("TDISP", colnum, keyname, status);
432       tstatus = 0;
433       cform[0] = '\0';
434 
435       if (ffgkys(fptr, keyname, dispfmt, NULL, &tstatus) == 0)
436       {
437            /* convert the Fortran style TDISPn to a C style format */
438            ffcdsp(dispfmt, cform);
439       }
440 
441       if (!cform[0])
442       {
443             /* no TDISPn keyword; use TFORMn instead */
444 
445             ffkeyn("TFORM", colnum, keyname, status);
446             ffgkys(fptr, keyname, dispfmt, NULL, status);
447 
448             if (scaled && tcode <= TSHORT)
449             {
450                   /* scaled short integer column == float */
451                   strcpy(cform, "%#14.6G");
452             }
453             else if (scaled && tcode == TLONG)
454             {
455                   /* scaled long integer column == double */
456                   strcpy(cform, "%#23.15G");
457             }
458             else if (scaled && tcode == TLONGLONG)
459             {
460                   /* scaled long long integer column == double */
461                   strcpy(cform, "%#23.15G");
462             }
463             else
464             {
465                ffghdt(fptr, &hdutype, status);
466                if (hdutype == ASCII_TBL)
467                {
468                   /* convert the Fortran style TFORMn to a C style format */
469                   ffcdsp(dispfmt, cform);
470                }
471                else
472                {
473                  /* this is a binary table, need to convert the format */
474                   if (tcode == TBIT) {            /* 'X' */
475                      strcpy(cform, "%4d");
476                   } else if (tcode == TBYTE) {    /* 'B' */
477                      strcpy(cform, "%4d");
478                   } else if (tcode == TSHORT) {   /* 'I' */
479                      strcpy(cform, "%6d");
480                   } else if (tcode == TLONG) {    /* 'J' */
481                      strcpy(cform, "%11.0f");
482                      intcol = 0;  /* needed to support unsigned int */
483                   } else if (tcode == TFLOAT) {   /* 'E' */
484                      strcpy(cform, "%#14.6G");
485                   } else if (tcode == TDOUBLE) {  /* 'D' */
486                      strcpy(cform, "%#23.15G");
487                   }
488                }
489             }
490       }
491 
492       if (nulval) {
493           strncpy(tmpnull, nulval,79);
494           tmpnull[79]='\0';
495           nulwidth = strlen(tmpnull);
496       } else {
497           strcpy(tmpnull, " ");
498           nulwidth = 1;
499       }
500 
501       /* write the formated string for each value */
502       for (ii = 0; ii < nelem; ii++)
503       {
504            if (tcode == TBIT)
505            {
506                byteval = (char) darray[ii];
507 
508                for (ll=0; ll < 8; ll++)
509                {
510                    if ( ((unsigned char) (byteval << ll)) >> 7 )
511                        *(array[ii] + ll) = '1';
512                    else
513                        *(array[ii] + ll) = '0';
514                }
515                *(array[ii] + 8) = '\0';
516            }
517            /* test for null value */
518            else if ( (nultyp == 1 && darray[ii] == DOUBLENULLVALUE) ||
519                 (nultyp == 2 && nularray[ii]) )
520            {
521               *array[ii] = '\0';
522               if (dwidth < nulwidth)
523                   strncat(array[ii], tmpnull, dwidth);
524               else
525                   sprintf(array[ii],"%*s",dwidth,tmpnull);
526            }
527            else
528            {
529               if (intcol) {
530                 snprintf(tmpstr, 400,cform, (int) darray[ii]);
531               } else {
532                 snprintf(tmpstr, 400,cform, darray[ii]);
533               }
534 
535               /* fill field with '*' if number is too wide */
536               dlen = strlen(tmpstr);
537 	      if (dlen > dwidth) {
538 	         memset(tmpstr, '*', dwidth);
539               }
540 
541               *array[ii] = '\0';
542               strncat(array[ii], tmpstr, dwidth);
543            }
544       }
545 
546       free(darray);  /* free the memory */
547     }
548     return(*status);
549 }
550 /*--------------------------------------------------------------------------*/
ffgcdw(fitsfile * fptr,int colnum,int * width,int * status)551 int ffgcdw( fitsfile *fptr,   /* I - FITS file pointer                       */
552             int  colnum,      /* I - number of column (1 = 1st col)      */
553             int  *width,      /* O - display width                       */
554             int  *status)     /* IO - error status                           */
555 /*
556   Get Column Display Width.
557 */
558 {
559     tcolumn *colptr;
560     char *cptr;
561     char message[FLEN_ERRMSG], keyname[FLEN_KEYWORD], dispfmt[20];
562     int tcode, hdutype, tstatus, scaled;
563     double tscale;
564 
565     if (*status > 0)  /* inherit input status value if > 0 */
566         return(*status);
567 
568     if (fptr->HDUposition != (fptr->Fptr)->curhdu)
569         ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
570 
571     if (colnum < 1 || colnum > (fptr->Fptr)->tfield)
572     {
573         snprintf(message, FLEN_ERRMSG,"Specified column number is out of range: %d",
574                 colnum);
575         ffpmsg(message);
576         return(*status = BAD_COL_NUM);
577     }
578 
579     colptr  = (fptr->Fptr)->tableptr;   /* point to first column */
580     colptr += (colnum - 1);     /* offset to correct column structure */
581     tcode = abs(colptr->tdatatype);
582 
583     /* use the TDISPn keyword if it exists */
584     ffkeyn("TDISP", colnum, keyname, status);
585 
586     *width = 0;
587     tstatus = 0;
588     if (ffgkys(fptr, keyname, dispfmt, NULL, &tstatus) == 0)
589     {
590           /* parse TDISPn get the display width */
591           cptr = dispfmt;
592           while(*cptr == ' ') /* skip leading blanks */
593               cptr++;
594 
595           if (*cptr == 'A' || *cptr == 'a' ||
596               *cptr == 'I' || *cptr == 'i' ||
597               *cptr == 'O' || *cptr == 'o' ||
598               *cptr == 'Z' || *cptr == 'z' ||
599               *cptr == 'F' || *cptr == 'f' ||
600               *cptr == 'E' || *cptr == 'e' ||
601               *cptr == 'D' || *cptr == 'd' ||
602               *cptr == 'G' || *cptr == 'g')
603           {
604 
605             while(!isdigit((int) *cptr) && *cptr != '\0') /* find 1st digit */
606               cptr++;
607 
608             *width = atoi(cptr);
609             if (tcode >= TCOMPLEX)
610               *width = (2 * (*width)) + 3;
611           }
612     }
613 
614     if (*width == 0)
615     {
616         /* no valid TDISPn keyword; use TFORMn instead */
617 
618         ffkeyn("TFORM", colnum, keyname, status);
619         ffgkys(fptr, keyname, dispfmt, NULL, status);
620 
621         /* check if  column is scaled */
622         ffkeyn("TSCAL", colnum, keyname, status);
623         tstatus = 0;
624         scaled = 0;
625 
626         if (ffgkyd(fptr, keyname, &tscale, NULL, &tstatus) == 0)
627         {
628             if (tscale != 1.0)
629                 scaled = 1;    /* yes, this is a scaled column */
630         }
631 
632         if (scaled && tcode <= TSHORT)
633         {
634             /* scaled short integer col == float; default format is 14.6G */
635             *width = 14;
636         }
637         else if (scaled && tcode == TLONG)
638         {
639             /* scaled long integer col == double; default format is 23.15G */
640             *width = 23;
641         }
642         else if (scaled && tcode == TLONGLONG)
643         {
644             /* scaled long long integer col == double; default format is 23.15G */
645             *width = 23;
646         }
647 
648         else
649         {
650            ffghdt(fptr, &hdutype, status);  /* get type of table */
651            if (hdutype == ASCII_TBL)
652            {
653               /* parse TFORMn get the display width */
654               cptr = dispfmt;
655               while(!isdigit((int) *cptr) && *cptr != '\0') /* find 1st digit */
656                  cptr++;
657 
658               *width = atoi(cptr);
659            }
660            else
661            {
662                  /* this is a binary table */
663                   if (tcode == TBIT)           /* 'X' */
664                      *width = 8;
665                   else if (tcode == TBYTE)     /* 'B' */
666                      *width = 4;
667                   else if (tcode == TSHORT)    /* 'I' */
668                      *width = 6;
669                   else if (tcode == TLONG)     /* 'J' */
670                      *width = 11;
671                   else if (tcode == TLONGLONG) /* 'K' */
672                      *width = 20;
673                   else if (tcode == TFLOAT)    /* 'E' */
674                      *width = 14;
675                   else if (tcode == TDOUBLE)   /* 'D' */
676                      *width = 23;
677                   else if (tcode == TCOMPLEX)  /* 'C' */
678                      *width = 31;
679                   else if (tcode == TDBLCOMPLEX)  /* 'M' */
680                      *width = 49;
681                   else if (tcode == TLOGICAL)  /* 'L' */
682                      *width = 1;
683                   else if (tcode == TSTRING)   /* 'A' */
684                   {
685 		    int typecode;
686 		    long int repeat = 0, rwidth = 0;
687 		    int gstatus = 0;
688 
689 		    /* Deal with possible vector string with repeat / width  by parsing
690 		       the TFORM=rAw keyword */
691 		    if (ffgtcl(fptr, colnum, &typecode, &repeat, &rwidth, &gstatus) == 0 &&
692 			rwidth >= 1 && rwidth < repeat) {
693 		      *width = rwidth;
694 
695 		    } else {
696 
697 		      /* Hmmm, we couldn't parse the TFORM keyword by standard, so just do
698 			 simple parsing */
699 		      cptr = dispfmt;
700 		      while(!isdigit((int) *cptr) && *cptr != '\0')
701 			cptr++;
702 
703 		      *width = atoi(cptr);
704 		    }
705 
706                     if (*width < 1)
707                          *width = 1;  /* default is at least 1 column */
708                   }
709             }
710         }
711     }
712     return(*status);
713 }
714 /*--------------------------------------------------------------------------*/
ffgcls2(fitsfile * fptr,int colnum,LONGLONG firstrow,LONGLONG firstelem,LONGLONG nelem,int nultyp,char * nulval,char ** array,char * nularray,int * anynul,int * status)715 int ffgcls2 ( fitsfile *fptr,   /* I - FITS file pointer                       */
716             int  colnum,      /* I - number of column to read (1 = 1st col) */
717             LONGLONG  firstrow,   /* I - first row to read (1 = 1st row)        */
718             LONGLONG  firstelem,  /* I - first vector element to read (1 = 1st) */
719             LONGLONG  nelem,      /* I - number of strings to read              */
720             int   nultyp,     /* I - null value handling code:               */
721                               /*     1: set undefined pixels = nulval        */
722                               /*     2: set nularray=1 for undefined pixels  */
723             char  *nulval,    /* I - value for null pixels if nultyp = 1     */
724             char **array,     /* O - array of values that are read           */
725             char *nularray,   /* O - array of flags = 1 if nultyp = 2        */
726             int  *anynul,     /* O - set to 1 if any values are null; else 0 */
727             int  *status)     /* IO - error status                           */
728 /*
729   Read an array of string values from a column in the current FITS HDU.
730 */
731 {
732     double dtemp;
733     long nullen;
734     int tcode, maxelem, hdutype, nulcheck;
735     long twidth, incre;
736     long ii, jj, ntodo;
737     LONGLONG repeat, startpos, elemnum, readptr, tnull, rowlen, rownum, remain, next;
738     double scale, zero;
739     char tform[20];
740     char message[FLEN_ERRMSG];
741     char snull[20];   /*  the FITS null value  */
742     tcolumn *colptr;
743 
744     double cbuff[DBUFFSIZE / sizeof(double)]; /* align cbuff on word boundary */
745     char *buffer, *arrayptr;
746 
747     if (*status > 0 || nelem == 0)  /* inherit input status value if > 0 */
748         return(*status);
749 
750     if (fptr->HDUposition != (fptr->Fptr)->curhdu)
751         ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
752 
753     if (anynul)
754         *anynul = 0;
755 
756     if (nultyp == 2)
757         memset(nularray, 0, (size_t) nelem);   /* initialize nullarray */
758 
759     /*---------------------------------------------------*/
760     /*  Check input and get parameters about the column: */
761     /*---------------------------------------------------*/
762     if (colnum < 1 || colnum > (fptr->Fptr)->tfield)
763     {
764         snprintf(message, FLEN_ERRMSG,"Specified column number is out of range: %d",
765                 colnum);
766         ffpmsg(message);
767         return(*status = BAD_COL_NUM);
768     }
769 
770     colptr  = (fptr->Fptr)->tableptr;   /* point to first column */
771     colptr += (colnum - 1);     /* offset to correct column structure */
772     tcode = colptr->tdatatype;
773 
774     if (tcode == -TSTRING) /* variable length column in a binary table? */
775     {
776       /* only read a single string; ignore value of firstelem */
777 
778       if (ffgcprll( fptr, colnum, firstrow, 1, 1, 0, &scale, &zero,
779         tform, &twidth, &tcode, &maxelem, &startpos,  &elemnum, &incre,
780         &repeat, &rowlen, &hdutype, &tnull, snull, status) > 0)
781         return(*status);
782 
783       remain = 1;
784       twidth = (long) repeat;
785     }
786     else if (tcode == TSTRING)
787     {
788       if (ffgcprll( fptr, colnum, firstrow, firstelem, nelem, 0, &scale, &zero,
789         tform, &twidth, &tcode, &maxelem, &startpos,  &elemnum, &incre,
790         &repeat, &rowlen, &hdutype, &tnull, snull, status) > 0)
791         return(*status);
792 
793       /* if string length is greater than a FITS block (2880 char) then must */
794       /* only read 1 string at a time, to force reading by ffgbyt instead of */
795       /* ffgbytoff (ffgbytoff can't handle this case) */
796       if (twidth > IOBUFLEN) {
797         maxelem = 1;
798         incre = twidth;
799         repeat = 1;
800       }
801 
802       remain = nelem;
803     }
804     else
805         return(*status = NOT_ASCII_COL);
806 
807     nullen = strlen(snull);   /* length of the undefined pixel string */
808     if (nullen == 0)
809         nullen = 1;
810 
811     /*------------------------------------------------------------------*/
812     /*  Decide whether to check for null values in the input FITS file: */
813     /*------------------------------------------------------------------*/
814     nulcheck = nultyp; /* by default check for null values in the FITS file */
815 
816     if (nultyp == 1 && nulval == 0)
817        nulcheck = 0;    /* calling routine does not want to check for nulls */
818 
819     else if (nultyp == 1 && nulval && nulval[0] == 0)
820        nulcheck = 0;    /* calling routine does not want to check for nulls */
821 
822     else if (snull[0] == ASCII_NULL_UNDEFINED)
823        nulcheck = 0;   /* null value string in ASCII table not defined */
824 
825     else if (nullen > twidth)
826        nulcheck = 0;   /* null value string is longer than width of column  */
827                        /* thus impossible for any column elements to = null */
828 
829     /*---------------------------------------------------------------------*/
830     /*  Now read the strings one at a time from the FITS column.           */
831     /*---------------------------------------------------------------------*/
832     next = 0;                 /* next element in array to be read  */
833     rownum = 0;               /* row number, relative to firstrow     */
834 
835     while (remain)
836     {
837       /* limit the number of pixels to process at one time to the number that
838          will fit in the buffer space or to the number of pixels that remain
839          in the current vector, which ever is smaller.
840       */
841       ntodo = (long) minvalue(remain, maxelem);
842       ntodo = (long) minvalue(ntodo, (repeat - elemnum));
843 
844       readptr = startpos + ((LONGLONG)rownum * rowlen) + (elemnum * incre);
845       ffmbyt(fptr, readptr, REPORT_EOF, status);  /* move to read position */
846 
847       /* read the array of strings from the FITS file into the buffer */
848 
849       if (incre == twidth)
850          ffgbyt(fptr, ntodo * twidth, cbuff, status);
851       else
852          ffgbytoff(fptr, twidth, ntodo, incre - twidth, cbuff, status);
853 
854       /* copy from the buffer into the user's array of strings */
855       /* work backwards from last char of last string to 1st char of 1st */
856 
857       buffer = ((char *) cbuff) + (ntodo * twidth) - 1;
858 
859       for (ii = (long) (next + ntodo - 1); ii >= next; ii--)
860       {
861          arrayptr = array[ii] + twidth - 1;
862 
863          for (jj = twidth - 1; jj > 0; jj--)  /* ignore trailing blanks */
864          {
865             if (*buffer == ' ')
866             {
867               buffer--;
868               arrayptr--;
869             }
870             else
871               break;
872          }
873          *(arrayptr + 1) = 0;  /* write the string terminator */
874 
875          for (; jj >= 0; jj--)    /* copy the string itself */
876          {
877            *arrayptr = *buffer;
878            buffer--;
879            arrayptr--;
880          }
881 
882          /* check if null value is defined, and if the   */
883          /* column string is identical to the null string */
884          if (nulcheck && !strncmp(snull, array[ii], nullen) )
885          {
886            *anynul = 1;   /* this is a null value */
887            if (nultyp == 1) {
888 
889 	     if (nulval)
890                 strcpy(array[ii], nulval);
891 	     else
892 	        strcpy(array[ii], " ");
893 
894            } else
895              nularray[ii] = 1;
896          }
897       }
898 
899       if (*status > 0)  /* test for error during previous read operation */
900       {
901          dtemp = (double) next;
902          snprintf(message,FLEN_ERRMSG,
903           "Error reading elements %.0f thru %.0f of data array (ffpcls).",
904              dtemp+1., dtemp+ntodo);
905 
906          ffpmsg(message);
907          return(*status);
908       }
909 
910       /*--------------------------------------------*/
911       /*  increment the counters for the next loop  */
912       /*--------------------------------------------*/
913       next += ntodo;
914       remain -= ntodo;
915       if (remain)
916       {
917           elemnum += ntodo;
918           if (elemnum == repeat)  /* completed a row; start on next row */
919           {
920               elemnum = 0;
921               rownum++;
922           }
923       }
924     }  /*  End of main while Loop  */
925 
926     return(*status);
927 }
928 
929