gnuastro-commits
[Top][All Lists]
Advanced

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

[gnuastro-commits] master 620146e 028/125: Library function for writing


From: Mohammad Akhlaghi
Subject: [gnuastro-commits] master 620146e 028/125: Library function for writing columns to txt file
Date: Sun, 23 Apr 2017 22:36:30 -0400 (EDT)

branch: master
commit 620146e4c0fd7f3152cea732d52f492257995958
Author: Mohammad Akhlaghi <address@hidden>
Commit: Mohammad Akhlaghi <address@hidden>

    Library function for writing columns to txt file
    
    It is now possible to write a linked list of data structure columns into an
    ASCII text file with the `gal_txt_write' function. This function is also
    called by `gal_table_write' function which (in the next commits) will also
    functions for writing FITS tables.
---
 bin/table/args.h            |   8 +-
 bin/table/asttable.conf     |   1 -
 bin/table/main.h            |   4 +-
 bin/table/table.c           |   4 +-
 bin/table/ui.c              |  97 ++++++++++----
 doc/gnuastro.texi           |  18 ++-
 lib/data-arithmetic-other.c |   4 +-
 lib/data.c                  |  40 +++---
 lib/fits.c                  |  28 +++-
 lib/gnuastro/data.h         |   3 +-
 lib/gnuastro/fits.h         |   8 +-
 lib/gnuastro/table.h        |  30 ++++-
 lib/gnuastro/txt.h          |  11 +-
 lib/table.c                 |  77 +++++++++--
 lib/txt.c                   | 314 ++++++++++++++++++++++++++++++++++++++++++++
 15 files changed, 557 insertions(+), 90 deletions(-)

diff --git a/bin/table/args.h b/bin/table/args.h
index b1e9255..913c083 100644
--- a/bin/table/args.h
+++ b/bin/table/args.h
@@ -123,11 +123,11 @@ static struct argp_option options[] =
       2
     },
     {
-      "fitstabletype",
+      "outtabletype",
       't',
       "STR",
       0,
-      "Only `ascii', or `binary' are acceptable.",
+      "Type of output: `txt', `fits-ascii', `fits-binary'.",
       2
     },
 
@@ -203,8 +203,8 @@ parse_opt(int key, char *arg, struct argp_state *state)
 
     /* Output: */
     case 't':
-      gal_checkset_allocate_copy(arg, &p->up.fitstabletype);
-      p->up.fitstabletypeset=1;
+      gal_checkset_allocate_copy(arg, &p->up.outtabletype);
+      p->up.outtabletypeset=1;
       break;
 
 
diff --git a/bin/table/asttable.conf b/bin/table/asttable.conf
index d76b989..5d82e1d 100644
--- a/bin/table/asttable.conf
+++ b/bin/table/asttable.conf
@@ -22,4 +22,3 @@
  searchin         name
 
 # Output:
- fitstabletype    binary
diff --git a/bin/table/main.h b/bin/table/main.h
index 9225956..9939d62 100644
--- a/bin/table/main.h
+++ b/bin/table/main.h
@@ -40,14 +40,14 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 struct uiparams
 {
   char              *filename;
-  char         *fitstabletype;
+  char          *outtabletype;
   gal_data_t      *allcolinfo;
   char              *searchin;
 
   /* If values are set: */
   int          informationset;
   int           ignorecaseset;
-  int        fitstabletypeset;
+  int         outtabletypeset;
   int             searchinset;
 };
 
diff --git a/bin/table/table.c b/bin/table/table.c
index 98d2fb9..222e8d5 100644
--- a/bin/table/table.c
+++ b/bin/table/table.c
@@ -30,6 +30,7 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 #include <unistd.h>
 
 #include <gnuastro/fits.h>
+#include <gnuastro/table.h>
 
 #include "main.h"
 
@@ -43,5 +44,6 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 void
 table(struct tableparams *p)
 {
-
+  gal_table_write(p->table, NULL, p->outtabletype, p->cp.output,
+                  p->cp.dontdelete);
 }
diff --git a/bin/table/ui.c b/bin/table/ui.c
index 11d5e4d..c3f8c29 100644
--- a/bin/table/ui.c
+++ b/bin/table/ui.c
@@ -133,11 +133,11 @@ readconfig(char *filename, struct tableparams *p)
       else if(strcmp(name, "output")==0)
         gal_checkset_allocate_copy_set(value, &cp->output, &cp->outputset);
 
-      else if (strcmp(name, "fitstabletype")==0)
+      else if (strcmp(name, "outtabletype")==0)
         {
-          if(p->up.fitstabletypeset) continue;
-          gal_checkset_allocate_copy_set(value, &p->up.fitstabletype,
-                                         &p->up.fitstabletypeset);
+          if(p->up.outtabletypeset) continue;
+          gal_checkset_allocate_copy_set(value, &p->up.outtabletype,
+                                         &p->up.outtabletypeset);
         }
 
 
