gnuastro-commits
[Top][All Lists]
Advanced

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

[gnuastro-commits] master 07a043c 026/125: Starting to use the new data


From: Mohammad Akhlaghi
Subject: [gnuastro-commits] master 07a043c 026/125: Starting to use the new data structure to Table
Date: Sun, 23 Apr 2017 22:36:30 -0400 (EDT)

branch: master
commit 07a043cc77bbef494951aedefe07aebf25c3faf9
Author: Mohammad Akhlaghi <address@hidden>
Commit: Mohammad Akhlaghi <address@hidden>

    Starting to use the new data structure to Table
    
    Reading and writing columns of data are a very important part of most
    programs and also for the libraries. So Table was chosen as the second
    program to migrate to the new data structure. Each column can be read as
    one data structure and all the necessary information is stored in it. A new
    `table.h' library header was defined and practically all of what was in the
    Table program is now slowly shifting in there so all the programs and also
    library users can benefit from easy reading and writing of columns.
    
    For now, Table will print the full information of a given FITS table. It
    can also select the columns based on the `--column' option as before (but
    much better). Similar the AWK, if the users want regular expression search,
    they should put the value in to slashes like `/ /', and all of AWK's regexp
    syntax is applied. It is also possible to choose which information of a
    column should be checked: the name, the units or the comments. While the
    columns can be chosen, work is still on-going on the library to finalize
    the reading and writing of table columns.
    
    To help in re-writing Table, its folder was essentially copied outside and
    all its functions cleaned, so we can cleanly re-write all those important
    functions into the library with the new data structure.
---
 bin/table/args.h                | 156 ++-------
 bin/table/asttable.conf         |   9 +-
 bin/table/main.h                |  71 +---
 bin/table/table.c               | 390 ---------------------
 bin/table/ui.c                  | 748 +++++-----------------------------------
 doc/gnuastro.texi               |  67 ++--
 lib/Makefile.am                 |   7 +-
 lib/data.c                      |   5 +-
 lib/fits.c                      | 186 +++++++---
 lib/gnuastro/data.h             |   2 +-
 lib/gnuastro/fits.h             |  10 +-
 lib/gnuastro/linkedlist.h       |   3 +
 lib/gnuastro/{txt.h => table.h} |  65 +++-
 lib/gnuastro/txt.h              |  26 +-
 lib/linkedlist.c                |  18 +
 lib/table.c                     | 327 ++++++++++++++++++
 lib/txt.c                       |  22 +-
 17 files changed, 744 insertions(+), 1368 deletions(-)

diff --git a/bin/table/args.h b/bin/table/args.h
index b4978f6..b1e9255 100644
--- a/bin/table/args.h
+++ b/bin/table/args.h
@@ -74,10 +74,10 @@ const char doc[] =
 
 /* Available letters for short options:
 
-   a b d e f g j k l m n p r s u v w x y z
+   a b d e f g j k l m n p r u v w x y z
    A B C E F G H J L M O Q R T U W X Y Z
 
-   Number keys used: 1008
+   Number keys used (larger than 1000): 1000
 
    Options with keys (second structure element) larger than 500 do not
    have a short version.
@@ -94,7 +94,15 @@ static struct argp_option options[] =
       'c',
       "STR",
       0,
-      "Input column name, number or regular expression.",
+      "Column number (counting from 1) or search string.",
+      1
+    },
+    {
+      "searchin",
+      's',
+      "STR",
+      0,
+      "Search for columns in `name', `units', `comments'.",
       1
     },
     {
@@ -115,70 +123,6 @@ static struct argp_option options[] =
       2
     },
     {
-      "feg",
-      1001,
-      "STR",
-      0,
-      "`f': only decimals, `e': scientific, `g': either.",
-      2
-    },
-    {
-      "sintwidth",
-      1002,
-      "INT",
-      0,
-      "Shorter integer column(s) width (num charachers).",
-      2
-    },
-    {
-      "lintwidth",
-      1003,
-      "INT",
-      0,
-      "Longer integer column(s) width (num charachers).",
-      2
-    },
-    {
-      "floatwidth",
-      1004,
-      "INT",
-      0,
-      "`float' column(s) width (num charachers).",
-      2
-    },
-    {
-      "doublewidth",
-      1005,
-      "INT",
-      0,
-      "`double' column(s) width (num charachers).",
-      2
-    },
-    {
-      "strwidth",
-      1006,
-      "INT",
-      0,
-      "String column(s) width (num charachers).",
-      2
-    },
-    {
-      "floatprecision",
-      1007,
-      "INT",
-      0,
-      "`float' column(s) precision.",
-      2
-    },
-    {
-      "doubleprecision",
-      1008,
-      "INT",
-      0,
-      "`double' column(s) precision.",
-      2
-    },
-    {
       "fitstabletype",
       't',
       "STR",
@@ -243,92 +187,40 @@ parse_opt(int key, char *arg, struct argp_state *state)
     /* Input: */
     case 'c':
       gal_checkset_allocate_copy(arg, &tstring);
-      gal_linkedlist_add_to_stll(&p->up.columns, tstring);
+      gal_linkedlist_add_to_stll(&p->columns, tstring);
+      break;
+
+    case 's':
+      gal_checkset_allocate_copy(arg, &p->up.searchin);
+      p->up.searchinset=1;
       break;
 
     case 'I':
-      p->up.ignorecase=1;
+      p->ignorecase=1;
       p->up.ignorecaseset=1;
       break;
 
 
     /* Output: */
-    case 1001:
-      checksetfge(arg, &p->up.feg, NULL, 0);
-      p->up.fegset=1;
-      break;
-
-    case 1002:
-      gal_checkset_sizet_el_zero(arg, &p->up.sintwidth, "sintwidth", key,
-                                 SPACK, NULL, 0);
-      p->up.sintwidthset=1;
-      break;
-
-    case 1003:
-      gal_checkset_sizet_el_zero(arg, &p->up.lintwidth, "lintwidth", key,
-                                 SPACK, NULL, 0);
-      p->up.lintwidthset=1;
-      break;
-
-    case 1004:
-      gal_checkset_sizet_el_zero(arg, &p->up.floatwidth, "floatwidth", key,
-                                 SPACK, NULL, 0);
-      p->up.floatwidthset=1;
-      break;
-
-    case 1005:
-      gal_checkset_sizet_el_zero(arg, &p->up.doublewidth, "doublewidth", key,
-                                 SPACK, NULL, 0);
-      p->up.doublewidthset=1;
-      break;
-
-    case 1006:
-      gal_checkset_sizet_el_zero(arg, &p->up.strwidth, "strwidth", key,
-                                 SPACK, NULL, 0);
-      p->up.strwidthset=1;
-      break;
-
-    case 1007:
-      gal_checkset_sizet_el_zero(arg, &p->up.floatprecision,
-                                 "floatprecision", key, SPACK, NULL, 0);
-      p->up.floatprecisionset=1;
-      break;
-
-    case 1008:
-      gal_checkset_sizet_el_zero(arg, &p->up.doubleprecision,
-                                 "doubleprecision", key, SPACK, NULL, 0);
-      p->up.doubleprecisionset=1;
-      break;
-
     case 't':
-      checksetfitstabletype(arg, &p->up.feg, NULL, 0);
+      gal_checkset_allocate_copy(arg, &p->up.fitstabletype);
       p->up.fitstabletypeset=1;
       break;
 
 
     /* Operating modes: */
     case 'i':
-      p->up.information=1;
+      p->information=1;
       p->up.informationset=1;
       break;
 
 
-    /* Read the non-option arguments: */
+    /* Read the non-option tokens (arguments): */
     case ARGP_KEY_ARG:
-
-      /* Table gets only one input argument. */
-      if(p->up.inputset)
-        argp_error(state, "only one input file should be given");
-
-      /* This is the first (and must be only) argument. */
-      p->up.inputset=1;
-
-      /* See what type of input this is, and save the value. */
-      if( gal_fits_name_is_fits(arg) )
-        p->up.fitsname=arg;
+      if(p->up.filename)
+        argp_error(state, "only one argument (input file) should be given");
       else
-        p->up.txtname=arg;
-
+        p->up.filename=arg;
       break;
 
 
diff --git a/bin/table/asttable.conf b/bin/table/asttable.conf
index 7bb2a00..d76b989 100644
--- a/bin/table/asttable.conf
+++ b/bin/table/asttable.conf
@@ -19,14 +19,7 @@
 
 # Input:
  hdu              0
+ searchin         name
 
 # Output:
- feg              f
- sintwidth        5
- lintwidth       15
- floatwidth      10
- doublewidth     15
- strwidth        20
- floatprecision   3
- doubleprecision  8
  fitstabletype    binary
diff --git a/bin/table/main.h b/bin/table/main.h
index bf6d7e9..b3943ff 100644
--- a/bin/table/main.h
+++ b/bin/table/main.h
@@ -32,22 +32,6 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 #define SPACK_NAME      "Table"    /* Subpackage full name.       */
 #define SPACK_STRING    SPACK_NAME" ("PACKAGE_NAME") "PACKAGE_VERSION
 
-#define MAX_COL_FORMAT_LENGTH 20
-
-
-
-/* Structure to keep the information for each output column */
-struct outcolumn
-{
-  size_t inindex;               /* Row index (from 0) in input array.   */
-  int   datatype;               /* Type of data (from CFITSIO macros).  */
-  int     anynul;               /* If there is any blank characters.    */
-  void   *nulval;               /* The blank value for this column.     */
-  void     *data;               /* Array keeping the column data.       */
-  size_t   esize;               /* Size of each element in this column. */
-  char fmt[MAX_COL_FORMAT_LENGTH];  /* format to use in printf.         */
-};
-
 
 
 
@@ -55,46 +39,16 @@ struct outcolumn
 /* User interface structure. */
 struct uiparams
 {
-  int             information;  /* ==1, only print FITS information.    */
-  char              *fitsname;  /* Name of input FITS file.             */
-  char               *txtname;  /* Name of input text file.             */
-  int              ignorecase;  /* Ignore case matching column names.   */
-
-  /* Input table parameters. */
-  size_t                ncols;  /* Number of columns in table.          */
-  int               *datatype;  /* Type of data in column.              */
-  char                **ttstr;  /* TFORM (another format for type).     */
-  char                **tname;  /* Column name (one word).              */
-  char                **tunit;  /* Unit of values in column.            */
-  double            *txtarray;  /* Array keeping text file values.      */
-  int         infitstabletype;  /* Input table is ASCII or binary.      */
-
-  /* Print parameters: */
-  int                     feg;  /* format of floating points.           */
-  size_t            sintwidth;  /* Full width for short integers.       */
-  size_t            lintwidth;  /* Full width for short integers.       */
-  size_t           floatwidth;  /* Full width for all floats.           */
-  size_t          doublewidth;  /* Full width for all doubles.          */
-  size_t             strwidth;  /* Full width for all floats.           */
-  size_t       floatprecision;  /* Number of decimals for floats.       */
-  size_t      doubleprecision;  /* Number of decimals for doubles.      */
+  char              *filename;
+  char         *fitstabletype;
+  gal_data_t      *allcolinfo;
+  char              *searchin;
 
   /* If values are set: */
-  int                inputset;
   int          informationset;
   int           ignorecaseset;
-  int                  fegset;
-  int            sintwidthset;
-  int            lintwidthset;
-  int           floatwidthset;
-  int          doublewidthset;
-  int             strwidthset;
-  int       floatprecisionset;
-  int      doubleprecisionset;
   int        fitstabletypeset;
-
-
-  struct gal_linkedlist_stll *columns;
+  int             searchinset;
 };
 
 
@@ -108,17 +62,18 @@ struct tableparams
   struct uiparams          up;  /* User interface parameters.           */
   struct gal_commonparams  cp;  /* Common parameters.                   */
 
-  /* Input: */
-  fitsfile           *fitsptr;  /* FITS pointer (input or output).      */
+  /* Input */
+  struct gal_linkedlist_stll *columns; /* List of given columns. */
 
   /* Output: */
   size_t                nrows;  /* Number of rows in table.             */
   size_t               nocols;  /* Number of output columns.            */
-  struct outcolumn     *ocols;  /* Array of output column informatio.   */
-  int            outputtofits;  /* ==1: output is a FITS file.          */
-  int             outputtotxt;  /* ==1: output is a text file.          */
-  int          outputtostdout;  /* ==1: output is the standard output.  */
-  int           fitstabletype;  /* ASCII, or binary table CFITSIO macro.*/
+  int                 outtype;  /* Type of output table.                */
+
+  /* Operating modes */
+  int             information;  /* ==1, only print FITS information.    */
+  int              ignorecase;  /* Ignore case matching column names.   */
+  int                searchin;  /* Where to search in column info.      */
 
   /* Internal: */
   int                onlyview;
diff --git a/bin/table/table.c b/bin/table/table.c
index 4bcaedd..98d2fb9 100644
--- a/bin/table/table.c
+++ b/bin/table/table.c
@@ -35,391 +35,6 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 
 
 
-/**************************************************************/
-/***************        Input table         *******************/
-/**************************************************************/
-/* Set the format string for each column: */
-void
-setformatstring(struct tableparams *p, size_t outcolid)
-{
-  struct uiparams *up=&p->up;
-  char width[10], accu[10], *type=NULL;
-  struct outcolumn *ocol=&p->ocols[outcolid];
-
-
-  switch(ocol->datatype)
-    {
-    case TBIT:
-      error(EXIT_FAILURE, 0, "Table doesn't print TBIT data type "
-            "currently, please contact us at %s so we can implement "
-            "it.", PACKAGE_BUGREPORT);
-
-    case TBYTE:
-      type="u";
-      sprintf(width, "%zu", up->sintwidth);
-      accu[0]='\0';
-      break;
-
-    case TLOGICAL: case TSBYTE:
-      type="d";
-      sprintf(width, "%zu", up->sintwidth);
-      accu[0]='\0';
-      break;
-
-    case TSTRING:
-      type="s";
-      if(up->sintwidth) sprintf(width, "%zu", up->sintwidth);
-      else width[0]='\0';
-      accu[0]='\0';
-      break;
-
-    case TSHORT:
-      type="d";
-      sprintf(width, "%zu", up->sintwidth);
-      accu[0]='\0';
-      break;
-
-    case TLONG:
-      type="ld";
-      sprintf(width, "%zu", up->lintwidth);
-      accu[0]='\0';
-      break;
-
-    case TLONGLONG:
-      type="ld";
-      sprintf(width, "%zu", up->lintwidth);
-      accu[0]='\0';
-      break;
-
-    case TFLOAT:
-      type = up->feg=='f' ? "f" : ( up->feg=='e' ? "e" : "g");
-      sprintf(width, "%zu", up->floatwidth);
-      sprintf(accu, ".%zu", up->floatprecision);
-      break;
-
-    case TDOUBLE:
-      type = up->feg=='f' ? "f" : ( up->feg=='e' ? "e" : "g");
-      sprintf(width, "%zu", up->doublewidth);
-      sprintf(accu, ".%zu", up->doubleprecision);
-      break;
-
-    case TCOMPLEX:
-      error(EXIT_FAILURE, 0, "Table doesn't print TCOMPLEX data type "
-            "currently, please contact us at %s so we can implement "
-            "it.", PACKAGE_BUGREPORT);
-      break;
-
-    case TDBLCOMPLEX:
-      error(EXIT_FAILURE, 0, "Table doesn't print TDBLCOMPLEX data type "
-            "currently, please contact us at %s so we can implement "
-            "it.", PACKAGE_BUGREPORT);
-      break;
-
-    case TINT:
-      type="d";
-      sprintf(width, "%zu", up->sintwidth);
-      accu[0]='\0';
-      break;
-
-    case TUINT:
-      type="u";
-      sprintf(width, "%zu", up->sintwidth);
-      accu[0]='\0';
-      break;
-
-    case TUSHORT:
-      type="u";
-      sprintf(width, "%zu", up->sintwidth);
-      accu[0]='\0';
-      break;
-
-    case TULONG:
-      type="lu";
-      sprintf(width, "%zu", up->lintwidth);
-      accu[0]='\0';
-      break;
-
-    default:
-      error(EXIT_FAILURE, 0, "datatype value of %d not recognized in "
-            "setformatstring (table.c)", ocol->datatype);
-    }
-
-  /* Put the type, width and accu into the format string for this
-     column: */
-  sprintf(ocol->fmt, "%%-%s%s%s", width, accu, type);
-}
-
-
-
-
-
-/* Read all the input columns */
-void
-readinputcols(struct tableparams *p)
-{
-  double *colfromtxt;
-  struct outcolumn *col;
-  int type, status=0;
-  size_t i, j, nrows=p->nrows, incols=p->up.ncols;
-
-  /* Get the contents of each table column: */
-  for(i=0;i<p->nocols;++i)
-    {
-      /* Variables for simple reading */
-      col=&p->ocols[i];
-
-      type=gal_fits_datatype_to_type(col->datatype);
-
-      /* Allocate the blank value for this column. Note that we will also
-         need the blankvalue for a text file when outputing to a FITS. */
-      col->nulval=gal_data_alloc_blank(type);
-
-      /* Read the input column. */
-      if(p->fitsptr)
-        {
-          /* Allocate space for the data in this column */
-          col->data=gal_data_alloc(type, nrows);
-
-          /* Call CFITSIO to read the column information. */
-          fits_read_col(p->fitsptr, col->datatype, col->inindex+1, 1, 1,
-                        nrows, col->nulval, col->data, &col->anynul,
-                        &status);
-        }
-      else
-        {
-          /* This is a text file, read by Gnuastro's current txtarray
-             library. This library currently only reads a 2D table into a
-             2D array of type double. The important thing here is that the
-             array is row-contiguous. But here we want column contiguous
-             data. So we allocate an array to only put this column's values
-             in.*/
-          errno=0;
-          colfromtxt=col->data=malloc(nrows * col->esize);
-          if(col->data==NULL)
-            error(EXIT_FAILURE, errno, "%zu bytes for col->data",
-                  nrows * col->esize);
-
-          for(j=0;j<nrows;++j)
-            colfromtxt[j]=p->up.txtarray[ j * incols + col->inindex ];
-        }
-
-      /* Set the format string to print the column values if the output is
-         to be printed as text (either in a text file or to the standard
-         output. */
-      if(p->outputtotxt || p->outputtostdout)
-        setformatstring(p, i);
-    }
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-/**************************************************************/
-/***************       Output table         *******************/
-/**************************************************************/
-void
-saveouttofits(struct tableparams *p)
-{
-  size_t i;
-  int status=0;
-  fitsfile *fptr;
-  struct uiparams *up=&p->up;
-  char **ttype, **tform, **tunit;
-  struct outcolumn *ocols=p->ocols;
-
-  /* Allocate the information arrays for CFITSIO. */
-  errno=0;
-  ttype=malloc(p->nocols*sizeof *ttype);
-  if(ttype==NULL)
-    error(EXIT_FAILURE, errno, "%zu bytes for ttype",
-          p->nocols*sizeof *ttype);
-  errno=0;
-  tform=malloc(p->nocols*sizeof *tform);
-  if(tform==NULL)
-    error(EXIT_FAILURE, errno, "%zu bytes for tform",
-          p->nocols*sizeof *tform);
-  errno=0;
-  tunit=malloc(p->nocols*sizeof *tunit);
-  if(tunit==NULL)
-    error(EXIT_FAILURE, errno, "%zu bytes for tunit",
-          p->nocols*sizeof *tunit);
-
-  /* Fill in the information arrays: */
-  for(i=0;i<p->nocols;++i)
-    {
-      tform[i]=up->ttstr[ ocols[i].inindex ];
-      ttype[i]=up->tname[ ocols[i].inindex ];
-      tunit[i]=up->tunit[ ocols[i].inindex ];
-    }
-
-  /* Open the output FITS file. */
-  if(access(p->cp.output,F_OK) != -1 )
-    fits_open_file(&fptr, p->cp.output, READWRITE, &status);
-  else
-    fits_create_file(&fptr, p->cp.output, &status);
-
-  /* Create a new table extension */
-  fits_create_tbl(fptr, p->fitstabletype, p->nrows, p->nocols, ttype,
-                  tform, tunit, "Table", &status);
-
-  /* Write this column's data into the FITS file. */
-  for(i=0;i<p->nocols;++i)
-    fits_write_colnull(fptr, ocols[i].datatype, i+1, 1, 1, p->nrows,
-                       ocols[i].data, ocols[i].nulval, &status);
-
-  /* Include the ending comments and close the file. */
-  gal_fits_write_keys_version(fptr, NULL, SPACK_STRING);
-  fits_close_file(fptr, &status);
-  gal_fits_io_error(status, NULL);
-
-  /* Clean up */
-  free(ttype);
-  free(tform);
-  free(tunit);
-}
-
-
-
-
-
-void
-printoutput(struct tableparams *p)
-{
-  FILE *fp;
-  size_t i, row;
-  struct outcolumn *ocols=p->ocols;
-
-  /* Determine the output stream and open the file for writing if its a
-     file. */
-  if(p->outputtotxt)
-    {
-      errno=0;
-      fp=fopen(p->cp.output, "w");
-      if(fp==NULL)
-        error(EXIT_FAILURE, errno, "%s", p->cp.output);
-    }
-  else
-    fp=stdout;
-
-  /* Print each column and each row: */
-  for(row=0;row<p->nrows;++row)
-    {
-      for(i=0;i<p->nocols;++i)
-        switch(ocols[i].datatype)
-          {
-          case TBIT:
-            error(EXIT_FAILURE, 0, "Table doesn't print TBIT data type "
-                  "currently, please contact us at %s so we can implement "
-                  "it.", PACKAGE_BUGREPORT);
-
-          case TBYTE:
-            fprintf(fp, ocols[i].fmt, ((unsigned char *)ocols[i].data)[row]);
-            break;
-
-          case TLOGICAL: case TSBYTE:
-            fprintf(fp, ocols[i].fmt, ((char *)ocols[i].data)[row]);
-            break;
-
-          case TSTRING:
-            fprintf(fp, ocols[i].fmt, ((char **)ocols[i].data)[row]);
-            break;
-
-          case TSHORT:
-            fprintf(fp, ocols[i].fmt, ((short *)ocols[i].data)[row]);
-            break;
-
-          case TLONG:
-            fprintf(fp, ocols[i].fmt, ((long *)ocols[i].data)[row]);
-            break;
-
-          case TLONGLONG:
-            fprintf(fp, ocols[i].fmt, ((LONGLONG *)ocols[i].data)[row]);
-            break;
-
-          case TFLOAT:
-            fprintf(fp, ocols[i].fmt, ((float *)ocols[i].data)[row]);
-            break;
-
-          case TDOUBLE:
-            fprintf(fp, ocols[i].fmt, ((double *)ocols[i].data)[row]);
-            break;
-
-          case TCOMPLEX:
-            error(EXIT_FAILURE, 0, "Table doesn't print TCOMPLEX data type "
-                  "currently, please contact us at %s so we can implement "
-                  "it.", PACKAGE_BUGREPORT);
-            break;
-
-          case TDBLCOMPLEX:
-            error(EXIT_FAILURE, 0, "Table doesn't print TDBLCOMPLEX data "
-                  "type currently, please contact us at %s so we can "
-                  "implement it.", PACKAGE_BUGREPORT);
-            break;
-
-          case TINT:
-            fprintf(fp, ocols[i].fmt, ((char *)ocols[i].data)[row]);
-            break;
-
-          case TUINT:
-            fprintf(fp, ocols[i].fmt, ((unsigned int *)ocols[i].data)[row]);
-            break;
-
-          case TUSHORT:
-            fprintf(fp, ocols[i].fmt, ((unsigned short *)ocols[i].data)[row]);
-            break;
-
-          case TULONG:
-            fprintf(fp, ocols[i].fmt, ((unsigned long *)ocols[i].data)[row]);
-            break;
-
-          default:
-            error(EXIT_FAILURE, 0, "datatype value of %d not recognized in "
-                  "printoutput", ocols[i].datatype);
-          }
-      fprintf(fp, "\n");
-    }
-
-  /* If we printed to a file, then close it. */
-  if(p->outputtotxt)
-    {
-      errno=0;
-      if( fclose(fp) == EOF )
-        error(EXIT_FAILURE, errno, "%s", p->cp.output);
-    }
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
 
 
 /**************************************************************/
@@ -428,10 +43,5 @@ printoutput(struct tableparams *p)
 void
 table(struct tableparams *p)
 {
-  readinputcols(p);
 
-  if(p->outputtofits)
-    saveouttofits(p);
-  else
-    printoutput(p);
 }
diff --git a/bin/table/ui.c b/bin/table/ui.c
index 42e4ace..825020f 100644
--- a/bin/table/ui.c
+++ b/bin/table/ui.c
@@ -32,6 +32,7 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 #include <fitsio.h>
 
 #include <gnuastro/fits.h>
+#include <gnuastro/table.h>
 #include <gnuastro/txtarray.h>
 
 #include <nproc.h>               /* From Gnulib.                   */
@@ -65,54 +66,6 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 /**************************************************************/
 /**************       Options and parameters    ***************/
 /**************************************************************/
-/* Check the value given for the fge option. */
-void
-checksetfge(char *optarg, int *fge, char *filename, size_t lineno)
-{
-  *fge=optarg[0];
-  if( *fge!='f' && *fge!='g' && *fge!='g' )
-    {
-      if(filename)
-        error_at_line(EXIT_FAILURE, 0, filename, lineno,
-                      "the value of `fge' must only be one of the three "
-                      "`f', `g', or `e' characters. You have given `%s'",
-                      optarg);
-      else
-        error(EXIT_FAILURE, 0, "the value of `--fge' (`-f') must only be "
-              "one of the three `f', `g', or `e' characters. You have "
-              "given `%s'", optarg);
-    }
-}
-
-
-
-
-
-void
-checksetfitstabletype(char *optarg, int *fitstabletype, char *filename,
-                   size_t lineno)
-{
-  if( !strcmp(optarg, "ascii") )
-    *fitstabletype=ASCII_TBL;
-  else if( !strcmp(optarg, "binary") )
-    *fitstabletype=BINARY_TBL;
-  else
-    {
-      if(filename)
-        error_at_line(EXIT_FAILURE, 0, filename, lineno,
-                      "The value to the `fitstabletype' must be either "
-                      "`ascii', or `binary'. You have given `%s'", optarg);
-      else
-        error(EXIT_FAILURE, 0, "The value to the `--fitstabletype' (`-t') "
-              "option must be either one of `ascii', or `binary'. You have, "
-              "given `%s'", optarg);
-    }
-}
-
-
-
-
-
 void
 readconfig(char *filename, struct tableparams *p)
 {
@@ -156,13 +109,20 @@ readconfig(char *filename, struct tableparams *p)
       else if(strcmp(name, "column")==0)
         {
           gal_checkset_allocate_copy(value, &tstring);
-          gal_linkedlist_add_to_stll(&p->up.columns, tstring);
+          gal_linkedlist_add_to_stll(&p->columns, tstring);
+        }
+
+      else if(strcmp(name, "searchin")==0)
+        {
+          if(p->up.searchinset) continue;
+          gal_checkset_allocate_copy(value, &p->up.searchin);
+          p->up.searchinset=1;
         }
 
       else if(strcmp(name, "ignorecase")==0)
         {
           if(p->up.ignorecaseset) continue;
-          gal_checkset_int_zero_or_one(value, &p->up.ignorecase, "ignorecase",
+          gal_checkset_int_zero_or_one(value, &p->ignorecase, "ignorecase",
                                        key, SPACK, filename, lineno);
           p->up.ignorecaseset=1;
         }
@@ -173,73 +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, "feg")==0)
-        {
-          if(p->up.fegset) continue;
-          checksetfge(value, &p->up.feg, filename, lineno);
-          p->up.fegset=1;
-        }
-
-      else if (strcmp(name, "sintwidth")==0)
-        {
-          if(p->up.sintwidthset) continue;
-          gal_checkset_sizet_el_zero(value, &p->up.sintwidth, name,
-                                       key, SPACK, filename, lineno);
-          p->up.sintwidthset=1;
-        }
-
-      else if (strcmp(name, "lintwidth")==0)
-        {
-          if(p->up.lintwidthset) continue;
-          gal_checkset_sizet_el_zero(value, &p->up.lintwidth, name,
-                                       key, SPACK, filename, lineno);
-          p->up.lintwidthset=1;
-        }
-
-      else if (strcmp(name, "floatwidth")==0)
-        {
-          if(p->up.floatwidthset) continue;
-          gal_checkset_sizet_el_zero(value, &p->up.floatwidth, name,
-                                       key, SPACK, filename, lineno);
-          p->up.floatwidthset=1;
-        }
-
-      else if (strcmp(name, "doublewidth")==0)
-        {
-          if(p->up.doublewidthset) continue;
-          gal_checkset_sizet_el_zero(value, &p->up.doublewidth, name,
-                                       key, SPACK, filename, lineno);
-          p->up.doublewidthset=1;
-        }
-
-      else if (strcmp(name, "strwidth")==0)
-        {
-          if(p->up.strwidthset) continue;
-          gal_checkset_sizet_el_zero(value, &p->up.strwidth, name,
-                                       key, SPACK, filename, lineno);
-          p->up.strwidthset=1;
-        }
-
-      else if (strcmp(name, "floatprecision")==0)
-        {
-          if(p->up.floatprecisionset) continue;
-          gal_checkset_sizet_el_zero(value, &p->up.floatprecision,
-                                       name, key, SPACK, filename, lineno);
-          p->up.floatprecisionset=1;
-        }
-
-      else if (strcmp(name, "doubleprecision")==0)
-        {
-          if(p->up.doubleprecisionset) continue;
-          gal_checkset_sizet_el_zero(value, &p->up.doubleprecision,
-                                       name, key, SPACK, filename, lineno);
-          p->up.doubleprecisionset=1;
-        }
       else if (strcmp(name, "fitstabletype")==0)
         {
           if(p->up.fitstabletypeset) continue;
-          checksetfitstabletype(value, &p->fitstabletype, filename, lineno);
-          p->up.fitstabletypeset=1;
+          gal_checkset_allocate_copy_set(value, &p->up.fitstabletype,
+                                         &p->up.fitstabletypeset);
         }
 
 
@@ -248,7 +146,7 @@ readconfig(char *filename, struct tableparams *p)
       else if (strcmp(name, "information")==0)
         {
           if(p->up.informationset) continue;
-          gal_checkset_int_zero_or_one(value, &p->up.information, name,
+          gal_checkset_int_zero_or_one(value, &p->information, name,
                                        key, SPACK, filename, lineno);
           p->up.informationset=1;
         }
@@ -284,33 +182,18 @@ printvalues(FILE *fp, struct tableparams *p)
   fprintf(fp, "\n# Input:\n");
   if(cp->hduset)
     GAL_CHECKSET_PRINT_STRING_MAYBE_WITH_SPACE("hdu", cp->hdu);
-  if(up->columns)
-    for(tmp=up->columns;tmp!=NULL;tmp=tmp->next)
+  if(p->columns)
+    for(tmp=p->columns;tmp!=NULL;tmp=tmp->next)
       GAL_CHECKSET_PRINT_STRING_MAYBE_WITH_SPACE("column", tmp->v);
   if(up->ignorecaseset)
-    fprintf(fp, CONF_SHOWFMT"%d\n", "ignorecase", up->ignorecase);
+    fprintf(fp, CONF_SHOWFMT"%d\n", "ignorecase", p->ignorecase);
+  if(up->searchinset)
+    fprintf(fp, CONF_SHOWFMT"%s\n", "searchin", up->searchin);
 
 
   fprintf(fp, "\n# Output:\n");
-  if(up->fegset)
-    fprintf(fp, CONF_SHOWFMT"%c\n", "feg", up->feg);
-  if(up->sintwidthset)
-    fprintf(fp, CONF_SHOWFMT"%zu\n", "sintwidth", up->sintwidth);
-  if(up->lintwidthset)
-    fprintf(fp, CONF_SHOWFMT"%zu\n", "lintwidth", up->lintwidth);
-  if(up->floatwidthset)
-    fprintf(fp, CONF_SHOWFMT"%zu\n", "floatwidth", up->floatwidth);
-  if(up->doublewidthset)
-    fprintf(fp, CONF_SHOWFMT"%zu\n", "doublewidth", up->doublewidth);
-  if(up->strwidthset)
-    fprintf(fp, CONF_SHOWFMT"%zu\n", "strwidth", up->strwidth);
-  if(up->floatprecisionset)
-    fprintf(fp, CONF_SHOWFMT"%zu\n", "floatprecision", up->floatprecision);
-  if(up->doubleprecisionset)
-    fprintf(fp, CONF_SHOWFMT"%zu\n", "doubleprecision", up->doubleprecision);
   if(up->fitstabletypeset)
-    fprintf(fp, CONF_SHOWFMT"%s\n", "fitstabletype",
-            p->fitstabletype==ASCII_TBL ? "ascii" : "binary");
+    fprintf(fp, CONF_SHOWFMT"%s\n", "fitstabletype", p->up.fitstabletype);
 
 
   /* For the operating mode, first put the macro to print the common
@@ -318,7 +201,7 @@ printvalues(FILE *fp, struct tableparams *p)
      program). */
   fprintf(fp, "\n# Operating mode:\n");
   if(up->informationset)
-    fprintf(fp, CONF_SHOWFMT"%d\n", "information", up->information);
+    fprintf(fp, CONF_SHOWFMT"%d\n", "information", p->information);
 
   GAL_CONFIGFILES_PRINT_COMMONOPTIONS;
 }
@@ -341,24 +224,10 @@ checkifset(struct tableparams *p)
   if(cp->hduset==0)
     GAL_CONFIGFILES_REPORT_NOTSET("hdu");
 
-  if(up->fegset==0)
-    GAL_CONFIGFILES_REPORT_NOTSET("feg");
-  if(up->sintwidthset==0)
-    GAL_CONFIGFILES_REPORT_NOTSET("sintwidth");
-  if(up->lintwidthset==0)
-    GAL_CONFIGFILES_REPORT_NOTSET("lintwidth");
-  if(up->floatwidthset==0)
-    GAL_CONFIGFILES_REPORT_NOTSET("floatwidth");
-  if(up->doublewidthset==0)
-    GAL_CONFIGFILES_REPORT_NOTSET("doublewidth");
-  if(up->strwidthset==0)
-    GAL_CONFIGFILES_REPORT_NOTSET("strwidth");
-  if(up->floatprecisionset==0)
-    GAL_CONFIGFILES_REPORT_NOTSET("floatprecision");
-  if(up->doubleprecisionset==0)
-    GAL_CONFIGFILES_REPORT_NOTSET("doubleprecision");
   if(up->fitstabletypeset==0)
     GAL_CONFIGFILES_REPORT_NOTSET("fitstabletype");
+  if(up->searchinset==0)
+    GAL_CONFIGFILES_REPORT_NOTSET("searchin");
 
   GAL_CONFIGFILES_END_OF_NOTSET_REPORT;
 }
@@ -383,259 +252,34 @@ checkifset(struct tableparams *p)
 
 
 /**************************************************************/
-/************     Read and Write column info    ***************/
+/***************       Sanity Check         *******************/
 /**************************************************************/
-
-/*  */
-  /* Allocate the arrays to keep the column information. Initialize the
-     arrays with a NULL pointer to make sure that they are all found in the
-     end if they are necessary. The values that are directly read from the
-     input file are initialized to NULL, so they can be treated
-     appropriately if they do not exist in the input (for example if they
-     are mandatory, or if they need to be printed).*/
-void
-allocinputcolinfo(struct tableparams *p)
-{
-  char **c, **fc;
-  size_t ncols=p->up.ncols;
-  struct uiparams *up=&p->up;
-
-  /* up->datatype keeps the type of data in each column as CFITSIO type
-     macros. */
-  errno=0;
-  up->datatype=malloc(ncols * sizeof *up->datatype);
-  if(up->datatype==NULL)
-    error(EXIT_FAILURE, errno, "%zu bytes for up->datatype",
-          ncols * sizeof *up->datatype);
-
-  /* up->ttstr keeps the actual string used to specify the datatype. */
-  errno=0;
-  up->ttstr=malloc(ncols * sizeof *up->ttstr);
-  if(up->ttstr==NULL)
-    error(EXIT_FAILURE, errno, "%zu bytes for ttstr",
-          ncols * sizeof *up->ttstr);
-  fc=(c=up->ttstr)+ncols; do *c++=NULL; while(c<fc);
-
-  /* up->tname keeps the name of the column. */
-  errno=0;
-  up->tname=malloc(ncols * sizeof *up->tname);
-  if(up->tname==NULL)
-    error(EXIT_FAILURE, errno, "%zu bytes for tname",
-          ncols * sizeof *up->tname);
-  fc=(c=up->tname)+ncols; do *c++=NULL; while(c<fc);
-
-  /* up->tunit keeps the input units of the column. */
-  errno=0;
-  up->tunit=malloc(ncols * sizeof *up->tunit);
-  if(up->tunit==NULL)
-    error(EXIT_FAILURE, errno, "%zu bytes for tunit",
-          ncols * sizeof *up->tunit);
-  fc=(c=up->tunit)+ncols; do *c++=NULL; while(c<fc);
-}
-
-
-
-
-
-/* This function will read all the table information from a FITS table HDU
-   and store them in arrays for use later. It is mainly good for getting
-   all the information in a FITS table HDU. This function will only go
-   through the header keywords once and does not depend on the ordering of
-   the keywords, so it is much more efficient than having to ask for each
-   column's information separately.*/
 void
-allfitscolinfo(struct tableparams *p)
+sanitycheck(struct tableparams *p)
 {
-  char *tailptr;
-  int i, status=0, type;
   struct uiparams *up=&p->up;
-  size_t index, ncols=p->up.ncols;
-  char keyname[FLEN_KEYWORD]="XXXXXXXXXXXXX", value[FLEN_VALUE];
 
-
-  /* First allocate the arrays to keep the input column information. */
-  allocinputcolinfo(p);
-
-
-  /* Read all the keywords one by one and if they match, then put them in
-     the correct value. Note that we are starting from keyword 9 because
-     according to the FITS standard, the first 8 keys in a FITS table are
-     reserved. */
-  for(i=9; strcmp(keyname, "END"); ++i)
+  /* 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))
     {
-      /* Read the next keyword. */
-      fits_read_keyn(p->fitsptr, i, keyname, value, NULL, &status);
-
-      /* Check the type of the keyword. */
-      if(strncmp(keyname, "TFORM", 5)==0)
-        {
-          /* Currently we can only read repeat==1 cases. When no number
-             exists before the defined capital letter, it defaults to 1,
-             but if a number exists (for example `5D'), then the repeat is
-             5 (there are actually five values here. Note that value[0] is
-             a single quote.*/
-          if(isdigit(value[1] && value[1]!='1'))
-             error(EXIT_FAILURE, 0, "The repeat value of column %d is "
-                   "%c, currently Table can only use columns with a repeat "
-                   "of 1.", i+1, value[1]);
-
-
-          /* The values to TFORM are only a single character, so start the
-             pointer to copy at 1 and put the string terminator at 3. */
-          value[2]='\0';
-          index=strtoul(&keyname[5], &tailptr, 10)-1;
-          if(index<ncols)
-            {
-              type=gal_fits_tform_to_type(value[1]);
-              up->datatype[index]=gal_fits_type_to_datatype(type);
-              gal_checkset_allocate_copy(&value[1], &up->ttstr[index] );
-            }
-        }
-      else if(strncmp(keyname, "TTYPE", 5)==0)
-        {
-          /* All strings in CFITSIO start and finish with single quotation
-             marks, CFITSIO puts them in itsself, so if we don't remove
-             them here, we might have duplicates later, its easier to just
-             remove them to have a simple string that might be used else
-             where too (without the single quotes). */
-          value[strlen(value)-1]='\0';
-          index=strtoul(&keyname[5], &tailptr, 10)-1;
-          if(index<ncols)
-            gal_checkset_allocate_copy(&value[1], &up->tname[index] );
-        }
-      else if(strncmp(keyname, "TUNIT", 5)==0)
-        {
-          /* similar to tname, see above.*/
-          value[strlen(value)-1]='\0';
-          index=strtoul(&keyname[5], &tailptr, 10)-1;
-          if(index<ncols)
-            gal_checkset_allocate_copy(&value[1], &up->tunit[index] );
-        }
-    }
-
-
-  /* Check if the mandatory TFORMn values are set: */
-  for(i=0;i<ncols;++i)
-    if(!up->ttstr[i])
-      error(EXIT_FAILURE, 0, "TFORM%d could not be found in header", i+1);
-}
-
-
-
-
-
-/* Prepare column information from a text input file. Note that we are
-   currently using Gnuastro's very simple txtarray library, which was only
-   designed for a 2D array of floating point numbers. Later, we must update
-   it to be more aware of the types of input columns and also accept
-   non-number columns.*/
-void
-alltxtcolinfo(struct tableparams *p)
-{
-  size_t i;
-  size_t ncols=p->up.ncols;
-
-  /* Check if there were any strings in the array. If there were strings,
-     then warn the user that we currently can't deal with them. */
-  if(gal_checkset_check_file_report(GAL_TXTARRAY_LOG))
-    error(EXIT_FAILURE, 0, "The input text file `%s' contained "
-          "non-numerical values (probably strings). Please see `%s' for "
-          "a listing of all such terms. Currently Table cannot operate on "
-          "such files. We are working on correcting this issue.",
-          p->up.txtname, GAL_TXTARRAY_LOG);
-
-  /* Allocate the arrays to keep the input column information. */
-  allocinputcolinfo(p);
-
-  /* Set all the column types to double and leave the other fields
-     blank.*/
-  for(i=0;i<ncols;++i)
-    {
-      p->up.datatype[i]=TDOUBLE;
-      gal_checkset_allocate_copy("D", &p->up.ttstr[i] );
-      gal_checkset_allocate_copy("", &p->up.tname[i] );
-      gal_checkset_allocate_copy("", &p->up.tunit[i] );
+      if( !strcmp(up->fitstabletype, "ascii") )
+        p->outtype=GAL_TABLE_TYPE_AFITS;
+      else if( !strcmp(up->fitstabletype, "binary") )
+        p->outtype=GAL_TABLE_TYPE_BFITS;
+      else
+        error(EXIT_FAILURE, 0, "the value to the `--fitstabletype' "
+              "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);
     }
-}
-
-
-
-
-/* Print the column information. */
-void
-printinfo(struct tableparams *p)
-{
-  size_t i;
-  char *typestring=NULL;
-  struct uiparams *up=&p->up;
-
-  printf("---------------------------------------------------------\n");
-  if(up->fitsname)
-    printf("%s (hdu: %s)\n", p->up.fitsname, p->cp.hdu);
   else
-    printf("%s\n", p->up.txtname);
-  printf("%-5s%-25s%-15s%s\n", "No.", "Column name", "Units",
-         "Data type");
-  printf("---------------------------------------------------------\n");
-  for(i=0;i<up->ncols;++i)
-    {
-      switch(up->datatype[i])
-        {
-        case TBIT:
-          typestring="bit";
-          break;
-        case TBYTE:
-          typestring="byte";
-          break;
-        case TLOGICAL:
-          typestring="logicals";
-          break;
-        case TSTRING:
-          typestring="string";
-          break;
-        case TSHORT:
-          typestring="short";
-          break;
-        case TLONG:
-          typestring="long";
-          break;
-        case TLONGLONG:
-          typestring="longlong";
-          break;
-        case TFLOAT:
-          typestring="float";
-          break;
-        case TDOUBLE:
-          typestring="double";
-          break;
-        case TCOMPLEX:
-          typestring="complex";
-          break;
-        case TDBLCOMPLEX:
-          typestring="dblcomplex";
-          break;
-        case TSBYTE:
-          typestring="signed byte";
-          break;
-        case TUINT:
-          typestring="unsigned int";
-          break;
-        case TUSHORT:
-          typestring="unsigned short";
-          break;
-        default:
-          error(EXIT_FAILURE, 0, "%d (from TFORM%zu='%c') is not a "
-                "recognized CFITSIO datatype.", up->datatype[i],
-                i, up->ttstr[i][0]);
-        }
-      printf("%-5zu%-25s%-15s%s\n", i+1, up->tname[i] ? up->tname[i] : "---",
-             up->tunit[i] ? up->tunit[i] : "---", typestring);
-    }
-
+    p->outtype=GAL_TABLE_TYPE_TXT;
 
-  /* Print the number of rows: */
-  printf("---------------------------------------------------------\n");
-  printf("Number of rows: %zu\n", p->nrows);
+  /* Set the searchin integer value. */
+  p->searchin=gal_table_searchin_from_str(p->up.searchin);
 }
 
 
@@ -658,63 +302,47 @@ printinfo(struct tableparams *p)
 
 
 /**************************************************************/
-/***************       Sanity Check         *******************/
+/***************          Information         *****************/
 /**************************************************************/
 void
-sanitycheck(struct tableparams *p)
+print_information_exit(struct tableparams *p)
 {
-  struct uiparams *up=&p->up;
-
-  /* If the desired FITS output type is ASCII, then inform the user that
-     this type is not yet supported. */
-  if(up->fitsname && p->fitstabletype==ASCII_TBL)
-    error(EXIT_FAILURE, 0, "output to ASCII type FITS tables is currently "
-          "not supported (due to lack of need!). If you need this feature, "
-          "please get in touch with us at %s so we can increase the "
-          "priority of this feature.", PACKAGE_BUGREPORT);
-
-  if(up->fitsname)
-    {
-      /* Set the FITS pointer and check the type of the fits file. */
-      gal_fits_read_hdu(p->up.fitsname, p->cp.hdu, 1, &p->fitsptr);
-      gal_fits_table_size(p->fitsptr, &p->nrows, &up->ncols);
-      up->infitstabletype=gal_fits_table_type(p->fitsptr);
-      allfitscolinfo(p);
-    }
-  else
-    {
-      /* Read the text file into an input array and make the basic column
-         information. */
-      gal_txtarray_txt_to_array(up->txtname, &up->txtarray, &p->nrows,
-                                &up->ncols);
-      alltxtcolinfo(p);
-    }
-
-  /* Print the column information and exit successfully if the
-     `--information' option is given. */
-  if(p->up.information)
+  int tabletype;
+  size_t i, numcols;
+  gal_data_t *allcols;
+  char *name, *unit, *comment;
+
+  allcols=gal_table_info(p->up.filename, p->cp.hdu, &numcols,
+                         &tabletype);
+
+  /* Print the legend */
+  printf("Column information for\n");
+  printf("%s (hdu: %s)\n", p->up.filename, p->cp.hdu);
+  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)
     {
-      printinfo(p);
-      freeandreport(p);
-      exit(EXIT_SUCCESS);
+      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 : "N/A" ,
+             unit ? unit : "N/A" ,
+             gal_data_type_string(allcols[i].type),
+             comment ? comment : "N/A");
+      if(name)    free(name);
+      if(unit)    free(unit);
+      if(comment) free(comment);
     }
 
-  /* Check the status of the output file. If no output file is set, then
-     the output will be printed to standard output on the terminal.*/
-  p->outputtofits=p->outputtotxt=p->outputtostdout=0;
-  if(p->cp.outputset)
-    {
-      /* First check if the file exists and remove it if it does. */
-      gal_checkset_check_remove_file(p->cp.output, p->cp.dontdelete);
-
-      /* Now set the type of output. */
-      if(gal_fits_name_is_fits(p->cp.output))
-        p->outputtofits=1;
-      else
-        p->outputtotxt=1;
-    }
-  else
-    p->outputtostdout=1;
+  /* Clean everything else up and return successfully. */
+  free(allcols);
+  freeandreport(p);
+  exit(EXIT_SUCCESS);
 }
 
 
