gnuastro-commits
[Top][All Lists]
Advanced

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

[gnuastro-commits] master c4979d7: Table: New --sort and --range columns


From: Mohammad Akhlaghi
Subject: [gnuastro-commits] master c4979d7: Table: New --sort and --range columns to select/modify rows
Date: Sun, 10 Mar 2019 21:16:14 -0400 (EDT)

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

    Table: New --sort and --range columns to select/modify rows
    
    Until now, the Table program could only select certain input columns for
    the output which was not convenient when you only need a subsection of them
    and want to preserve the metadata (so a simple AWK call isn't an
    option). With these two options, the output rows of Table can also be
    selected and modified.
    
    To enable this easily, the old `gal_qsort_index_single_i' and
    `gal_qsort_index_single_d' functions have been generalized to accommodate
    all numeric data types.
---
 NEWS                            |  20 ++
 bin/table/args.h                |  40 ++++
 bin/table/main.h                |  18 +-
 bin/table/table.c               | 235 +++++++++++++++++++++-
 bin/table/ui.c                  | 432 +++++++++++++++++++++++++++++++++++++++-
 bin/table/ui.h                  |  10 +-
 doc/gnuastro.texi               | 115 ++++++++---
 lib/gnuastro-internal/options.h |   4 +
 lib/gnuastro/qsort.h            |  60 +++++-
 lib/gnuastro/table.h            |   5 +
 lib/label.c                     |   4 +-
 lib/options.c                   |  85 ++++++++
 lib/qsort.c                     | 158 ++++++++++++++-
 lib/table.c                     |  23 ++-
 14 files changed, 1152 insertions(+), 57 deletions(-)

diff --git a/NEWS b/NEWS
index 27d1b0b..acf16eb 100644
--- a/NEWS
+++ b/NEWS
@@ -85,13 +85,28 @@ GNU Astronomy Utilities NEWS                          -*- 
outline -*-
   Statistics:
    --interpmetric: Similar to NoiseChisel.
 
+  Table:
+   --range: Limit the output rows to those with a value within the given
+     numeric range with this format: `--range=COL,low,high'. This is very
+     useful when only certain rows of the input are required not the
+     output. The advantage over pipeing to AWK is that you can save the
+     output directly to FITS (preserving the metadata). See the book for
+     more.
+   --sort: Sort the output rows based on the value of the given column in
+     ascending order.
+   --descending: When called with `--sort', will arrange the output rows in
+     decending order.
+
   Library:
     GAL_BLANK_LONG: new macro for the `long' type blank value.
     GAL_BLANK_ULONG: new macro for the `unsigned long' type blank value.
     gal_blank_number: Return the number of blank elements in a dataset.
     gal_dimension_dist_radial: Radial distance between two coordinates.
+    gal_qsort_index_single_TYPE_i: Set of functions to sort indexs ascending.
+    gal_qsort_index_single_TYPE_d: Set of functions to sort indexs descending.
     gal_statistics_outlier_cumulative: Uses flatness of the cumulative
        distribution to find outliers.
+    gal_table_list_of_indexs: returns the list of indexs matching columns.
     gal_type_is_int: to see if we have an integer (any width, any sign).
 
 ** Removed features
@@ -130,6 +145,11 @@ GNU Astronomy Utilities NEWS                          -*- 
outline -*-
   Statistics:
    --ignoreblankintiles: similar to same option in NoiseChisel.
 
+  Table:
+   --colinfoinstdout: now corresponds to the `-O' short option. Until this
+     version, the `-s' short option was used for it. But with the new
+     `--sort' option, `-s' may cause confusion.
+
 ** Bugs fixed
   bug #55313: Fits program writing --write values in reverse order
   bug #55333: Fits program crash when --write or --update have no value.
diff --git a/bin/table/args.h b/bin/table/args.h
index afb9bde..4c151d1 100644
--- a/bin/table/args.h
+++ b/bin/table/args.h
@@ -76,6 +76,46 @@ struct argp_option program_options[] =
       GAL_OPTIONS_NOT_MANDATORY,
       GAL_OPTIONS_NOT_SET
     },
+    {
+      "range",
+      UI_KEY_RANGE,
+      "STR,FLT:FLT",
+      0,
+      "Column, and range to limit output.",
+      GAL_OPTIONS_GROUP_OUTPUT,
+      &p->range,
+      GAL_TYPE_STRING,
+      GAL_OPTIONS_RANGE_ANY,
+      GAL_OPTIONS_NOT_MANDATORY,
+      GAL_OPTIONS_NOT_SET,
+      gal_options_parse_name_and_values
+    },
+    {
+      "sort",
+      UI_KEY_SORT,
+      "STR,INT",
+      0,
+      "Column name or number for sorting.",
+      GAL_OPTIONS_GROUP_OUTPUT,
+      &p->sort,
+      GAL_TYPE_STRING,
+      GAL_OPTIONS_RANGE_ANY,
+      GAL_OPTIONS_NOT_MANDATORY,
+      GAL_OPTIONS_NOT_SET
+    },
+    {
+      "descending",
+      UI_KEY_DESCENDING,
+      0,
+      0,
+      "Sort in descending order: largets first.",
+      GAL_OPTIONS_GROUP_OUTPUT,
+      &p->descending,
+      GAL_OPTIONS_NO_ARG_TYPE,
+      GAL_OPTIONS_RANGE_0_OR_1,
+      GAL_OPTIONS_NOT_MANDATORY,
+      GAL_OPTIONS_NOT_SET
+    },
 
 
 
diff --git a/bin/table/main.h b/bin/table/main.h
index bc9af45..f3e4bb7 100644
--- a/bin/table/main.h
+++ b/bin/table/main.h
@@ -37,6 +37,14 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 
 
 
+struct list_range
+{
+  gal_data_t           *v;
+  struct list_range *next;
+};
+
+
+
 
 
 /* Main program parameters structure */
@@ -48,10 +56,18 @@ struct tableparams
   gal_list_str_t     *columns;  /* List of given columns.               */
   uint8_t         information;  /* ==1: only print FITS information.    */
   uint8_t     colinfoinstdout;  /* ==1: print column metadata in CL.    */
+  gal_data_t           *range;  /* Range to limit output.               */
+  char                  *sort;  /* Column name or number for sorting.   */
+  uint8_t          descending;  /* Sort columns in descending order.    */
 
-  /* Output: */
+  /* Internal. */
   gal_data_t           *table;  /* Linked list of output table columns. */
   gal_data_t      *allcolinfo;  /* Information of all the columns.      */
+  gal_data_t         *sortcol;  /* Column to define a sorting.          */
+  struct list_range *rangecol;  /* Column to define a range.            */
+  uint8_t            freesort;  /* If the sort column should be freed.  */
+  uint8_t          *freerange;  /* If the range column should be freed. */
+  uint8_t              sortin;  /* If the sort column is in the output. */
   time_t              rawtime;  /* Starting time of the program.        */
 };
 
diff --git a/bin/table/table.c b/bin/table/table.c
index 2c9b54c..1b5008c 100644
--- a/bin/table/table.c
+++ b/bin/table/table.c
@@ -29,12 +29,239 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 #include <stdlib.h>
 #include <unistd.h>
 
+#include <gsl/gsl_heapsort.h>
+
 #include <gnuastro/fits.h>
 #include <gnuastro/table.h>
+#include <gnuastro/qsort.h>
+#include <gnuastro/arithmetic.h>
+#include <gnuastro/statistics.h>
+#include <gnuastro/permutation.h>
 
 #include <gnuastro-internal/checkset.h>
 
 #include "main.h"
