gnuastro-commits
[Top][All Lists]
Advanced

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

[gnuastro-commits] master 909fa0d 050/125: Table info printing in librar


From: Mohammad Akhlaghi
Subject: [gnuastro-commits] master 909fa0d 050/125: Table info printing in libraries, updates to Table program
Date: Sun, 23 Apr 2017 22:36:35 -0400 (EDT)

branch: master
commit 909fa0d5b995dee3271ed1c83670c1ae73c66016
Author: Mohammad Akhlaghi <address@hidden>
Commit: Mohammad Akhlaghi <address@hidden>

    Table info printing in libraries, updates to Table program
    
    Printing the information of a given table on the command line in a nicely
    formatted manner is now defined as the library function
    `gal_table_print_info'. Previously, it was only usable within the Table
    program. This was done because it is a very convenient feature and will
    certainly be useful for checks or debugging in many program or library
    development scenarios.
    
    As part of this process, the width of the columns when printing column
    information is not a hard-coded value any more, `gal_table_print_info' will
    check the values before hand and set the width based on the values.
    
    Another major change in this commit is that when the output of
    `gal_txt_table_write' is not a file (to be sent to `stdout'), the column
    information and comments will not be printed. This was done to allow easy
    piping to other programs like AWK, or sort. The book was also corrected to
    fully explain this change in the Table program.
---
 bin/table/ui.c       | 103 ++++++++++++++-------------------------------------
 doc/gnuastro.texi    |  54 +++++++++++++++------------
 lib/gnuastro/table.h |   3 ++
 lib/table.c          |  55 +++++++++++++++++++++++++++
 lib/txt.c            | 102 +++++++++++++++++++++++++++++++++-----------------
 5 files changed, 183 insertions(+), 134 deletions(-)

diff --git a/bin/table/ui.c b/bin/table/ui.c
index 4bfd1b9..8168572 100644
--- a/bin/table/ui.c
+++ b/bin/table/ui.c
@@ -304,72 +304,6 @@ sanitycheck(struct tableparams *p)
 
 
 /**************************************************************/