@@ -739,183 +367,15 @@ sanitycheck(struct tableparams *p)
 /**************************************************************/
 /***************       Preparations         *******************/
 /**************************************************************/
-
-/* FUnction to print regular expression error. This is taken from the GNU C
-   library manual, with small modifications to fit out style, */
-void
-regexerrorexit(int errcode, regex_t *compiled, char *input)
-{
-  char *regexerrbuf;
-  size_t length = regerror (errcode, compiled, NULL, 0);
-
-  errno=0;
-  regexerrbuf=malloc(length);
-  if(regexerrbuf==NULL)
-    error(EXIT_FAILURE, errno, "%zu bytes for regexerrbuf", length);
-  (void) regerror(errcode, compiled, regexerrbuf, length);
-
-  error(EXIT_FAILURE, 0, "Regular expression error: %s in value to "
-        "`--column' (`-c'): `%s'", regexerrbuf, input);
-}
-
-
-
-
-
-/* If values were given to the columns option, use them to make a list of
-   columns that must be output. Note that because regular expressions are
-   also allowed as values to the column option, we have no idea how many
-   columns must be printed at first, so we define a linked list to keep the
-   column numbers for later.*/
-void
-outputcolumns(struct tableparams *p)
-{
-  long tlong;
-  regex_t *regex;
-  int regreturn=0;
-  size_t i, inindex;
-  char *tailptr, *colstring;
-  struct uiparams *up=&p->up;
-  struct gal_linkedlist_sll *colsll=NULL;
-
-  /* Go through each given column string and take the appropriate step. */
-  while(p->up.columns)
-    {
-      /* Pop out the top node in the string linked list. */
-      gal_linkedlist_pop_from_stll(&p->up.columns, &colstring);
-
-
-      /* First, see if this given column is an integer or a name/regex. If
-         the string is an integer, then tailptr shoult 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. */
-      tlong=strtol(colstring, &tailptr,0);
-      if(*tailptr=='\0')
-        {
-          /* Make sure we are not dealing with a negative number! */
-          if(tlong<0)
-            error(EXIT_FAILURE, 0, "the column numbers given to the "
-                  "`--column' (`-c') option must not be negative, you "
-                  "have given a value of `%ld'", tlong);
-
-          /* Check if the given value is not larger than the number of
-             columns in the input catalog. */
-          if(tlong>up->ncols)
-            error(EXIT_FAILURE, 0, "%s (hdu: %s) has %zu columns, but "
-                  "you have asked for column number %zu", p->up.fitsname,
-                  p->cp.hdu, up->ncols, 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(&colsll, tlong-1);
-        }
-      else
-        {
-          /* Allocate the regex_t structure: */
-          errno=0; regex=malloc(sizeof *regex);
-          if(regex==NULL)
-            error(EXIT_FAILURE, errno, "%zu bytes for regex", sizeof *regex);
-
-          /* Go through all the columns names and see if this matches
-             them. But first we have to "compile" the string into the
-             regular expression, see the "POSIX Regular Expression
-             Compilation" section of the GNU C Library.
-
-             About the case of the string: the FITS standard says: "It is
-             _strongly recommended_ that every field of the table be
-             assigned a unique, case insensitive name with this keyword..."
-             So the column names can be case-sensitive.
-
-             Here, we don't care about the details of a match, the only
-             important thing is a match, so we are using the REG_NOSUB
-             flag.*/
-          regreturn=0;
-          regreturn=regcomp(regex, colstring, ( p->up.ignorecase
-                                                ? REG_NOSUB + REG_ICASE
-                                                : REG_NOSUB ) );
-          if(regreturn)
-            regexerrorexit(regreturn, regex, colstring);
-
-
-          /* With the regex structure "compile"d you can go through all the
-             column names. Just note that column names are not mandatory in
-             the FITS standard, so some (or all) columns might not have
-             names, if so `p->tname[i]' will be NULL. */
-          for(i=0;i<up->ncols;++i)
-            if(up->tname[i] && regexec(regex, up->tname[i], 0, 0, 0)==0)
-              gal_linkedlist_add_to_sll(&colsll, i);
-
-          /* Free the regex_t structure: */
-          regfree(regex);
-        }
-
-      /* We don't need this user provided column string any more. */
-      free(colstring);
-    }
-
-  /* Based on the number of columns found above, allocate an array of
-     `outcolumn' structures to keep the information for each column. */
-  p->nocols=gal_linkedlist_num_in_sll(colsll);
-  errno=0;
-  p->ocols=malloc(p->nocols*sizeof *p->ocols);
-  if(p->ocols==NULL)
-    error(EXIT_FAILURE, errno, "%zu bytes for p->ocols",
-          p->nocols*sizeof *p->ocols);
-
-  /* Fill in the output column with the needed input table
-     information. Note that a simple linked list is first-in-last-out, so
-     we have to fill in the output columns in reverse order. Also, note
-     that we are popping from the linked list keeping the indexs of the
-     output columns and thus also freeing their allocated space. */
-  i=p->nocols-1;
-  while(colsll)
-    {
-      int type;
-      gal_linkedlist_pop_from_sll(&colsll, &inindex);
-      p->ocols[i].inindex=inindex;
-      p->ocols[i].datatype=up->datatype[inindex];
-      type=gal_fits_datatype_to_type(p->ocols[i].datatype);
-      p->ocols[i].esize=gal_data_sizeof(type);
-      --i;
-    }
-}
-
-
-
-
-
 void
 preparearrays(struct tableparams *p)
 {
-  size_t i;
-  struct uiparams *up=&p->up;
+  /* Pull out the columns that we are looking for. */
+  gal_linkedlist_reverse_stll(&p->columns);
+  gal_table_read_cols(p->up.filename, p->cp.hdu, p->columns,
+                      p->searchin, p->ignorecase);
 
-  /* Reverse the columns linked list here (before possibly printing).*/
-  gal_linkedlist_reverse_stll(&up->columns);
 
-  /* Set the columns that should be included in the output. If up->columns
-     is set, then use it, otherwise, set all the columns for printing. */
-  if(p->up.columns)
-    outputcolumns(p);
-  else
-    {
-      p->nocols=up->ncols;
-      errno=0;
-      p->ocols=malloc(p->nocols * sizeof *p->ocols);
-      if(p->ocols==NULL)
-        error(EXIT_FAILURE, errno, "%zu bytes for p->ocols",
-              p->nocols * sizeof *p->ocols);
-      for(i=0;i<p->nocols;++i)
-        {
-          int type;
-          p->ocols[i].inindex=i;
-          p->ocols[i].datatype=up->datatype[i];
-          type=gal_fits_datatype_to_type(p->ocols[i].datatype);
-          p->ocols[i].esize=gal_data_sizeof(type);
-        }
-    }
 }
 
 
@@ -953,10 +413,8 @@ setparams(int argc, char *argv[], struct tableparams *p)
   cp->removedirinfo = 1;
 
   /* Initialize this utility's pointers to NULL. */
-  p->ocols=NULL;
-  up->columns=NULL;
-  up->txtname=up->fitsname=NULL;
-  up->ttstr=up->tname=up->tunit=NULL;
+  p->columns=NULL;
+  up->filename=NULL;
 
   /* Read the arguments. */
   errno=0;
@@ -976,9 +434,12 @@ 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);
-
 }
 
 
