1 /*  This file, putcolu.c, contains routines that write data elements to    */
2 /*  a FITS image or table.  Writes null values.                            */
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 <string.h>
9 #include <stdlib.h>
10 #include "fitsio2.h"
11 
12 /*--------------------------------------------------------------------------*/
ffppru(fitsfile * fptr,long group,LONGLONG firstelem,LONGLONG nelem,int * status)13 int ffppru( fitsfile *fptr,  /* I - FITS file pointer                       */
14             long  group,      /* I - group to write(1 = 1st group)          */
15             LONGLONG  firstelem,  /* I - first vector element to write(1 = 1st) */
16             LONGLONG  nelem,      /* I - number of values to write              */
17             int  *status)     /* IO - error status                          */
18 /*
19   Write null values to the primary array.
20 
21 */
22 {
23     long row;
24 
25     /*
26       the primary array is represented as a binary table:
27       each group of the primary array is a row in the table,
28       where the first column contains the group parameters
29       and the second column contains the image itself.
30     */
31 
32     if (fits_is_compressed_image(fptr, status))
33     {
34         /* this is a compressed image in a binary table */
35 
36         ffpmsg("writing to compressed image is not supported");
37 
38         return(*status = DATA_COMPRESSION_ERR);
39     }
40 
41     row=maxvalue(1,group);
42 
43     ffpclu(fptr, 2, row, firstelem, nelem, status);
44     return(*status);
45 }
46 /*--------------------------------------------------------------------------*/
ffpprn(fitsfile * fptr,LONGLONG firstelem,LONGLONG nelem,int * status)47 int ffpprn( fitsfile *fptr,  /* I - FITS file pointer                       */
48             LONGLONG  firstelem,  /* I - first vector element to write(1 = 1st) */
49             LONGLONG  nelem,      /* I - number of values to write              */
50             int  *status)     /* IO - error status                          */
51 /*
52   Write null values to the primary array. (Doesn't support groups).
53 
54 */
55 {
56     long row = 1;
57 
58     /*
59       the primary array is represented as a binary table:
60       each group of the primary array is a row in the table,
61       where the first column contains the group parameters
62       and the second column contains the image itself.
63     */
64 
65     if (fits_is_compressed_image(fptr, status))
66     {
67         /* this is a compressed image in a binary table */
68 
69         ffpmsg("writing to compressed image is not supported");
70 
71         return(*status = DATA_COMPRESSION_ERR);
72     }
73 
74     ffpclu(fptr, 2, row, firstelem, nelem, status);
75     return(*status);
76 }
77 /*--------------------------------------------------------------------------*/
ffpclu(fitsfile * fptr,int colnum,LONGLONG firstrow,LONGLONG firstelem,LONGLONG nelempar,int * status)78 int ffpclu( fitsfile *fptr,  /* I - FITS file pointer                       */
79             int  colnum,     /* I - number of column to write (1 = 1st col) */
80             LONGLONG  firstrow,  /* I - first row to write (1 = 1st row)        */
81             LONGLONG  firstelem, /* I - first vector element to write (1 = 1st) */
82             LONGLONG  nelempar,     /* I - number of values to write               */
83             int  *status)    /* IO - error status                           */
84 /*
85   Set elements of a table column to the appropriate null value for the column
86   The column number may refer to a real column in an ASCII or binary table,
87   or it may refer to a virtual column in a 1 or more grouped FITS primary
88   array.  FITSIO treats a primary array as a binary table
89   with 2 vector columns: the first column contains the group parameters (often
90   with length = 0) and the second column contains the array of image pixels.
91   Each row of the table represents a group in the case of multigroup FITS
92   images.
93 
94   This routine support COMPLEX and DOUBLE COMPLEX binary table columns, and
95   sets both the real and imaginary components of the element to a NaN.
96 */
97 {
98     int tcode, maxelem, hdutype, writemode = 2, leng;
99     short i2null;
100     INT32BIT i4null;
101     long twidth, incre;
102     LONGLONG ii;
103     LONGLONG largeelem, nelem, tnull, i8null;
104     LONGLONG repeat, startpos, elemnum, wrtptr, rowlen, rownum, remain, next, ntodo;
105     double scale, zero;
106     unsigned char i1null, lognul = 0;
107     char tform[20], *cstring = 0;
108     char message[FLEN_ERRMSG];
109     char snull[20];   /*  the FITS null value  */
110     long   jbuff[2] = { -1, -1};  /* all bits set is equivalent to a NaN */
111     size_t buffsize;
112 
113     if (*status > 0)           /* inherit input status value if > 0 */
114         return(*status);
115 
116     nelem = nelempar;
117 
118     largeelem = firstelem;
119 
120     /*---------------------------------------------------*/
121     /*  Check input and get parameters about the column: */
122     /*---------------------------------------------------*/
123 
124     /* note that writemode = 2 by default (not 1), so that the returned */
125     /* repeat and incre values will be the actual values for this column. */
126 
127     /* If writing nulls to a variable length column then dummy data values  */
128     /* must have already been written to the heap. */
129     /* We just have to overwrite the previous values with null values. */
130     /* Set writemode = 0 in this case, to test that values have been written */
131 
132     fits_get_coltype(fptr, colnum, &tcode, NULL, NULL, status);
133     if (tcode < 0)
134          writemode = 0;  /* this is a variable length column */
135 
136     if (abs(tcode) >= TCOMPLEX)
137     { /* treat complex columns as pairs of numbers */
138       largeelem = (largeelem - 1) * 2 + 1;
139       nelem *= 2;
140     }
141 
142     if (ffgcprll( fptr, colnum, firstrow, largeelem, nelem, writemode, &scale,
143        &zero, tform, &twidth, &tcode, &maxelem, &startpos,  &elemnum, &incre,
144         &repeat, &rowlen, &hdutype, &tnull, snull, status) > 0)
145         return(*status);
146 
147     if (tcode == TSTRING)
148     {
149       if (snull[0] == ASCII_NULL_UNDEFINED)
150       {
151         ffpmsg(
152         "Null value string for ASCII table column is not defined (FTPCLU).");
153         return(*status = NO_NULL);
154       }
155 
156       /* allocate buffer to hold the null string.  Must write the entire */
157       /* width of the column (twidth bytes) to avoid possible problems */
158       /* with uninitialized FITS blocks, in case the field spans blocks */
159 
160       buffsize = maxvalue(20, twidth);
161       cstring = (char *) malloc(buffsize);
162       if (!cstring)
163          return(*status = MEMORY_ALLOCATION);
164 
165       memset(cstring, ' ', buffsize);  /* initialize  with blanks */
166 
167       leng = strlen(snull);
168       if (hdutype == BINARY_TBL)
169          leng++;        /* copy the terminator too in binary tables */
170 
171       strncpy(cstring, snull, leng);  /* copy null string to temp buffer */
172     }
173     else if ( tcode == TBYTE  ||
174               tcode == TSHORT ||
175               tcode == TLONG  ||
176               tcode == TLONGLONG)
177     {
178       if (tnull == NULL_UNDEFINED)
179       {
180         ffpmsg(
181         "Null value for integer table column is not defined (FTPCLU).");
182         return(*status = NO_NULL);
183       }
184 
185       if (tcode == TBYTE)
186          i1null = (unsigned char) tnull;
187       else if (tcode == TSHORT)
188       {
189          i2null = (short) tnull;
190 #if BYTESWAPPED
191          ffswap2(&i2null, 1); /* reverse order of bytes */
192 #endif
193       }
194       else if (tcode == TLONG)
195       {
196          i4null = (INT32BIT) tnull;
197 #if BYTESWAPPED
198          ffswap4(&i4null, 1); /* reverse order of bytes */
199 #endif
200       }
201       else
202       {
203          i8null = tnull;
204 #if BYTESWAPPED
205          ffswap8((double *)(&i8null), 1);  /* reverse order of bytes */
206 #endif
207       }
208     }
209 
210     /*---------------------------------------------------------------------*/
211     /*  Now write the pixels to the FITS column.                           */
212     /*---------------------------------------------------------------------*/
213     remain = nelem;           /* remaining number of values to write  */
214     next = 0;                 /* next element in array to be written  */
215     rownum = 0;               /* row number, relative to firstrow     */
216     ntodo = remain;           /* number of elements to write at one time */
217 
218     while (ntodo)
219     {
220         /* limit the number of pixels to process at one time to the number that
221            will fit in the buffer space or to the number of pixels that remain
222            in the current vector, which ever is smaller.
223         */
224         ntodo = minvalue(ntodo, (repeat - elemnum));
225         wrtptr = startpos + ((LONGLONG)rownum * rowlen) + (elemnum * incre);
226 
227         ffmbyt(fptr, wrtptr, IGNORE_EOF, status); /* move to write position */
228 
229         switch (tcode)
230         {
231             case (TBYTE):
232 
233                 for (ii = 0; ii < ntodo; ii++)
234                   ffpbyt(fptr, 1,  &i1null, status);
235                 break;
236 
237             case (TSHORT):
238 
239                 for (ii = 0; ii < ntodo; ii++)
240                   ffpbyt(fptr, 2, &i2null, status);
241                 break;
242 
243             case (TLONG):
244 
245                 for (ii = 0; ii < ntodo; ii++)
246                   ffpbyt(fptr, 4, &i4null, status);
247                 break;
248 
249             case (TLONGLONG):
250 
251                 for (ii = 0; ii < ntodo; ii++)
252                   ffpbyt(fptr, 8, &i8null, status);
253                 break;
254 
255             case (TFLOAT):
256 
257                 for (ii = 0; ii < ntodo; ii++)
258                   ffpbyt(fptr, 4, jbuff, status);
259                 break;
260 
261             case (TDOUBLE):
262 
263                 for (ii = 0; ii < ntodo; ii++)
264                   ffpbyt(fptr, 8, jbuff, status);
265                 break;
266 
267             case (TLOGICAL):
268 
269                 for (ii = 0; ii < ntodo; ii++)
270                   ffpbyt(fptr, 1, &lognul, status);
271                 break;
272 
273             case (TSTRING):  /* an ASCII table column */
274                 /* repeat always = 1, so ntodo is also guaranteed to = 1 */
275                 ffpbyt(fptr, twidth, cstring, status);
276                 break;
277 
278             default:  /*  error trap  */
279                 snprintf(message,FLEN_ERRMSG,
280                    "Cannot write null value to column %d which has format %s",
281                      colnum,tform);
282                 ffpmsg(message);
283                 return(*status);
284 
285         } /* End of switch block */
286 
287         /*-------------------------*/
288         /*  Check for fatal error  */
289         /*-------------------------*/
290         if (*status > 0)  /* test for error during previous write operation */
291         {
292            snprintf(message,FLEN_ERRMSG,
293              "Error writing %.0f thru %.0f of null values (ffpclu).",
294               (double) (next+1), (double) (next+ntodo));
295            ffpmsg(message);
296 
297            if (cstring)
298               free(cstring);
299 
300            return(*status);
301         }
302 
303         /*--------------------------------------------*/
304         /*  increment the counters for the next loop  */
305         /*--------------------------------------------*/
306         remain -= ntodo;
307         if (remain)
308         {
309             next += ntodo;
310             elemnum += ntodo;
311             if (elemnum == repeat)  /* completed a row; start on next row */
312             {
313                 elemnum = 0;
314                 rownum++;
315             }
316         }
317         ntodo = remain;  /* this is the maximum number to do in next loop */
318 
319     }  /*  End of main while Loop  */
320 
321     if (cstring)
322        free(cstring);
323 
324     return(*status);
325 }
326 /*--------------------------------------------------------------------------*/
ffpcluc(fitsfile * fptr,int colnum,LONGLONG firstrow,LONGLONG firstelem,LONGLONG nelem,int * status)327 int ffpcluc( fitsfile *fptr,  /* I - FITS file pointer                       */
328             int  colnum,     /* I - number of column to write (1 = 1st col) */
329             LONGLONG  firstrow,  /* I - first row to write (1 = 1st row)        */
330             LONGLONG  firstelem, /* I - first vector element to write (1 = 1st) */
331             LONGLONG  nelem,     /* I - number of values to write               */
332             int  *status)    /* IO - error status                           */
333 /*
334   Set elements of a table column to the appropriate null value for the column
335   The column number may refer to a real column in an ASCII or binary table,
336   or it may refer to a virtual column in a 1 or more grouped FITS primary
337   array.  FITSIO treats a primary array as a binary table
338   with 2 vector columns: the first column contains the group parameters (often
339   with length = 0) and the second column contains the array of image pixels.
340   Each row of the table represents a group in the case of multigroup FITS
341   images.
342 
343   This routine does not do anything special in the case of COMPLEX table columns
344   (unlike the similar ffpclu routine).  This routine is mainly for use by
345   ffpcne which already compensates for the effective doubling of the number of
346   elements in a complex column.
347 */
348 {
349     int tcode, maxelem, hdutype, writemode = 2, leng;
350     short i2null;
351     INT32BIT i4null;
352     long twidth, incre;
353     LONGLONG ii;
354     LONGLONG tnull, i8null;
355     LONGLONG repeat, startpos, elemnum, wrtptr, rowlen, rownum, remain, next, ntodo;
356     double scale, zero;
357     unsigned char i1null, lognul = 0;
358     char tform[20], *cstring = 0;
359     char message[FLEN_ERRMSG];
360     char snull[20];   /*  the FITS null value  */
361     long   jbuff[2] = { -1, -1};  /* all bits set is equivalent to a NaN */
362     size_t buffsize;
363 
364     if (*status > 0)           /* inherit input status value if > 0 */
365         return(*status);
366 
367     /*---------------------------------------------------*/
368     /*  Check input and get parameters about the column: */
369     /*---------------------------------------------------*/
370 
371     /* note that writemode = 2 by default (not 1), so that the returned */
372     /* repeat and incre values will be the actual values for this column. */
373 
374     /* If writing nulls to a variable length column then dummy data values  */
375     /* must have already been written to the heap. */
376     /* We just have to overwrite the previous values with null values. */
377     /* Set writemode = 0 in this case, to test that values have been written */
378 
379     fits_get_coltype(fptr, colnum, &tcode, NULL, NULL, status);
380     if (tcode < 0)
381          writemode = 0;  /* this is a variable length column */
382 
383     if (ffgcprll( fptr, colnum, firstrow, firstelem, nelem, writemode, &scale,
384        &zero, tform, &twidth, &tcode, &maxelem, &startpos,  &elemnum, &incre,
385         &repeat, &rowlen, &hdutype, &tnull, snull, status) > 0)
386         return(*status);
387 
388     if (tcode == TSTRING)
389     {
390       if (snull[0] == ASCII_NULL_UNDEFINED)
391       {
392         ffpmsg(
393         "Null value string for ASCII table column is not defined (FTPCLU).");
394         return(*status = NO_NULL);
395       }
396 
397       /* allocate buffer to hold the null string.  Must write the entire */
398       /* width of the column (twidth bytes) to avoid possible problems */
399       /* with uninitialized FITS blocks, in case the field spans blocks */
400 
401       buffsize = maxvalue(20, twidth);
402       cstring = (char *) malloc(buffsize);
403       if (!cstring)
404          return(*status = MEMORY_ALLOCATION);
405 
406       memset(cstring, ' ', buffsize);  /* initialize  with blanks */
407 
408       leng = strlen(snull);
409       if (hdutype == BINARY_TBL)
410          leng++;        /* copy the terminator too in binary tables */
411 
412       strncpy(cstring, snull, leng);  /* copy null string to temp buffer */
413 
414     }
415     else if ( tcode == TBYTE  ||
416               tcode == TSHORT ||
417               tcode == TLONG  ||
418               tcode == TLONGLONG)
419     {
420       if (tnull == NULL_UNDEFINED)
421       {
422         ffpmsg(
423         "Null value for integer table column is not defined (FTPCLU).");
424         return(*status = NO_NULL);
425       }
426 
427       if (tcode == TBYTE)
428          i1null = (unsigned char) tnull;
429       else if (tcode == TSHORT)
430       {
431          i2null = (short) tnull;
432 #if BYTESWAPPED
433          ffswap2(&i2null, 1); /* reverse order of bytes */
434 #endif
435       }
436       else if (tcode == TLONG)
437       {
438          i4null = (INT32BIT) tnull;
439 #if BYTESWAPPED
440          ffswap4(&i4null, 1); /* reverse order of bytes */
441 #endif
442       }
443       else
444       {
445          i8null = tnull;
446 #if BYTESWAPPED
447          ffswap8((double *)(&i8null), 1);  /* reverse order of bytes */
448 #endif
449       }
450     }
451 
452     /*---------------------------------------------------------------------*/
453     /*  Now write the pixels to the FITS column.                           */
454     /*---------------------------------------------------------------------*/
455     remain = nelem;           /* remaining number of values to write  */
456     next = 0;                 /* next element in array to be written  */
457     rownum = 0;               /* row number, relative to firstrow     */
458     ntodo = remain;           /* number of elements to write at one time */
459 
460     while (ntodo)
461     {
462         /* limit the number of pixels to process at one time to the number that
463            will fit in the buffer space or to the number of pixels that remain
464            in the current vector, which ever is smaller.
465         */
466         ntodo = minvalue(ntodo, (repeat - elemnum));
467         wrtptr = startpos + ((LONGLONG)rownum * rowlen) + (elemnum * incre);
468 
469         ffmbyt(fptr, wrtptr, IGNORE_EOF, status); /* move to write position */
470 
471         switch (tcode)
472         {
473             case (TBYTE):
474 
475                 for (ii = 0; ii < ntodo; ii++)
476                   ffpbyt(fptr, 1,  &i1null, status);
477                 break;
478 
479             case (TSHORT):
480 
481                 for (ii = 0; ii < ntodo; ii++)
482                   ffpbyt(fptr, 2, &i2null, status);
483                 break;
484 
485             case (TLONG):
486 
487                 for (ii = 0; ii < ntodo; ii++)
488                   ffpbyt(fptr, 4, &i4null, status);
489                 break;
490 
491             case (TLONGLONG):
492 
493                 for (ii = 0; ii < ntodo; ii++)
494                   ffpbyt(fptr, 8, &i8null, status);
495                 break;
496 
497             case (TFLOAT):
498 
499                 for (ii = 0; ii < ntodo; ii++)
500                   ffpbyt(fptr, 4, jbuff, status);
501                 break;
502 
503             case (TDOUBLE):
504 
505                 for (ii = 0; ii < ntodo; ii++)
506                   ffpbyt(fptr, 8, jbuff, status);
507                 break;
508 
509             case (TLOGICAL):
510 
511                 for (ii = 0; ii < ntodo; ii++)
512                   ffpbyt(fptr, 1, &lognul, status);
513                 break;
514 
515             case (TSTRING):  /* an ASCII table column */
516                 /* repeat always = 1, so ntodo is also guaranteed to = 1 */
517                 ffpbyt(fptr, twidth, cstring, status);
518                 break;
519 
520             default:  /*  error trap  */
521                 snprintf(message, FLEN_ERRMSG,
522                    "Cannot write null value to column %d which has format %s",
523                      colnum,tform);
524                 ffpmsg(message);
525                 return(*status);
526 
527         } /* End of switch block */
528 
529         /*-------------------------*/
530         /*  Check for fatal error  */
531         /*-------------------------*/
532         if (*status > 0)  /* test for error during previous write operation */
533         {
534            snprintf(message,FLEN_ERRMSG,
535              "Error writing %.0f thru %.0f of null values (ffpclu).",
536               (double) (next+1), (double) (next+ntodo));
537            ffpmsg(message);
538 
539            if (cstring)
540               free(cstring);
541 
542            return(*status);
543         }
544 
545         /*--------------------------------------------*/
546         /*  increment the counters for the next loop  */
547         /*--------------------------------------------*/
548         remain -= ntodo;
549         if (remain)
550         {
551             next += ntodo;
552             elemnum += ntodo;
553             if (elemnum == repeat)  /* completed a row; start on next row */
554             {
555                 elemnum = 0;
556                 rownum++;
557             }
558         }
559         ntodo = remain;  /* this is the maximum number to do in next loop */
560 
561     }  /*  End of main while Loop  */
562 
563     if (cstring)
564        free(cstring);
565 
566     return(*status);
567 }
568 /*--------------------------------------------------------------------------*/
ffprwu(fitsfile * fptr,LONGLONG firstrow,LONGLONG nrows,int * status)569 int ffprwu(fitsfile *fptr,
570            LONGLONG firstrow,
571            LONGLONG nrows,
572            int *status)
573 
574 /*
575  * fits_write_nullrows / ffprwu - write TNULLs to all columns in one or more rows
576  *
577  * fitsfile *fptr - pointer to FITS HDU opened for read/write
578  * long int firstrow - first table row to set to null. (firstrow >= 1)
579  * long int nrows - total number or rows to set to null. (nrows >= 1)
580  * int *status - upon return, *status contains CFITSIO status code
581  *
582  * RETURNS: CFITSIO status code
583  *
584  * written by Craig Markwardt, GSFC
585  */
586 {
587   LONGLONG ntotrows;
588   int ncols, i;
589   int typecode = 0;
590   LONGLONG repeat = 0, width = 0;
591   int nullstatus;
592 
593   if (*status > 0) return *status;
594 
595   if ((firstrow <= 0) || (nrows <= 0)) return (*status = BAD_ROW_NUM);
596 
597   fits_get_num_rowsll(fptr, &ntotrows, status);
598 
599   if (firstrow + nrows - 1 > ntotrows) return (*status = BAD_ROW_NUM);
600 
601   fits_get_num_cols(fptr, &ncols, status);
602   if (*status) return *status;
603 
604 
605   /* Loop through each column and write nulls */
606   for (i=1; i <= ncols; i++) {
607     repeat = 0;  typecode = 0;  width = 0;
608     fits_get_coltypell(fptr, i, &typecode, &repeat, &width, status);
609     if (*status) break;
610 
611     /* NOTE: data of TSTRING type must not write the total repeat
612        count, since the repeat count is the *character* count, not the
613        nstring count.  Divide by string width to get number of
614        strings. */
615 
616     if (typecode == TSTRING) repeat /= width;
617 
618     /* Write NULLs */
619     nullstatus = 0;
620     fits_write_col_null(fptr, i, firstrow, 1, repeat*nrows, &nullstatus);
621 
622     /* ignore error if no null value is defined for the column */
623     if (nullstatus && nullstatus != NO_NULL) return (*status = nullstatus);
624 
625   }
626 
627   return *status;
628 }
629 
630