+#include "ui.h"
+
+
+
+/**************************************************************/
+/********     Selecting and ordering of columns      **********/
+/**************************************************************/
+static void
+table_apply_permutation(gal_data_t *table, size_t *permutation,
+                        size_t newsize, int inverse)
+{
+  gal_data_t *tmp;
+
+  for(tmp=table;tmp!=NULL;tmp=tmp->next)
+    {
+      /* Apply the permutation. */
+      if(inverse)
+        gal_permutation_apply_inverse(tmp, permutation);
+      else
+        gal_permutation_apply(tmp, permutation);
+
+      /* Correct the size. */
+      tmp->size=tmp->dsize[0]=newsize;
+    }
+}
+
+
+
+
+
+static void
+table_range(struct tableparams *p)
+{
+  uint8_t *u;
+  double *rarr;
+  gal_data_t *mask;
+  struct list_range *tmp;
+  gal_data_t *ref, *perm, *range;
+  size_t i, g, b, *s, *sf, one=1, ngood=0;
+  gal_data_t *min, *max, *ltmin, *gemax, *sum;
+
+  int numok=GAL_ARITHMETIC_NUMOK;
+  int inplace=GAL_ARITHMETIC_INPLACE;
+
+  /* Allocate datasets for the necessary numbers and write them in. */
+  min=gal_data_alloc(NULL, GAL_TYPE_FLOAT64, 1, &one, NULL, 0, -1,
+                     NULL, NULL, NULL);
+  max=gal_data_alloc(NULL, GAL_TYPE_FLOAT64, 1, &one, NULL, 0, -1,
+                     NULL, NULL, NULL);
+  perm=gal_data_alloc(NULL, GAL_TYPE_SIZE_T, 1, p->table->dsize, NULL, 0,
+                      p->cp.minmapsize, NULL, NULL, NULL);
+  mask=gal_data_alloc(NULL, GAL_TYPE_UINT8, 1, p->table->dsize, NULL, 1,
+                      p->cp.minmapsize, NULL, NULL, NULL);
+
+  /* Go over all the necessary range options. */
+  range=p->range;
+  for(tmp=p->rangecol;tmp!=NULL;tmp=tmp->next)
+    {
+      /* Set the minimum and maximum values. */
+      rarr=range->array;
+      ((double *)(min->array))[0] = rarr[0];
+      ((double *)(max->array))[0] = rarr[1];
+
+      /* Set the reference column to read values from. */
+      ref=tmp->v;
+
+      /* Find all the bad elements (smaller than the minimum and larger than
+         the maximum) so we can flag them. */
+      ltmin=gal_arithmetic(GAL_ARITHMETIC_OP_LT, numok,   ref,   min);
+      gemax=gal_arithmetic(GAL_ARITHMETIC_OP_GE, numok,   ref,   max);
+      ltmin=gal_arithmetic(GAL_ARITHMETIC_OP_OR, inplace, ltmin, gemax);
+
+      /* Add these flags to all previous flags. */
+      mask=gal_arithmetic(GAL_ARITHMETIC_OP_OR, inplace, mask, ltmin);
+
+      /* For a check.
+      {
+        float *f=ref->array;
+        uint8_t *m=mask->array;
+        uint8_t *u=ltmin->array, *uf=u+ltmin->size;
+        printf("\n\nInput column: %s\n", ref->name ? ref->name : "No Name");
+        printf("Range: %g, %g\n", rarr[0], rarr[1]);
+        printf("%-20s%-20s%-20s\n", "Value", "This mask",
+               "Including previous");
+        do printf("%-20f%-20u%-20u\n", *f++, *u++, *m++); while(u<uf);
+        exit(0);
+      }
+      */
+
+      /* Clean up. */
+      gal_data_free(ltmin);
+      gal_data_free(gemax);
+
+      /* Increment pointers. */
+      range=range->next;
+    }
+
+  /* Count the number of bad elements. */
+  sum=gal_statistics_sum(mask);
+  ngood = p->table->size - ((double *)(sum->array))[0];
+
+  /* Define the permutation: elements within range remain on the top of
+     the list, while the ones outside of will be placed after them
+     (starting from the index after the last good one). */
+  g=0;          /* Good indexs (starting from 0). */
+  b=ngood;      /* Bad indexs (starting from total number of good). */
+  u=mask->array;
+  sf=(s=perm->array)+perm->size;
+  do *s = *u++ ? b++ : g++; while(++s<sf);
+
+  /* For a check
+  {
+    size_t i;
+    double *v=ref->array;
+    uint8_t *a=mask->array;
+    printf("ref->type: %s\n", gal_type_name(ref->type, 1));
+    for(i=0;i<ref->size;++i) printf("%u, %g\n", a[i], v[i]);
+    gal_permutation_check(perm->array, perm->size);
+  }
+  */
+
+  /* Apply the final permutation to the whole table. */
+  table_apply_permutation(p->table, perm->array, ngood, 1);
+
+  /* If the sort column is not in the table (the proper range has already
+     been applied to it), and we need to sort the resulting columns
+     afterwards, we should also apply the permutation on the sort
+     column. */
+  if(p->sortcol && p->sortin==0)
+    table_apply_permutation(p->sortcol, perm->array, ngood, 1);
+
+  /* Clean up. */
+  i=0;
+  for(tmp=p->rangecol;tmp!=NULL;tmp=tmp->next)
+    { if(p->freerange[i]) {gal_data_free(tmp->v); tmp->v=NULL;} ++i; }
+  ui_list_range_free(p->rangecol, 0);
+  gal_data_free(mask);
+  gal_data_free(perm);
+  gal_data_free(sum);
+  gal_data_free(min);
+  gal_data_free(max);
+  free(p->freerange);
+}
+
+
+
+
+
+static void
+table_sort(struct tableparams *p)
+{
+  gal_data_t *perm;
+  size_t c=0, *s, *sf;
+  int (*qsortfn)(const void *, const void *)=NULL;
+
+  /* In case there are no columns to sort, skip this function. */
+  if(p->table->size==0) return;
+
+  /* Allocate the permutation array and fill it. */
+  perm=gal_data_alloc(NULL, GAL_TYPE_SIZE_T, 1, p->table->dsize, NULL, 0,
+                      p->cp.minmapsize, NULL, NULL, NULL);
+  sf=(s=perm->array)+perm->size; do *s=c++; while(++s<sf);
+
+  /* Set the proper qsort function. */
+  if(p->descending)
+    switch(p->sortcol->type)
+      {
+      case GAL_TYPE_UINT8:   qsortfn=gal_qsort_index_single_uint8_d;   break;
+      case GAL_TYPE_INT8:    qsortfn=gal_qsort_index_single_int8_d;    break;
+      case GAL_TYPE_UINT16:  qsortfn=gal_qsort_index_single_uint16_d;  break;
+      case GAL_TYPE_INT16:   qsortfn=gal_qsort_index_single_int16_d;   break;
+      case GAL_TYPE_UINT32:  qsortfn=gal_qsort_index_single_uint32_d;  break;
+      case GAL_TYPE_INT32:   qsortfn=gal_qsort_index_single_int32_d;   break;
+      case GAL_TYPE_UINT64:  qsortfn=gal_qsort_index_single_uint64_d;  break;
+      case GAL_TYPE_INT64:   qsortfn=gal_qsort_index_single_int64_d;   break;
+      case GAL_TYPE_FLOAT32: qsortfn=gal_qsort_index_single_float32_d; break;
+      case GAL_TYPE_FLOAT64: qsortfn=gal_qsort_index_single_float64_d; break;
+      default:
+        error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at %s to fix "
+              "the problem. The code `%u' wasn't recognized as a data type",
+              __func__, PACKAGE_BUGREPORT, p->sortcol->type);
+      }
+  else
+    switch(p->sortcol->type)
+      {
+      case GAL_TYPE_UINT8:   qsortfn=gal_qsort_index_single_uint8_i;   break;
+      case GAL_TYPE_INT8:    qsortfn=gal_qsort_index_single_int8_i;    break;
+      case GAL_TYPE_UINT16:  qsortfn=gal_qsort_index_single_uint16_i;  break;
+      case GAL_TYPE_INT16:   qsortfn=gal_qsort_index_single_int16_i;   break;
+      case GAL_TYPE_UINT32:  qsortfn=gal_qsort_index_single_uint32_i;  break;
+      case GAL_TYPE_INT32:   qsortfn=gal_qsort_index_single_int32_i;   break;
+      case GAL_TYPE_UINT64:  qsortfn=gal_qsort_index_single_uint64_i;  break;
+      case GAL_TYPE_INT64:   qsortfn=gal_qsort_index_single_int64_i;   break;
+      case GAL_TYPE_FLOAT32: qsortfn=gal_qsort_index_single_float32_i; break;
+      case GAL_TYPE_FLOAT64: qsortfn=gal_qsort_index_single_float64_i; break;
+      default:
+        error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at %s to fix "
+              "the problem. The code `%u' wasn't recognized as a data type",
+              __func__, PACKAGE_BUGREPORT, p->sortcol->type);
+      }
+
+  /* Sort the indexs from the values. */
+  gal_qsort_index_single=p->sortcol->array;
+  qsort(perm->array, perm->size, sizeof *s, qsortfn);
+
+  /* For a check (only on float32 type `sortcol'):
+  {
+    float *f=p->sortcol->array;
+    sf=(s=perm->array)+perm->size;
+    do printf("%f\n", f[*s]); while(++s<sf);
+    exit(0);
+  }
+  */
+
+  /* Sort all the output columns with this permutation. */
+  table_apply_permutation(p->table, perm->array, perm->size, 0);
+
+  /* Clean up. */
+  gal_data_free(perm);
+  if(p->freesort) gal_data_free(p->sortcol);
+}
 
 
 
