[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;