@@ -192,8 +192,8 @@ printvalues(FILE *fp, struct tableparams *p)
 
 
   fprintf(fp, "\n# Output:\n");
-  if(up->fitstabletypeset)
-    fprintf(fp, CONF_SHOWFMT"%s\n", "fitstabletype", p->up.fitstabletype);
+  if(up->outtabletypeset)
+    fprintf(fp, CONF_SHOWFMT"%s\n", "outtabletype", p->up.outtabletype);
 
 
   /* For the operating mode, first put the macro to print the common
@@ -224,8 +224,6 @@ checkifset(struct tableparams *p)
   if(cp->hduset==0)
     GAL_CONFIGFILES_REPORT_NOTSET("hdu");
 
-  if(up->fitstabletypeset==0)
-    GAL_CONFIGFILES_REPORT_NOTSET("fitstabletype");
   if(up->searchinset==0)
     GAL_CONFIGFILES_REPORT_NOTSET("searchin");
 
@@ -257,29 +255,78 @@ checkifset(struct tableparams *p)
 void
 sanitycheck(struct tableparams *p)
 {
+  char *suffix=NULL;
   struct uiparams *up=&p->up;
 
-  /* If we had a FITS filename, the output table type is automatically set
-     with the `--fitstabletype' option. However, when the file is a text
-     file, that option should be ignored and outtype should be set to
-     the text file macro.*/
-  if(gal_fits_name_is_fits(up->filename))
+
+  /* Set the searchin integer value. */
+  p->searchin=gal_table_searchin_from_str(p->up.searchin);
+
+
+  /* If the outtabletype option was given, then convert it to an easiy
+     usable integer. Note we cannot do this in the output filename check
+     below, since it is also necessary when there is an output file.*/
+  if(up->outtabletypeset)
     {
-      if( !strcmp(up->fitstabletype, "ascii") )
+      if( !strcmp(up->outtabletype, "txt") )
+        p->outtabletype=GAL_TABLE_TYPE_TXT;
+      else if( !strcmp(up->outtabletype, "fits-ascii") )
         p->outtabletype=GAL_TABLE_TYPE_AFITS;
-      else if( !strcmp(up->fitstabletype, "binary") )
+      else if( !strcmp(up->outtabletype, "fits-binary") )
         p->outtabletype=GAL_TABLE_TYPE_BFITS;
       else
-        error(EXIT_FAILURE, 0, "the value to the `--fitstabletype' "
+        error(EXIT_FAILURE, 0, "the value to the `--outtabletype' "
               "option on the command line or `fitstabletype' variable in "
-              "any of the configuration files must be either `ascii', or "
-              "`binary'. You have given `%s'", up->fitstabletype);
+              "any of the configuration files must be either `txt', "
+              "`fits-ascii' or `fits-binary'. You have given `%s'",
+              up->outtabletype);
     }
-  else
-    p->outtabletype=GAL_TABLE_TYPE_TXT;
 
-  /* Set the searchin integer value. */
-  p->searchin=gal_table_searchin_from_str(p->up.searchin);
+
+  /* Set the output name if it wasn't given. */
+  if(p->cp.output==NULL)
+    {
+      /* Only set the output filename automatically if the output type is
+         given. A `NULL' output filename will indicate that the table
+         should be printed in STDOUT.*/
+      if(up->outtabletypeset)
+        {
+          /* Set the filename based on the type of table desired. For the
+             time being, there is only txt and FITS table formats, but we
+             might add other formats in the future, so the structure below
+             is defined to account for those future types.
+
+             Note that `p->outtabletype' is set above internally, so we
+             don't need a `default' case here.*/
+          switch(p->outtabletype)
+            {
+            case GAL_TABLE_TYPE_TXT:
+              suffix="_table.txt";
+              break;
+
+            case GAL_TABLE_TYPE_AFITS:
+            case GAL_TABLE_TYPE_BFITS:
+              suffix="_table.fits";
+              break;
+            }
+
+          /* Set the output name */
+          if(suffix)
+            gal_checkset_automatic_output(p->up.filename, suffix,
+                                          p->cp.removedirinfo,
+                                          p->cp.dontdelete, &p->cp.output);
+        }
+    }
+  /* If the output name was set and is a FITS file, make sure that the type
+     of the table is not a `txt'. */
+  else
+    {
+      if( gal_fits_name_is_fits(p->cp.output)
+          && p->outtabletype==GAL_TABLE_TYPE_TXT)
+        error(EXIT_FAILURE, 0, "desired output table is a FITS file, but "
+              "`outtabletype' is not a FITS table type. Please set it to "
+              "`fits-ascii', or `fits-binary'");
+    }
 }
 
 