@@ -46,7 +273,13 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 void
 table(struct tableparams *p)
 {
-  gal_checkset_writable_remove(p->cp.output, 0, p->cp.dontdelete);
+  /* Apply a certain range (if required) to the output sample. */
+  if(p->range) table_range(p);
+
+  /* Sort it (if required). */
+  if(p->sort) table_sort(p);
+
+  /* Write the output. */
   gal_table_write(p->table, NULL, p->cp.tableformat, p->cp.output,
                   "TABLE", p->colinfoinstdout);
 }
diff --git a/bin/table/ui.c b/bin/table/ui.c
index ddac7e4..2fe3058 100644
--- a/bin/table/ui.c
+++ b/bin/table/ui.c
@@ -26,9 +26,11 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 #include <errno.h>
 #include <error.h>
 #include <stdio.h>
+#include <string.h>
 
 #include <gnuastro/fits.h>
 #include <gnuastro/table.h>
+#include <gnuastro/pointer.h>
 
 #include <gnuastro-internal/timing.h>
 #include <gnuastro-internal/options.h>
@@ -113,7 +115,6 @@ ui_initialize_options(struct tableparams *p,
   cp->program_authors    = PROGRAM_AUTHORS;
   cp->coptions           = gal_commonopts_options;
 
-
   /* Modify common options. */
   for(i=0; !gal_options_is_last(&cp->coptions[i]); ++i)
     {
@@ -217,11 +218,28 @@ parse_opt(int key, char *arg, struct argp_state *state)
 static void
 ui_read_check_only_options(struct tableparams *p)
 {
+  double *darr;
+  gal_data_t *tmp;
 
   /* Check if the format of the output table is valid, given the type of
      the output. */
   gal_tableintern_check_fits_format(p->cp.output, p->cp.tableformat);
 
+  /* Some checks on `--range'. */
+  if(p->range)
+    for(tmp=p->range;tmp!=NULL;tmp=tmp->next)
+      {
+        /* Range needs two input numbers. */
+        if(tmp->size!=2)
+          error(EXIT_FAILURE, 0, "two values (separated by comma) necessary "
+                "for `--range' in this format: `--range=COLUMN,min,max'");
+
+        /* The first must be smaller than the second. */
+        darr=tmp->array;
+        if( darr[0] > darr[1] )
+          error(EXIT_FAILURE, 0, "first value (%g) given to `--range' must "
+                "be smaller than the second (%g)", darr[0], darr[1]);
+      }
 }
 
 
@@ -261,6 +279,98 @@ ui_check_options_and_arguments(struct tableparams *p)
 
 
 
+/**************************************************************/
+/***************   List of range datasets   *******************/
+/**************************************************************/
+static void
+ui_list_range_add(struct list_range **list, gal_data_t *dataset)
+{
+  struct list_range *newnode;
+
+  errno=0;
+  newnode=malloc(sizeof *newnode);
+  if(newnode==NULL)
+    error(EXIT_FAILURE, errno, "%s: allocating new node", __func__);
+
+  newnode->v=dataset;
+  newnode->next=*list;
+  *list=newnode;
+}
+
+
+
+
+
+static gal_data_t *
+ui_list_range_pop(struct list_range **list)
+{
+  gal_data_t *out=NULL;
+  struct list_range *tmp;
+  if(*list)
+    {
+      tmp=*list;
+      out=tmp->v;
+      *list=tmp->next;
+      free(tmp);
+    }
+  return out;
+}
+
+
+
+
+
+static void
+ui_list_range_reverse(struct list_range **list)
+{
+  gal_data_t *thisdata;
+  struct list_range *correctorder=NULL;
+
+  /* Only do the reversal if there is more than one element. */
+  if( *list && (*list)->next )
+    {
+      while(*list!=NULL)
+        {
+          thisdata=ui_list_range_pop(list);
+          ui_list_range_add(&correctorder, thisdata);
+        }
+      *list=correctorder;
+    }
+}
+
+
+
+
+
+void
+ui_list_range_free(struct list_range *list, int freevalue)
+{
+  struct list_range *tmp;
+  while(list!=NULL)
+    {
+      tmp=list->next;
+      if(freevalue)
+        gal_data_free(list->v);
+      free(list);
+      list=tmp;
+    }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
 
 
 /**************************************************************/
@@ -273,7 +383,7 @@ ui_print_info_exit(struct tableparams *p)
   int tableformat;
   gal_data_t *allcols;
   gal_list_str_t *lines;
-  size_t i, numcols, numrows;
+  size_t numcols, numrows;
 
   /* Read the table information for the number of columns and rows. */
   lines=gal_options_check_stdin(p->filename, p->cp.stdintimeout, "input");
@@ -299,9 +409,7 @@ ui_print_info_exit(struct tableparams *p)
 
 
   /* Free the information from all the columns. */
-  for(i=0;i<numcols;++i)
-    gal_data_free_contents(&allcols[i]);
-  free(allcols);
+  gal_data_array_free(allcols, numcols, 0);
 
 
   /* Free the allocated spaces and exit. Otherwise, add the number of
@@ -359,38 +467,348 @@ ui_columns_prepare(struct tableparams *p)
 
 
 
+/* The users give column numbers counting from 1. But we need an `index'
+   (starting from 0). So if we can read it as a number, we'll subtract one
+   from it. */
+static size_t
+ui_check_range_sort_read_col_ind(char *string)
+{
+  size_t out;
+  void *ptr=&out;
+
+  if( gal_type_from_string(&ptr, string, GAL_TYPE_SIZE_T) )
+    out=GAL_BLANK_SIZE_T;
+  else out-=1;
+
+  return out;
+}
+
+
+
+
+
+/* See if the `--range' and `--sort' columns should also be added. */
+static void
+ui_check_range_sort_before(struct tableparams *p, gal_list_str_t *lines,
+                           size_t *nrange, size_t *origoutncols,
+                           size_t *sortindout, size_t **rangeindout_out)
+{
+  size_t *rangeindout;
+  size_t *rangeind=NULL;
+  gal_data_t *dtmp, *allcols;
+  int tableformat, rangehasname=0;
+  gal_list_sizet_t *tmp, *indexll;
+  gal_list_str_t *stmp, *add=NULL;
+  size_t i, j, *s, *sf, allncols, numcols, numrows, sortind;
+
+
+  /* Allocate necessary spaces. */
+  if(p->range)
+    {
+      *nrange=gal_list_data_number(p->range);
+      rangeind=gal_pointer_allocate(GAL_TYPE_SIZE_T, *nrange, 0,
+                                    __func__, "rangeind");
+      rangeindout=gal_pointer_allocate(GAL_TYPE_SIZE_T, *nrange, 0,
+                                        __func__, "rangeindout");
+      sf=(s=rangeindout)+*nrange; do *s++=GAL_BLANK_SIZE_T; while(s<sf);
+      *rangeindout_out=rangeindout;
+    }
+
+
+  /* See if the given columns are numbers or names. */
+  i=0;
+  if(p->sort)  sortind  = ui_check_range_sort_read_col_ind(p->sort);
+  if(p->range)
+    for(dtmp=p->range;dtmp!=NULL;dtmp=dtmp->next)
+      {
+        rangeind[i] = ui_check_range_sort_read_col_ind(dtmp->name);
+        ++i;
+      }
+
+
+  /* Get all the column information. */
+  allcols=gal_table_info(p->filename, p->cp.hdu, lines, &numcols,
+                         &numrows, &tableformat);
+
+
+  /* If the values are numbers, we'll check if the given value is less than
+     the total number of columns. Just note that the indexs count from
+     zero. */
+  if(p->sort && sortind!=GAL_BLANK_SIZE_T && sortind>=numcols)
+    error(EXIT_FAILURE, 0, "%s has %zu columns, less than the column "
+          "number given to  `--sort' (%s)",
+          gal_fits_name_save_as_string(p->filename, p->cp.hdu), numcols,
+          p->sort);
+  if(p->range)
+    for(i=0;i<*nrange;++i)
+      if(rangeind[i]!=GAL_BLANK_SIZE_T && rangeind[i]>=numcols)
+        error(EXIT_FAILURE, 0, "%s has %zu columns, less than the column "
+              "number given to  `--range' (%zu)",
+              gal_fits_name_save_as_string(p->filename, p->cp.hdu), numcols,
+              rangeind[i]);
+
+
+  /* If any of the columns isn't specified by an index, go over the table
+     information and set the index based on the names. */
+  if(p->range)
+    for(i=0;i<*nrange;++i)
+      if(rangeind[i]==GAL_BLANK_SIZE_T) { rangehasname=1; break; }
+  if( (p->sort && sortind==GAL_BLANK_SIZE_T) || rangehasname )
+    {
+      /* Go over all the columns, and if they have a name, see if their
+         names matches the requested name. */
+      for(i=0;i<numcols;++i)
+        if(allcols[i].name)
+          {
+            if(p->sort && sortind==GAL_BLANK_SIZE_T)
+              {if( !strcasecmp(allcols[i].name, p->sort) ) sortind=i; }
+
+            if(p->range)
+              {
+                j=0;
+                for(dtmp=p->range;dtmp!=NULL;dtmp=dtmp->next)
+                  {
+                    if(rangeind[j]==GAL_BLANK_SIZE_T)
+                      {
+                        if( !strcasecmp(allcols[i].name, dtmp->name) )
+                          { rangeind[j]=i; break; }
+                      }
+                    ++j;
+                  }
+              }
+          }
+    }
+
+
+  /* Both columns must be good indexs now, if they aren't the user didn't
+     specify the name properly and the program must abort. */
+  if( p->sort && sortind==GAL_BLANK_SIZE_T )
+    error(EXIT_FAILURE, 0, "%s: no column named `%s' (value to `--sort') "
+          "you can either specify a name or number",
+          gal_fits_name_save_as_string(p->filename, p->cp.hdu), p->sort);
+  if(p->range)
+    for(i=0;i<*nrange;++i)
+      if(rangeind[i]==GAL_BLANK_SIZE_T)
+        error(EXIT_FAILURE, 0, "%s: no column named `%s' (value to "
+              "`--range') you can either specify a name or number",
+              gal_fits_name_save_as_string(p->filename, p->cp.hdu), p->sort);
+
+
+  /* See which columns the user has asked for. */
+  indexll=gal_table_list_of_indexs(p->columns, allcols, numcols,
+                                   p->cp.searchin, p->cp.ignorecase,
+                                   p->filename, p->cp.hdu, NULL);
+  allncols=*origoutncols=gal_list_sizet_number(indexll);
+
+
+  /* See if the requested columns are already on the to-read list. If so,
+     keep the counter. */
+  i=0;
+  for(tmp=indexll; tmp!=NULL; tmp=tmp->next)
+    {
+      if(p->sort  && *sortindout==GAL_BLANK_SIZE_T  && tmp->v == sortind)
+        *sortindout=i;
+      if(p->range)
+        for(j=0;j<*nrange;++j)
+          if(rangeindout[j]==GAL_BLANK_SIZE_T && tmp->v==rangeind[j])
+            rangeindout[j]=i;
+      ++i;
+    }
+
+
+  /* See if any of the necessary columns (for `--sort' and `--range')
+     aren't requested as an output by the user. If there is any, such
+     columns, keep them here. */
+  if( p->sort && *sortindout==GAL_BLANK_SIZE_T )
+    { *sortindout=allncols++;  gal_list_str_add(&add, p->sort, 0); }
+
+
+  /* Note that the sorting and range may be requested on the same
+     column. In this case, we don't want to read the same column twice. */
+  if(p->range)
+    {
+      i=0;
+      for(dtmp=p->range;dtmp!=NULL;dtmp=dtmp->next)
+        {
+          if(*sortindout!=GAL_BLANK_SIZE_T
+             && rangeindout[i]==*sortindout)
+            rangeindout[i]=*sortindout;
+          else
+            {
+              if( rangeindout[i]==GAL_BLANK_SIZE_T )
+                {
+                  rangeindout[i]=allncols++;
+                  gal_list_str_add(&add, dtmp->name, 0);
+                }
+            }
+          ++i;
+        }
+    }
+
+
+  /* Add the possibly new set of columns to read. */
+  if(add)
+    {
+      gal_list_str_reverse(&add);
+      for(stmp=p->columns; stmp!=NULL; stmp=stmp->next)
+        if(stmp->next==NULL) { stmp->next=add; break; }
+    }
+
+
+  /* Clean up. */
+  if(rangeind) free(rangeind);
+  gal_list_sizet_free(indexll);
+  gal_data_array_free(allcols, numcols, 0);
+}
+
+
+
+
+
+static void
+ui_check_range_sort_after(struct tableparams *p, size_t nrange,
+                          size_t origoutncols, size_t sortindout,
+                          size_t *rangeindout)
+{
+  gal_data_t *tmp, *last;
+  struct list_range *rtmp;
+  size_t i, j, *rangein=NULL;
+
+  /* Allocate the necessary arrays. */
+  if(p->range)
+    {
+      rangein=gal_pointer_allocate(GAL_TYPE_UINT8, nrange, 0,
+                                   __func__, "rangein");
+      p->freerange=gal_pointer_allocate(GAL_TYPE_UINT8, nrange, 1,
+                                        __func__, "p->freerange");
+    }
+
+
+  /* Set the proper pointers. For `rangecol' we'll need to do it separately
+     (because the orders can get confused).*/
+  i=0;
+  for(tmp=p->table; tmp!=NULL; tmp=tmp->next)
+    {
+      if(i==origoutncols-1)           last=tmp;
+      if(p->sort && i==sortindout) p->sortcol=tmp;
+      ++i;
+    }
+
+
+  /* Find the range columns. */
+  for(i=0;i<nrange;++i)
+    {
+      j=0;
+      for(tmp=p->table; tmp!=NULL; tmp=tmp->next)
+        {
+          if(j==rangeindout[i])
+            {
+              ui_list_range_add(&p->rangecol, tmp);
+              break;
+            }
+          ++j;
+        }
+    }
+  ui_list_range_reverse(&p->rangecol);
+
+
+  /* Terminate the actual table where it should be terminated (by setting
+     `last->next' to NULL. */
+  last->next=NULL;
+
+
+  /*  Also, remove any possibly existing `next' pointer for `sortcol' and
+     `rangecol'. */
+  if(p->sort && sortindout>=origoutncols)
+    { p->sortcol->next=NULL;  p->freesort=1; }
+  else p->sortin=1;
+  if(p->range)
+    {
+      i=0;
+      for(rtmp=p->rangecol;rtmp!=NULL;rtmp=rtmp->next)
+        {
+          if(rangeindout[i]>=origoutncols)
+            {
+              rtmp->v->next=NULL;
+              p->freerange[i] = (rtmp->v==p->sortcol) ? 0 : 1;
+            }
+          else rangein[i]=1;
+          ++i;
+        }
+    }
+
+
+  /* Clean up. */
+  if(rangein) free(rangein);
+}
+
+
+
+
+
+
 static void
 ui_preparations(struct tableparams *p)
 {
   gal_list_str_t *lines;
+  size_t nrange, origoutncols;
   struct gal_options_common_params *cp=&p->cp;
+  size_t sortindout=GAL_BLANK_SIZE_T, *rangeindout=NULL;
 
   /* If there were no columns specified or the user has asked for
      information on the columns, we want the full set of columns. */
   if(p->information)
     ui_print_info_exit(p);
 
+
   /* Prepare the column names. */
   ui_columns_prepare(p);
 
-  /* Read in the table columns. */
+
+  /* If the input is from stdin, save it as `lines'. */
   lines=gal_options_check_stdin(p->filename, p->cp.stdintimeout, "input");
+
+
+  /* If sort or range are given, see if we should read them also. */
+  if(p->range || p->sort)
+    ui_check_range_sort_before(p, lines, &nrange, &origoutncols, &sortindout,
+                               &rangeindout);
+
+
+  /* Read the necessary columns. */
   p->table=gal_table_read(p->filename, cp->hdu, lines, p->columns,
                           cp->searchin, cp->ignorecase, cp->minmapsize,
                           NULL);
-  if(p->filename==NULL) p->filename="Standard-input";
+  if(p->filename==NULL) p->filename="stdin";
   gal_list_str_free(lines, 1);
 
+
+  /* If the range and sort options are requested, keep them as separate
+     datasets. */
+  if(p->range || p->sort)
+    ui_check_range_sort_after(p, nrange, origoutncols, sortindout,
+                              rangeindout);
+
+
   /* If there was no actual data in the file, then inform the user and
      abort. */
   if(p->table==NULL)
     error(EXIT_FAILURE, 0, "%s: no usable data rows (non-commented and "
           "non-blank lines)", p->filename);
 
+
   /* Now that the data columns are ready, we can free the string linked
      list. */
   gal_list_str_free(p->columns, 1);
   p->columns=NULL;
+
+
+  /* Make sure the (possible) output name is writable. */
+  gal_checkset_writable_remove(p->cp.output, 0, p->cp.dontdelete);
+
+
+  /* Clean up. */
+  if(rangeindout) free(rangeindout);
 }
 
 
diff --git a/bin/table/ui.h b/bin/table/ui.h
index e1f0d84..da7fce7 100644
--- a/bin/table/ui.h
+++ b/bin/table/ui.h
@@ -32,7 +32,7 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 
 /* Available letters for short options:
 
-   a b d e f g j k l m n p r t u v w x y z
+   a b d e f g j k l m n p t u v w x y z
    A B C E G H J L O Q R W X Y
 */
 enum option_keys_enum
@@ -40,7 +40,10 @@ enum option_keys_enum
   /* With short-option version. */
   UI_KEY_COLUMN          = 'c',
   UI_KEY_INFORMATION     = 'i',
-  UI_KEY_COLINFOINSTDOUT = 's',
+  UI_KEY_COLINFOINSTDOUT = 'O',
+  UI_KEY_RANGE           = 'r',
+  UI_KEY_SORT            = 's',
+  UI_KEY_DESCENDING      = 'd',
 
   /* Only with long version (start with a value 1000, the rest will be set
      automatically). */
@@ -54,6 +57,9 @@ void
 ui_read_check_inputs_setup(int argc, char *argv[], struct tableparams *p);
 
 void
+ui_list_range_free(struct list_range *list, int freevalue);
+
+void
 ui_free_report(struct tableparams *p);
 
 #endif
diff --git a/doc/gnuastro.texi b/doc/gnuastro.texi
index 6f20a18..0da2040 100644
--- a/doc/gnuastro.texi
+++ b/doc/gnuastro.texi
@@ -11206,8 +11206,18 @@ $ asttable bintab.fits --information
 ## the name starts with "MAG_":
 $ asttable bintab.fits --column=RA --column=DEC --column=/^MAG_/
 
-## Similar to above, but with one call to --column (or -c) and writes
-## the columns to a file (with metadata) instead of the command-line.
+## Similar to the above, but with one call to `--column' (or `-c'),
+## also sort the rows by the input's photometric redshift (`Z_PHOT')
+## column. To confirm the sort, you can add `Z_PHOT' to the columns
+## to print.
+$ asttable bintab.fits -cRA,DEC,/^MAG_/ --sort=Z_PHOT
+
+## Similar to the above, but only print rows that have a photometric
+## redshift between 2 and 3.
+$ asttable bintab.fits -cRA,DEC,/^MAG_/ --range=Z_PHOT,2:3
+
+## Similar to above, but writes the columns to a file (with metadata)
+## instead of the command-line.
 $ asttable bintab.fits -cRA,DEC,/^MAG_/ --output=out.txt
 
 ## Only print the 2nd column, and the third column multiplied by 5:
@@ -11230,13 +11240,18 @@ $ asttable plaintext.txt --output=table.fits 
--tabletype=fits-binary
 
 Table's input dataset can be given either as a file or from Standard input
 (see @ref{Standard input}). In the absence of selected columns, all the
-input's columns will be written to the output. If the specified output is a
-FITS file, the type of FITS table (binary or ASCII) will be determined from
-the @option{--tabletype} option. If the output is not a FITS file, it will
-be printed as a plain text table (with space characters between the
-columns). When the columns are accompanied by meta-data (like column name,
-units, or comments), this information will also printed in the plain text
-file before the table, as described in @ref{Gnuastro text table format}.
+input's columns and rows will be written to the output. If any output file
+is explicity requested (with @option{--output}) the output table will be
+written in it. When no output file is explicitly requested the output table
+will be written to the standard output.
+
+If the specified output is a FITS file, the type of FITS table (binary or
+ASCII) will be determined from the @option{--tabletype} option. If the
+output is not a FITS file, it will be printed as a plain text table (with
+space characters between the columns). When the columns are accompanied by
+meta-data (like column name, units, or comments), this information will
+also printed in the plain text file before the table, as described in
address@hidden text table format}.
 
 For the full list of options common to all Gnuastro programs please see
 @ref{Common options}. Options can also be stored in directory, user or
@@ -11287,6 +11302,42 @@ 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 -O
address@hidden --colinfoinstdout
address@hidden Standard output
+Add column metadata when the output is printed in the standard
+output. Usually the standard output is used for a fast visual check or to
+pipe into other program for further processing. So by default meta-data
+aren't included.
+
address@hidden -r STR,FLT:FLT
address@hidden --range=STR,FLT:FLT
+Only print the output rows that have a value within the given range in the
address@hidden column (can be a name or counter). For example with
address@hidden,5:20} the output's columns will only contain rows that
+have a value between 5 and 20 in the @code{sn} column (not case-sensitive).
+
+This option can be called multiple times (different ranges for different
+columns) in one run of the Table program. This is very useful for selecting
+the final rows from multiple criteria/columns.
+
+The chosen column doesn't have to be in the output columns. This is good
+when you just want to select using one column's values, but don't need that
+column anymore afterwards.
+
address@hidden -s STR
address@hidden --sort=STR
+Sort the output rows based on the values in the @code{STR} column (can be a
+column name or number). By default the sort is done in ascending/increasing
+order, to sort in a descending order, use @option{--descending}.
+
+The chosen column doesn't have to be in the output columns. This is good
+when you just want to sort using one column's values, but don't need that
+column anymore afterwards.
+
address@hidden -d
address@hidden --descending
+When called with @option{--sort}, rows will be sorted in descending order.
 
 @end table
 
@@ -25668,6 +25719,14 @@ same number of elements as nodes in the @code{cols} 
list. The number of
 columns that matched each input column will be stored in each element.
 @end deftypefun
 
address@hidden {gal_list_sizet_t *} gal_table_list_of_indexs (gal_list_str_t 
@code{*cols}, gal_data_t @code{*allcols}, size_t @code{numcols}, int 
@code{searchin}, int @code{ignorecase}, char @code{*filename}, char 
@code{*hdu}, size_t @code{*colmatch})
+Returns a list of indexs (starting from 0) of the input columns that match
+the names/numbers given to @code{cols}. This is a low-level operation which
+is called by @code{gal_table_read} (described above), see there for more on
+each argument's description. @code{allcols} is the returned array of
address@hidden
address@hidden deftypefun
+
 @cindex Git
 @deftypefun void gal_table_comments_add_intro (gal_list_str_t 
@code{**comments}, char @code{*program_string}, time_t @code{*rawtime})
 Add some basic information to the list of @code{comments}. This basic
@@ -27977,13 +28036,14 @@ below.
 @deffn {Global variable} {gal_qsort_index_single}
 @cindex Thread-safety
 @cindex Multi-threaded operation
-Pointer to a floating point array (@code{float *}) to use as a reference in
address@hidden or @code{gal_qsort_index_single_i}, see the
-explanation of these functions for more. Note that if more than one array
-is to be sorted in a multi-threaded operation, the two functions will not
-work as expected. Therefore, if the operation is multi-threaded, but all
-the threads just sort the indexs based on a single array, this global
-variable can safely be used.
+Pointer to an array (for example @code{float *} or @code{int *}) to use as
+a reference in @code{gal_qsort_index_single_TYPE_d} or
address@hidden, see the explanation of these
+functions for more. Note that if @emph{more than one} array is to be sorted
+in a multi-threaded operation, these functions will not work as
+expected. However, when all the threads just sort the indexs based on a
address@hidden array}, this global variable can safely be used in a
+multi-threaded scenario.
 @end deffn
 
 @deftp {Type (C @code{struct})} gal_qsort_index_multi
