gnuastro-commits
[Top][All Lists]
Advanced

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

[gnuastro-commits] master 6d68470 033/125: Column info format for writin


From: Mohammad Akhlaghi
Subject: [gnuastro-commits] master 6d68470 033/125: Column info format for writing ASCII tables
Date: Sun, 23 Apr 2017 22:36:31 -0400 (EDT)

branch: master
commit 6d68470dec359c527c5747970bff498f0a4ad227
Author: Mohammad Akhlaghi <address@hidden>
Commit: Mohammad Akhlaghi <address@hidden>

    Column info format for writing ASCII tables
    
    The old ASCII column information was very rudimentary and included the
    exact `printf' formatting for that column. However, for all numerical types
    this detailed information is irrelevant and for strings, we only need the
    width. So now, the column information follows this format (where all the
    values written in capital letters can be randomly set).
    
      # Column NUM: NAME  [UNIT, TYPE] COMMENT
    
    `NAME', `UNIT', and `COMMENT' are just strings and can have any ASCII
    characters except the new-line and `[' for NAME, and `,' for UNIT (which
    specify the limits of the respective field in the last two cases). Also,
    any number of spaces between each element and the next separator is
    acceptable.
    
    During the process the following two issues were also addressed:
    
     * A notice was put in `gal_fits_table_write' to inform the user that this
       function is not ready/implemented yet.
    
     * Report an error if the user asks for column number 0. The column
       numbering starts from one in Gnuastro. Until now, the numberical value
       was stored in the same `if' statement, so when the input value was `0',
       it would fail and go onto making an exact match check. Now, the long
       type value is read before the check, so if it is zero, control goes into
       the numerical/integer branch.
    
     * In making an exact match, until now there was no check, so if there was
       no exact match, it would just ignore it. But now if there is at least
       not one match, there will be an error.
    
     * In `configure.ac', the result for `HAVE_BIN_OP_LONGLONG', was mistakenly
       written as `HAVE_BIN_OP_LONG', so in the output `lib/config.h', it would
       be blank. This is now corrected.
---
 configure.ac |   2 +-
 lib/fits.c   |   2 +-
 lib/table.c  | 101 ++++++++++++++++++++++++++++++++++++++---------------------
 lib/txt.c    |  80 +++++++++++++++++++++++++++++++---------------
 4 files changed, 123 insertions(+), 62 deletions(-)

diff --git a/configure.ac b/configure.ac
index 36cda35..d61293e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -396,7 +396,7 @@ AC_ARG_ENABLE([bin-op-longlong],
 AS_IF([test "x$binop_longlong" != x0], [binoptprint=yes], [binoptprint=no])
 AC_DEFINE_UNQUOTED([GAL_CONFIG_BIN_OP_LONGLONG], [$binop_longlong],
                    [Native binary operations on LONGLONG data.])
-AC_SUBST(HAVE_BIN_OP_LONG, [$binop_longlong])
+AC_SUBST(HAVE_BIN_OP_LONGLONG, [$binop_longlong])
 AC_MSG_RESULT($binoptprint)
 
 AC_MSG_CHECKING(whether to compile float native binary data operators)
diff --git a/lib/fits.c b/lib/fits.c
index 44b4cd8..e5efd59 100644
--- a/lib/fits.c
+++ b/lib/fits.c
@@ -1917,5 +1917,5 @@ void
 gal_fits_table_write(gal_data_t *cols, char *comments, int tabletype,
                      char *filename, int dontdelete)
 {
-
+  error(EXIT_FAILURE, 0, "writing FITS tables is not implemented yet!");
 }
diff --git a/lib/table.c b/lib/table.c
index deaf460..80f0efb 100644
--- a/lib/table.c
+++ b/lib/table.c
@@ -174,16 +174,17 @@ make_list_of_indexs(struct gal_linkedlist_stll *cols, 
gal_data_t *allcols,
                     size_t numcols, int searchin, int ignorecase,
                     char *filename, char *hdu)
 {
-  size_t i;
   long tlong;
   int regreturn;
   regex_t *regex;
+  size_t i, numexact;
   char *str, *strcheck, *tailptr;
   struct gal_linkedlist_stll *tmp;
   struct gal_linkedlist_sll *indexll=NULL;
 
   for(tmp=cols; tmp!=NULL; tmp=tmp->next)
     {
+
       /* REGULAR EXPRESSION: When the first and last characters are `/'. */
       if( tmp->v[0]=='/' && tmp->v[strlen(tmp->v)-1]=='/' )
         {
@@ -234,46 +235,76 @@ make_list_of_indexs(struct gal_linkedlist_stll *cols, 
gal_data_t *allcols,
           regfree(regex);
         }
 
-      /* INTEGER: If the string is an integer, then tailptr should point to
-         the null character. If it points to anything else, it shows that
-         we are not dealing with an integer (usable as a column number). So
-         floating point values are also not acceptable. */
-      else if( (tlong=strtol(tmp->v, &tailptr, 0)) && *tailptr=='\0')
+
+      /* Not regular expression. */
+      else
         {
-          /* Make sure we are not dealing with a negative number! */
-          if(tlong<0)
-            error(EXIT_FAILURE, 0, "the column numbers given to the "
-                  "must not be negative, you have asked for `%ld'", tlong);
-
-          /* Check if the given value is not larger than the number of
-             columns in the input catalog (note that the user is counting
-             from 1, not 0!) */
-          if(tlong>numcols)
+          tlong=strtol(tmp->v, &tailptr, 0);
+
+          /* INTEGER: If the string is an integer, then tailptr should
+             point to the null character. If it points to anything else, it
+             shows that we are not dealing with an integer (usable as a
+             column number). So floating point values are also not
+             acceptable. Since it is possible for the users to give zero
+             for the column number, we need to read the string as a number
+             first, then check it here. */
+          if(*tailptr=='\0')
             {
-              if(gal_fits_name_is_fits(filename))
-                error(EXIT_FAILURE, 0, "%s (hdu %s): has %zu columns, but "
-                      "you have asked for column number %zu", filename,
-                      hdu, numcols, tlong);
-              else
-                error(EXIT_FAILURE, 0, "%s: has %zu columns, but you have "
-                      "asked for column number %zu", filename,
-                      numcols, tlong);
+              /* Make sure the number is larger than zero! */
+              if(tlong<=0)
+                error(EXIT_FAILURE, 0, "the column numbers given to the "
+                      "must not be zero, or negative. You have asked for "
+                      "column %ld", tlong);
+
+              /* Check if the given value is not larger than the number of
+                 columns in the input catalog (note that the user is
+                 counting from 1, not 0!) */
+              if(tlong>numcols)
+                {
+                  if(gal_fits_name_is_fits(filename))
+                    error(EXIT_FAILURE, 0, "%s (hdu %s): has %zu columns, "
+                          "but you have asked for column number %zu",
+                          filename, hdu, numcols, tlong);
+                  else
+                    error(EXIT_FAILURE, 0, "%s: has %zu columns, but you "
+                          "have asked for column number %zu", filename,
+                          numcols, tlong);
+                }
+
+              /* Everything seems to be fine, put this column number in the
+                 output column numbers linked list. Note that internally,
+                 the column numbers start from 0, not 1.*/
+              gal_linkedlist_add_to_sll(&indexll, tlong-1);
             }
 
-          /* Everything seems to be fine, put this column number in the
-             output column numbers linked list. Note that internally, the
-             column numbers start from 0, not 1.*/
-          gal_linkedlist_add_to_sll(&indexll, tlong-1);
-        }
 
-      /* EXACT MATCH: */
-      else
-        {
-          for(i=0;i<numcols;++i)
+
+          /* EXACT MATCH: */
+          else
             {
-              SET_STRCHECK;
-              if(strcheck && strcmp(tmp->v, strcheck)==0)
-                gal_linkedlist_add_to_sll(&indexll, i);
+              /* Go through all the desired column information and add the
+                 column number when there is a match.*/
+              numexact=0;
+              for(i=0;i<numcols;++i)
+                {
+                  SET_STRCHECK;
+                  if(strcheck && strcmp(tmp->v, strcheck)==0 )
+                    {
+                      ++numexact;
+                      gal_linkedlist_add_to_sll(&indexll, i);
+                    }
+                }
+
+              /* If there was no match, then report an error. */
+              if(numexact==0)
+                error(EXIT_FAILURE, 0, "`%s' didn't match exactly with any "
+                      "of the column %s in %s (hdu: %s). To search in the "
+                      "columns, or match multiple of them, enclose your "
+                      "string in slashes (e.g., `/%s/') to use regular "
+                      "expressions", tmp->v,
+                      ( searchin==GAL_TABLE_SEARCH_NAME ? "names"
+                        : ( searchin==GAL_TABLE_SEARCH_UNIT ? "units"
+                            : "comments") ), filename, hdu, tmp->v );
             }
         }
     }
diff --git a/lib/txt.c b/lib/txt.c
index 0b23069..478d8ed 100644
--- a/lib/txt.c
+++ b/lib/txt.c
@@ -156,15 +156,17 @@ gal_txt_table_info(char *filename, size_t *numcols)
 /************************************************************************/
 /***************          Write a txt table               ***************/
 /************************************************************************/
+/* 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). */
 static char **
 make_fmts_for_printf(gal_data_t *cols, size_t numcols, int leftadjust,
                      size_t *len)
 {
-  size_t i=0;
   char **fmts;
   gal_data_t *tmp;
-  char *fmt=NULL, *lng;
   int width=0, precision=0;
+  size_t i=0, j, maxstrlen=0;
+  char *fmt=NULL, *lng, **strarr;
 
   /* Allocate space for the output. */
   errno=0;
@@ -185,10 +187,11 @@ make_fmts_for_printf(gal_data_t *cols, size_t numcols, 
int leftadjust,
       /* First allocate the necessary space to keep the string. */
       errno=0;
       fmts[i*2]=malloc(GAL_TXT_MAX_FMT_LENGTH*sizeof *fmts[i*2]);
-      if(fmts[i*2]==NULL)
-        error(EXIT_FAILURE, errno, "%zu bytes for fmts[%zu] in "
-              "`make_fmts_for_printf' of txt.c",
-              GAL_TXT_MAX_FMT_LENGTH*sizeof *fmts[i], i);
+      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)
+        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);
 
       /* Write the proper format. */
       switch(tmp->type)
@@ -200,11 +203,21 @@ make_fmts_for_printf(gal_data_t *cols, size_t numcols, 
int leftadjust,
           break;
 
         case GAL_DATA_TYPE_STRING:
+          /* Set the basic information. */
           fmt="s";
           width=( tmp->disp_width<0 ? GAL_TABLE_DEF_STR_WIDTH
                   : tmp->disp_width );
           precision=( tmp->disp_precision<0 ? GAL_TABLE_DEF_STR_PRECISION
                       : tmp->disp_precision );
+
+          /* For strings, we also need the maximum length of all the
+             columns, so go through all the strings in the column and find
+             the maximum length. */
+          strarr=tmp->array;
+          for(j=0;j<tmp->size;++j)
+            maxstrlen = ( strlen(strarr[j]) > maxstrlen
+                          ? strlen(strarr[j])
+                          : maxstrlen );
           break;
 
 
@@ -282,13 +295,21 @@ make_fmts_for_printf(gal_data_t *cols, size_t numcols, 
int leftadjust,
                 "column %zu (counting from 1)", tmp->type, i+1);
         }
 
-      /* Print the result into the allocated string. The space in the end
-         here is to ensure that if the printed string is larger than the
-         expected width, it the columns will not merger and at least one
-         space character will be put between them.*/
+      /* 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. */
       *len += 1 + sprintf(fmts[i*2], "%%%s%d.%d%s%s ", leftadjust ? "-" : "",
                           width, precision, lng, fmt);
-      fmts[i*2+1] = gal_data_type_string(tmp->type, 0);
+
+      /* Set the string for the Gnuastro type. For strings, we also need to
+         write the maximum number of characters.*/
+      if(tmp->type==GAL_DATA_TYPE_STRING)
+        sprintf(fmts[i*2+1], "%s%zu", gal_data_type_string(tmp->type, 0),
+                maxstrlen);
+      else
+        strcpy(fmts[i*2+1], gal_data_type_string(tmp->type, 0));
+
 
       /* Increment the column counter. */
       ++i;
@@ -309,21 +330,30 @@ gal_txt_write(gal_data_t *cols, char *comment, char 
*filename,
   FILE *fp;
   char **fmts;
   gal_data_t *tmp;
+  int iw=0, nw=0, uw=0, tw=0;
   size_t i, j, numcols=0, fmtlen;
-  int iw=0, fw=0, nw=0, uw=0, tw=0;
 
 
   /* Find the number of columns, do a small sanity check, and get the
      maximum width of the name and unit string if they are present. */
   for(tmp=cols;tmp!=NULL;tmp=tmp->next)
     {
+      /* Count. */
       ++numcols;
+
+      /* Make sure the columns are 1 dimensional. */
+      if(cols->ndim!=1)
+        error(EXIT_FAILURE, 0, "columns to print as an ASCII file must have "
+              "only one dimension. column %zu of the given set has %zu "
+              "dimensions", numcols, cols->ndim);
+
+      /* Make sure sizes match. */
       if(cols->size!=tmp->size)
-        error(EXIT_FAILURE, 0, "to print a set of columns, into a file, they "
-              "must all have the same number of elements/rows. The inputs to "
-              "`gal_txt_write' have different sizes: the first column has "
-              "%zu, while column %zu as %zu elements", cols->size, numcols,
-              tmp->size);
+        error(EXIT_FAILURE, 0, "to print a set of columns, as an ASCII "
+              "table, they must currently all have the same number of "
+              "elements/rows. The inputs to `gal_txt_write' have different "
+              "sizes: the first column has %zu, while column %zu as %zu "
+              "elements", cols->size, numcols, tmp->size);
       if( tmp->name && strlen(tmp->name)>nw ) nw=strlen(tmp->name);
       if( tmp->unit && strlen(tmp->unit)>uw ) uw=strlen(tmp->unit);
     }
@@ -348,13 +378,10 @@ gal_txt_write(gal_data_t *cols, char *comment, char 
*filename,
      for the full list and concatenate all the separate input into it. */
   fmts=make_fmts_for_printf(cols, numcols, 1, &fmtlen);
   for(i=0;i<numcols;++i)
-    {
-      fw = strlen( fmts[ i*2   ] ) > fw ? strlen( fmts[ i*2   ] ) : fw;
-      tw = strlen( fmts[ i*2+1 ] ) > tw ? strlen( fmts[ i*2+1 ] ) : tw;
-    }
+    tw = strlen( fmts[ i*2+1 ] ) > tw ? strlen( fmts[ i*2+1 ] ) : tw;
 
 
-  /* Write the comments if there as any */
+  /* Write the comments if there are any */
   if(comment) fprintf(fp, "%s\n", comment);
 
 
@@ -363,12 +390,11 @@ gal_txt_write(gal_data_t *cols, char *comment, char 
*filename,
   iw=log10(numcols)+1;
   for(tmp=cols;tmp!=NULL;tmp=tmp->next)
     {
-      fprintf(fp, "# Column %-*zu %-*s [ %-*s , %-*s , %-*s] %s\n",
+      fprintf(fp, "# Column %-*zu: %-*s [%-*s, %-*s] %s\n",
               iw, i+1,
               nw, tmp->name    ? tmp->name    : "",
               uw, tmp->unit    ? tmp->unit    : "",
               tw, fmts[i*2+1],
-              fw, fmts[i*2],
               tmp->comment ? tmp->comment : "");
       ++i;
     }
@@ -432,7 +458,11 @@ 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.*/
-  for(i=0;i<numcols;++i) free(fmts[i*2]);
+  for(i=0;i<numcols;++i)
+    {
+      free(fmts[i*2]);
+      free(fmts[i*2+1]);
+    }
   free(fmts);
   if(filename)
     {



reply via email to

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