@@ -1006,44 +467,7 @@ setparams(int argc, char *argv[], struct tableparams *p)
 void
 freeandreport(struct tableparams *p)
 {
-  size_t i, j;
-  int status=0;
-  char **rowofstrings;
-  struct uiparams *up=&p->up;
-
   /* Free the allocated arrays: */
   free(p->cp.hdu);
-  free(up->txtarray);
-  free(up->datatype);
   free(p->cp.output);
-
-  /* Free the input column information: */
-  for(i=0;i<up->ncols;++i)
-    {
-      if(up->ttstr) free(up->ttstr[i]);
-      if(up->tname) free(up->tname[i]);
-      if(up->tunit) free(up->tunit[i]);
-    }
-  free(up->ttstr);
-  free(up->tname);
-  free(up->tunit);
-
-  /* Free the output column information: */
-  for(i=0;i<p->nocols;++i)
-    {
-      free(p->ocols[i].nulval);
-      if(p->ocols[i].datatype==TSTRING)
-        {
-          rowofstrings=(char **)(p->ocols[i].data);
-          for(j=0;j<p->nrows;++j)
-            free(rowofstrings[j]);
-        }
-      else
-        free(p->ocols[i].data);
-    }
-  free(p->ocols);
-
-  /* Close the FITS file: */
-  if(p->up.fitsname && fits_close_file(p->fitsptr, &status))
-    gal_fits_io_error(status, NULL);
 }