@@ -28018,12 +28078,14 @@ types}, for example @code{gal_qsort_int32_i}, or
 @code{gal_qsort_float64_i}.
 @end deftypefun
 
address@hidden int gal_qsort_index_single_d (const void @code{*a}, const void 
@code{*b})
address@hidden int gal_qsort_index_single_TYPE_d (const void @code{*a}, const 
void @code{*b})
 When passed to @code{qsort}, this function will sort a @code{size_t} array
-based on decreasing values in the @code{gal_qsort_index_arr} single
-precision floating point array. The floating point array will not be
-changed, it is only read. For example, if we have the following source
-code:
+based on decreasing values in the @code{gal_qsort_index_single}. The global
address@hidden pointer has a @code{void *} pointer which
+will be cast to the proper type based on this function: for example
address@hidden will cast the array to an unsigned
+16-bit integer type. The array that @code{gal_qsort_index_single} points to
+will not be changed, it is only read. For example, see this demo program:
 
 @example
 #include <stdio.h>
@@ -28035,8 +28097,8 @@ main (void)
 @{
   size_t address@hidden, 1, 2, address@hidden;
   float address@hidden,0.2,1.8,address@hidden;
-  gal_qsort_index_arr=f;
-  qsort(s, 4, sizeof(size_t), gal_qsort_index_single_d);
+  gal_qsort_index_single=f;
+  qsort(s, 4, sizeof(size_t), gal_qsort_index_single_float_d);
   printf("%zu, %zu, %zu, %zu\n", s[0], s[1], s[2], s[3]);
   return EXIT_SUCCESS;
 @}