-/***************          Information         *****************/
-/**************************************************************/
-void
-print_information_exit(struct tableparams *p)
-{
-  int tabletype;
-  gal_data_t *allcols;
-  size_t i, numcols, numrows;
-  char *name, *unit, *comment;
-
-  allcols=gal_table_info(p->up.filename, p->cp.hdu, &numcols, &numrows,
-                         &tabletype);
-
-  /* Print the legend */
-  if(gal_fits_name_is_fits(p->up.filename))
-    printf("%s (hdu: %s):\n", p->up.filename, p->cp.hdu);
-  else
-    printf("%s:\n", p->up.filename);
-  printf("Number of rows: %zu\n", numrows);
-  printf("%-8s%-25s%-20s%-18s%s\n", "No.", "Name", "Units", "Type",
-         "Comment");
-  printf("%-8s%-25s%-20s%-18s%s\n", "---", "----", "-----", "----",
-         "-------");
-
-  /* For each column, print the information, then free them. */
-  for(i=0;i<numcols;++i)
-    {
-      name    = allcols[i].name;       /* Just defined for easier     */
-      unit    = allcols[i].unit;       /* readability. The compiiler  */
-      comment = allcols[i].comment;    /* optimizer will remove them. */
-      printf("%-8zu%-25s%-20s%-18s%s\n", i+1,
-             name ? name : GAL_DATA_BLANK_STRING ,
-             unit ? unit : GAL_DATA_BLANK_STRING ,
-             gal_data_type_as_string(allcols[i].type, 1),
-             comment ? comment : GAL_DATA_BLANK_STRING);
-      if(name)    free(name);
-      if(unit)    free(unit);
-      if(comment) free(comment);
-    }
-
-  /* Clean everything else up and return successfully. */
-  free(allcols);
-  freeandreport(p);
-  exit(EXIT_SUCCESS);
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-/**************************************************************/
 /***************       Preparations         *******************/
 /**************************************************************/
 void
@@ -390,20 +324,41 @@ preparearrays(struct tableparams *p)
 
       /* If there was no actual data in the file, then inform the user */
       if(allcols==NULL)
-        error(EXIT_FAILURE, 0, "%s: no usable data rows (non-commented and "
-              "non-blank lines)", p->up.filename);
+        error(EXIT_FAILURE, 0, "%s: no usable data rows", p->up.filename);
+
+      /* If the user just wanted information, then print it. */
+      if(p->information)
+        {
+          /* Print the file information. */
+          printf("--------\n");
+          printf("%s", p->up.filename);
+          if(gal_fits_name_is_fits(p->up.filename))
+            printf(" (hdu: %s)\n", p->cp.hdu);
+          else
+            printf("\n");
+
+          /* Print each column's information. */
+          gal_table_print_info(allcols, numcols, numrows);
+        }
 
       /* Free the information from all the columns. */
       for(i=0;i<numcols;++i)
         gal_data_free(&allcols[i], 1);
       free(allcols);
 
-      /* Add the number of columns to the list. */
-      for(i=1;i<=numcols;++i)
+      /* Add the number of columns to the list if the user wanted to print
+         the columns (didn't just want their information. */
+      if(p->information)
         {
-          asprintf(&numstr, "%zu", i);
-          gal_linkedlist_add_to_stll(&p->columns, numstr);
+          freeandreport(p);
+          exit(EXIT_SUCCESS);
         }
+      else
+        for(i=1;i<=numcols;++i)
+          {
+            asprintf(&numstr, "%zu", i);
+            gal_linkedlist_add_to_stll(&p->columns, numstr);
+          }
     }
 
   /* Reverse the list of column search criteria that we are looking for
@@ -481,10 +436,6 @@ setparams(int argc, char *argv[], struct tableparams *p)
   /* Do a sanity check. */
   sanitycheck(p);
 
-  /* If the user just wanted the information, just print them and exit. */
-  if(p->information)
-    print_information_exit(p);
-
   /* Make the array of input images. */
   preparearrays(p);
 }
diff --git a/doc/gnuastro.texi b/doc/gnuastro.texi
index fe4677e..ba84e4b 100644
--- a/doc/gnuastro.texi
+++ b/doc/gnuastro.texi
@@ -6588,7 +6588,7 @@ some simple examples.
 Table will read/write, select, convert, or show the information of the
 columns in FITS ASCII table, FITS binary table and plain text table files,
 see @ref{Table formats}. Output columns can also be determined by number or
-regular expression matching of column names, units or comments. The
+regular expression matching of column names, units, or comments. The
 executable name is @file{asttable} with the following general template
 
 @example
@@ -6606,48 +6606,56 @@ $ asttable bintab.fits --information
 $ asttable bintab.fits --column=/^MAG_/
 
 ## Only print the 2nd column, and the third column multiplied by 5
-$ asttable bintab.fits | awk '!/^#/@{print $2, address@hidden'
+$ asttable bintab.fits | awk '@{print $2, address@hidden'
 
 ## Only print those rows with a value in the 10th column above 100000
-$ asttable bintab.fits | awk '!/^#/$10>10e5 @address@hidden'
+$ asttable bintab.fits | awk '$10>10e5 @address@hidden'
 
 ## Sort the output columns by the third column, save output
-$ asttable bintab.fits | awk '!/^#/ | 'sort -k3 > output.txt
+$ asttable bintab.fits | 'sort -k3 > output.txt
 
 ## Convert a plain text table to a binary FITS table
 $ asttable plaintext.txt --output=table.fits --tabletype=fits-binary
 @end example
 