diff --git a/doc/gnuastro.texi b/doc/gnuastro.texi
index 7c47b18..3c75a6b 100644
--- a/doc/gnuastro.texi
+++ b/doc/gnuastro.texi
@@ -6234,12 +6234,12 @@ within a FITS file.
 @cindex AWK
 @cindex GNU AWK
 However, this comes at a cost: binary tables are not easily readable by
-human eyes. There is no standard on how the zero and ones should be
-interpretted. The Unix-like operating systems have flourished because of a
-simple fact: communication between the various tools is based on human
-readable address@hidden ``The art of Unix programming'', Eric
-Raymond makes this suggestion to programmers: ``When you feel the urge to
-design a complex binary file format, or a complex binary application
+human eyes. There is no fixed/unified standard on how the zero and ones
+should be interpretted. The Unix-like operating systems have flourished
+because of a simple fact: communication between the various tools is based
+on human readable address@hidden ``The art of Unix programming'',
+Eric Raymond makes this suggestion to programmers: ``When you feel the urge
+to design a complex binary file format, or a complex binary application
 protocol, it is generally wise to lie down until the feeling
 passes.''. This is a great book and strongly recommended, give it a look if
 you want to truly enjoy your work/life in this environment.}. So while the
@@ -6282,7 +6282,7 @@ One line examples:
 $ asttable bintab.fits --information
 
 ## Only print those columns which have a name starting with "MAG_"