@@ -28046,9 +28108,10 @@ main (void)
 The output will be: @code{2, 0, 1, 3}.
 @end deftypefun
 
address@hidden int gal_qsort_index_single_i (const void @code{*a}, const void 
@code{*b})
-Similar to @code{gal_qsort_index_single_d}, but will sort the indexes such
-that the values of @code{gal_qsort_index_arr} are in increasing order.
address@hidden int gal_qsort_index_single_TYPE_i (const void @code{*a}, const 
void @code{*b})
+Similar to @code{gal_qsort_index_single_TYPE_d}, but will sort the indexes
+such that the values of @code{gal_qsort_index_single} can be parsed in
+increasing order.
 @end deftypefun
 
 @deftypefun int gal_qsort_index_multi_d (const void @code{*a}, const void 
@code{*b})
diff --git a/lib/gnuastro-internal/options.h b/lib/gnuastro-internal/options.h
index 2584ea9..ec5b4ed 100644
--- a/lib/gnuastro-internal/options.h
+++ b/lib/gnuastro-internal/options.h
@@ -304,6 +304,10 @@ void *
 gal_options_read_sigma_clip(struct argp_option *option, char *arg,
                             char *filename, size_t lineno, void *junk);
 
+void *
+gal_options_parse_name_and_values(struct argp_option *option, char *arg,
+                                  char *filename, size_t lineno, void *junk);
+
 
 /**********************************************************************/
 /************            Command-line options           ***************/