@@ -332,7 +379,7 @@ print_information_exit(struct tableparams *p)
       printf("%-8zu%-25s%-20s%-18s%s\n", i+1,
              name ? name : "N/A" ,
              unit ? unit : "N/A" ,
-             gal_data_type_string(allcols[i].type),
+             gal_data_type_string(allcols[i].type, 1),
              comment ? comment : "N/A");
       if(name)    free(name);
       if(unit)    free(unit);
@@ -375,8 +422,8 @@ preparearrays(struct tableparams *p)
      elements were added to the list is the reverse of the order that they
      will be popped). */
   gal_linkedlist_reverse_stll(&p->columns);
-  p->table=gal_table_read_cols(p->up.filename, p->cp.hdu, p->columns,
-                               p->searchin, p->ignorecase, p->cp.minmapsize);
+  p->table=gal_table_read(p->up.filename, p->cp.hdu, p->columns,
+                          p->searchin, p->ignorecase, p->cp.minmapsize);
 }
 
 
diff --git a/doc/gnuastro.texi b/doc/gnuastro.texi
index 3c75a6b..f770892 100644
--- a/doc/gnuastro.texi
+++ b/doc/gnuastro.texi
@@ -6429,12 +6429,18 @@ single precision floating point numbers.
 (@option{=INT}) The number of digits to print after the floating point for
 double precision floating point numbers.
 
address@hidden --fitstabletype
-(@option{=STR}) The type of FITS table when a FITS file is specified as the
-output. This option can only have two values: @option{binary}, or
address@hidden However, currently ASCII FITS table outputs are not yet
-implemented due to lack of need. If you need it, please get in touch with
-so we implement it.
address@hidden --outtabletype
+(@option{=STR}) The output table type (for example plain text, FITS ascii,
+or FITS binary). If this option is not called on the command-line or any of
+the configuration files and no output filename is given with the
address@hidden option (see @ref{Common options}), then the columns that
+are read will be printed in the standard output (on the command-line).
+However, if it is called, it can only have one of these values:
address@hidden, @option{fits-ascii}, @option{fits-binary} for the current
+types of recognized output table types. If the output is a FITS file, this
+option is necessary because there are two types of FITS tables.
+
+
 @end table
 
 
diff --git a/lib/data-arithmetic-other.c b/lib/data-arithmetic-other.c
index bb26b2d..0478c2a 100644
--- a/lib/data-arithmetic-other.c
+++ b/lib/data-arithmetic-other.c
@@ -281,7 +281,7 @@ check_float_input(gal_data_t *in, int operator, char 
*numstr)
             "after it so it is directly read into the proper precision "
             "floating point number (based on the number of non-zero "
             "decimals it has)", gal_data_operator_string(operator), numstr,
-            gal_data_type_string(in->type));
+            gal_data_type_string(in->type, 1));
     }
 }
 
@@ -786,7 +786,7 @@ data_arithmetic_where(unsigned char flags, gal_data_t *out,
     error(EXIT_FAILURE, 0, "the condition operand to "
           "`data_arithmetic_where' must be an `unsigned char' type, but "
           "the given condition operator has a `%s' type",
-          gal_data_type_string(cond->type));
+          gal_data_type_string(cond->type, 1));
 
   /* The dimension and sizes of the out and condition data sets must be the
      same. */
diff --git a/lib/data.c b/lib/data.c
index 548f70b..6bad8af 100644
--- a/lib/data.c
+++ b/lib/data.c
@@ -35,6 +35,7 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 #include <sys/mman.h>
 
 #include <gnuastro/data.h>
+#include <gnuastro/table.h>
 
 #include <checkset.h>
 #include <data-copy.h>