-$ asttable bintab.fits --columns=^MAG_
+$ asttable bintab.fits --columns=/^MAG_/
 
 ## Only print the 2nd column, and the third column multiplied by 5
 $ asttable bintab.fits | awk '@{print $2, address@hidden'
@@ -6325,25 +6325,52 @@ 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.
 
address@hidden AWK
address@hidden GNU AWK
 @item -c
 @itemx --column
 (@option{=STR} or @option{=INT}) Specify the columns to output for this
-table. If an integer number is given, the column number will be used
-(counting from 1). Otherwise the value (a string) will be passed to an
-internal regular expression processor which will try to match all the
-columns in the table with the given regular expression. Currently only FITS
-tables might have column names (it is an optional feature in the FITS
-standard). There is currently no particular standard to name plain text
+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 negative
+values are given). When the value isn't a number, the value's string of
+characters will be used to match one of the pieces of information for the
+columns. See the @option{--searchin} option description for more on where
+the matching/searching will take place. The matching will be done following
+this convention (similar to AWK):
+
address@hidden
address@hidden
+If the value is enclosed in two slashes (for example @command{-c/MAG_/}, or
address@hidden/MAG_/}), then it is assumed to be a regular expression
+with the same convention as GNU AWK. GNU AWK has a
address@hidden://wwww.gnu.org/s/gawk/manual/html_node/Regexp.html,complete
+chapter} describing regular expressions, so we we will not continue
+discussing it here. Regular expressions are a very powerful tool in
+matching text and since FITS binary tables usually have a large number of
+columns, this feature can greatly simply the selection of the output
 columns.
 