diff --git a/lib/gnuastro/qsort.h b/lib/gnuastro/qsort.h
index 2437b95..f7bd374 100644
--- a/lib/gnuastro/qsort.h
+++ b/lib/gnuastro/qsort.h
@@ -123,7 +123,7 @@ gal_qsort_float64_i(const void *a, const void *b);
 /* Pointer used to sort the indexs of an array based on their flux (value
    in this array). Note: when EACH THREAD USES A DIFFERENT ARRAY, this is
    not thread-safe . */
-extern float *gal_qsort_index_single;
+extern void *gal_qsort_index_single;
 
 
 /* When each thread is working on a different array, we'll need to keep the
@@ -136,10 +136,64 @@ struct gal_qsort_index_multi
 };
 
 int
-gal_qsort_index_single_d(const void *a, const void *b);
+gal_qsort_index_single_uint8_d(const void *a, const void *b);
 
 int
-gal_qsort_index_single_i(const void *a, const void *b);
+gal_qsort_index_single_uint8_i(const void *a, const void *b);
+
+int
+gal_qsort_index_single_int8_d(const void *a, const void *b);
+
+int
+gal_qsort_index_single_int8_i(const void *a, const void *b);
+
+int
+gal_qsort_index_single_uint16_d(const void *a, const void *b);
+
+int
+gal_qsort_index_single_uint16_i(const void *a, const void *b);
+
+int
+gal_qsort_index_single_int16_d(const void *a, const void *b);
+
+int
+gal_qsort_index_single_int16_i(const void *a, const void *b);
+
+int
+gal_qsort_index_single_uint32_d(const void *a, const void *b);
+
+int
+gal_qsort_index_single_uint32_i(const void *a, const void *b);
+
+int
+gal_qsort_index_single_int32_d(const void *a, const void *b);
+
+int
+gal_qsort_index_single_int32_i(const void *a, const void *b);
+
+int
+gal_qsort_index_single_uint64_d(const void *a, const void *b);
+
+int
+gal_qsort_index_single_uint64_i(const void *a, const void *b);
+
+int
+gal_qsort_index_single_int64_d(const void *a, const void *b);
+
+int
+gal_qsort_index_single_int64_i(const void *a, const void *b);
+
+int
+gal_qsort_index_single_float32_d(const void *a, const void *b);
+
+int
+gal_qsort_index_single_float32_i(const void *a, const void *b);
+
+int
+gal_qsort_index_single_float64_d(const void *a, const void *b);
+
+int
+gal_qsort_index_single_float64_i(const void *a, const void *b);
 
 int
 gal_qsort_index_multi_d(const void *a, const void *b);
diff --git a/lib/gnuastro/table.h b/lib/gnuastro/table.h
index ed183a9..bcb34f6 100644
--- a/lib/gnuastro/table.h
+++ b/lib/gnuastro/table.h
@@ -141,6 +141,11 @@ gal_table_read(char *filename, char *hdu, gal_list_str_t 
*lines,
                gal_list_str_t *cols, int searchin, int ignorecase,
                size_t minmapsize, size_t *colmatch);
 
+gal_list_sizet_t *
+gal_table_list_of_indexs(gal_list_str_t *cols, gal_data_t *allcols,
+                         size_t numcols, int searchin, int ignorecase,
+                         char *filename, char *hdu, size_t *colmatch);
+
 
 
 /************************************************************************/
