gnuastro-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[gnuastro-commits] master 2e02c46 2/2: Table can print column contents w


From: Mohammad Akhlaghi
Subject: [gnuastro-commits] master 2e02c46 2/2: Table can print column contents with no rows
Date: Thu, 12 Jul 2018 20:21:10 -0400 (EDT)

branch: master
commit 2e02c462dd4bb08384821308258a8e832070a18b
Author: Mohammad Akhlaghi <address@hidden>
Commit: Mohammad Akhlaghi <address@hidden>

    Table can print column contents with no rows
    
    When there are no rows in the table, until now, Table would crash. It would
    complain about not being able to allocate a zero-sized array. With this
    commit, this has been fixed by adding checks on the number of rows when
    reading FITS and plain text files.
    
    This fixes bug #54298.
---
 NEWS              |   2 +-
 doc/gnuastro.texi |  15 +++--
 lib/fits.c        | 168 ++++++++++++++++++++++++++++++++----------------------
 lib/txt.c         |  22 +++++--
 4 files changed, 127 insertions(+), 80 deletions(-)

diff --git a/NEWS b/NEWS
index 40f2773..b59edc8 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,5 @@
 GNU Astronomy Utilities NEWS                          -*- outline -*-
 
-
 * Noteworthy changes in release X.X (library 5.0.0) (YYYY-MM-DD) [alpha]
 
 ** New features
@@ -41,6 +40,7 @@ GNU Astronomy Utilities NEWS                          -*- 
outline -*-
   bug #54285: make check fails if g++ not present.
   bug #54286: BuildProgram's configuration file, not built by default.
   bug #54297: No Match output when --notmatched called and no match.
+  bug #54298: Table not writing array when there are no rows.
 
 
 