-In the absence of an output file, the selected columns will be printed on
-the command-line. In the absence of selected columns, all columns will be
-output. For the full list of options common to all Gnuastro programs please
-see @ref{Common options}. Options can also be stored in directory, user or
address@hidden GNU AWK
+In the absence of selected columns, all the input file's columns will be
+output. If the specified output is a FITS file, the type of FITS table
+(binary or ASCII) will be determined from the @option{--tabletype}
+option. If the output is not a FITS file, it will be printed as a plain
+text table (with space characters between the columns). When the columns
+are accompanied by meta-data (like column name, units, or comments), this
+information will also printed in the plain text file before the table, as
+described in @ref{Gnuastro text table format}.
+
+For the full list of options common to all Gnuastro programs please see
address@hidden options}. Options can also be stored in directory, user or
 system-wide configuration files to avoid repeating on the command-line, see
address@hidden files}.
-
-Table does not follow Automatic output that is common in most Gnuastro, see
address@hidden output}. If no value is given to the @option{--output}
-option, the desired columns will be printed to the standard output (on the
-command-line). This feature makes it very useful to directly pipe the
-output as input to other programs as the examples above demonstrate.
address@hidden files}. Table does not follow Automatic output that is
+common in most Gnuastro programs, see @ref{Automatic output}. Thus, in the
+absence of an output file, the selected columns will be printed on the
+command-line with no column information, ready for redirecting to other
+tools like AWK or sort, similar to the examples above.
 
 @table @option
 
 @item -i
 @itemx --information
-Print the information for each column and abort. The information for each
-column will be printed as a row on the command-line. The column name (if
-present), units (if present) and datatype will printed. Note that the FITS
-standard does not require a name or units for columns, only the datatype is
-mandatory. For plain text files, even types aren't mandatory, and all
-columns with no type will show a @code{double} type (see @ref{Gnuastro text
-table format})
+Only print the column information in the specified table on the
+command-line and exit. Each columns information (number, name, units, data
+type, and comments) will be printed as a row on the command-line. Note that
+the FITS standard only requires the data type (see @ref{Data types}) and in
+plain text tables, no meta-data/information is mandatory. Gnuastro has its
+own convention in the comments of a plain text table to store and transfer
+this information as described in @ref{Gnuastro text table format}. Note
+that if columns have been requested with the @option{--column} option
+(below), this option will be ignored if given.
 
 @cindex AWK
 @cindex GNU AWK
 @item -c
 @itemx --column
-(@option{=STR} or @option{=INT}) Specify the columns to output for this
+(@option{=STR}, or @option{=INT}) Specify the columns to output for this
 table. If the value to this option is an integer number, the column number
 will be used (counting from 1, Table will abort with an error if zero or
 negative values are given). When the value can't be interpretted as an a
diff --git a/lib/gnuastro/table.h b/lib/gnuastro/table.h
index 6acc21a..419e84d 100644
--- a/lib/gnuastro/table.h
+++ b/lib/gnuastro/table.h
@@ -122,6 +122,9 @@ int
 gal_table_string_to_searchin(char *string);
 
 void
+gal_table_print_info(gal_data_t *allcols, size_t numcols, size_t numrows);
+
+void
 gal_table_col_print_info(gal_data_t *col, int tabletype,
                          char *fmt, char *lng);
 
diff --git a/lib/table.c b/lib/table.c
index f28a919..62be3c2 100644
--- a/lib/table.c
+++ b/lib/table.c
@@ -122,6 +122,61 @@ gal_table_string_to_searchin(char *string)
 /************************************************************************/
 /***************          Printing information            ***************/
 /************************************************************************/
