[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[gnuastro-commits] master 3c7773f 037/125: Table library prints ASCII co
From: |
Mohammad Akhlaghi |
Subject: |
[gnuastro-commits] master 3c7773f 037/125: Table library prints ASCII columns with blanks |
Date: |
Sun, 23 Apr 2017 22:36:32 -0400 (EDT) |
branch: master
commit 3c7773fd9aac536338cc80ce9a677779cf44e124
Author: Mohammad Akhlaghi <address@hidden>
Commit: Mohammad Akhlaghi <address@hidden>
Table library prints ASCII columns with blanks
Until now, the information for columns with blank values weren't correctly
written in an ASCII table information comment. But now, if a column
contains blank values, the value will be printed in the information column,
making it easy for parsers to specify which fields are blank. Also, when
dealing with blank strings, we now print a `blank' placeholder.
During the process, a problem in `gal_data_has_blank' was corrected: the
value to the ending pointers was based on `data->array' (which has `void *'
type), so adding `data->size' to it was useless, the ending pointers are
now defined based on the starting pointers (which have a type and thus a
size) to use.
---
lib/data.c | 29 ++++----
lib/gnuastro/txt.h | 9 ++-
lib/txt.c | 201 ++++++++++++++++++++++++++++++++++++++++-------------
3 files changed, 175 insertions(+), 64 deletions(-)
diff --git a/lib/data.c b/lib/data.c
index 11d5fcc..21da39e 100644
--- a/lib/data.c
+++ b/lib/data.c
@@ -1098,21 +1098,20 @@ gal_data_has_blank(gal_data_t *data)
/* 'value' will only be read from one of these based on the
datatype. Which the caller assigned. If there is any problem, it is
their responsability, not this function's.*/
- unsigned char *uc = data->array, *ucf = data->array + data->size;
- char *c = data->array, *cf = data->array + data->size;
- char **str = data->array, **strf = data->array + data->size;
- unsigned short *us = data->array, *usf = data->array + data->size;
- short *s = data->array, *sf = data->array + data->size;
- unsigned int *ui = data->array, *uif = data->array + data->size;
- int *in = data->array, *inf = data->array + data->size;
- unsigned long *ul = data->array, *ulf = data->array + data->size;
- long *l = data->array, *lf = data->array + data->size;
- LONGLONG *L = data->array, *Lf = data->array + data->size;
- float *f = data->array, *ff = data->array + data->size;
- double *d = data->array, *df = data->array + data->size;
- gsl_complex_float *cx = data->array, *cxf = data->array + data->size;
- gsl_complex *dcx = data->array, *dcxf = data->array + data->size;
-
+ unsigned char *uc = data->array, *ucf = uc + data->size;
+ char *c = data->array, *cf = c + data->size;
+ char **str = data->array, **strf = str + data->size;
+ unsigned short *us = data->array, *usf = us + data->size;
+ short *s = data->array, *sf = s + data->size;
+ unsigned int *ui = data->array, *uif = ui + data->size;
+ int *in = data->array, *inf = in + data->size;
+ unsigned long *ul = data->array, *ulf = ul + data->size;
+ long *l = data->array, *lf = l + data->size;
+ LONGLONG *L = data->array, *Lf = L + data->size;
+ float *f = data->array, *ff = f + data->size;
+ double *d = data->array, *df = d + data->size;
+ gsl_complex_float *cx = data->array, *cxf = cx + data->size;
+ gsl_complex *dcx = data->array, *dcxf = dcx + data->size;
/* Go over the pixels and check: */
switch(data->type)
diff --git a/lib/gnuastro/txt.h b/lib/gnuastro/txt.h
index b9cf306..a1f791f 100644
--- a/lib/gnuastro/txt.h
+++ b/lib/gnuastro/txt.h
@@ -53,8 +53,15 @@ __BEGIN_C_DECLS /* From C++ preparations */
-/* Macros */
+/* Macros.
+
+ Note on `GAL_TXT_STRING_BLANK': Within Gnuastro, a blank string value is
+ just a NULL pointer, but here, we are dealing with the outside world. In
+ particular we want to write the column to the outside world. So this macro
+ acts as a place holder for the blank string columns ONLY in ASCII
+ tables.*/
#define GAL_TXT_DELIMITERS " ,\t\f\v"
+#define GAL_TXT_STRING_BLANK "blank"
#define GAL_TXT_MAX_FMT_LENGTH 20
diff --git a/lib/txt.c b/lib/txt.c
index cdd61b6..d353fa2 100644
--- a/lib/txt.c
+++ b/lib/txt.c
@@ -820,6 +820,7 @@ gal_txt_table_read(char *filename, size_t numrows,
gal_data_t *colinfo,
/************************************************************************/
/* Make an array of two strings for each column (in practice a two
dimensional array with 2 columns and a row for each input column). */
+#define FMTS_COLS 3
static char **
make_fmts_for_printf(gal_data_t *cols, size_t numcols, int leftadjust,
size_t *len)
@@ -828,48 +829,60 @@ make_fmts_for_printf(gal_data_t *cols, size_t numcols,
int leftadjust,
size_t i=0, j;
gal_data_t *col;
char *fmt=NULL, *lng, **strarr;
+ char bfmt[GAL_TXT_MAX_FMT_LENGTH];
int width=0, precision=0, maxstrlen;
+
/* Allocate space for the output. */
errno=0;
- fmts=malloc(2*numcols*sizeof *fmts);
+ fmts=malloc(FMTS_COLS*numcols*sizeof *fmts);
if(fmts==NULL)
error(EXIT_FAILURE, errno, "%zu bytes for fmts in `gal_txt_write'",
- numcols*sizeof *fmts);
+ FMTS_COLS*numcols*sizeof *fmts);
+
/* Initialize the length to 0. */
*len=0;
+
/* Go over all the columns and make their formats. */
for(col=cols;col!=NULL;col=col->next)
{
/* Initialize */
lng="";
+
/* First allocate the necessary space to keep the string. */
errno=0;
- fmts[i*2]=malloc(GAL_TXT_MAX_FMT_LENGTH*sizeof *fmts[i*2]);
- fmts[i*2+1]=malloc(GAL_TXT_MAX_FMT_LENGTH*sizeof *fmts[i*2+1]);
- if(fmts[i*2]==NULL || fmts[i*2+1]==NULL)
+ fmts[ i*FMTS_COLS ] = malloc(GAL_TXT_MAX_FMT_LENGTH*sizeof **fmts);
+ fmts[ i*FMTS_COLS+1 ] = malloc(GAL_TXT_MAX_FMT_LENGTH*sizeof **fmts);
+ if(fmts[i*FMTS_COLS]==NULL || fmts[i*FMTS_COLS+1]==NULL)
error(EXIT_FAILURE, errno, "%zu bytes for fmts[%zu] or fmts[%zu] "
"in `make_fmts_for_printf' of txt.c",
- GAL_TXT_MAX_FMT_LENGTH*sizeof *fmts[i], i*2, i*2+1);
+ GAL_TXT_MAX_FMT_LENGTH*sizeof **fmts,
+ i*FMTS_COLS, i*FMTS_COLS+1);
+
/* Write the proper format. */
switch(col->type)
{
+
+
case GAL_DATA_TYPE_BIT:
error(EXIT_FAILURE, 0, "printing of bit types is currently "
"not supported");
break;
+
+
case GAL_DATA_TYPE_STRING:
/* Set the basic information. */
fmt="s";
- /* Go through all the strings in the column and find the maximum
- length to use as printing width when no value was given. */
+ /* If `disp_width' was not set (is negative), go through all the
+ strings in the column and find the maximum length to use as
+ printing width when no value was given. */
if(col->disp_width<=0)
{
maxstrlen=-1;
@@ -886,11 +899,21 @@ make_fmts_for_printf(gal_data_t *cols, size_t numcols,
int leftadjust,
break;
+
case GAL_DATA_TYPE_UCHAR:
case GAL_DATA_TYPE_USHORT:
case GAL_DATA_TYPE_UINT:
case GAL_DATA_TYPE_ULONG:
+ /* Set the final printing format. */
+ switch(col->disp_fmt)
+ {
+ case GAL_TABLE_DISPLAY_FMT_UDECIMAL: fmt="u"; break;
+ case GAL_TABLE_DISPLAY_FMT_OCTAL: fmt="o"; break;
+ case GAL_TABLE_DISPLAY_FMT_HEX: fmt="X"; break;
+ default: fmt="u";
+ }
+
/* If we have a long type, then make changes. */
if(col->type==GAL_DATA_TYPE_ULONG)
{
@@ -902,18 +925,10 @@ make_fmts_for_printf(gal_data_t *cols, size_t numcols,
int leftadjust,
: col->disp_width );
precision=( col->disp_precision<0 ? GAL_TABLE_DEF_INT_PRECISION
: col->disp_precision );
-
- /* Set the final printing format. */
- switch(col->disp_fmt)
- {
- case GAL_TABLE_DISPLAY_FMT_UDECIMAL: fmt="u"; break;
- case GAL_TABLE_DISPLAY_FMT_OCTAL: fmt="o"; break;
- case GAL_TABLE_DISPLAY_FMT_HEX: fmt="X"; break;
- default: fmt="u";
- }
break;
+
case GAL_DATA_TYPE_CHAR:
case GAL_DATA_TYPE_LOGICAL:
case GAL_DATA_TYPE_SHORT:
@@ -926,6 +941,7 @@ make_fmts_for_printf(gal_data_t *cols, size_t numcols, int
leftadjust,
break;
+
case GAL_DATA_TYPE_LONG:
case GAL_DATA_TYPE_LONGLONG:
fmt="d";
@@ -937,6 +953,7 @@ make_fmts_for_printf(gal_data_t *cols, size_t numcols, int
leftadjust,
break;
+
case GAL_DATA_TYPE_FLOAT:
case GAL_DATA_TYPE_DOUBLE:
switch(col->disp_fmt)
@@ -946,7 +963,7 @@ make_fmts_for_printf(gal_data_t *cols, size_t numcols, int
leftadjust,
case GAL_TABLE_DISPLAY_FMT_GENERAL: fmt="g"; break;
default: fmt="f";
}
- width=( col->disp_width<0
+ width=( col->disp_width<=0
? ( col->type==GAL_DATA_TYPE_FLOAT
? GAL_TABLE_DEF_FLT_WIDTH
: GAL_TABLE_DEF_DBL_WIDTH )
@@ -955,31 +972,101 @@ make_fmts_for_printf(gal_data_t *cols, size_t numcols,
int leftadjust,
: col->disp_precision );
break;
+
+
default:
error(EXIT_FAILURE, 0, "type code %d not recognized for output "
"column %zu (counting from 1)", col->type, i+1);
}
+
+ /* Print the blank value if there is any blank values in this
+ column. */
+ if(gal_data_has_blank(col))
+ {
+ sprintf(bfmt, "%%%s%s", lng, fmt);
+ switch(col->type)
+ {
+ case GAL_DATA_TYPE_STRING:
+ gal_checkset_allocate_copy(GAL_TXT_STRING_BLANK,
+ &fmts[i*FMTS_COLS+2]);
+ break;
+ case GAL_DATA_TYPE_UCHAR:
+ asprintf(&fmts[i*FMTS_COLS+2], bfmt,
+ (unsigned char)GAL_DATA_BLANK_UCHAR);
+ break;
+ case GAL_DATA_TYPE_CHAR:
+ asprintf(&fmts[i*FMTS_COLS+2], bfmt,
+ (char)GAL_DATA_BLANK_CHAR);
+ break;
+ case GAL_DATA_TYPE_USHORT:
+ asprintf(&fmts[i*FMTS_COLS+2], bfmt,
+ (unsigned short)GAL_DATA_BLANK_USHORT);
+ break;
+ case GAL_DATA_TYPE_SHORT:
+ asprintf(&fmts[i*FMTS_COLS+2], bfmt,
+ (short)GAL_DATA_BLANK_SHORT);
+ break;
+ case GAL_DATA_TYPE_UINT:
+ asprintf(&fmts[i*FMTS_COLS+2], bfmt,
+ (unsigned int)GAL_DATA_BLANK_UINT);
+ break;
+ case GAL_DATA_TYPE_INT:
+ asprintf(&fmts[i*FMTS_COLS+2], bfmt,
+ (int)GAL_DATA_BLANK_INT);
+ break;
+ case GAL_DATA_TYPE_ULONG:
+ asprintf(&fmts[i*FMTS_COLS+2], bfmt,
+ (unsigned long)GAL_DATA_BLANK_ULONG);
+ break;
+ case GAL_DATA_TYPE_LONG:
+ asprintf(&fmts[i*FMTS_COLS+2], bfmt,
+ (long)GAL_DATA_BLANK_LONG);
+ break;
+ case GAL_DATA_TYPE_LONGLONG:
+ asprintf(&fmts[i*FMTS_COLS+2], bfmt,
+ (LONGLONG)GAL_DATA_BLANK_LONGLONG);
+ break;
+ case GAL_DATA_TYPE_FLOAT:
+ asprintf(&fmts[i*FMTS_COLS+2], bfmt, GAL_DATA_BLANK_FLOAT);
+ break;
+ case GAL_DATA_TYPE_DOUBLE:
+ asprintf(&fmts[i*FMTS_COLS+2], bfmt, GAL_DATA_BLANK_DOUBLE);
+ break;
+ }
+
+ /* Adjust the width based on the blank value. */
+ width = ( strlen(fmts[i*FMTS_COLS+2]) > width
+ ? strlen(fmts[i*FMTS_COLS+2]) : width );
+ }
+ else fmts[i*FMTS_COLS+2]=NULL;
+
+
/* Print the result into the allocated string and add its length to
the final length of the overall format statement. The space in the
end of `fmts[i*2]' is to ensure that the columns don't merge, even
if the printed string is larger than the expected width. */
if(precision<0)
- *len += 1 + sprintf(fmts[i*2], "%%%s%d.%d%s%s ",
+ *len += 1 + sprintf(fmts[i*FMTS_COLS], "%%%s%d.%d%s%s ",
leftadjust ? "-" : "", width, precision,
lng, fmt);
else
- *len += 1 + sprintf(fmts[i*2], "%%%s%d%s%s ",
+ *len += 1 + sprintf(fmts[i*FMTS_COLS], "%%%s%d%s%s ",
leftadjust ? "-" : "", width, lng, fmt);
/* Set the string for the Gnuastro type. For strings, we also need to
write the maximum number of characters.*/
if(col->type==GAL_DATA_TYPE_STRING)
- sprintf(fmts[i*2+1], "%s%d", gal_data_type_as_string(col->type, 0),
- width);
+ sprintf(fmts[i*FMTS_COLS+1], "%s%d",
+ gal_data_type_as_string(col->type, 0), width);
else
- strcpy(fmts[i*2+1], gal_data_type_as_string(col->type, 0));
+ strcpy(fmts[i*FMTS_COLS+1], gal_data_type_as_string(col->type, 0));
+
+
+ /* Update the column width and precision: */
+ col->disp_width = width;
+ col->disp_precision = precision;
/* Increment the column counter. */
@@ -999,10 +1086,10 @@ gal_txt_write(gal_data_t *cols, char *comment, char
*filename,
int dontdelete)
{
FILE *fp;
- char **fmts;
gal_data_t *col;
- int iw=0, nw=0, uw=0, tw=0;
+ char **fmts, *tmp;
size_t i, j, numcols=0, fmtlen;
+ int iw=0, nw=0, uw=0, tw=0, bw=0;
/* Find the number of columns, do a small sanity check, and get the
@@ -1046,10 +1133,15 @@ gal_txt_write(gal_data_t *cols, char *comment, char
*filename,
/* Prepare the necessary formats for each column, then allocate the space
- for the full list and concatenate all the separate input into it. */
+ for the full list and concatenate all the separate inputs into it. */
fmts=make_fmts_for_printf(cols, numcols, 1, &fmtlen);
for(i=0;i<numcols;++i)
- tw = strlen( fmts[ i*2+1 ] ) > tw ? strlen( fmts[ i*2+1 ] ) : tw;
+ {
+ if( (tmp=fmts[ i*FMTS_COLS+1 ]) )
+ tw = strlen(tmp) > tw ? strlen(tmp) : tw;
+ if( (tmp=fmts[ i*FMTS_COLS+2 ]) )
+ bw = strlen(tmp) > bw ? strlen(tmp) : bw;
+ }
/* Write the comments if there are any */
@@ -1061,11 +1153,12 @@ gal_txt_write(gal_data_t *cols, char *comment, char
*filename,
iw=log10(numcols)+1;
for(col=cols;col!=NULL;col=col->next)
{
- fprintf(fp, "# Column %-*zu: %-*s [%-*s, %-*s] %s\n",
+ fprintf(fp, "# Column %-*zu: %-*s [%-*s,%-*s,%-*s] %s\n",
iw, i+1,
nw, col->name ? col->name : "",
uw, col->unit ? col->unit : "",
- tw, fmts[i*2+1],
+ tw, fmts[i*FMTS_COLS+1] ? fmts[i*FMTS_COLS+1] : "",
+ bw, fmts[i*FMTS_COLS+2] ? fmts[i*FMTS_COLS+2] : "",
col->comment ? col->comment : "");
++i;
}
@@ -1079,42 +1172,53 @@ gal_txt_write(gal_data_t *cols, char *comment, char
*filename,
{
switch(col->type)
{
- case GAL_DATA_TYPE_STRING:
- fprintf(fp, fmts[j*2], ((char **)col->array)[i]);
- break;
+ /* Integer types */
case GAL_DATA_TYPE_UCHAR:
- fprintf(fp, fmts[j*2], ((unsigned char *)col->array)[i]);
+ fprintf(fp, fmts[j*FMTS_COLS],
+ ((unsigned char *)col->array)[i]);
break;
case GAL_DATA_TYPE_CHAR:
case GAL_DATA_TYPE_LOGICAL:
- fprintf(fp, fmts[j*2], ((char *)col->array)[i]);
+ fprintf(fp, fmts[j*FMTS_COLS], ((char *)col->array)[i]);
break;
case GAL_DATA_TYPE_USHORT:
- fprintf(fp, fmts[j*2], ((unsigned short *)col->array)[i]);
+ fprintf(fp, fmts[j*FMTS_COLS],
+ ((unsigned short *)col->array)[i]);
break;
case GAL_DATA_TYPE_SHORT:
- fprintf(fp, fmts[j*2], ((short *)col->array)[i]);
+ fprintf(fp, fmts[j*FMTS_COLS], ((short *)col->array)[i]);
break;
case GAL_DATA_TYPE_UINT:
- fprintf(fp, fmts[j*2], ((unsigned int *)col->array)[i]);
+ fprintf(fp, fmts[j*FMTS_COLS], ((unsigned int *)col->array)[i]);
break;
case GAL_DATA_TYPE_INT:
- fprintf(fp, fmts[j*2], ((int *)col->array)[i]);
+ fprintf(fp, fmts[j*FMTS_COLS], ((int *)col->array)[i]);
break;
case GAL_DATA_TYPE_ULONG:
- fprintf(fp, fmts[j*2], ((unsigned long *)col->array)[i]);
+ fprintf(fp, fmts[j*FMTS_COLS],
+ ((unsigned long *)col->array)[i]);
break;
case GAL_DATA_TYPE_LONG:
- fprintf(fp, fmts[j*2], ((long *)col->array)[i]);
+ fprintf(fp, fmts[j*FMTS_COLS], ((long *)col->array)[i]);
break;
case GAL_DATA_TYPE_LONGLONG:
- fprintf(fp, fmts[j*2], ((LONGLONG *)col->array)[i]);
+ fprintf(fp, fmts[j*FMTS_COLS], ((LONGLONG *)col->array)[i]);
break;
+
+ /* Special consideration (string, float, double). */
+ case GAL_DATA_TYPE_STRING:
+ if(((char **)col->array)[i])
+ fprintf(fp, fmts[j*FMTS_COLS], ((char **)col->array)[i]);
+ else
+ fprintf(fp, "%-*s ", col->disp_width, GAL_TXT_STRING_BLANK);
+ break;
+
case GAL_DATA_TYPE_FLOAT:
- fprintf(fp, fmts[j*2], ((float *)col->array)[i]);
+ fprintf(fp, fmts[j*FMTS_COLS], ((float *)col->array)[i]);
break;
+
case GAL_DATA_TYPE_DOUBLE:
- fprintf(fp, fmts[j*2], ((double *)col->array)[i]);
+ fprintf(fp, fmts[j*FMTS_COLS], ((double *)col->array)[i]);
break;
default:
error(EXIT_FAILURE, 0, "type code %d not recognized for "
@@ -1126,13 +1230,14 @@ gal_txt_write(gal_data_t *cols, char *comment, char
*filename,
}
- /* Clean up, close the input file and return. For the fmts[i*2] elements,
- the reason is that fmts[i*2+1] are literal strings, not allocated. So
- they don't need freeing.*/
+ /* Clean up, close the input file and return. For the fmts[i*FMTS_COLS]
+ elements, the reason is that fmts[i*FMTS_COLS+1] are literal strings,
+ not allocated. So they don't need freeing.*/
for(i=0;i<numcols;++i)
{
- free(fmts[i*2]);
- free(fmts[i*2+1]);
+ free(fmts[i*FMTS_COLS]);
+ free(fmts[i*FMTS_COLS+1]);
+ free(fmts[i*FMTS_COLS+2]);
}
free(fmts);
if(filename)
- [gnuastro-commits] master d0aa78e 005/125: Arithmetic operation on data structures in library, (continued)
- [gnuastro-commits] master d0aa78e 005/125: Arithmetic operation on data structures in library, Mohammad Akhlaghi, 2017/04/23
- [gnuastro-commits] master 0ad0906 014/125: Bitwise operators available in arithmetic operations, Mohammad Akhlaghi, 2017/04/23
- [gnuastro-commits] master 3ad83a4 010/125: data-arithmetic and data-copy separated from data.c, Mohammad Akhlaghi, 2017/04/23
- [gnuastro-commits] master 6c6382a 013/125: Use of function instead of macros for binary operators, Mohammad Akhlaghi, 2017/04/23
- [gnuastro-commits] master ce73959 030/125: Reading FITS keywords into linked list not array, Mohammad Akhlaghi, 2017/04/23
- [gnuastro-commits] master e0e8679 017/125: Removed `anyblank' from datastructure, several new operators, Mohammad Akhlaghi, 2017/04/23
- [gnuastro-commits] master 6d68470 033/125: Column info format for writing ASCII tables, Mohammad Akhlaghi, 2017/04/23
- [gnuastro-commits] master 0fd75fe 040/125: With no columns, Table program will print all columns, Mohammad Akhlaghi, 2017/04/23
- [gnuastro-commits] master 8090e6d 038/125: Corrections to FITS table reading, Mohammad Akhlaghi, 2017/04/23
- [gnuastro-commits] master 1156793 035/125: ASCII table information fully ready for selection, Mohammad Akhlaghi, 2017/04/23
- [gnuastro-commits] master 3c7773f 037/125: Table library prints ASCII columns with blanks,
Mohammad Akhlaghi <=
- [gnuastro-commits] master 1dca684 047/125: Minor corrections to Gnuastro plain text table format, Mohammad Akhlaghi, 2017/04/23
- [gnuastro-commits] master 620146e 028/125: Library function for writing columns to txt file, Mohammad Akhlaghi, 2017/04/23
- [gnuastro-commits] master 9ec7556 039/125: Table's output file type set common sense, Mohammad Akhlaghi, 2017/04/23
- [gnuastro-commits] master de80e97 046/125: Further explanations on Gnuastro's plain text tables, Mohammad Akhlaghi, 2017/04/23
- [gnuastro-commits] master a5a7c45 048/125: Correction in Gnuastro text table format, Mohammad Akhlaghi, 2017/04/23
- [gnuastro-commits] master 7b33afa 043/125: FITS ascii and binary table I/O done with tests, Mohammad Akhlaghi, 2017/04/23
- [gnuastro-commits] master beeb995 055/125: Corrected options added for make check, Mohammad Akhlaghi, 2017/04/23
- [gnuastro-commits] master 0a1036f 025/125: Data structure with name, units, comments and status, Mohammad Akhlaghi, 2017/04/23
- [gnuastro-commits] master e5373e0 034/125: Column info read from comments in ASCII tables, Mohammad Akhlaghi, 2017/04/23
- [gnuastro-commits] master e8ddf69 058/125: Option description correction in mkprof, Mohammad Akhlaghi, 2017/04/23