diff --git a/lib/label.c b/lib/label.c
index 8d2e3a7..f22c564 100644
--- a/lib/label.c
+++ b/lib/label.c
@@ -246,7 +246,9 @@ gal_label_watershed(gal_data_t *values, gal_data_t *indexs,
     {
       gal_qsort_index_single=values->array;
       qsort(indexs->array, indexs->size, sizeof(size_t),
-            min0_max1 ? gal_qsort_index_single_d : gal_qsort_index_single_i);
+            ( min0_max1
+              ? gal_qsort_index_single_float32_d
+              : gal_qsort_index_single_float32_i) );
     }
 
 
diff --git a/lib/options.c b/lib/options.c
index 5e1d38a..8b34aea 100644
--- a/lib/options.c
+++ b/lib/options.c
@@ -595,6 +595,7 @@ gal_options_parse_list_of_numbers(char *string, char 
*filename, size_t lineno)
 
         /* Comma marks the transition to the next number. */
         case ',':
+        case ':':
           if(isnan(numerator))
             error_at_line(EXIT_FAILURE, 0, filename, lineno, "a number "
                           "must be given before `,'. You have given: `%s'",
@@ -1077,6 +1078,90 @@ gal_options_read_sigma_clip(struct argp_option *option, 
char *arg,
 
 
 
+/* Parse name and (float64) values:  name,value1,value2,value3,...
+
+   The output is a `gal_data_t', where the `name' is the given name and the
+   values are in its array (of `float64' type).
+ */
+void *
+gal_options_parse_name_and_values(struct argp_option *option, char *arg,
+                                  char *filename, size_t lineno, void *junk)
+{
+  size_t i, nc;
+  double *darray;
+  char *c, *name, *values;
+  gal_data_t *tmp, *existing, *dataset;
+  char *str, sstr[GAL_OPTIONS_STATIC_MEM_FOR_VALUES];
+
+  /* We want to print the stored values. */
+  if(lineno==-1)
+    {
+      /* Set the value pointer to `dataset'. */
+      existing=*(gal_data_t **)(option->value);
+      darray = existing->array;
+
+      /* First write the name. */
+      nc=0;
+      nc += sprintf(sstr+nc, "%s,", existing->name);
+
+      /* Write the values into a string. */
+      for(i=0;i<existing->size;++i)
+        {
+          if( nc > GAL_OPTIONS_STATIC_MEM_FOR_VALUES-100 )
+            error(EXIT_FAILURE, 0, "%s: a bug! please contact us at %s so we "
+                  "can address the problem. The number of necessary "
+                  "characters in the statically allocated string has become "
+                  "too close to %d", __func__, PACKAGE_BUGREPORT,
+                  GAL_OPTIONS_STATIC_MEM_FOR_VALUES);
+          nc += sprintf(sstr+nc, "%g,", darray[i]);
+        }
+      sstr[nc-1]='\0';
+
+      /* Copy the string into a dynamically allocated space, because it
+         will be freed later.*/
+      gal_checkset_allocate_copy(sstr, &str);
+      return str;
+    }
+  else
+    {
+      /* Parse until the comma or the end of the string.*/
+      c=arg; while(*c!='\0' && *c!=',') ++c;
+      values = (*c=='\0') ? NULL : c+1;
+
+      /* Name of the dataset (note that `c' is already pointing the end of
+         the `name' and `values' points to the next character). So we can
+         safely set `c' to `\0' to have the `name'. */
+      *c='\0';
+      gal_checkset_allocate_copy(arg, &name);
+
+      /* Read the values and write the name. */
+      dataset=gal_options_parse_list_of_numbers(values, filename, lineno);
+      dataset->name=name;
+
+      /* Add the given dataset to the end of an existing dataset. */
+      existing = *(gal_data_t **)(option->value);
+      if(existing)
+        {
+          for(tmp=existing;tmp!=NULL;tmp=tmp->next)
+            if(tmp->next==NULL) { tmp->next=dataset; break; }
+        }
+      else
+        *(gal_data_t **)(option->value) = dataset;
+
+      /* For a check.
+      printf("arg: %s\n", arg);
+      darray=dataset->array;
+      for(i=0;i<dataset->size;++i) printf("%f\n", darray[i]);
+      exit(0);
+      */
+
+      /* Our job is done, return NULL. */
+      return NULL;
+    }
+}
+
+
+
 
 
 
diff --git a/lib/qsort.c b/lib/qsort.c
index b7725c3..3bba8c6 100644
--- a/lib/qsort.c
+++ b/lib/qsort.c
@@ -188,21 +188,165 @@ gal_qsort_float64_i(const void *a, const void *b)
 /***************          Sorting indexs        ******************/
 /*****************************************************************/
 /* Initialize the array for sorting indexs to NULL. */
-float *gal_qsort_index_single=NULL;
+void *gal_qsort_index_single=NULL;
 
 int
-gal_qsort_index_single_d(const void *a, const void *b)
+gal_qsort_index_single_uint8_d(const void *a, const void *b)
 {
-  float ta=gal_qsort_index_single[ *(size_t *)a ];
-  float tb=gal_qsort_index_single[ *(size_t *)b ];
+  uint8_t ta=((uint8_t *)(gal_qsort_index_single))[ *(size_t *)a ];
+  uint8_t tb=((uint8_t *)(gal_qsort_index_single))[ *(size_t *)b ];
   return (tb > ta) - (tb < ta);
 }
 
 int
-gal_qsort_index_single_i(const void *a, const void *b)
+gal_qsort_index_single_uint8_i(const void *a, const void *b)
 {
-  float ta=gal_qsort_index_single[ *(size_t *)a ];
-  float tb=gal_qsort_index_single[ *(size_t *)b ];
+  uint8_t ta=((uint8_t *)(gal_qsort_index_single))[ *(size_t *)a ];
+  uint8_t tb=((uint8_t *)(gal_qsort_index_single))[ *(size_t *)b ];
+  return (ta > tb) - (ta < tb);
+}
+
+int
+gal_qsort_index_single_int8_d(const void *a, const void *b)
+{
+  int8_t ta=((int8_t *)(gal_qsort_index_single))[ *(size_t *)a ];
+  int8_t tb=((int8_t *)(gal_qsort_index_single))[ *(size_t *)b ];
+  return (tb > ta) - (tb < ta);
+}
+
+int
+gal_qsort_index_single_int8_i(const void *a, const void *b)
+{
+  int8_t ta=((int8_t *)(gal_qsort_index_single))[ *(size_t *)a ];
+  int8_t tb=((int8_t *)(gal_qsort_index_single))[ *(size_t *)b ];
+  return (ta > tb) - (ta < tb);
+}
+
+int
+gal_qsort_index_single_uint16_d(const void *a, const void *b)
+{
+  uint16_t ta=((uint16_t *)(gal_qsort_index_single))[ *(size_t *)a ];
+  uint16_t tb=((uint16_t *)(gal_qsort_index_single))[ *(size_t *)b ];
+  return (tb > ta) - (tb < ta);
+}
+
+int
+gal_qsort_index_single_uint16_i(const void *a, const void *b)
+{
+  uint16_t ta=((uint16_t *)(gal_qsort_index_single))[ *(size_t *)a ];
+  uint16_t tb=((uint16_t *)(gal_qsort_index_single))[ *(size_t *)b ];
+  return (ta > tb) - (ta < tb);
+}
+
+int
+gal_qsort_index_single_int16_d(const void *a, const void *b)
+{
+  int16_t ta=((int16_t *)(gal_qsort_index_single))[ *(size_t *)a ];
+  int16_t tb=((int16_t *)(gal_qsort_index_single))[ *(size_t *)b ];
+  return (tb > ta) - (tb < ta);
+}
+
+int
+gal_qsort_index_single_int16_i(const void *a, const void *b)
+{
+  int16_t ta=((int16_t *)(gal_qsort_index_single))[ *(size_t *)a ];
+  int16_t tb=((int16_t *)(gal_qsort_index_single))[ *(size_t *)b ];
+  return (ta > tb) - (ta < tb);
+}
+
+int
+gal_qsort_index_single_uint32_d(const void *a, const void *b)
+{
+  uint32_t ta=((uint32_t *)(gal_qsort_index_single))[ *(size_t *)a ];
+  uint32_t tb=((uint32_t *)(gal_qsort_index_single))[ *(size_t *)b ];
+  return (tb > ta) - (tb < ta);
+}
+
+int
+gal_qsort_index_single_uint32_i(const void *a, const void *b)
+{
+  uint32_t ta=((uint32_t *)(gal_qsort_index_single))[ *(size_t *)a ];
+  uint32_t tb=((uint32_t *)(gal_qsort_index_single))[ *(size_t *)b ];
+  return (ta > tb) - (ta < tb);
+}
+
+int
+gal_qsort_index_single_int32_d(const void *a, const void *b)
+{
+  int32_t ta=((int32_t *)(gal_qsort_index_single))[ *(size_t *)a ];
+  int32_t tb=((int32_t *)(gal_qsort_index_single))[ *(size_t *)b ];
+  return (tb > ta) - (tb < ta);
+}
+
+int
+gal_qsort_index_single_int32_i(const void *a, const void *b)
+{
+  int32_t ta=((int32_t *)(gal_qsort_index_single))[ *(size_t *)a ];
+  int32_t tb=((int32_t *)(gal_qsort_index_single))[ *(size_t *)b ];
+  return (ta > tb) - (ta < tb);
+}
+
+int
+gal_qsort_index_single_uint64_d(const void *a, const void *b)
+{
+  uint64_t ta=((uint64_t *)(gal_qsort_index_single))[ *(size_t *)a ];
+  uint64_t tb=((uint64_t *)(gal_qsort_index_single))[ *(size_t *)b ];
+  return (tb > ta) - (tb < ta);
+}
+
+int
+gal_qsort_index_single_uint64_i(const void *a, const void *b)
+{
+  uint64_t ta=((uint64_t *)(gal_qsort_index_single))[ *(size_t *)a ];
+  uint64_t tb=((uint64_t *)(gal_qsort_index_single))[ *(size_t *)b ];
+  return (ta > tb) - (ta < tb);
+}
+
+int
+gal_qsort_index_single_int64_d(const void *a, const void *b)
+{
+  int64_t ta=((int64_t *)(gal_qsort_index_single))[ *(size_t *)a ];
+  int64_t tb=((int64_t *)(gal_qsort_index_single))[ *(size_t *)b ];
+  return (tb > ta) - (tb < ta);
+}
+
+int
+gal_qsort_index_single_int64_i(const void *a, const void *b)
+{
+  int64_t ta=((int64_t *)(gal_qsort_index_single))[ *(size_t *)a ];
+  int64_t tb=((int64_t *)(gal_qsort_index_single))[ *(size_t *)b ];
+  return (ta > tb) - (ta < tb);
+}
+
+int
+gal_qsort_index_single_float32_d(const void *a, const void *b)
+{
+  float ta=((float *)(gal_qsort_index_single))[ *(size_t *)a ];
+  float tb=((float *)(gal_qsort_index_single))[ *(size_t *)b ];
+  return (tb > ta) - (tb < ta);
+}
+
+int
+gal_qsort_index_single_float32_i(const void *a, const void *b)
+{
+  float ta=((float *)(gal_qsort_index_single))[ *(size_t *)a ];
+  float tb=((float *)(gal_qsort_index_single))[ *(size_t *)b ];
+  return (ta > tb) - (ta < tb);
+}
+
+int
+gal_qsort_index_single_float64_d(const void *a, const void *b)
+{
+  double ta=((double *)(gal_qsort_index_single))[ *(size_t *)a ];
+  double tb=((double *)(gal_qsort_index_single))[ *(size_t *)b ];
+  return (tb > ta) - (tb < ta);
+}
+
+int
+gal_qsort_index_single_float64_i(const void *a, const void *b)
+{
+  double ta=((double *)(gal_qsort_index_single))[ *(size_t *)a ];
+  double tb=((double *)(gal_qsort_index_single))[ *(size_t *)b ];
   return (ta > tb) - (ta < tb);
 }
 
diff --git a/lib/table.c b/lib/table.c
index 82e02da..d6d82ce 100644
--- a/lib/table.c
+++ b/lib/table.c
@@ -210,10 +210,10 @@ table_set_strcheck(gal_data_t *col, int searchin)
 
 
 
-static gal_list_sizet_t *
-table_list_of_indexs(gal_list_str_t *cols, gal_data_t *allcols,
-                    size_t numcols, int searchin, int ignorecase,
-                    char *filename, char *hdu, size_t *colmatch)
+gal_list_sizet_t *
+gal_table_list_of_indexs(gal_list_str_t *cols, gal_data_t *allcols,
+                         size_t numcols, int searchin, int ignorecase,
+                         char *filename, char *hdu, size_t *colmatch)
 {
   long tlong;
   int regreturn;
@@ -375,10 +375,15 @@ table_list_of_indexs(gal_list_str_t *cols, gal_data_t 
*allcols,
     for(i=0;i<numcols;++i)
       gal_list_sizet_add(&indexll, i);
 
-
-
   /* Reverse the list. */
   gal_list_sizet_reverse(&indexll);
+
+  /* For a check.
+  gal_list_sizet_print(indexll);
+  exit(0);
+  */
+
+  /* Return the list. */
   return indexll;
 }
 
@@ -419,9 +424,9 @@ gal_table_read(char *filename, char *hdu, gal_list_str_t 
*lines,
   /* If there was no actual data in the file, then return NULL. */
   if(allcols==NULL) return NULL;
 
-  /* Get the list of indexs in the same order as the input list */
-  indexll=table_list_of_indexs(cols, allcols, numcols, searchin,
-                              ignorecase, filename, hdu, colmatch);
+  /* Get the list of indexs in the same order as the input list. */
+  indexll=gal_table_list_of_indexs(cols, allcols, numcols, searchin,
+                                   ignorecase, filename, hdu, colmatch);
 
   /* Depending on the table format, read the columns into the output
      structure. Note that the functions here pop each index, read/store the



reply via email to

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