diff --git a/doc/gnuastro.texi b/doc/gnuastro.texi
index 154201d..91b9370 100644
--- a/doc/gnuastro.texi
+++ b/doc/gnuastro.texi
@@ -24688,16 +24688,19 @@ of table formats based on the filename (see 
@ref{Table input output}).
 @end deftypefun
 
 @deftypefun {gal_data_t *} gal_fits_tab_read (char @code{*filename}, char 
@code{*hdu}, size_t @code{numrows}, gal_data_t @code{*colinfo}, 
gal_list_sizet_t @code{*indexll}, size_t @code{minmapsize})
-Read the columns given in the list @code{indexll} from a FITS table into a
-linked list of data structures, see @ref{List of size_t} and @ref{List of
+Read the columns given in the list @code{indexll} from a FITS table (in
address@hidden and HDU/extension @code{hdu}) into the returned linked list
+of data structures, see @ref{List of size_t} and @ref{List of
 gal_data_t}. If the necessary space for each column is larger than
 @code{minmapsize}, don't keep it in the RAM, but in a file in the HDD/SSD,
 see the description under the same name in @ref{Generic data container}.
 
-Note that this is a low-level function, so the output data linked list is
-the inverse of the input indexs linked list. It is recommended to use
address@hidden for generic reading of tables, see @ref{Table input
-output}.
+Each column will have @code{numrows} rows and @code{colinfo} contains any
+further information about the columns (returned by
address@hidden, described above). Note that this is a low-level
+function, so the output data linked list is the inverse of the input indexs
+linked list. It is recommended to use @code{gal_table_read} for generic
+reading of tables, see @ref{Table input output}.
 @end deftypefun
 
 @deftypefun void gal_fits_tab_write (gal_data_t @code{*cols}, gal_list_str_t 
@code{*comments}, int @code{tableformat}, char @code{*filename})
diff --git a/lib/fits.c b/lib/fits.c
index 18ee668..772c621 100644
--- a/lib/fits.c
+++ b/lib/fits.c
@@ -2404,10 +2404,7 @@ fits_tab_read_ascii_float_special(char *filename, char 
*hdu, fitsfile *fptr,
 
 
 
-/* Read the column indexs given in the `indexll' linked list from a FITS
-   table into a linked list of data structures, note that this is a
-   low-level function, so the output data linked list is the inverse of the
-   input indexs linked list. */
+/* Read the column indexs into a dataset. */
 gal_data_t *
 gal_fits_tab_read(char *filename, char *hdu, size_t numrows,
                   gal_data_t *allcols, gal_list_sizet_t *indexll,
@@ -2415,88 +2412,121 @@ gal_fits_tab_read(char *filename, char *hdu, size_t 
numrows,
 {
   size_t i=0;
   void *blank;
-  size_t dsize;
   char **strarr;
   fitsfile *fptr;
   gal_data_t *out=NULL;
   gal_list_sizet_t *ind;
   int isfloat, status=0, anynul=0, hdutype;
 
-  /* Open the FITS file */
-  fptr=gal_fits_hdu_open_format(filename, hdu, 1);
+  /* We actually do have columns to read. */
+  if(numrows)
+    {
+      /* Open the FITS file */
+      fptr=gal_fits_hdu_open_format(filename, hdu, 1);
 
-  /* See if its a Binary or ASCII table (necessary for floating point blank
-     values). */
-  if (fits_get_hdu_type(fptr, &hdutype, &status) )
-    gal_fits_io_error(status, NULL);
+      /* See if its a Binary or ASCII table (necessary for floating point
+         blank values). */
+      if (fits_get_hdu_type(fptr, &hdutype, &status) )
+        gal_fits_io_error(status, NULL);
 
-  /* Pop each index and read/store the array. */
-  for(ind=indexll; ind!=NULL; ind=ind->next)
-    {
-      /* Allocate the necessary data structure (including the array) for
-         this column. */
-      dsize=numrows;
-      gal_list_data_add_alloc(&out, NULL, allcols[ind->v].type, 1, &dsize,
-                              NULL, 0, minmapsize, allcols[ind->v].name,
-                              allcols[ind->v].unit, allcols[ind->v].comment);
-
-      /* For a string column, we need an allocated array for each element,
-         even in binary values. This value should be stored in the
-         disp_width element of the data structure, which is done
-         automatically in `gal_fits_table_info'. */
-      if(out->type==GAL_TYPE_STRING)
+      /* Pop each index and read/store the array. */
+      for(ind=indexll; ind!=NULL; ind=ind->next)
         {
-          strarr=out->array;
-          for(i=0;i<numrows;++i)
+          /* Allocate the necessary data structure (including the array)
+             for this column. */
+          gal_list_data_add_alloc(&out, NULL, allcols[ind->v].type, 1,
+                                  &numrows, NULL, 0, minmapsize,
+                                  allcols[ind->v].name, allcols[ind->v].unit,
+                                  allcols[ind->v].comment);
+
+          /* For a string column, we need an allocated array for each element,
+             even in binary values. This value should be stored in the
+             disp_width element of the data structure, which is done
+             automatically in `gal_fits_table_info'. */
+          if(out->type==GAL_TYPE_STRING)
             {
-              errno=0;
-              strarr[i]=calloc(allcols[ind->v].disp_width+1,
-                               sizeof *strarr[i]);
-              if(strarr[i]==NULL)
-                error(EXIT_FAILURE, errno, "%s: allocating %zu bytes for "
-                      "strarr[%zu]", __func__,
-                      (allcols[ind->v].disp_width+1) * sizeof *strarr[i], i);
+              strarr=out->array;
+              for(i=0;i<numrows;++i)
+                {
+                  errno=0;
+                  strarr[i]=calloc(allcols[ind->v].disp_width+1,
+                                   sizeof *strarr[i]);
+                  if(strarr[i]==NULL)
+                    error(EXIT_FAILURE, errno, "%s: allocating %zu bytes for "
+                          "strarr[%zu]", __func__,
+                          (allcols[ind->v].disp_width+1) * sizeof *strarr[i],
+                          i);
+                }
             }
-        }
 
-      /* Allocate a blank value for the given type and read/store the
-         column using CFITSIO. Note that for binary tables, we only need
-         blank values for integer types. For binary floating point types,
-         the FITS standard defines blanks as NaN (same as almost any other
-         software like Gnuastro). However if a blank value is specified,
-         CFITSIO will convert other special numbers like `inf' to NaN
-         also. We want to be able to distringuish `inf' and NaN here, so
-         for floating point types in binary tables, we won't define any
-         blank value. In ASCII tables, CFITSIO doesn't read the `NAN'
-         values (that it has written itself) unless we specify a blank
-         pointer/value. */
-      isfloat = out->type==GAL_TYPE_FLOAT32 || out->type==GAL_TYPE_FLOAT64;
-      blank = ( ( hdutype==BINARY_TBL && isfloat )
-                ? NULL
-                : gal_blank_alloc_write(out->type) );
-      fits_read_col(fptr, gal_fits_type_to_datatype(out->type), ind->v+1,
-                    1, 1, out->size, blank, out->array, &anynul, &status);
-
-      /* In the ASCII table format, CFITSIO might not be able to read `INF'
-         or `-INF'. In this case, it will set status to `BAD_C2D' or
-         `BAD_C2F'. So, we'll use our own parser for the column values. */
-      if( hdutype==ASCII_TBL
-          && isfloat
-          && (status==BAD_C2D || status==BAD_C2F) )
-        {
-          fits_tab_read_ascii_float_special(filename, hdu, fptr, out,
-                                            ind->v+1, numrows, minmapsize);
-          status=0;
+          /* Allocate a blank value for the given type and read/store the
+             column using CFITSIO. Note that for binary tables, we only
+             need blank values for integer types. For binary floating point
+             types, the FITS standard defines blanks as NaN (same as almost
+             any other software like Gnuastro). However if a blank value is
+             specified, CFITSIO will convert other special numbers like
+             `inf' to NaN also. We want to be able to distringuish `inf'
+             and NaN here, so for floating point types in binary tables, we
+             won't define any blank value. In ASCII tables, CFITSIO doesn't
+             read the `NAN' values (that it has written itself) unless we
+             specify a blank pointer/value. */
+          isfloat = ( out->type==GAL_TYPE_FLOAT32
+                      || out->type==GAL_TYPE_FLOAT64 );
+          blank = ( ( hdutype==BINARY_TBL && isfloat )
+                    ? NULL
+                    : gal_blank_alloc_write(out->type) );
+          fits_read_col(fptr, gal_fits_type_to_datatype(out->type), ind->v+1,
+                        1, 1, out->size, blank, out->array, &anynul, &status);
+
+          /* In the ASCII table format, CFITSIO might not be able to read
+             `INF' or `-INF'. In this case, it will set status to `BAD_C2D'
+             or `BAD_C2F'. So, we'll use our own parser for the column
+             values. */
+          if( hdutype==ASCII_TBL
+              && isfloat
+              && (status==BAD_C2D || status==BAD_C2F) )
+            {
+              fits_tab_read_ascii_float_special(filename, hdu, fptr, out,
+                                                ind->v+1, numrows,
+                                                minmapsize);
+              status=0;
+            }
+
+          /* Clean up and sanity check. */
+          if(blank) free(blank);
+          gal_fits_io_error(status, NULL);
         }
 
-      /* Clean up and sanity check. */
-      if(blank) free(blank);
+      /* Close the FITS file */
+      fits_close_file(fptr, &status);
       gal_fits_io_error(status, NULL);
     }
 
-  /* Close the FITS file */
-  fits_close_file(fptr, &status);
-  gal_fits_io_error(status, NULL);
+  /* There are no rows to read (`numrows==NULL'). Make an empty-sized
+     array. */
+  else
+    {
+      /* We are setting a 1-element array to avoid any allocation
+         errors. Then we are freeing the allocated spaces and correcting
+         the sizes. */
+      numrows=1;
+      for(ind=indexll; ind!=NULL; ind=ind->next)
+        {
+          /* Do the allocation. */
+          gal_list_data_add_alloc(&out, NULL, allcols[ind->v].type, 1,
+                                  &numrows, NULL, 0, minmapsize,
+                                  allcols[ind->v].name, allcols[ind->v].unit,
+                                  allcols[ind->v].comment);
+
+          /* Correct the array and sizes. */
+          out->size=0;
+          free(out->array);
+          free(out->dsize);
+          out->dsize=out->array=NULL;
+        }
+    }
+
+  /* Return the output. */
   return out;
 }
 
diff --git a/lib/txt.c b/lib/txt.c
index a8655e0..6b16337 100644
--- a/lib/txt.c
+++ b/lib/txt.c
@@ -863,7 +863,7 @@ gal_txt_read(char *filename, size_t *dsize, gal_data_t 
*info,
   char **tokens;
   gal_data_t *out=NULL;
   gal_list_sizet_t *ind;
-  size_t maxcolnum=0, rowind=0, lineno=0, ndim;
+  size_t one=1, maxcolnum=0, rowind=0, lineno=0, ndim;
   size_t linelen=10;        /* `linelen' will be increased by `getline'. */
 
   /* Open the file. */
@@ -892,13 +892,27 @@ gal_txt_read(char *filename, size_t *dsize, gal_data_t 
*info,
     case TXT_FORMAT_TABLE:
       for(ind=indexll; ind!=NULL; ind=ind->next)
         {
+          /* Allocate the necessary space. We are setting a 1-element array
+             to avoid any allocation errors. Then we are freeing the
+             allocated spaces and correcting the sizes.*/
           ndim=1;
           maxcolnum = maxcolnum>ind->v+1 ? maxcolnum : ind->v+1;
-          gal_list_data_add_alloc(&out, NULL, info[ind->v].type, ndim, dsize,
-                                  NULL, 0, minmapsize, info[ind->v].name,
-                                  info[ind->v].unit, info[ind->v].comment);
+          gal_list_data_add_alloc(&out, NULL, info[ind->v].type, ndim,
+                                  dsize[0]?dsize:&one, NULL, 0, minmapsize,
+                                  info[ind->v].name, info[ind->v].unit,
+                                  info[ind->v].comment);
           out->disp_width=info[ind->v].disp_width;
           out->status=ind->v+1;
+
+          /* If there were no actual rows (dsize[0]==0), free the allocated
+             spaces and correct the size. */
+          if(dsize[0]==0)
+            {
+              out->size=0;
+              free(out->array);
+              free(out->dsize);
+              out->dsize=out->array=NULL;
+            }
         }
       break;
 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]