-This option can be called any number of times with one run of Table. The
-order of the output columns will be determined by the input order. This
-option is also not mandatory. If not given, all the input table columns are
-output.
address@hidden
+Only columns that exactly match the given string (the case can be ignored
+with the @option{--ignorecase} option) in the given piece of column in
+formation will be selected.
address@hidden itemize
+
+Note that in both cases, it is possible to select multiple columns with one
+call to this function. The order of the selected columns (with one call to
+this option) will be the same order as they appear in the table.
 
-Regular expressions are a very powerful tool in matching text and since
-FITS binary tables usually have a large number of columns, this feature can
-greatly simply the selection of the output columns.
+To select several output columns, this option can also be called any number
+times in one call to Table. The order of the output columns will be the
+same call order on the command-line. This option is not mandatory, if no
+specific columns are requested, all the input table columns are
+output. When this option is called multiple times, it is possible to output
+one column more than once.
+
address@hidden -s
address@hidden --searchin
+Where to match/search for columns (if the value to @option{--column} wasn't
+a number).
 
 @item -I
 @itemx --ignorescase
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 3099c4b..196ba34 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -43,8 +43,8 @@ libgnuastro_la_LDFLAGS = -version-info $(GAL_LT_VERSION)
 libgnuastro_la_SOURCES = array.c box.c checkset.c configfiles.c data.c  \
   data-arithmetic-binary.c data-arithmetic-onlyint.c                    \
   data-arithmetic-other.c data-copy.c fits.c git.c linkedlist.c mesh.c  \
-  mode.c polygon.c qsort.c spatialconvolve.c statistics.c threads.c     \
-  timing.c txt.c wcs.c
+  mode.c polygon.c qsort.c spatialconvolve.c statistics.c table.c       \
+  threads.c timing.c txt.c wcs.c
 
 
 
@@ -59,7 +59,8 @@ pkginclude_HEADERS = gnuastro/config.h $(headersdir)/array.h  
          \
   $(headersdir)/git.h $(headersdir)/linkedlist.h $(headersdir)/mesh.h   \
   $(headersdir)/polygon.h $(headersdir)/qsort.h                         \
   $(headersdir)/spatialconvolve.h $(headersdir)/statistics.h            \
-  $(headersdir)/threads.h $(headersdir)/wcs.h $(headersdir)/txt.h
+  $(headersdir)/table.h $(headersdir)/threads.h $(headersdir)/wcs.h     \
+  $(headersdir)/txt.h
 
 
 
diff --git a/lib/data.c b/lib/data.c
index 7b6db63..e3c0c2f 100644
--- a/lib/data.c
+++ b/lib/data.c
@@ -515,8 +515,7 @@ gal_data_free(gal_data_t *data, int only_contents)
   if(data->type==GAL_DATA_TYPE_STRING)
     do if(str) free(str); while(++str<strf);
 
-  /* Free the array. Note that if the array is mmap'd, then we need to
-     delete the file that kept it. */
+  /* Free the array. */
   if(data->mmapname)
     {
       /* Delete the file keeping the array. */
@@ -526,7 +525,7 @@ gal_data_free(gal_data_t *data, int only_contents)
       free(data->mmapname);
     }
   else
-    free(data->array);
+    if(data->array) free(data->array);
 
 
   /* Finally, free the actual data structure. */
diff --git a/lib/fits.c b/lib/fits.c
index bf733c0..255f273 100644
--- a/lib/fits.c
+++ b/lib/fits.c
@@ -26,6 +26,7 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 #include <errno.h>
 #include <error.h>
 #include <stdio.h>