+void
+gal_table_print_info(gal_data_t *allcols, size_t numcols, size_t numrows)
+{
+  size_t i;
+  int Nw=3, nw=4, uw=5, tw=4;   /* Initial width from label's width */
+  char *name, *unit, *comment;
+
+  /* Set the widths to print the column information. The width for the
+     column number can easily be identified from the logarithm of the
+     number of columns. */
+  Nw=log10(numcols)+1;
+  for(i=0;i<numcols;++i)
+    {
+      if(allcols[i].name && strlen(allcols[i].name)>nw)
+        nw=strlen(allcols[i].name);
+      if(allcols[i].unit && strlen(allcols[i].unit)>uw)
+        uw=strlen(allcols[i].unit);
+      if(allcols[i].type
+         && strlen(gal_data_type_as_string(allcols[i].type, 1))>tw)
+        tw=strlen(gal_data_type_as_string(allcols[i].type, 1));
+    }
+
+  /* We want one column space between the columns for readability, not the
+     exact length, so increment all the numbers. */
+  Nw+=2; nw+=2; uw+=2; tw+=2;
+
+  /* Print these column names. */
+  printf("%-*s%-*s%-*s%-*s%s\n", Nw, "---", nw, "----", uw,
+         "-----", tw, "----", "-------");
+  printf("%-*s%-*s%-*s%-*s%s\n", Nw, "No.", nw, "Name", uw,
+         "Units", tw, "Type", "Comment");
+  printf("%-*s%-*s%-*s%-*s%s\n", Nw, "---", nw, "----", uw,
+         "-----", tw, "----", "-------");
+
+  /* For each column, print the information, then free them. */
+  for(i=0;i<numcols;++i)
+    {
+      name    = allcols[i].name;       /* Just defined for easier     */
+      unit    = allcols[i].unit;       /* readability. The compiler   */
+      comment = allcols[i].comment;    /* optimizer will remove them. */
+      printf("%-*zu%-*s%-*s%-*s%s\n", Nw, i+1,
+             nw, name ? name : GAL_DATA_BLANK_STRING ,
+             uw, unit ? unit : GAL_DATA_BLANK_STRING ,
+             tw, gal_data_type_as_string(allcols[i].type, 1),
+             comment ? comment : GAL_DATA_BLANK_STRING);
+    }
+
+  /* Print the number of rows. */
+  printf("--------\nNumber of rows: %zu\n--------\n", numrows);
+}
+
+
+
+
+
 /* Fill in/adjust the basic information necessary to print a column. This
    information can be used for printing a plain text file or for FITS ASCII
    tables. The `fmt' and `lng' should point to pre-allocated arrays. The
diff --git a/lib/txt.c b/lib/txt.c
index 1a4becc..1f52917 100644
--- a/lib/txt.c
+++ b/lib/txt.c
@@ -933,10 +933,11 @@ gal_txt_table_write(gal_data_t *cols, char *comment, char 
*filename,
                     int dontdelete)
 {
   FILE *fp;
+  char *nstr;
   gal_data_t *col;
   char **fmts, *tmp;
   size_t i, j, numcols=0, fmtlen;
-  int iw=0, nw=0, uw=0, tw=0, bw=0;
+  int nlen, nw=0, uw=0, tw=0, bw=0;
 
 
   /* Find the number of columns, do a small sanity check, and get the
@@ -964,21 +965,6 @@ gal_txt_table_write(gal_data_t *cols, char *comment, char 
*filename,
     }
 
 
-  /* Set the output FILE pointer: if it isn't NULL, its an actual file,
-     otherwise, its the standard output. */
-  if(filename)
-    {
-      gal_checkset_check_remove_file(filename, dontdelete);
-      errno=0;
-      fp=fopen(filename, "w");
-      if(fp==NULL)
-        error(EXIT_FAILURE, errno, "%s: couldn't be open to write text "
-              "table", filename);
-    }
-  else
-    fp=stdout;
-
-
   /* Prepare the necessary formats for each column, then allocate the space
      for the full list and concatenate all the separate inputs into it. */
   fmts=make_fmts_for_printf(cols, numcols, 1, &fmtlen);
@@ -991,24 +977,68 @@ gal_txt_table_write(gal_data_t *cols, char *comment, char 
*filename,
     }
 
 