@@ -387,7 +388,9 @@ gal_data_initialize(gal_data_t *data, void *array, int type,
   size_t i;
   gal_data_t in;
 
-  /* Do the simple copying  cases. */
+  /* Do the simple copying cases. For the display elements, set them all to
+     impossible (negative) values so if not explicitly set by later steps,
+     the default values are used if/when printing.*/
   data->status=0;
   data->next=NULL;
   data->ndim=ndim;
@@ -396,6 +399,7 @@ gal_data_initialize(gal_data_t *data, void *array, int type,
   gal_checkset_allocate_copy(unit, &data->unit);
   gal_checkset_allocate_copy(name, &data->name);
   gal_checkset_allocate_copy(comment, &data->comment);
+  data->disp_fmt=data->disp_width=data->disp_precision=-1;
 
 
   /* Copy the WCS structure. Note that the `in' data structure was just
@@ -1361,57 +1365,57 @@ gal_data_flag_blank(gal_data_t *data)
  **************       Types and copying       ***************
  *************************************************************/
 char *
-gal_data_type_string(int type)
+gal_data_type_string(int type, int long_name)
 {
   switch(type)
     {
     case GAL_DATA_TYPE_BIT:
-      return "bit";
+      if(long_name) return "bit";             else return "b";
 
     case GAL_DATA_TYPE_UCHAR:
-      return "unsigned char";
+      if(long_name) return "unsigned char";   else return "uc";
 
       /* CFITSIO says "int for keywords, char for table columns". Here we
          are only assuming table columns. So in practice this also applies
          to TSBYTE.*/
     case GAL_DATA_TYPE_CHAR: case GAL_DATA_TYPE_LOGICAL:
-      return "char";
+      if(long_name) return "char";            else return "c";
 
     case GAL_DATA_TYPE_STRING:
-      return "string";
+      if(long_name) return "string";          else return "str";
 
     case GAL_DATA_TYPE_USHORT:
-      return "unsigned short";
+      if(long_name) return "unsigned short";  else return "us";
 
     case GAL_DATA_TYPE_SHORT:
-      return "short";
+      if(long_name) return "short";           else return "s";
 
     case GAL_DATA_TYPE_UINT:
-      return "unsigned int";
+      if(long_name) return "unsigned int";    else return "ui";
 
     case GAL_DATA_TYPE_INT:
-      return "int";
+      if(long_name) return "int";             else return "i";
 
     case GAL_DATA_TYPE_ULONG:
-      return "unsigned long";
+      if(long_name) return "unsigned long";   else return "ul";
 
     case GAL_DATA_TYPE_LONG:
-      return "long";
+      if(long_name) return "long";            else return "l";
 
     case GAL_DATA_TYPE_LONGLONG:
-      return "LONGLONG";
+      if(long_name) return "LONGLONG";        else return "L";
 
     case GAL_DATA_TYPE_FLOAT:
-      return "float";
+      if(long_name) return "float";           else return "f";
 
     case GAL_DATA_TYPE_DOUBLE:
-      return "double";
+      if(long_name) return "double";          else return "d";
 
     case GAL_DATA_TYPE_COMPLEX:
-      return "complex float";
+      if(long_name) return "complex float";   else return "cf";
 
     case GAL_DATA_TYPE_DCOMPLEX:
-      return "complex double";
+      if(long_name) return "complex double";  else return "cd";
 
     default:
       error(EXIT_FAILURE, 0, "type value of %d not recognized in "
@@ -1922,7 +1926,7 @@ data_arithmetic_convert_to_compiled_type(gal_data_t *in, 
unsigned char flags)
         }
       else
         {
-          typestring=gal_data_type_string(in->type);
+          typestring=gal_data_type_string(in->type, 1);
           error(EXIT_FAILURE, 0, "The given %s type data given to "
                 "binary operators is not compiled for native operation "
                 "and no larger types are compiled either.\n\nThe "
diff --git a/lib/fits.c b/lib/fits.c
index f7166ad..41e2ce0 100644
--- a/lib/fits.c
+++ b/lib/fits.c
@@ -1651,12 +1651,16 @@ static void
 set_display_format(char *tdisp, gal_data_t *data, char *filename, char *hdu,
                    char *keyname)
 {
-  int isanint;
+  int isanint=0;
   char *tailptr;
 
   /* First, set the general display format */
   switch(tdisp[0])
     {
+    case 'A':
+      data->disp_fmt=GAL_TABLE_DISPLAY_FMT_STRING;
+      break;
+
     case 'I':
       isanint=1;
       data->disp_fmt=GAL_TABLE_DISPLAY_FMT_DECIMAL;
@@ -1673,18 +1677,15 @@ set_display_format(char *tdisp, gal_data_t *data, char 
*filename, char *hdu,
       break;
 
     case 'F':
-      isanint=0;
       data->disp_fmt=GAL_TABLE_DISPLAY_FMT_FLOAT;
       break;
 
     case 'E':
     case 'D':
-      isanint=0;
       data->disp_fmt=GAL_TABLE_DISPLAY_FMT_EXP;
       break;
 
     case 'G':
-      isanint=0;
       data->disp_fmt=GAL_TABLE_DISPLAY_FMT_GENERAL;
       break;
 
@@ -1709,7 +1710,7 @@ set_display_format(char *tdisp, gal_data_t *data, char 
*filename, char *hdu,
 
     case '\0':     /* No precision given, use a default value.     */
       data->disp_precision = ( isanint
-                               ? GAL_TABLE_DEF_FLT_PRECISION
+                               ? GAL_TABLE_DEF_INT_PRECISION
                                : GAL_TABLE_DEF_FLT_PRECISION );
       break;
 
@@ -1863,8 +1864,8 @@ gal_fits_table_info(char *filename, char *hdu, size_t 
*numcols,
    low-level function, so the output data linked list is the inverse of the
    input indexs linked list. You can use */
 gal_data_t *
-gal_fits_read_cols(char *filename, char *hdu, gal_data_t *colinfo,
-                   struct gal_linkedlist_sll *indexll, int minmapsize)
+gal_fits_table_read(char *filename, char *hdu, gal_data_t *colinfo,
+                    struct gal_linkedlist_sll *indexll, int minmapsize)
 {
   size_t ind;
   void *blank;
@@ -1906,3 +1907,16 @@ gal_fits_read_cols(char *filename, char *hdu, gal_data_t 
*colinfo,
   gal_fits_io_error(status, NULL);
   return out;
 }
+
+
+
+
+
+/* Write the given columns (a linked list of `gal_data_t') into a FITS
+   table.*/
+void
+gal_fits_table_write(gal_data_t *cols, char *comments, int tabletype,
+                     char *filename, int dontdelete)
+{
+
+}
diff --git a/lib/gnuastro/data.h b/lib/gnuastro/data.h
index deeea19..c0155df 100644
--- a/lib/gnuastro/data.h
+++ b/lib/gnuastro/data.h
@@ -103,7 +103,6 @@ __BEGIN_C_DECLS  /* From C++ preparations */
 
 
 
-
 /* Macros to identify the type of data. The macros in the comment
    parenthesis is the equivalent macro in CFITSIO. */
 enum gal_data_types
@@ -324,7 +323,7 @@ gal_data_flag_blank(gal_data_t *data);
  **************       Types and copying        ***************
  *************************************************************/
 char *
-gal_data_type_string(int type);
+gal_data_type_string(int type, int long_name);
 
 gal_data_t *
 gal_data_copy(gal_data_t *in);
diff --git a/lib/gnuastro/fits.h b/lib/gnuastro/fits.h
index 8ccd595..21b1251 100644
--- a/lib/gnuastro/fits.h
+++ b/lib/gnuastro/fits.h
@@ -46,6 +46,7 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 
 #include <gnuastro/data.h>
 #include <gnuastro/table.h>
+#include <gnuastro/linkedlist.h>
 
 /* C++ Preparations */
 #undef __BEGIN_C_DECLS
@@ -258,9 +259,12 @@ gal_fits_table_info(char *filename, char *hdu, size_t 
*numcols,
                     int *tabletype);
 
 gal_data_t *
-gal_fits_read_cols(char *filename, char *hdu, gal_data_t *colinfo,
-                   struct gal_linkedlist_sll *indexll, int minmapsize);
+gal_fits_table_read(char *filename, char *hdu, gal_data_t *colinfo,
+                    struct gal_linkedlist_sll *indexll, int minmapsize);
 
+void
+gal_fits_table_write(gal_data_t *cols, char *comments, int tabletype,
+                     char *filename, int dontdelete);
 
 
 
diff --git a/lib/gnuastro/table.h b/lib/gnuastro/table.h
index ab620b6..56564e7 100644
--- a/lib/gnuastro/table.h
+++ b/lib/gnuastro/table.h
@@ -55,9 +55,18 @@ __BEGIN_C_DECLS  /* From C++ preparations */
 
 
 /* Macros: */
+#define GAL_TABLE_DEF_STR_WIDTH       10
+#define GAL_TABLE_DEF_INT_WIDTH       6
+#define GAL_TABLE_DEF_LINT_WIDTH      10
+#define GAL_TABLE_DEF_FLT_WIDTH       10
+#define GAL_TABLE_DEF_DBL_WIDTH       15
+
+#define GAL_TABLE_DEF_STR_PRECISION   0
+#define GAL_TABLE_DEF_INT_PRECISION   0
+#define GAL_TABLE_DEF_FLT_PRECISION   6
+#define GAL_TABLE_DEF_DBL_PRECISION   14
+
 
-#define GAL_TABLE_DEF_INT_PRECISION 0
-#define GAL_TABLE_DEF_FLT_PRECISION 8
 
 
 
@@ -93,7 +102,9 @@ enum gal_table_where_to_search
    data.*/
 enum gal_table_diplay_formats
 {
-  GAL_TABLE_DISPLAY_FMT_DECIMAL,        /* Integers: decimal.          */
+  GAL_TABLE_DISPLAY_FMT_STRING,         /* String/Character.           */
+  GAL_TABLE_DISPLAY_FMT_DECIMAL,        /* Integers: signed decimal.   */
+  GAL_TABLE_DISPLAY_FMT_UDECIMAL,       /* Integers: unsigned decimal. */
   GAL_TABLE_DISPLAY_FMT_OCTAL,          /* Integers: octal.            */
   GAL_TABLE_DISPLAY_FMT_HEX,            /* Integers: hexadecimal.      */
   GAL_TABLE_DISPLAY_FMT_FLOAT,          /* Floats: with decimal point. */
@@ -106,6 +117,7 @@ enum gal_table_diplay_formats
 
 
 /* Functions */
+
 gal_data_t *
 gal_table_info(char *filename, char *hdu, size_t *numcols, int *tabletype);
 
@@ -113,9 +125,15 @@ int
 gal_table_searchin_from_str(char *searchin_str);
 
 gal_data_t *
-gal_table_read_cols(char *filename, char *hdu,
-                    struct gal_linkedlist_stll *cols, int searchin,
-                    int ignorecase, int minmapsize);
+gal_table_read(char *filename, char *hdu, struct gal_linkedlist_stll *cols,
+               int searchin, int ignorecase, int minmapsize);
+
+void
+gal_table_write(gal_data_t *cols, char *comments, int tabletype,
+                char *filename, int dontdelete);
+
+
+
 
 
 __END_C_DECLS    /* From C++ preparations */
diff --git a/lib/gnuastro/txt.h b/lib/gnuastro/txt.h
index 68c3698..277d8c4 100644
--- a/lib/gnuastro/txt.h
+++ b/lib/gnuastro/txt.h
@@ -26,7 +26,7 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 /* Include other headers if necessary here. Note that other header files
    must be included before the C++ preparations below */
 
-#include <gnuastro/fits.h> /* Includes `gnuastro/data.h' and `fitsio.h' */
+#include <gnuastro/data.h>
 
 
 
@@ -53,10 +53,19 @@ __BEGIN_C_DECLS  /* From C++ preparations */
 
 
 
+/* Macros */
+#define GAL_TXT_MAX_FMT_LENGTH 20
 
+
+/* Functions */
 gal_data_t *
 gal_txt_table_info(char *filename, size_t *numcols);
 
+void
+gal_txt_write(gal_data_t *cols, char *comment, char *filename,
+              int dontdelete);
+
+
 
 
 
diff --git a/lib/table.c b/lib/table.c
index b81402c..deaf460 100644
--- a/lib/table.c
+++ b/lib/table.c
@@ -33,6 +33,14 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 #include <gnuastro/table.h>
 
 
+
+
+
+
+
+
+
+
 /************************************************************************/
 /***************         Information about a table        ***************/
 /************************************************************************/
@@ -283,23 +291,21 @@ make_list_of_indexs(struct gal_linkedlist_stll *cols, 
gal_data_t *allcols,
    linked list of data structures. If the file is FITS, then `hdu' will
    also be used, otherwise, `hdu' is ignored. The information to search for
    columns should be specified by the `cols' linked list as string values
-   in each node of the list. The `tosearch' value comes from the
+   in each node of the list, the strings in each node can be a number, an
+   exact match to a column name, or a regular expression (in GNU AWK
+   format) enclosed in `/ /'. The `tosearch' value comes from the
    `gal_table_where_to_search' enumerator and has to be one of its given
    types. If `cols' is NULL, then this function will read the full table.
 
    The output is a linked list with the same order of the cols linked
-   list. If all the columns are to be read, the output will be the in the
-   order of the table, so the first column is the first popped data
-   structure and so on.
-
-   Recall that linked lists are last-in-first-out, so the last element you
-   add to the list is the first one that this function will pop. If you
-   want to reverse this order, you can call the
-   `gal_linkedlist_reverse_stll' function in `linkedlist.h'.*/
+   list. Note that one column node in the `cols' list might give multiple
+   columns, in this case, the order of output columns that correspond to
+   that one input, are in order of the table (which column was read first).
+   So the first requested column is the first popped data structure and so
+   on. */
 gal_data_t *
-gal_table_read_cols(char *filename, char *hdu,
-                    struct gal_linkedlist_stll *cols, int searchin,
-                    int ignorecase, int minmapsize)
+gal_table_read(char *filename, char *hdu, struct gal_linkedlist_stll *cols,
+               int searchin, int ignorecase, int minmapsize)
 {
   int tabletype;
   size_t i, numcols;
@@ -332,7 +338,7 @@ gal_table_read_cols(char *filename, char *hdu,
 
     case GAL_TABLE_TYPE_AFITS:
     case GAL_TABLE_TYPE_BFITS:
-      out=gal_fits_read_cols(filename, hdu, allcols, indexll, minmapsize);
+      out=gal_fits_table_read(filename, hdu, allcols, indexll, minmapsize);
       break;
 
     default:
@@ -352,3 +358,48 @@ gal_table_read_cols(char *filename, char *hdu,
   /* Return the final linked list. */
   return out;
 }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/************************************************************************/
+/***************              Write a table               ***************/
+/************************************************************************/
+void
+gal_table_write(gal_data_t *cols, char *comments, int tabletype,
+                char *filename, int dontdelete)
+{
+  /* If a filename was given, then the tabletype is relevant and must be
+     used. When the filename is empty, a text table must be printed on the
+     standard output (on the command-line). */
+  if(filename)
+    switch(tabletype)
+      {
+      case GAL_TABLE_TYPE_TXT:
+        gal_txt_write(cols, comments, filename, dontdelete);
+        break;
+
+      case GAL_TABLE_TYPE_AFITS:
+      case GAL_TABLE_TYPE_BFITS:
+        gal_fits_table_write(cols, comments, tabletype, filename, dontdelete);
+        break;
+      }
+  else
+    gal_txt_write(cols, comments, filename, dontdelete);
+}
diff --git a/lib/txt.c b/lib/txt.c
index 696e18b..7272238 100644
--- a/lib/txt.c
+++ b/lib/txt.c
@@ -22,12 +22,17 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 **********************************************************************/
 #include <config.h>
 
+#include <math.h>
 #include <stdio.h>
 #include <errno.h>
 #include <error.h>
+#include <string.h>
 #include <stdlib.h>
 
 #include <gnuastro/txt.h>
+#include <gnuastro/table.h>
+
+#include <checkset.h>
 
 
 /************************************************************************/
@@ -39,3 +44,312 @@ gal_txt_table_info(char *filename, size_t *numcols)
 
   return NULL;
 }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/************************************************************************/
+/***************          Write a txt table               ***************/
+/************************************************************************/
+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;
+
+  /* Allocate space for the output. */
+  errno=0;
+  fmts=malloc(2*numcols*sizeof *fmts);
+  if(fmts==NULL)
+    error(EXIT_FAILURE, errno, "%zu bytes for fmts in `gal_txt_write'",
+          numcols*sizeof *fmts);
+
+  /* Initialize the length to 0. */
+  *len=0;
+
+  /* Go over all the columns and make their formats. */
+  for(tmp=cols;tmp!=NULL;tmp=tmp->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]);
+      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);
+
+      /* Write the proper format. */
+      switch(tmp->type)
+        {
+
+        case GAL_DATA_TYPE_BIT:
+          error(EXIT_FAILURE, 0, "printing of bit types is currently "
+                "not supported");
+          break;
+
+        case GAL_DATA_TYPE_STRING:
+          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 );
+          break;
+
+
+        case GAL_DATA_TYPE_UCHAR:
+        case GAL_DATA_TYPE_USHORT:
+        case GAL_DATA_TYPE_UINT:
+        case GAL_DATA_TYPE_ULONG:
+
+          /* If we have a long type, then make changes. */
+          if(tmp->type==GAL_DATA_TYPE_ULONG)
+            {
+              lng="l";
+              width=( tmp->disp_width<0 ? GAL_TABLE_DEF_LINT_WIDTH
+                      : tmp->disp_width );
+            }
+          else width=( tmp->disp_width<0 ? GAL_TABLE_DEF_INT_WIDTH
+                       : tmp->disp_width );
+          precision=( tmp->disp_precision<0 ? GAL_TABLE_DEF_INT_PRECISION
+                      : tmp->disp_precision );
+
+          /* Set the final printing format. */
+          switch(tmp->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:
+        case GAL_DATA_TYPE_INT:
+          fmt="d";
+          width=( tmp->disp_width<0 ? GAL_TABLE_DEF_INT_WIDTH
+                  : tmp->disp_width );
+          precision=( tmp->disp_precision<0 ? GAL_TABLE_DEF_INT_PRECISION
+                      : tmp->disp_precision );
+          break;
+
+
+        case GAL_DATA_TYPE_LONG:
+        case GAL_DATA_TYPE_LONGLONG:
+          fmt="d";
+          lng = tmp->type==GAL_DATA_TYPE_LONG ? "l" : "ll";
+          width=( tmp->disp_width<0 ? GAL_TABLE_DEF_LINT_WIDTH
+                  : tmp->disp_width );
+          precision=( tmp->disp_precision<0 ? GAL_TABLE_DEF_INT_PRECISION
+                      : tmp->disp_precision );
+          break;
+
+
+        case GAL_DATA_TYPE_FLOAT:
+        case GAL_DATA_TYPE_DOUBLE:
+          switch(tmp->disp_fmt)
+            {
+            case GAL_TABLE_DISPLAY_FMT_FLOAT:    fmt="f"; break;
+            case GAL_TABLE_DISPLAY_FMT_EXP:      fmt="e"; break;
+            case GAL_TABLE_DISPLAY_FMT_GENERAL:  fmt="g"; break;
+            default:                             fmt="f";
+            }
+          width=( tmp->disp_width<0
+                  ? ( tmp->type==GAL_DATA_TYPE_FLOAT
+                      ? GAL_TABLE_DEF_FLT_WIDTH
+                      : GAL_TABLE_DEF_DBL_WIDTH )
+                  : tmp->disp_width );
+          precision=( tmp->disp_precision<0 ? GAL_TABLE_DEF_FLT_PRECISION
+                      : tmp->disp_precision );
+          break;
+
+        default:
+          error(EXIT_FAILURE, 0, "type code %d not recognized for output "
+                "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.*/
+      *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);
+
+      /* Increment the column counter. */
+      ++i;
+    }
+
+  /* Return the array. */
+  return fmts;
+}
+
+
+
+
+
+void
+gal_txt_write(gal_data_t *cols, char *comment, char *filename,
+              int dontdelete)
+{
+  FILE *fp;
+  char **fmts;
+  gal_data_t *tmp;
+  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)
+    {
+      ++numcols;
+      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);
+      if( tmp->name && strlen(tmp->name)>nw ) nw=strlen(tmp->name);
+      if( tmp->unit && strlen(tmp->unit)>uw ) uw=strlen(tmp->unit);
+    }
+
+
+  /* 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 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;
+    }
+
+
+  /* Write the comments if there as any */
+  if(comment) fprintf(fp, "%s\n", comment);
+
+
+  /* Write the given information. */
+  i=0;
+  iw=log10(numcols)+1;
+  for(tmp=cols;tmp!=NULL;tmp=tmp->next)
+    {
+      fprintf(fp, "# Column %-*zu %-*s [ %-*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;
+    }
+
+
+  /* Print the output */
+  for(i=0;i<cols->size;++i)                   /* Loop over each row.    */
+    {
+      j=0;
+      for(tmp=cols;tmp!=NULL;tmp=tmp->next)   /* Loop over each column. */
+        {
+          switch(tmp->type)
+            {
+            case GAL_DATA_TYPE_UCHAR:
+              fprintf(fp, fmts[j*2], ((unsigned char *)tmp->array)[i]);
+              break;
+            case GAL_DATA_TYPE_CHAR:
+            case GAL_DATA_TYPE_LOGICAL:
+              fprintf(fp, fmts[j*2], ((char *)tmp->array)[i]);
+              break;
+            case GAL_DATA_TYPE_STRING:
+              fprintf(fp, fmts[j*2], ((char **)tmp->array)[i]);
+              break;
+            case GAL_DATA_TYPE_USHORT:
+              fprintf(fp, fmts[j*2], ((unsigned short *)tmp->array)[i]);
+              break;
+            case GAL_DATA_TYPE_SHORT:
+              fprintf(fp, fmts[j*2], ((short *)tmp->array)[i]);
+              break;
+            case GAL_DATA_TYPE_UINT:
+              fprintf(fp, fmts[j*2], ((unsigned int *)tmp->array)[i]);
+              break;
+            case GAL_DATA_TYPE_INT:
+              fprintf(fp, fmts[j*2], ((int *)tmp->array)[i]);
+              break;
+            case GAL_DATA_TYPE_ULONG:
+              fprintf(fp, fmts[j*2], ((unsigned long *)tmp->array)[i]);
+              break;
+            case GAL_DATA_TYPE_LONG:
+              fprintf(fp, fmts[j*2], ((long *)tmp->array)[i]);
+              break;
+            case GAL_DATA_TYPE_LONGLONG:
+              fprintf(fp, fmts[j*2], ((LONGLONG *)tmp->array)[i]);
+              break;
+            case GAL_DATA_TYPE_FLOAT:
+              fprintf(fp, fmts[j*2], ((float *)tmp->array)[i]);
+              break;
+            case GAL_DATA_TYPE_DOUBLE:
+              fprintf(fp, fmts[j*2], ((double *)tmp->array)[i]);
+              break;
+            default:
+              error(EXIT_FAILURE, 0, "type code %d not recognized for "
+                    "tmp->type in `gal_txt_write'", tmp->type);
+            }
+          ++j;
+        }
+      fprintf(fp, "\n");
+    }
+
+
+  /* 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]);
+  free(fmts);
+  if(filename)
+    {
+      errno=0;
+      if(fclose(fp))
+        error(EXIT_FAILURE, errno, "%s: couldn't close file after writing "
+              "of text table", filename);
+    }
+}



reply via email to

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