+#include <ctype.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
@@ -260,7 +261,9 @@ gal_fits_type_to_bitpix(int type)
 /* The values to the TFORM header keyword are single letter capital
    letters, but that is useless in identifying the data type of the
    column. So this function will do the conversion based on the CFITSIO
-   manual.*/
+   manual.
+
+   Note that the characters are the same for ASCII or binary tables.*/
 int
 gal_fits_tform_to_type(char tform)
 {
@@ -530,34 +533,10 @@ gal_fits_img_info(fitsfile *fptr, int *type, size_t 
*ndim, long **dsize)
 /**************************************************************/
 /**********                  HDU                   ************/
 /**************************************************************/
-static char *
-hdutypestring(int hdutype)
-{
-  switch(hdutype)
-    {
-    case IMAGE_HDU:
-      return "an Image";
-    case ASCII_TBL:
-      return "an ASCII table";
-    case BINARY_TBL:
-      return "a binary table";
-      break;
-    default:
-      error(EXIT_FAILURE, 0, "HDU code %d in CFITSIO not recognized",
-            hdutype);
-    }
-  return NULL;
-}
-
-
-
-
-
 /* Check the desired HDU in a FITS image and also if it has the
    desired type. */
-void
-gal_fits_read_hdu(char *filename, char *hdu, unsigned char img0_tab1,
-                  fitsfile **outfptr)
+fitsfile *
+gal_fits_read_hdu(char *filename, char *hdu, unsigned char img0_tab1)
 {
   size_t len;
   char *ffname;
@@ -573,9 +552,8 @@ gal_fits_read_hdu(char *filename, char *hdu, unsigned char 
img0_tab1,
   sprintf(ffname, "%s[%s#]", filename, hdu);
 
   /* Open the FITS file: */
-  if( fits_open_file(outfptr, ffname, READONLY, &status) )
+  if( fits_open_file(&fptr, ffname, READONLY, &status) )
     gal_fits_io_error(status, "reading this FITS file");
-  fptr=*outfptr;
 
   /* Check the type of the given HDU: */
   if (fits_get_hdu_type(fptr, &hdutype, &status) )
@@ -587,18 +565,19 @@ gal_fits_read_hdu(char *filename, char *hdu, unsigned 
char img0_tab1,
   if(img0_tab1)
     {
       if(hdutype==IMAGE_HDU)
-        error(EXIT_FAILURE, 0, "%s: HDU %s is an image, not a table",
+        error(EXIT_FAILURE, 0, "%s (hdu: %s): is not a table",
               filename, hdu);
     }
   else
     {
       if(hdutype!=IMAGE_HDU)
-        error(EXIT_FAILURE, 0, "%s: HDU %s is %s, not an image",
-              filename, hdu, hdutypestring(hdutype));
+        error(EXIT_FAILURE, 0, "%s (hdu: %s): not an image",
+              filename, hdu);
     }
 
-  /* Clean up. */
+  /* Clean up and return. */
   free(ffname);
+  return fptr;
 }
 
 
@@ -1215,7 +1194,7 @@ gal_fits_read_wcs(char *filename, char *hdu, size_t 
hstartwcs,
   fitsfile *fptr;
 
   /* Check HDU for realistic conditions: */
-  gal_fits_read_hdu(filename, hdu, 0, &fptr);
+  fptr=gal_fits_read_hdu(filename, hdu, 0);
 
   /* Read the WCS information: */
   gal_fits_read_wcs_from_pointer(fptr, nwcs, wcs, hstartwcs, hendwcs);
@@ -1266,7 +1245,7 @@ gal_fits_read_img_hdu(char *filename, char *hdu, char 
*maskname,
 
 
   /* Check HDU for realistic conditions: */
-  gal_fits_read_hdu(filename, hdu, 0, &fptr);
+  fptr=gal_fits_read_hdu(filename, hdu, 0);
 
 
   /* Get the info and allocate the data structure. */
@@ -1616,9 +1595,9 @@ gal_fits_table_type(fitsfile *fptr)
   if(status==0)
     {
       if(!strcmp(value, "TABLE   "))
-        return ASCII_TBL;
+        return GAL_TABLE_TYPE_AFITS;
       else if(!strcmp(value, "BINTABLE"))
-        return BINARY_TBL;
+        return GAL_TABLE_TYPE_BFITS;
       else
         error(EXIT_FAILURE, 0, "The `XTENSION' keyword of this FITS file "
               "doesn't have a standard value (`%s')", value);
@@ -1627,9 +1606,7 @@ gal_fits_table_type(fitsfile *fptr)
     {
       if(status==KEY_NO_EXIST)
         error(EXIT_FAILURE, 0, "the `gal_fits_table_type' function was "
-              "called on a FITS extension which is not a table. As part "
-              "of a utility, this is bug, so please contact us at %s so "
-              "we can fix it.", PACKAGE_BUGREPORT);
+              "called on a FITS extension which is not a table.");
       else
         gal_fits_io_error(status, NULL);
     }
@@ -1639,3 +1616,132 @@ gal_fits_table_type(fitsfile *fptr)
         "the end of the function! This must not happen", PACKAGE_BUGREPORT);
   return -1;
 }
+
+
+
+
+static void
+remove_trailing_space(char *str)
+{
+  size_t i;
+
+  /* Start from the second last character (the last is a single quote) and
+     go down until you hit a non-space character. */
+  for(i=strlen(str)-2;i>0;--i)
+    if(str[i]!=' ')
+      break;
+
+  /* If the string is empty, it will stop at the first character that is a
+     single quote. So no need to check further. */
+  str[i+1]='\0';
+}
+
+
+
+
+
+/* See the descriptions of `gal_table_info'. */
+gal_data_t *
+gal_fits_table_info(char *filename, char *hdu, size_t *numcols,
+                    int *tabletype)
+{
+  int tfields;        /* The maximum number of fields in FITS is 999 */
+  int status=0;
+  size_t index;
+  fitsfile *fptr;
+  size_t i, numrows;
+  gal_data_t *cols=NULL;
+  char *tailptr, keyname[FLEN_KEYWORD]="XXXXXXXXXXXXX", value[FLEN_VALUE];
+
+
+  /* Open the FITS file and get the basic information. */
+  fptr=gal_fits_read_hdu(filename, hdu, 1);
+  *tabletype=gal_fits_table_type(fptr);
+  gal_fits_table_size(fptr, &numrows, numcols);
+
+
+  /* Read the total number of fields, then allocate space for the data
+     structure and store the information within it. */
+  fits_read_key(fptr, TINT, "TFIELDS", &tfields, NULL, &status);
+  errno=0;
+  cols=malloc(tfields*sizeof *cols);
+  if(cols==NULL)
+    error(EXIT_FAILURE, errno, "%zu bytes for cols in `gal_fits_table_info'",
+          tfields*sizeof *cols);
+
+
+  /* Read all the keywords one by one and if they match, then put them in
+     the correct value. Note that we are starting from keyword 9 because
+     according to the FITS standard, the first 8 keys in a FITS table are
+     reserved. */
+  for(i=9; strcmp(keyname, "END"); ++i)
+    {
+      /* Read the next keyword. */
+      fits_read_keyn(fptr, i, keyname, value, NULL, &status);
+
+      /* COLUMN DATA TYPE. According the the FITS standard, the value of
+         TFORM is most generally in this format: `rTa'. `T' is actually a
+         code of the datatype. `r' is the `repeat' counter and `a' is
+         depreciated. Currently we can only read repeat==1 cases. When no
+         number exists before the defined capital letter, it defaults to 1,
+         but if a number exists (for example `5D'), then the repeat is 5
+         (there are actually five values in each column). Note that
+         value[0] is a single quote.*/
+      if(strncmp(keyname, "TFORM", 5)==0)
+        {
+          /* Small sanity check. */
+          if(isdigit(value[1] && value[1]!='1'))
+             error(EXIT_FAILURE, 0, "The repeat value of %s is "
+                   "%c, currently Table can only use columns with a repeat "
+                   "of 1.", keyname, value[1]);
+
+          /* If they don't start with a `1', the values to TFORM are only a
+             single character. so start the pointer to copy at 1 and put
+             the string terminator at 3. */
+          if(value[1]=='1') value[1]=value[2];
+          value[2]='\0';
+          index = strtoul(&keyname[5], &tailptr, 10) - 1;
+          if(index<tfields)     /* Counting from zero was corrected above. */
+            cols[index].type=gal_fits_tform_to_type(value[1]);
+        }
+
+      /* COLUMN NAME. All strings in CFITSIO start and finish with single
+         quotation marks, CFITSIO puts them in itsself, so if we don't
+         remove them here, we might have duplicates later, its easier to
+         just remove them to have a simple string that might be used else
+         where too (without the single quotes).*/
+      else if(strncmp(keyname, "TTYPE", 5)==0)
+        {
+          remove_trailing_space(value);
+          index = strtoul(&keyname[5], &tailptr, 10) - 1;
+          if(index<tfields)
+            gal_checkset_allocate_copy(&value[1], &cols[index].name);
+        }
+
+      /* COLUMN UNITS. */
+      else if(strncmp(keyname, "TUNIT", 5)==0)
+        {
+          /* similar to tname, see above.*/
+          remove_trailing_space(value);
+          index = strtoul(&keyname[5], &tailptr, 10) - 1;
+          if(index<tfields)
+            gal_checkset_allocate_copy(&value[1], &cols[index].unit);
+        }
+
+      /* COLUMN COMMENTS */
+      else if(strncmp(keyname, "TCOMM", 5)==0)
+        {
+          /* similar to tname, see above.*/
+          remove_trailing_space(value);
+          index = strtoul(&keyname[5], &tailptr, 10) - 1;
+          if(index<tfields)
+            gal_checkset_allocate_copy(&value[1], &cols[index].comment);
+        }
+    }
+
+
+  /* Close the FITS file and report an error if we had any. */
+  fits_close_file(fptr, &status);
+  gal_fits_io_error(status, NULL);
+  return cols;
+}
diff --git a/lib/gnuastro/data.h b/lib/gnuastro/data.h
index fe3dea4..fd30a96 100644
--- a/lib/gnuastro/data.h
+++ b/lib/gnuastro/data.h
@@ -106,7 +106,7 @@ __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_alltypes
+enum gal_data_types
 {
   GAL_DATA_TYPE_BIT,       /* Bit              (TBIT).        */
   GAL_DATA_TYPE_UCHAR,     /* unsigned char    (TBYTE).       */
diff --git a/lib/gnuastro/fits.h b/lib/gnuastro/fits.h
index b61c377..e9faf32 100644
--- a/lib/gnuastro/fits.h
+++ b/lib/gnuastro/fits.h
@@ -45,6 +45,7 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 #include <wcslib/wcsfix.h>
 
 #include <gnuastro/data.h>
+#include <gnuastro/table.h>
 
 /* C++ Preparations */
 #undef __BEGIN_C_DECLS
@@ -150,9 +151,8 @@ gal_fits_img_info(fitsfile *fptr, int *type, size_t *ndim, 
long **dsize);
 /**********                  HDU                   ************/
 /**************************************************************/
 
-void
-gal_fits_read_hdu(char *filename, char *hdu, unsigned char img0_tab1,
-                  fitsfile **outfptr);
+fitsfile *
+gal_fits_read_hdu(char *filename, char *hdu, unsigned char img0_tab1);
 
 
 
@@ -253,6 +253,10 @@ gal_fits_table_size(fitsfile *fitsptr, size_t *nrows, 
size_t *ncols);
 int
 gal_fits_table_type(fitsfile *fptr);
 
+gal_data_t *
+gal_fits_table_info(char *filename, char *hdu, size_t *numcols,
+                    int *tabletype);
+
 
 
 
diff --git a/lib/gnuastro/linkedlist.h b/lib/gnuastro/linkedlist.h
index 87f4952..105d046 100644
--- a/lib/gnuastro/linkedlist.h
+++ b/lib/gnuastro/linkedlist.h
@@ -158,6 +158,9 @@ void
 gal_linkedlist_pop_from_sll(struct gal_linkedlist_sll **list,
                             size_t *value);
 
+void
+gal_linkedlist_reverse_sll(struct gal_linkedlist_sll **list);
+
 size_t
 gal_linkedlist_num_in_sll(struct gal_linkedlist_sll *list);
 
diff --git a/lib/gnuastro/txt.h b/lib/gnuastro/table.h
similarity index 55%
copy from lib/gnuastro/txt.h
copy to lib/gnuastro/table.h
index 8b478f7..007f8ff 100644
--- a/lib/gnuastro/txt.h
+++ b/lib/gnuastro/table.h
@@ -1,5 +1,5 @@
 /*********************************************************************
-data -- Structure and functions to represent/work with data
+table -- functions for table input and output.
 This is part of GNU Astronomy Utilities (Gnuastro) package.
 
 Original author:
@@ -20,25 +20,16 @@ General Public License for more details.
 You should have received a copy of the GNU General Public License
 along with Gnuastro. If not, see <http://www.gnu.org/licenses/>.
 **********************************************************************/
-#ifndef __GAL_TXT_H__
-#define __GAL_TXT_H__
+#ifndef __GAL_TABLE_H__
+#define __GAL_TABLE_H__
 
 /* Include other headers if necessary here. Note that other header files
    must be included before the C++ preparations below */
 
-#include <gnuastro/data.h>
-
-/* When we are within Gnuastro's building process, `IN_GNUASTRO_BUILD' is
-   defined. In the build process, installation information (in particular
-   `GAL_CONFIG_ARITH_CHAR' and the rest of the types that we needed in the
-   arithmetic function) is kept in `config.h'. When building a user's
-   programs, this information is kept in `gnuastro/config.h'. Note that all
-   `.c' files must start with the inclusion of `config.h' and that
-   `gnuastro/config.h' is only created at installation time (not present
-   during the building of Gnuastro).*/
-#ifndef IN_GNUASTRO_BUILD
-#include <gnuastro/config.h>
-#endif
+#include <gnuastro/fits.h> /* Includes `gnuastro/data.h' and `fitsio.h' */
+#include <gnuastro/linkedlist.h>
+
+
 
 /* C++ Preparations */
 #undef __BEGIN_C_DECLS
@@ -54,16 +45,54 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 
 
 
+
+
 /* Actual header contants (the above were for the Pre-processor). */
 __BEGIN_C_DECLS  /* From C++ preparations */
 
 
 
+
+
+/* Types of table storage for input or output. */
+enum gal_table_types
+{
+  GAL_TABLE_TYPE_TXT,                     /* Plain text table.  */
+  GAL_TABLE_TYPE_AFITS,                   /* FITS ASCII table.  */
+  GAL_TABLE_TYPE_BFITS,                   /* FITS binary table. */
+};
+
+
+
+
+
+/* When the desired column is not a number, should the string match or
+   regular expression search be in the name, units or comments of the
+   columns? */
+enum gal_table_where_to_search
+{
+  GAL_TABLE_SEARCH_NAME,                   /* Match/search in names.    */
+  GAL_TABLE_SEARCH_UNIT,                   /* Match/search in units.    */
+  GAL_TABLE_SEARCH_COMMENT,                /* Match/search in comments. */
+};
+
+
+
+
+
+/* Functions */
 gal_data_t *
-gal_txt_read_cols(char *filename, size_t *cols);
+gal_table_info(char *filename, char *hdu, size_t *numcols, int *tabletype);
 
+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);
 
 
 __END_C_DECLS    /* From C++ preparations */
 
-#endif           /* __GAL_TXT_H__ */
+#endif           /* __GAL_TABLE_H__ */
diff --git a/lib/gnuastro/txt.h b/lib/gnuastro/txt.h
index 8b478f7..68c3698 100644
--- a/lib/gnuastro/txt.h
+++ b/lib/gnuastro/txt.h
@@ -1,5 +1,5 @@
 /*********************************************************************
-data -- Structure and functions to represent/work with data
+txt -- functions to deal with plain text files.
 This is part of GNU Astronomy Utilities (Gnuastro) package.
 
 Original author:
@@ -26,19 +26,10 @@ 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/data.h>
-
-/* When we are within Gnuastro's building process, `IN_GNUASTRO_BUILD' is
-   defined. In the build process, installation information (in particular
-   `GAL_CONFIG_ARITH_CHAR' and the rest of the types that we needed in the
-   arithmetic function) is kept in `config.h'. When building a user's
-   programs, this information is kept in `gnuastro/config.h'. Note that all
-   `.c' files must start with the inclusion of `config.h' and that
-   `gnuastro/config.h' is only created at installation time (not present
-   during the building of Gnuastro).*/
-#ifndef IN_GNUASTRO_BUILD
-#include <gnuastro/config.h>
-#endif
+#include <gnuastro/fits.h> /* Includes `gnuastro/data.h' and `fitsio.h' */
+
+
+
 
 /* C++ Preparations */
 #undef __BEGIN_C_DECLS
@@ -54,13 +45,18 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 
 
 
+
+
 /* Actual header contants (the above were for the Pre-processor). */
 __BEGIN_C_DECLS  /* From C++ preparations */
 
 
 
+
+
 gal_data_t *
-gal_txt_read_cols(char *filename, size_t *cols);
+gal_txt_table_info(char *filename, size_t *numcols);
+
 
 
 
diff --git a/lib/linkedlist.c b/lib/linkedlist.c
index 8ad9ee0..d89b660 100644
--- a/lib/linkedlist.c
+++ b/lib/linkedlist.c
@@ -448,6 +448,24 @@ gal_linkedlist_pop_from_sll(struct gal_linkedlist_sll 
**list, size_t *value)
 
 
 
+void
+gal_linkedlist_reverse_sll(struct gal_linkedlist_sll **list)
+{
+  size_t thisnum;
+  struct gal_linkedlist_sll *correctorder=NULL;
+
+  while(*list!=NULL)
+    {
+      gal_linkedlist_pop_from_sll(list, &thisnum);
+      gal_linkedlist_add_to_sll(&correctorder, thisnum);
+    }
+  *list=correctorder;
+}
+
+
+
+
+
 size_t
 gal_linkedlist_num_in_sll(struct gal_linkedlist_sll *list)
 {
diff --git a/lib/table.c b/lib/table.c
new file mode 100644
index 0000000..3ed5781
--- /dev/null
+++ b/lib/table.c
@@ -0,0 +1,327 @@
+/*********************************************************************
+txt -- Functions for I/O on text files.
+This is part of GNU Astronomy Utilities (Gnuastro) package.
+
+Original author:
+     Mohammad Akhlaghi <address@hidden>
+Contributing author(s):
+Copyright (C) 2016, Free Software Foundation, Inc.
+
+Gnuastro is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation, either version 3 of the License, or (at your
+option) any later version.
+
+Gnuastro is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Gnuastro. If not, see <http://www.gnu.org/licenses/>.
+**********************************************************************/
+#include <config.h>
+
+#include <stdio.h>
+#include <errno.h>
+#include <error.h>
+#include <regex.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <gnuastro/txt.h>
+#include <gnuastro/table.h>
+
+
+/************************************************************************/
+/***************         Information about a table        ***************/
+/************************************************************************/
+/* Store the information of each column in a table (either as a text file
+   or as a FITS table) into an array of data structures with `numcols'
+   structures (one data structure for each column). Note that the arrays in
+   the data structures will be empty.
+
+   The array of data structures will be returned, the number of columns
+   will be put in the `numcols' argument and the type of the table (e.g.,
+   ascii text file, or FITS binary or ASCII table) will be put in
+   `tabletype' (macros defined in `gnuastro/table.h'. */
+gal_data_t *
+gal_table_info(char *filename, char *hdu, size_t *numcols, int *tabletype)
+{
+  /* Get the table type and size (number of columns and rows). */
+  if(gal_fits_name_is_fits(filename))
+    return gal_fits_table_info(filename, hdu, numcols, tabletype);
+  else
+    {
+      *tabletype=GAL_TABLE_TYPE_TXT;
+      return gal_txt_table_info(filename, numcols);
+    }
+
+  /* Abort with an error if we get to this point. */
+  error(EXIT_FAILURE, 0, "A bug! please contact us at %s so we can fix "
+        "the problem. For some reason, control has reached the end of "
+        "`gal_table_info'", PACKAGE_BUGREPORT);
+  return NULL;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/************************************************************************/
+/***************               Read a table               ***************/
+/************************************************************************/
+/* In programs, the `searchin' variable is much more easier to type in as a
+   description than an integer (which is what `gal_table_read_cols'
+   needs). This function will check the string value and give the
+   corresponding integer value.*/
+int
+gal_table_searchin_from_str(char *searchin_str)
+{
+  if(strcmp(searchin_str, "name")==0)
+    return GAL_TABLE_SEARCH_NAME;
+  else if(strcmp(searchin_str, "unit")==0)
+    return GAL_TABLE_SEARCH_UNIT;
+  else if(strcmp(searchin_str, "comment")==0)
+    return GAL_TABLE_SEARCH_COMMENT;
+  else
+    error(EXIT_FAILURE, 0, "`--searchin' only recognizes the values "
+          "`name', `unit', and `comment', you have asked for `%s'",
+          searchin_str);
+
+  /* Report an error control reaches here. */
+  error(EXIT_FAILURE, 0, "A bug! please contact us at %s so we can address "
+        "the problem. For some reason control has reached the end of "
+        "`gal_table_searchin_from_str'", PACKAGE_BUGREPORT);
+  return -1;
+}
+
+
+
+
+
+/* Function to print regular expression error. This is taken from the GNU C
+   library manual, with small modifications to fit out style, */
+void
+regexerrorexit(int errcode, regex_t *compiled, char *input)
+{
+  char *regexerrbuf;
+  size_t length = regerror (errcode, compiled, NULL, 0);
+
+  errno=0;
+  regexerrbuf=malloc(length);
+  if(regexerrbuf==NULL)
+    error(EXIT_FAILURE, errno, "%zu bytes for regexerrbuf", length);
+  (void) regerror(errcode, compiled, regexerrbuf, length);
+
+  error(EXIT_FAILURE, 0, "Regular expression error: %s in value to "
+        "`--column' (`-c'): `%s'", regexerrbuf, input);
+}
+
+
+
+
+
+/* Macro to set the string to search in */
+#define SET_STRCHECK                                                    \
+  strcheck=NULL;                                                        \
+  switch(searchin)                                                      \
+    {                                                                   \
+    case GAL_TABLE_SEARCH_NAME:                                         \
+      strcheck=allcols[i].name;                                         \
+      break;                                                            \
+    case GAL_TABLE_SEARCH_UNIT:                                         \
+      strcheck=allcols[i].unit;                                         \
+      break;                                                            \
+    case GAL_TABLE_SEARCH_COMMENT:                                      \
+      strcheck=allcols[i].comment;                                      \
+      break;                                                            \
+    default:                                                            \
+      error(EXIT_FAILURE, 0, "the code %d to searchin was not "         \
+            "recognized in gal_table_read_cols", searchin);             \
+    }
+
+
+
+
+
+static struct gal_linkedlist_sll *
+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;
+  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]=='/' )
+        {
+          /* Remove the slashes, note that we don't want to change `tmp->v'
+             (because it should be freed later). So first we set the last
+             character to `\0', then define a new string from the first
+             element. */
+          tmp->v[strlen(tmp->v)-1]='\0';
+          str = tmp->v + 1;
+
+          /* Allocate the regex_t structure: */
+          errno=0; regex=malloc(sizeof *regex);
+          if(regex==NULL)
+            error(EXIT_FAILURE, errno, "%zu bytes for regex", sizeof *regex);
+
+          /* First we have to "compile" the string into the regular
+             expression, see the "POSIX Regular Expression Compilation"
+             section of the GNU C Library.
+
+             About the case of the string: the FITS standard says: "It is
+             _strongly recommended_ that every field of the table be
+             assigned a unique, case insensitive name with this keyword..."
+             So the column names can be case-sensitive.
+
+             Here, we don't care about the details of a match, the only
+             important thing is a match, so we are using the REG_NOSUB
+             flag.*/
+          regreturn=0;
+          regreturn=regcomp(regex, str, ( ignorecase
+                                          ? RE_SYNTAX_AWK | REG_ICASE
+                                          : RE_SYNTAX_AWK ) );
+          if(regreturn)
+            regexerrorexit(regreturn, regex, str);
+
+
+          /* With the regex structure "compile"d you can go through all the
+             column names. Just note that column names are not mandatory in
+             the FITS standard, so some (or all) columns might not have
+             names, if so `p->tname[i]' will be NULL. */
+          for(i=0;i<numcols;++i)
+            {
+              SET_STRCHECK;
+              if(strcheck && regexec(regex, strcheck, 0, 0, 0)==0)
+                gal_linkedlist_add_to_sll(&indexll, i);
+            }
+
+          /* Free the regex_t structure: */
+          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')
+        {
+          /* 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)
+            {
+              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);
+        }
+
+      /* EXACT MATCH: */
+      else
+        {
+          for(i=0;i<numcols;++i)
+            {
+              SET_STRCHECK;
+              if(strcheck && strcmp(tmp->v, strcheck)==0)
+                gal_linkedlist_add_to_sll(&indexll, i);
+            }
+        }
+    }
+
+  /* Reverse the list. */
+  gal_linkedlist_reverse_sll(&indexll);
+  return indexll;
+}
+
+
+
+
+
+/* Read the specified columns in a text file (named `filename') into a
+   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
+   `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'.*/
+gal_data_t *
+gal_table_read_cols(char *filename, char *hdu,
+                    struct gal_linkedlist_stll *cols, int searchin,
+                    int ignorecase)
+{
+  int tabletype;
+  size_t numcols;
+  gal_data_t *allcols, *out=NULL;
+  struct gal_linkedlist_sll *indexll;
+
+  /* First get the information of all the columns. */
+  allcols=gal_table_info(filename, hdu, &numcols, &tabletype);
+
+  /* Get the list of indexs in the same order as the input list */
+  indexll=make_list_of_indexs(cols, allcols, numcols, searchin,
+                              ignorecase, filename, hdu);
+
+  gal_linkedlist_print_sll(indexll);
+
+  /* Reverse the list of indexs so the data structure linked list will be
+     in the same order as the input list of columns.
+  while(indexll!=NULL)
+    {
+
+    }
+  */
+  printf("\n\n-----\ntmp stop.\n\n");
+  exit(0);
+  return out;
+}
diff --git a/lib/txt.c b/lib/txt.c
index 98147ee..696e18b 100644
--- a/lib/txt.c
+++ b/lib/txt.c
@@ -1,5 +1,5 @@
 /*********************************************************************
-txt -- Functions for I/O on text files.
+txt -- functions to deal with plain text files.
 This is part of GNU Astronomy Utilities (Gnuastro) package.
 
 Original author:
@@ -27,23 +27,15 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 #include <error.h>
 #include <stdlib.h>
 
-#include <gnuastro/data.h>
+#include <gnuastro/txt.h>
 
 
-/* Read the specified columns in a text file (named `filename' into an
-   array of data. The desired columns should be specified by the `cols'
-   array. Like a character string, the last element of this array is unique
-   and will mark its end. The unique value is `-1' (which is the largest
-   possible number in `size_t', since size_t is unsigned.
-
-   When the first element of the cols array is `-1', this function will
-   read all the columns from the text file and put the number of columns in
-   the space pointed to by `cols' (thus replacing the `-1' value). Note
-   that the number of rows is stored within each data element.*/
+/************************************************************************/
+/***************     Information about a txt table        ***************/
+/************************************************************************/
 gal_data_t *
-gal_txt_read_cols(char *filename, size_t *cols)
+gal_txt_table_info(char *filename, size_t *numcols)
 {
-  gal_data_t *out=NULL;
 
-  return out;
+  return NULL;
 }



reply via email to

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