-  /* Write the comments if there are any */
-  if(comment) fprintf(fp, "%s\n", comment);
+  /* Set the output FILE pointer: if it isn't NULL, its an actual file,
+     otherwise, its the standard output. */
+  if(filename)
+    {
+      gal_checkset_check_remove_file(filename, dontdelete);
+      errno=0;
+      fp=fopen(filename, "w");
+      if(fp==NULL)
+        error(EXIT_FAILURE, errno, "%s: couldn't be open to write text "
+              "table", filename);
 
 
-  /* Write the information for each column */
-  i=0;
-  iw=log10(numcols)+1;
-  for(col=cols;col!=NULL;col=col->next)
-    {
-      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*FMTS_COLS+1] ? fmts[i*FMTS_COLS+1] : "",
-              bw, fmts[i*FMTS_COLS+2] ? fmts[i*FMTS_COLS+2] : "",
-              col->comment ? col->comment : "");
-      ++i;
+      /* Write the comments if there were any. */
+      if(comment) fprintf(fp, "%s\n", comment);
+
+
+      /* Write the column information if the output is a file. When the
+         output is directed to standard output (the command-line), it is
+         most probably intended for piping into another program (for
+         example AWK for further processing, or sort, or anything) so the
+         user already has the column information and is probably going to
+         change them, so they are just a nuisance.
+
+         When there are more than 9 columns, we don't want to have cases
+         like `# Column 1 :' (note the space between `1' and `:', this
+         space won't exist for the 2 digit colum numbers).
+
+         To do this, we are first allocating and printing a string long
+         enough to keep the final column's `N:'. Then, for each column, we
+         print only the number into the allocated space and put the `:' in
+         manually immediately after the number. Note that the initial
+         `asprintf' put a `\0' in the allocated space, so we can safely
+         over-write the one that `sprintf' puts with a `:' for the columns
+         that have the same number of digits as the final column. */
+      i=0;
+      asprintf(&nstr, "%zu:", numcols);
+      nlen=strlen(nstr);
+      for(col=cols; col!=NULL; col=col->next)
+        {
+          /* Print the number into the number string, then add the `:'
+             immediately after the number. */
+          sprintf(nstr, "%zu", i+1);
+          for(j=1;j<nlen;++j)
+            if(!isdigit(nstr[j])) nstr[j] = isdigit(nstr[j-1]) ? ':' : ' ';
+
+          /* Now print the full column information. */
+          fprintf(fp, "# Column %s %-*s [%-*s,%-*s,%-*s] %s\n",
+                  nstr,
+                  nw, col->name    ? col->name    : "",
+                  uw, col->unit    ? col->unit    : "",
+                  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;
+        }
+
+
+      /* Clean up */
+      free(nstr);
     }
+  else      /* Output wasn't a file, so set it to standard output */
+    fp=stdout;
 
 
   /* Print the output */
@@ -1019,7 +1049,8 @@ gal_txt_table_write(gal_data_t *cols, char *comment, char 
*filename,
         {
           switch(col->type)
             {
-            /* Integer types */
+
+            /* Numerical types. */
             case GAL_DATA_TYPE_UCHAR:
               fprintf(fp, fmts[j*FMTS_COLS],
                       ((unsigned char *)col->array)[i]);
@@ -1085,9 +1116,7 @@ gal_txt_table_write(gal_data_t *cols, char *comment, char 
*filename,
     }
 
 
-  /* 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.*/
+  /* Clean up. */
   for(i=0;i<numcols;++i)
     {
       free(fmts[i*FMTS_COLS]);
@@ -1095,6 +1124,9 @@ gal_txt_table_write(gal_data_t *cols, char *comment, char 
*filename,
       free(fmts[i*FMTS_COLS+2]);
     }
   free(fmts);
+
+
+  /* Close the output file. */
   if(filename)
     {
       errno=0;



reply via email to

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