gnuastro-commits
[Top][All Lists]
Advanced

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

[gnuastro-commits] master f21c30f 105/113: Imported recent work in maste


From: Mohammad Akhlaghi
Subject: [gnuastro-commits] master f21c30f 105/113: Imported recent work in master, no conflicts
Date: Fri, 16 Apr 2021 10:34:01 -0400 (EDT)

branch: master
commit f21c30fd83112aec033c8bc347e2b2a9c712ba93
Merge: 353c0c1 be4b72d
Author: Mohammad Akhlaghi <mohammad@akhlaghi.org>
Commit: Mohammad Akhlaghi <mohammad@akhlaghi.org>

    Imported recent work in master, no conflicts
    
    There weren't any conflicts in this merge.
---
 .gitignore                       |    2 +
 NEWS                             |   75 +++
 THANKS                           |    3 +
 bin/TEMPLATE/Makefile.am         |    2 +-
 bin/arithmetic/Makefile.am       |    2 +-
 bin/arithmetic/arithmetic.c      |  534 +++++++++---------
 bin/arithmetic/arithmetic.h      |    1 +
 bin/arithmetic/operands.c        |   10 +-
 bin/buildprog/Makefile.am        |    2 +-
 bin/buildprog/buildprog.c        |    3 +-
 bin/convertt/Makefile.am         |    2 +-
 bin/convertt/color.c             |   22 +-
 bin/convertt/color.h             |    3 +
 bin/convertt/convertt.c          |   19 +-
 bin/convertt/convertt.h          |    3 +
 bin/convertt/ui.c                |    6 +-
 bin/convolve/Makefile.am         |    2 +-
 bin/convolve/convolve.c          |    2 +-
 bin/convolve/ui.c                |    2 +-
 bin/cosmiccal/Makefile.am        |    2 +-
 bin/cosmiccal/args.h             |   28 +
 bin/cosmiccal/cosmiccal.c        |    5 +
 bin/cosmiccal/main.h             |    3 +-
 bin/cosmiccal/ui.c               |  114 ++++
 bin/cosmiccal/ui.h               |    6 +-
 bin/crop/Makefile.am             |    2 +-
 bin/fits/Makefile.am             |    2 +-
 bin/fits/keywords.c              |    6 +-
 bin/match/Makefile.am            |    2 +-
 bin/match/match.c                |    2 +-
 bin/match/ui.c                   |    9 +-
 bin/mkcatalog/Makefile.am        |    2 +-
 bin/mkcatalog/args.h             |    8 +-
 bin/mknoise/Makefile.am          |    2 +-
 bin/mkprof/Makefile.am           |    2 +-
 bin/noisechisel/Makefile.am      |    2 +-
 bin/noisechisel/detection.c      |   39 +-
 bin/noisechisel/threshold.c      |    6 -
 bin/script/sort-by-night.in      |   29 +-
 bin/segment/Makefile.am          |    2 +-
 bin/statistics/Makefile.am       |    2 +-
 bin/statistics/args.h            |   57 ++
 bin/statistics/statistics.c      |   26 +-
 bin/statistics/ui.c              |   20 +-
 bin/statistics/ui.h              |    4 +
 bin/table/Makefile.am            |    6 +-
 bin/table/args.h                 |   52 ++
 bin/table/arithmetic.c           |  672 +++++++++++++++++++++++
 bin/table/{ui.h => arithmetic.h} |   43 +-
 bin/table/asttable.conf          |    3 +
 bin/table/main.h                 |   35 +-
 bin/table/table.c                |   73 ++-
 bin/table/ui.c                   |  222 +++++++-
 bin/table/ui.h                   |    8 +-
 bin/warp/Makefile.am             |    2 +-
 bin/warp/ui.c                    |    3 +
 bootstrap.conf                   |    3 +
 configure.ac                     |  147 ++++-
 doc/announce-acknowledge.txt     |    6 +
 doc/gnuastro.texi                | 1122 ++++++++++++++++++++++++++++++--------
 lib/Makefile.am                  |   15 +-
 lib/arithmetic.c                 |  189 ++++++-
 lib/cosmology.c                  |    2 +-
 lib/eps.c                        |   38 +-
 lib/fits.c                       |   51 +-
 lib/gnuastro/arithmetic.h        |    4 +
 lib/gnuastro/blank.h             |    8 +
 lib/gnuastro/cosmology.h         |    3 -
 lib/gnuastro/list.h              |   24 +
 lib/gnuastro/speclines.h         |  180 ++++++
 lib/gnuastro/statistics.h        |    7 +-
 lib/jpeg.c                       |   55 +-
 lib/list.c                       |  133 +++++
 lib/options.c                    |    6 +-
 lib/pdf.c                        |   31 +-
 lib/speclines.c                  |  231 ++++++++
 lib/statistics.c                 |  112 ++--
 lib/tableintern.c                |    2 +-
 lib/tiff.c                       |   39 +-
 lib/txt.c                        |   34 +-
 tests/Makefile.am                |    2 +-
 81 files changed, 3768 insertions(+), 872 deletions(-)

diff --git a/.gitignore b/.gitignore
index 426315e..b0ce3cc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -88,9 +88,11 @@ astmatch
 ltmain.sh
 .dirstamp
 configure
+.DS_Store
 .gnuastro
 astmkprof
 astheader
+astscript*
 astsegment
 runtest.sh
 astmknoise
diff --git a/NEWS b/NEWS
index 6a99ad9..d14635a 100644
--- a/NEWS
+++ b/NEWS
@@ -7,12 +7,87 @@ See the end of the file for license conditions.
 
 ** New features
 
+  Arithmetic:
+   - `unique' operator removes all duplicate (and blank) elements from the
+     dataset and returns a single-dimention output, containing only the
+     unique values in the dataset.
+
+  CosmicCalculator:
+   --obsline: alternative way to set the used redshift. With this option
+     instead of explicity giving the redshift, you can give a rest-frame
+     and observed wavelength and the redshift to use will be calculated
+     internally. For many lines, it is possible to give the line name
+     instead of its rest-frame wavelength. For example
+     `--obsline=lyalpha,6000' will use the redshift where the Lyman-alpha
+     line has been shifted to 6000 Angestroms.
+   --usedredshift: Print the used redshift as a "Specific calculation" (in
+     line with other single-valued calculations).
+
+  Statistics:
+   --sigclip-number, --sigclip-median, --sigclip-mean, --sigclip-std: Do
+     sigma-clipping and only print the desired value as a single-value
+     measurement. Until now sigma-clipping results included a lot of
+     visually useful information, which also made automatic usage of
+     results hard. These options fix this issue. Please see the example in
+     the book under `--sigclip-median' for a nice use case.
+
+  Table:
+   - Column arithmetic. It is now possible to apply many operations on the
+     input table columns before printing them in the output. Similar to
+     Arithmetic, but on table columns. The operators and notation is just
+     like the Arithmetic program. See the "Column Arithmetic" section of
+     the book for a detailed discussion and several examples.
+   - WCS to Image coordinate conversion with `wcstoimg' and `imgtowcs'. For
+     example if the input catalog has atleast an `ID' column and two `RA'
+     and `DEC' columns, the set of options below will produce 5 columns
+     where the last two columns are the image coordinates for each row
+     based on the WCS in `a.fits':
+           `-cID,RA,DEC -c"arith RA DEC wcstoimg" --wcsfile=a.fits'
+   --head: Only output the given number of rows from the top of columns.
+   --tail: Only output the given number of rows from the botoom of columns.
+
+  Library:
+   - New `speclines.h' library functions and macros related to spectral
+     lines. It has many macros with line wavelengths, and several functions
+     for using them in combination with their names.
+   - list.h: Functions to return the last element in linked lists. For
+     example `gal_list_sizet_last' or `gal_list_data_last'.
+   - gal_list_data_to_array_ptr: Make an array of pointers from the list.
+   - GAL_BLANK_INT: Blank value for `int' (can be 16-bit or 32-bit).
+   - GAL_BLANK_UINT: Blank value for unsigned `int' (can be 16-bit or 32-bit).
+   - gal_arithmetic_operator_string: Return operator string from code.
+   - gal_arithmetic_set_operator: Return operator code from string.
+
+
 ** Removed features
 
 ** Changed features
 
+  Installation:
+   - Better `./configure' tests (using Gnulib's `AC_LIB_HAVE_LINKFLAGS') to
+     avoid some crashes during `make' when the host had multiple
+     conflicting versions of some dependencies (GSL in particular).
+
+  Arithmetic:
+   - The output of coadding operators is no longer the same type as the
+     input in general. The output of the `min' and `max' operators are
+     still the same type as the input. However the `number' and
+     `sigclip-number' operators will output an unsigned 32-bit integer type
+     and the rest (`sum', `mean', `std', `median', `sigclip-median',
+     `sigclip-mean' and `sigclip-std') return 32-bit floating point
+     datasets
+
+  Library:
+   - gal_statistics_outlier_flat_cfp: Improved implementation with new API.
+
 ** Bugs fixed
   bug #56195: astscript-sort-by-night crashing because of AWK.
+  bug #56246: Single-valued measurement must abort with no value in Statistics.
+  bug #56256: Segmentation fault when reading plain text array/image.
+  bug #56257: ConvertType: Values not preserved when converting text to FITS.
+  bug #56299: cosmiccal fails at z=0.
+  bug #56324: Column metadata not usable when input is from pipe/stdin.
+  bug #56424: Warp crashes with empty string given to options.
 
 
 
diff --git a/THANKS b/THANKS
index 557cd3a..bfe6ab9 100644
--- a/THANKS
+++ b/THANKS
@@ -20,6 +20,7 @@ support in Gnuastro. The list is ordered alphabetically (by 
family name).
 
     Valentina Abril-melgarejo            valentina.abril@lam.fr
     Marjan Akbari                        mrjakbari@gmail.com
+    Hamed Altafi                         hamed.altafi2@gmail.com
     Roland Bacon                         roland.bacon@univ-lyon1.fr
     Roberto Baena Gallé                  rbaena@iac.es
     Karl Berry                           karl@gnu.org
@@ -37,6 +38,7 @@ support in Gnuastro. The list is ordered alphabetically (by 
family name).
     Gaspar Galaz                         ggalaz@astro.puc.cl
     Thérèse Godefroy                     godef.th@free.fr
     Madusha Gunawardhana                 gunawardhana@strw.leidenuniv.nl
+    Bruno Haible                         bruno@clisp.org
     Stephen Hamer                        stephen.hamer@univ-lyon1.fr
     Takashi Ichikawa                     ichikawa@astr.tohoku.ac.jp
     Raúl Infante Sainz                   infantesainz@gmail.com
@@ -59,6 +61,7 @@ support in Gnuastro. The list is ordered alphabetically (by 
family name).
     Mamta Pommier                        mamta.pommier@univ-lyon1.fr
     Bob Proulx                           bob@proulx.com
     Teymoor Saifollahi                   teymur.saif@gmail.com
+    Elham Saremi                         saremi@ipm.ir
     Yahya Sefidbakht                     y.sefidbakht@gmail.com
     Alejandro Serrano Borlaff            asborlaff@ucm.es
     Jenny Sorce                          jenny.sorce@univ-lyon1.fr
diff --git a/bin/TEMPLATE/Makefile.am b/bin/TEMPLATE/Makefile.am
index bab4ad9..abf9666 100644
--- a/bin/TEMPLATE/Makefile.am
+++ b/bin/TEMPLATE/Makefile.am
@@ -33,7 +33,7 @@ bin_PROGRAMS = astTEMPLATE
 ## don't keep external variables (needed in Argp) after the first link. So
 ## the `libgnu' (that is indirectly linked through `libgnuastro') can't see
 ## those variables. We thus need to explicitly link with `libgnu' first.
-astTEMPLATE_LDADD = $(top_builddir)/bootstrapped/lib/libgnu.la -lgnuastro
+astTEMPLATE_LDADD = $(top_builddir)/bootstrapped/lib/libgnu.la -lgnuastro 
$(CONFIG_LDADD)
 
 astTEMPLATE_SOURCES = main.c ui.c TEMPLATE.c
 
diff --git a/bin/arithmetic/Makefile.am b/bin/arithmetic/Makefile.am
index 6d562d8..332450b 100644
--- a/bin/arithmetic/Makefile.am
+++ b/bin/arithmetic/Makefile.am
@@ -29,7 +29,7 @@ AM_CPPFLAGS = -I\$(top_srcdir)/bootstrapped/lib 
-I\$(top_srcdir)/lib
 bin_PROGRAMS = astarithmetic
 
 ## Reason for linking with `libgnu' described in `bin/TEMPLATE/Makefile.am'.
-astarithmetic_LDADD = $(top_builddir)/bootstrapped/lib/libgnu.la -lgnuastro
+astarithmetic_LDADD = $(top_builddir)/bootstrapped/lib/libgnu.la -lgnuastro 
$(CONFIG_LDADD)
 
 astarithmetic_SOURCES = main.c ui.c arithmetic.c operands.c
 
diff --git a/bin/arithmetic/arithmetic.c b/bin/arithmetic/arithmetic.c
index 0c60cdb..7c85a94 100644
--- a/bin/arithmetic/arithmetic.c
+++ b/bin/arithmetic/arithmetic.c
@@ -877,6 +877,59 @@ arithmetic_tofile(struct arithmeticparams *p, char *token, 
int freeflag)
 
 
 
+/* Pull out unique elements */
+#define UNIQUE_BYTYPE(TYPE) {                                           \
+    size_t i, j;                                                        \
+    TYPE *a=input->array, b;                                            \
+                                                                        \
+    /* Write the blank value for this type into `b'. */                 \
+    gal_blank_write(&b, input->type);                                   \
+                                                                        \
+    /* Go over the elements, and set the duplicates to blank. */        \
+    /* Note that for integers and floats, the behavior of blank/NaN */  \
+    /* differs: for floats (NaN), we can identify a blank using the  */ \
+    /* fact that by definition, NaN!=NaN. */                            \
+    if(b==b)                                                            \
+      for(i=0;i<input->size;++i)                                        \
+        { if(a[i]!=b)    for(j=i+1;j<input->size;++j) if(a[i]==a[j]) a[j]=b;} \
+    else                                                                \
+      for(i=0;i<input->size;++i)                                        \
+        { if(a[i]==a[i]) for(j=i+1;j<input->size;++j) if(a[i]==a[j]) a[j]=b;} \
+  }
+
+void
+arithmetic_unique(struct arithmeticparams *p, char *token, int operator)
+{
+  gal_data_t *input = operands_pop(p, token);
+
+  /* Remove the duplicates based on size. */
+  switch(input->type)
+    {
+    case GAL_TYPE_UINT8:   UNIQUE_BYTYPE( uint8_t  ); break;
+    case GAL_TYPE_INT8:    UNIQUE_BYTYPE( int8_t   ); break;
+    case GAL_TYPE_UINT16:  UNIQUE_BYTYPE( uint16_t ); break;
+    case GAL_TYPE_INT16:   UNIQUE_BYTYPE( int16_t  ); break;
+    case GAL_TYPE_UINT32:  UNIQUE_BYTYPE( uint32_t ); break;
+    case GAL_TYPE_INT32:   UNIQUE_BYTYPE( int32_t  ); break;
+    case GAL_TYPE_UINT64:  UNIQUE_BYTYPE( uint64_t ); break;
+    case GAL_TYPE_INT64:   UNIQUE_BYTYPE( int64_t  ); break;
+    case GAL_TYPE_FLOAT32: UNIQUE_BYTYPE( float    ); break;
+    case GAL_TYPE_FLOAT64: UNIQUE_BYTYPE( double   ); break;
+    default:
+      error(EXIT_FAILURE, 0, "the `unique' operator doesn't support type "
+            "code `%u'", input->type);
+    }
+
+  /* Remove all blank elements. */
+  gal_blank_remove(input);
+
+  /* Clean up and add the collapsed dataset to the top of the operands. */
+  operands_add(p, NULL, input);
+}
+
+
+
+
 
 
 
@@ -896,6 +949,184 @@ arithmetic_tofile(struct arithmeticparams *p, char 
*token, int freeflag)
 /***************************************************************/
 /*************      Reverse Polish algorithm       *************/
 /***************************************************************/
+static int
+arithmetic_set_operator(char *string, size_t *num_operands)
+{
+  /* Use the library's main function for its own operators. */
+  int op = gal_arithmetic_set_operator(string, num_operands);
+
+  /* If its not a library operator, check if its an internal operator. */
+  if(op==GAL_ARITHMETIC_OP_INVALID)
+    {
+      /* Non-library operators. */
+      if      (!strcmp(string, "filter-mean"))
+        { op=ARITHMETIC_OP_FILTER_MEAN;           *num_operands=0; }
+      else if (!strcmp(string, "filter-median"))
+        { op=ARITHMETIC_OP_FILTER_MEDIAN;         *num_operands=0; }
+      else if (!strcmp(string, "filter-sigclip-mean"))
+        { op=ARITHMETIC_OP_FILTER_SIGCLIP_MEAN;   *num_operands=0; }
+      else if (!strcmp(string, "filter-sigclip-median"))
+        { op=ARITHMETIC_OP_FILTER_SIGCLIP_MEDIAN; *num_operands=0; }
+      else if (!strcmp(string, "erode"))
+        { op=ARITHMETIC_OP_ERODE;                 *num_operands=0; }
+      else if (!strcmp(string, "dilate"))
+        { op=ARITHMETIC_OP_DILATE;                *num_operands=0; }
+      else if (!strcmp(string, "connected-components"))
+        { op=ARITHMETIC_OP_CONNECTED_COMPONENTS;  *num_operands=0; }
+      else if (!strcmp(string, "fill-holes"))
+        { op=ARITHMETIC_OP_FILL_HOLES;            *num_operands=0; }
+      else if (!strcmp(string, "invert"))
+        { op=ARITHMETIC_OP_INVERT;                *num_operands=0; }
+      else if (!strcmp(string, "interpolate-medianngb"))
+        { op=ARITHMETIC_OP_INTERPOLATE_MEDIANNGB; *num_operands=0; }
+      else if (!strcmp(string, "collapse-sum"))
+        { op=ARITHMETIC_OP_COLLAPSE_SUM;          *num_operands=0; }
+      else if (!strcmp(string, "collapse-min"))
+        { op=ARITHMETIC_OP_COLLAPSE_MIN;          *num_operands=0; }
+      else if (!strcmp(string, "collapse-max"))
+        { op=ARITHMETIC_OP_COLLAPSE_MAX;          *num_operands=0; }
+      else if (!strcmp(string, "collapse-mean"))
+        { op=ARITHMETIC_OP_COLLAPSE_MEAN;         *num_operands=0; }
+      else if (!strcmp(string, "collapse-number"))
+        { op=ARITHMETIC_OP_COLLAPSE_NUMBER;       *num_operands=0; }
+      else if (!strcmp(string, "unique"))
+        { op=ARITHMETIC_OP_UNIQUE;                *num_operands=0; }
+      else
+        error(EXIT_FAILURE, 0, "the argument \"%s\" could not be "
+              "interpretted as a file name, named dataset, number, "
+              "or operator", string);
+    }
+
+  /* Return the operator code. */
+  return op;
+}
+
+
+
+
+
+static void
+arithmetic_operator_run(struct arithmeticparams *p, int operator,
+                        char *operator_string, size_t num_operands)
+{
+  size_t i;
+  unsigned int numop;
+  gal_data_t *d1=NULL, *d2=NULL, *d3=NULL;
+  int flags = ( GAL_ARITHMETIC_INPLACE | GAL_ARITHMETIC_FREE
+                | GAL_ARITHMETIC_NUMOK );
+
+  /* When `num_operands!=0', the operator is in the library. */
+  if(num_operands)
+    {
+      /* Pop the necessary number of operators. Note that the
+         operators are poped from a linked list (which is
+         last-in-first-out). So for the operators which need a
+         specific order, the first poped operand is actally the
+         last (right most, in in-fix notation) input operand.*/
+      switch(num_operands)
+        {
+        case 1:
+          d1=operands_pop(p, operator_string);
+          break;
+
+        case 2:
+          d2=operands_pop(p, operator_string);
+          d1=operands_pop(p, operator_string);
+          break;
+
+        case 3:
+          d3=operands_pop(p, operator_string);
+          d2=operands_pop(p, operator_string);
+          d1=operands_pop(p, operator_string);
+          break;
+
+        case -1:
+          /* This case is when the number of operands is itself an
+             operand. So except for sigma-clipping (that has other
+             parameters), the first popped operand must be an
+             integer number, we will use that to construct a linked
+             list of any number of operands within the single `d1'
+             pointer. */
+          numop=pop_number_of_operands(p, operator, operator_string, &d2);
+          for(i=0;i<numop;++i)
+            gal_list_data_add(&d1, operands_pop(p, operator_string));
+          break;
+
+        default:
+          error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at %s to fix "
+                "the problem. `%zu' is not recognized as an operand "
+                "counter (with `%s')", __func__, PACKAGE_BUGREPORT,
+                num_operands, operator_string);
+        }
+
+      /* Run the arithmetic operation. Note that `gal_arithmetic'
+         is a variable argument function (like printf). So the
+         number of arguments it uses depend on the operator. So
+         when the operator doesn't need three operands, the extra
+         arguments will be ignored. */
+      operands_add(p, NULL, gal_arithmetic(operator, p->cp.numthreads,
+                                           flags, d1, d2, d3));
+    }
+
+  /* No need to call the arithmetic library, call the proper
+     wrappers directly. */
+  else
+    {
+      switch(operator)
+        {
+        case ARITHMETIC_OP_FILTER_MEAN:
+        case ARITHMETIC_OP_FILTER_MEDIAN:
+        case ARITHMETIC_OP_FILTER_SIGCLIP_MEAN:
+        case ARITHMETIC_OP_FILTER_SIGCLIP_MEDIAN:
+          wrapper_for_filter(p, operator_string, operator);
+          break;
+
+        case ARITHMETIC_OP_ERODE:
+        case ARITHMETIC_OP_DILATE:
+          arithmetic_erode_dilate(p, operator_string, operator);
+          break;
+
+        case ARITHMETIC_OP_CONNECTED_COMPONENTS:
+          arithmetic_connected_components(p, operator_string);
+          break;
+
+        case ARITHMETIC_OP_FILL_HOLES:
+          arithmetic_fill_holes(p, operator_string);
+          break;
+
+        case ARITHMETIC_OP_INVERT:
+          arithmetic_invert(p, operator_string);
+          break;
+
+        case ARITHMETIC_OP_INTERPOLATE_MEDIANNGB:
+          arithmetic_interpolate(p, operator_string);
+          break;
+
+        case ARITHMETIC_OP_COLLAPSE_SUM:
+        case ARITHMETIC_OP_COLLAPSE_MIN:
+        case ARITHMETIC_OP_COLLAPSE_MAX:
+        case ARITHMETIC_OP_COLLAPSE_MEAN:
+        case ARITHMETIC_OP_COLLAPSE_NUMBER:
+          arithmetic_collapse(p, operator_string, operator);
+          break;
+
+        case ARITHMETIC_OP_UNIQUE:
+          arithmetic_unique(p, operator_string, operator);
+          break;
+
+        default:
+          error(EXIT_FAILURE, 0, "%s: a bug! please contact us at "
+                "%s to fix the problem. The code %d is not "
+                "recognized for `op'", __func__, PACKAGE_BUGREPORT,
+                operator);
+        }
+    }
+}
+
+
+
+
+
 /* This function implements the reverse polish algorithm as explained
    in the Wikipedia page.
 
@@ -904,13 +1135,11 @@ arithmetic_tofile(struct arithmeticparams *p, char 
*token, int freeflag)
 void
 reversepolish(struct arithmeticparams *p)
 {
-  int op=0, nop=0;
-  unsigned int numop, i;
+  gal_data_t *data;
+  size_t num_operands=0;
   gal_list_str_t *token;
-  gal_data_t *d1, *d2, *d3;
   char *hdu, *filename, *printnum;
-  int flags = ( GAL_ARITHMETIC_INPLACE | GAL_ARITHMETIC_FREE
-                | GAL_ARITHMETIC_NUMOK );
+  int operator=GAL_ARITHMETIC_OP_INVALID;
 
 
   /* Prepare the processing: */
@@ -926,6 +1155,7 @@ reversepolish(struct arithmeticparams *p)
          for a filename. If we have a name or number, then add it to the
          operands linked list. Otherwise, pull out two members and do the
          specified operation on them. */
+      operator=GAL_ARITHMETIC_OP_INVALID;
       if( !strncmp(OPERATOR_PREFIX_TOFILE, token->v,
                    OPERATOR_PREFIX_LENGTH_TOFILE) )
         arithmetic_tofile(p, token->v, 0);
@@ -938,274 +1168,14 @@ reversepolish(struct arithmeticparams *p)
       else if( gal_array_name_recognized(token->v)
           || operands_is_name(p, token->v) )
         operands_add(p, token->v, NULL);
-      else if( (d1=gal_data_copy_string_to_number(token->v)) )
-        operands_add(p, NULL, d1);
+      else if( (data=gal_data_copy_string_to_number(token->v)) )
+        operands_add(p, NULL, data);
+      /* Last option is an operator: the program will abort if the token
+         isn't an operator. */
       else
         {
-          /* Order is the same as in the manual. */
-          /* Simple arithmetic operators. */
-          if      (!strcmp(token->v, "+" ))
-            { op=GAL_ARITHMETIC_OP_PLUS;              nop=2;  }
-          else if (!strcmp(token->v, "-" ))
-            { op=GAL_ARITHMETIC_OP_MINUS;             nop=2;  }
-          else if (!strcmp(token->v, "x" ))
-            { op=GAL_ARITHMETIC_OP_MULTIPLY;          nop=2;  }
-          else if (!strcmp(token->v, "/" ))
-            { op=GAL_ARITHMETIC_OP_DIVIDE;            nop=2;  }
-          else if (!strcmp(token->v, "%" ))
-            { op=GAL_ARITHMETIC_OP_MODULO;            nop=2;  }
-
-          /* Mathematical Operators. */
-          else if (!strcmp(token->v, "abs"))
-            { op=GAL_ARITHMETIC_OP_ABS;               nop=1;  }
-          else if (!strcmp(token->v, "pow"))
-            { op=GAL_ARITHMETIC_OP_POW;               nop=2;  }
-          else if (!strcmp(token->v, "sqrt"))
-            { op=GAL_ARITHMETIC_OP_SQRT;              nop=1;  }
-          else if (!strcmp(token->v, "log"))
-            { op=GAL_ARITHMETIC_OP_LOG;               nop=1;  }
-          else if (!strcmp(token->v, "log10"))
-            { op=GAL_ARITHMETIC_OP_LOG10;             nop=1;  }
-
-          /* Statistical/higher-level operators. */
-          else if (!strcmp(token->v, "minvalue"))
-            { op=GAL_ARITHMETIC_OP_MINVAL;            nop=1;  }
-          else if (!strcmp(token->v, "maxvalue"))
-            { op=GAL_ARITHMETIC_OP_MAXVAL;            nop=1;  }
-          else if (!strcmp(token->v, "numbervalue"))
-            { op=GAL_ARITHMETIC_OP_NUMBERVAL;         nop=1;  }
-          else if (!strcmp(token->v, "sumvalue"))
-            { op=GAL_ARITHMETIC_OP_SUMVAL;            nop=1;  }
-          else if (!strcmp(token->v, "meanvalue"))
-            { op=GAL_ARITHMETIC_OP_MEANVAL;           nop=1;  }
-          else if (!strcmp(token->v, "stdvalue"))
-            { op=GAL_ARITHMETIC_OP_STDVAL;            nop=1;  }
-          else if (!strcmp(token->v, "medianvalue"))
-            { op=GAL_ARITHMETIC_OP_MEDIANVAL;         nop=1;  }
-          else if (!strcmp(token->v, "min"))
-            { op=GAL_ARITHMETIC_OP_MIN;               nop=-1; }
-          else if (!strcmp(token->v, "max"))
-            { op=GAL_ARITHMETIC_OP_MAX;               nop=-1; }
-          else if (!strcmp(token->v, "number"))
-            { op=GAL_ARITHMETIC_OP_NUMBER;            nop=-1; }
-          else if (!strcmp(token->v, "sum"))
-            { op=GAL_ARITHMETIC_OP_SUM;               nop=-1; }
-          else if (!strcmp(token->v, "mean"))
-            { op=GAL_ARITHMETIC_OP_MEAN;              nop=-1; }
-          else if (!strcmp(token->v, "std"))
-            { op=GAL_ARITHMETIC_OP_STD;               nop=-1; }
-          else if (!strcmp(token->v, "median"))
-            { op=GAL_ARITHMETIC_OP_MEDIAN;            nop=-1; }
-          else if (!strcmp(token->v, "sigclip-number"))
-            { op=GAL_ARITHMETIC_OP_SIGCLIP_NUMBER;    nop=-1; }
-          else if (!strcmp(token->v, "sigclip-mean"))
-            { op=GAL_ARITHMETIC_OP_SIGCLIP_MEAN;      nop=-1; }
-          else if (!strcmp(token->v, "sigclip-median"))
-            { op=GAL_ARITHMETIC_OP_SIGCLIP_MEDIAN;    nop=-1; }
-          else if (!strcmp(token->v, "sigclip-std"))
-            { op=GAL_ARITHMETIC_OP_SIGCLIP_STD;       nop=-1; }
-
-          /* Conditional operators. */
-          else if (!strcmp(token->v, "lt" ))
-            { op=GAL_ARITHMETIC_OP_LT;                nop=2;  }
-          else if (!strcmp(token->v, "le"))
-            { op=GAL_ARITHMETIC_OP_LE;                nop=2;  }
-          else if (!strcmp(token->v, "gt" ))
-            { op=GAL_ARITHMETIC_OP_GT;                nop=2;  }
-          else if (!strcmp(token->v, "ge"))
-            { op=GAL_ARITHMETIC_OP_GE;                nop=2;  }
-          else if (!strcmp(token->v, "eq"))
-            { op=GAL_ARITHMETIC_OP_EQ;                nop=2;  }
-          else if (!strcmp(token->v, "ne"))
-            { op=GAL_ARITHMETIC_OP_NE;                nop=2;  }
-          else if (!strcmp(token->v, "and"))
-            { op=GAL_ARITHMETIC_OP_AND;               nop=2;  }
-          else if (!strcmp(token->v, "or"))
-            { op=GAL_ARITHMETIC_OP_OR;                nop=2;  }
-          else if (!strcmp(token->v, "not"))
-            { op=GAL_ARITHMETIC_OP_NOT;               nop=1;  }
-          else if (!strcmp(token->v, "isblank"))
-            { op=GAL_ARITHMETIC_OP_ISBLANK;           nop=1;  }
-          else if (!strcmp(token->v, "where"))
-            { op=GAL_ARITHMETIC_OP_WHERE;             nop=3;  }
-
-          /* Bitwise operators. */
-          else if (!strcmp(token->v, "bitand"))
-            { op=GAL_ARITHMETIC_OP_BITAND;            nop=2;  }
-          else if (!strcmp(token->v, "bitor"))
-            { op=GAL_ARITHMETIC_OP_BITOR;             nop=2;  }
-          else if (!strcmp(token->v, "bitxor"))
-            { op=GAL_ARITHMETIC_OP_BITXOR;            nop=2;  }
-          else if (!strcmp(token->v, "lshift"))
-            { op=GAL_ARITHMETIC_OP_BITLSH;            nop=2;  }
-          else if (!strcmp(token->v, "rshift"))
-            { op=GAL_ARITHMETIC_OP_BITRSH;            nop=2;  }
-          else if (!strcmp(token->v, "bitnot"))
-            { op=GAL_ARITHMETIC_OP_BITNOT;            nop=1;  }
-
-          /* Type conversion. */
-          else if (!strcmp(token->v, "uint8"))
-            { op=GAL_ARITHMETIC_OP_TO_UINT8;          nop=1;  }
-          else if (!strcmp(token->v, "int8"))
-            { op=GAL_ARITHMETIC_OP_TO_INT8;           nop=1;  }
-          else if (!strcmp(token->v, "uint16"))
-            { op=GAL_ARITHMETIC_OP_TO_UINT16;         nop=1;  }
-          else if (!strcmp(token->v, "int16"))
-            { op=GAL_ARITHMETIC_OP_TO_INT16;          nop=1;  }
-          else if (!strcmp(token->v, "uint32"))
-            { op=GAL_ARITHMETIC_OP_TO_UINT32;         nop=1;  }
-          else if (!strcmp(token->v, "int32"))
-            { op=GAL_ARITHMETIC_OP_TO_INT32;          nop=1;  }
-          else if (!strcmp(token->v, "uint64"))
-            { op=GAL_ARITHMETIC_OP_TO_UINT64;         nop=1;  }
-          else if (!strcmp(token->v, "int64"))
-            { op=GAL_ARITHMETIC_OP_TO_INT64;          nop=1;  }
-          else if (!strcmp(token->v, "float32"))
-            { op=GAL_ARITHMETIC_OP_TO_FLOAT32;        nop=1;  }
-          else if (!strcmp(token->v, "float64"))
-            { op=GAL_ARITHMETIC_OP_TO_FLOAT64;        nop=1;  }
-
-          /* Library wrappers. */
-          else if (!strcmp(token->v, "filter-mean"))
-            { op=ARITHMETIC_OP_FILTER_MEAN;           nop=0;  }
-          else if (!strcmp(token->v, "filter-median"))
-            { op=ARITHMETIC_OP_FILTER_MEDIAN;         nop=0;  }
-          else if (!strcmp(token->v, "filter-sigclip-mean"))
-            { op=ARITHMETIC_OP_FILTER_SIGCLIP_MEAN;   nop=0;  }
-          else if (!strcmp(token->v, "filter-sigclip-median"))
-            { op=ARITHMETIC_OP_FILTER_SIGCLIP_MEDIAN; nop=0;  }
-          else if (!strcmp(token->v, "erode"))
-            { op=ARITHMETIC_OP_ERODE;                 nop=0;  }
-          else if (!strcmp(token->v, "dilate"))
-            { op=ARITHMETIC_OP_DILATE;                nop=0;  }
-          else if (!strcmp(token->v, "connected-components"))
-            { op=ARITHMETIC_OP_CONNECTED_COMPONENTS;  nop=0;  }
-          else if (!strcmp(token->v, "fill-holes"))
-            { op=ARITHMETIC_OP_FILL_HOLES;            nop=0;  }
-          else if (!strcmp(token->v, "invert"))
-            { op=ARITHMETIC_OP_INVERT;                nop=0;  }
-          else if (!strcmp(token->v, "interpolate-medianngb"))
-            { op=ARITHMETIC_OP_INTERPOLATE_MEDIANNGB; nop=0;  }
-          else if (!strcmp(token->v, "collapse-sum"))
-            { op=ARITHMETIC_OP_COLLAPSE_SUM;          nop=0; }
-          else if (!strcmp(token->v, "collapse-min"))
-            { op=ARITHMETIC_OP_COLLAPSE_MIN;          nop=0; }
-          else if (!strcmp(token->v, "collapse-max"))
-            { op=ARITHMETIC_OP_COLLAPSE_MAX;          nop=0; }
-          else if (!strcmp(token->v, "collapse-mean"))
-            { op=ARITHMETIC_OP_COLLAPSE_MEAN;         nop=0; }
-          else if (!strcmp(token->v, "collapse-number"))
-            { op=ARITHMETIC_OP_COLLAPSE_NUMBER;       nop=0; }
-          else
-            error(EXIT_FAILURE, 0, "the argument \"%s\" could not be "
-                  "interpretted as a file name, named dataset, number, or "
-                  "operator", token->v);
-
-          /* Initialize all the operand pointers (they may be remaining
-             from previous operators and we don't want them to cause
-             confusion. */
-          d1 = d2 = d3 = NULL;
-
-          /* See if the arithmetic library must be called or not. */
-          if(nop)
-            {
-              /* Pop the necessary number of operators. Note that the
-                 operators are poped from a linked list (which is
-                 last-in-first-out). So for the operators which need a
-                 specific order, the first poped operand is actally the
-                 last (right most, in in-fix notation) input operand.*/
-              switch(nop)
-                {
-                case 1:
-                  d1=operands_pop(p, token->v);
-                  break;
-
-                case 2:
-                  d2=operands_pop(p, token->v);
-                  d1=operands_pop(p, token->v);
-                  break;
-
-                case 3:
-                  d3=operands_pop(p, token->v);
-                  d2=operands_pop(p, token->v);
-                  d1=operands_pop(p, token->v);
-                  break;
-
-                case -1:
-                  /* This case is when the number of operands is itself an
-                     operand. So except for sigma-clipping (that has other
-                     parameters), the first popped operand must be an
-                     integer number, we will use that to construct a linked
-                     list of any number of operands within the single `d1'
-                     pointer. */
-                  numop=pop_number_of_operands(p, op, token->v, &d2);
-                  for(i=0;i<numop;++i)
-                    gal_list_data_add(&d1, operands_pop(p, token->v));
-                  break;
-
-                default:
-                  error(EXIT_FAILURE, 0, "no operators, `%s' needs %d "
-                        "operand(s)", token->v, nop);
-                }
-
-              /* Run the arithmetic operation. Note that `gal_arithmetic'
-                 is a variable argument function (like printf). So the
-                 number of arguments it uses depend on the operator. So
-                 when the operator doesn't need three operands, the extra
-                 arguments will be ignored. */
-              operands_add(p, NULL, gal_arithmetic(op, p->cp.numthreads,
-                                                   flags, d1, d2, d3));
-            }
-
-          /* No need to call the arithmetic library, call the proper
-             wrappers directly. */
-          else
-            {
-              switch(op)
-                {
-                case ARITHMETIC_OP_FILTER_MEAN:
-                case ARITHMETIC_OP_FILTER_MEDIAN:
-                case ARITHMETIC_OP_FILTER_SIGCLIP_MEAN:
-                case ARITHMETIC_OP_FILTER_SIGCLIP_MEDIAN:
-                  wrapper_for_filter(p, token->v, op);
-                  break;
-
-                case ARITHMETIC_OP_ERODE:
-                case ARITHMETIC_OP_DILATE:
-                  arithmetic_erode_dilate(p, token->v, op);
-                  break;
-
-                case ARITHMETIC_OP_CONNECTED_COMPONENTS:
-                  arithmetic_connected_components(p, token->v);
-                  break;
-
-                case ARITHMETIC_OP_FILL_HOLES:
-                  arithmetic_fill_holes(p, token->v);
-                  break;
-
-                case ARITHMETIC_OP_INVERT:
-                  arithmetic_invert(p, token->v);
-                  break;
-
-                case ARITHMETIC_OP_INTERPOLATE_MEDIANNGB:
-                  arithmetic_interpolate(p, token->v);
-                  break;
-
-                case ARITHMETIC_OP_COLLAPSE_SUM:
-                case ARITHMETIC_OP_COLLAPSE_MIN:
-                case ARITHMETIC_OP_COLLAPSE_MAX:
-                case ARITHMETIC_OP_COLLAPSE_MEAN:
-                case ARITHMETIC_OP_COLLAPSE_NUMBER:
-                  arithmetic_collapse(p, token->v, op);
-                  break;
-
-                default:
-                  error(EXIT_FAILURE, 0, "%s: a bug! please contact us at "
-                        "%s to fix the problem. The code %d is not "
-                        "recognized for `op'", __func__, PACKAGE_BUGREPORT,
-                        op);
-                }
-            }
+          operator=arithmetic_set_operator(token->v, &num_operands);
+          arithmetic_operator_run(p, operator, token->v, num_operands);
         }
 
       /* Increment the token counter. */
@@ -1253,38 +1223,38 @@ reversepolish(struct arithmeticparams *p)
 
   /* If the final data structure has more than one element, write it as a
      FITS file. Otherwise, print it in the standard output. */
-  d1=p->operands->data;
-  if(d1->size==1)
+  data=p->operands->data;
+  if(data->size==1)
     {
       /* Make the string to print the number. */
-      printnum=gal_type_to_string(d1->array, d1->type, 0);
+      printnum=gal_type_to_string(data->array, data->type, 0);
       printf("%s\n", printnum);
 
       /* Clean up. */
       free(printnum);
-      if(d2!=d1) gal_data_free(d2);
     }
   else
     {
       /* Put a copy of the WCS structure from the reference image, it
-         will be freed while freeing d1. */
-      d1->wcs=p->refdata.wcs;
-      if(d1->ndim==1 && p->onedasimage==0)
-        gal_table_write(d1, NULL, p->cp.tableformat, p->cp.output,
+         will be freed while freeing `data'. */
+      data->wcs=p->refdata.wcs;
+      if(data->ndim==1 && p->onedasimage==0)
+        gal_table_write(data, NULL, p->cp.tableformat, p->cp.output,
                         "ARITHMETIC", 0);
       else
-        gal_fits_img_write(d1, p->cp.output, NULL, PROGRAM_NAME);
+        gal_fits_img_write(data, p->cp.output, NULL, PROGRAM_NAME);
       if(!p->cp.quiet)
         printf(" - Write (final): %s\n", p->cp.output);
     }
 
 
   /* Clean up, note that above, we copied the pointer to `refdata->wcs'
-     into `d1', so it is freed when freeing d1. */
-  gal_data_free(d1);
+     into `data', so it is freed when freeing `data'. */
+  gal_data_free(data);
   free(p->refdata.dsize);
   gal_list_data_free(p->named);
 
+
   /* Clean up. Note that the tokens were taken from the command-line
      arguments, so the string within each token linked list must not be
      freed. */
diff --git a/bin/arithmetic/arithmetic.h b/bin/arithmetic/arithmetic.h
index 7132f41..d267a58 100644
--- a/bin/arithmetic/arithmetic.h
+++ b/bin/arithmetic/arithmetic.h
@@ -46,6 +46,7 @@ enum arithmetic_prog_operators
   ARITHMETIC_OP_COLLAPSE_MAX,
   ARITHMETIC_OP_COLLAPSE_MEAN,
   ARITHMETIC_OP_COLLAPSE_NUMBER,
+  ARITHMETIC_OP_UNIQUE,
 };
 
 
diff --git a/bin/arithmetic/operands.c b/bin/arithmetic/operands.c
index a5071f7..577fd93 100644
--- a/bin/arithmetic/operands.c
+++ b/bin/arithmetic/operands.c
@@ -362,15 +362,7 @@ operands_pop(struct arithmeticparams *p, char *operator)
          means that this is not the first image read. So, write its basic
          information into the reference data structure for future
          checks. */
-      if(p->refdata.ndim)
-        {
-          if( gal_dimension_is_different(&p->refdata, data) )
-            error(EXIT_FAILURE, 0, "%s (hdu=%s): has a different size "
-                  "compared to previous images. All the images must be "
-                  "the same size in order for Arithmetic to work",
-                  filename, hdu);
-        }
-      else
+      if(p->refdata.ndim==0)
         {
           /* Set the dimensionality. */
           p->refdata.ndim=(data)->ndim;
diff --git a/bin/buildprog/Makefile.am b/bin/buildprog/Makefile.am
index fa4f1c5..3c81205 100644
--- a/bin/buildprog/Makefile.am
+++ b/bin/buildprog/Makefile.am
@@ -35,7 +35,7 @@ AM_CPPFLAGS = -I\$(top_srcdir)/bootstrapped/lib 
-I\$(top_srcdir)/lib \
 bin_PROGRAMS = astbuildprog
 
 ## Reason for linking with `libgnu' described in `bin/TEMPLATE/Makefile.am'.
-astbuildprog_LDADD = $(top_builddir)/bootstrapped/lib/libgnu.la -lgnuastro
+astbuildprog_LDADD = $(top_builddir)/bootstrapped/lib/libgnu.la -lgnuastro 
$(CONFIG_LDADD)
 
 # Basic program sources.
 astbuildprog_SOURCES = main.c ui.c buildprog.c
diff --git a/bin/buildprog/buildprog.c b/bin/buildprog/buildprog.c
index ef706a8..52454ea 100644
--- a/bin/buildprog/buildprog.c
+++ b/bin/buildprog/buildprog.c
@@ -103,13 +103,14 @@ buildprog(struct buildprogparams *p)
       error(EXIT_FAILURE, 0, "%s: asprintf allocation", __func__);
 
   /* Write the full Libtool command into a string (to run afterwards). */
-  if( asprintf(&command, "%s -c \"%s %s %s%s --mode=link gcc %s %s "
+  if( asprintf(&command, "%s -c \"%s %s %s%s --mode=link gcc %s %s %s "
                "%s %s %s %s %s -I%s %s -o %s\"",
                GAL_CONFIG_GNULIBTOOL_SHELL,
                GAL_CONFIG_GNULIBTOOL_EXEC,
                p->cp.quiet ? "--quiet" : "",
                p->tag      ? "--tag="   : "",
                p->tag      ? p->tag    : "",
+               LDADD,                              /* From `config.h'. */
                warning     ? warning   : "",
                p->debug    ? "-g"      : "",
                optimize    ? optimize  : "",
diff --git a/bin/convertt/Makefile.am b/bin/convertt/Makefile.am
index c5f6e76..0f8fb5c 100644
--- a/bin/convertt/Makefile.am
+++ b/bin/convertt/Makefile.am
@@ -29,7 +29,7 @@ AM_CPPFLAGS = -I\$(top_srcdir)/bootstrapped/lib 
-I\$(top_srcdir)/lib
 bin_PROGRAMS = astconvertt
 
 ## Reason for linking with `libgnu' described in `bin/TEMPLATE/Makefile.am'.
-astconvertt_LDADD = $(top_builddir)/bootstrapped/lib/libgnu.la -lgnuastro
+astconvertt_LDADD = $(top_builddir)/bootstrapped/lib/libgnu.la -lgnuastro 
$(CONFIG_LDADD)
 
 astconvertt_SOURCES = main.c ui.c convertt.c color.c
 
diff --git a/bin/convertt/color.c b/bin/convertt/color.c
index 72806ee..7346e1d 100644
--- a/bin/convertt/color.c
+++ b/bin/convertt/color.c
@@ -31,8 +31,7 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 #include <gnuastro/statistics.h>
 
 #include "main.h"
-
-
+#include "convertt.h"
 
 
 
@@ -435,6 +434,25 @@ color_from_mono_sls(struct converttparams *p)
 
 
 
+void
+color_map_prepare(struct converttparams *p)
+{
+  switch(p->colormap->status)
+    {
+    case COLOR_HSV:  color_from_mono_hsv(p);     break;
+    case COLOR_SLS:  color_from_mono_sls(p);     break;
+    case COLOR_GRAY: convertt_scale_to_uchar(p); break;
+    default:
+      error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at %s to fix "
+            "the problem. The value %d is not a recognized color-space "
+            "code", __func__, PACKAGE_BUGREPORT, p->colormap->status);
+    }
+}
+
+
+
+
+
 
 
 
diff --git a/bin/convertt/color.h b/bin/convertt/color.h
index 1e329c5..a856ca9 100644
--- a/bin/convertt/color.h
+++ b/bin/convertt/color.h
@@ -24,6 +24,9 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 #define COLOR_H
 
 void
+color_map_prepare(struct converttparams *p);
+
+void
 color_from_mono_hsv(struct converttparams *p);
 
 void
diff --git a/bin/convertt/convertt.c b/bin/convertt/convertt.c
index b02971f..513f593 100644
--- a/bin/convertt/convertt.c
+++ b/bin/convertt/convertt.c
@@ -323,19 +323,6 @@ convertt(struct converttparams *p)
       convertt_truncate(p);
     }
 
-  /* Convert a mono/single color channel to a color format. */
-  if(p->colormap)
-    switch(p->colormap->status)
-      {
-      case COLOR_HSV:  color_from_mono_hsv(p);     break;
-      case COLOR_SLS:  color_from_mono_sls(p);     break;
-      case COLOR_GRAY: convertt_scale_to_uchar(p); break;
-      default:
-        error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at %s to fix "
-              "the problem. The value %d is not a recognized color-space "
-              "code", __func__, PACKAGE_BUGREPORT, p->colormap->status);
-      }
-
   /* Save the outputs: */
   switch(p->outformat)
     {
@@ -355,20 +342,20 @@ convertt(struct converttparams *p)
 
     /* JPEG: */
     case OUT_FORMAT_JPEG:
-      if(!p->colormap) convertt_scale_to_uchar(p);
+      if(p->colormap) color_map_prepare(p); else convertt_scale_to_uchar(p);
       gal_jpeg_write(p->chll, p->cp.output, p->quality, p->widthincm);
       break;
 
     /* EPS. */
     case OUT_FORMAT_EPS:
-      if(!p->colormap) convertt_scale_to_uchar(p);
+      if(p->colormap) color_map_prepare(p); else convertt_scale_to_uchar(p);
       gal_eps_write(p->chll, p->cp.output, p->widthincm, p->borderwidth,
                     p->hex, p->forcemin || p->forcemax, 0);
       break;
 
     /* PDF */
     case OUT_FORMAT_PDF:
-      if(!p->colormap) convertt_scale_to_uchar(p);
+      if(p->colormap) color_map_prepare(p); else convertt_scale_to_uchar(p);
       gal_pdf_write(p->chll, p->cp.output, p->widthincm, p->borderwidth,
                     p->forcemin || p->forcemax);
       break;
diff --git a/bin/convertt/convertt.h b/bin/convertt/convertt.h
index 35f1ac8..d693421 100644
--- a/bin/convertt/convertt.h
+++ b/bin/convertt/convertt.h
@@ -24,6 +24,9 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 #define CONVERTT_H
 
 void
+convertt_scale_to_uchar(struct converttparams *p);
+
+void
 convertt(struct converttparams *p);
 
 #endif
diff --git a/bin/convertt/ui.c b/bin/convertt/ui.c
index 284801c..a3c3330 100644
--- a/bin/convertt/ui.c
+++ b/bin/convertt/ui.c
@@ -809,7 +809,8 @@ ui_set_output(struct converttparams *p)
     {
       if(p->borderwidth==0 && p->widthincm==0)
         error(EXIT_FAILURE, 0, "at least one of `--widthincm' (`-u'), or "
-              "`--borderwidth (`-b') options are necessary for an EPS output");
+              "`--borderwidth (`-b') options are necessary for an EPS "
+              "output");
       p->outformat=OUT_FORMAT_EPS;
       if( gal_eps_suffix_is_eps(cp->output) )
         ui_add_dot_use_automatic_output(p);
@@ -820,7 +821,8 @@ ui_set_output(struct converttparams *p)
     {
       if(p->borderwidth==0 && p->widthincm==0)
         error(EXIT_FAILURE, 0, "at least one of `--widthincm' (`-u'), or "
-              "`--borderwidth (`-b') options are necessary for a PDF output");
+              "`--borderwidth (`-b') options are necessary for a PDF "
+                 "output");
       p->outformat=OUT_FORMAT_PDF;
       if( gal_pdf_suffix_is_pdf(cp->output) )
         ui_add_dot_use_automatic_output(p);
diff --git a/bin/convolve/Makefile.am b/bin/convolve/Makefile.am
index 72aeadd..c47d0f0 100644
--- a/bin/convolve/Makefile.am
+++ b/bin/convolve/Makefile.am
@@ -29,7 +29,7 @@ AM_CPPFLAGS = -I\$(top_srcdir)/bootstrapped/lib 
-I\$(top_srcdir)/lib
 bin_PROGRAMS = astconvolve
 
 ## Reason for linking with `libgnu' described in `bin/TEMPLATE/Makefile.am'.
-astconvolve_LDADD = $(top_builddir)/bootstrapped/lib/libgnu.la -lgnuastro
+astconvolve_LDADD = $(top_builddir)/bootstrapped/lib/libgnu.la -lgnuastro 
$(CONFIG_LDADD)
 
 astconvolve_SOURCES = main.c ui.c convolve.c
 
diff --git a/bin/convolve/convolve.c b/bin/convolve/convolve.c
index c374531..4d23262 100644
--- a/bin/convolve/convolve.c
+++ b/bin/convolve/convolve.c
@@ -790,7 +790,7 @@ convolve(struct convolveparams *p)
 
       /* Clean up: free the actual input and replace it's pointer with the
          convolved dataset to save as output. */
-      if(&cp->tl) gal_tile_full_free_contents(&cp->tl);
+      gal_tile_full_free_contents(&cp->tl);
       gal_data_free(p->input);
       p->input=out;
     }
diff --git a/bin/convolve/ui.c b/bin/convolve/ui.c
index 9b34719..7d131ba 100644
--- a/bin/convolve/ui.c
+++ b/bin/convolve/ui.c
@@ -384,7 +384,7 @@ ui_read_column(struct convolveparams *p, int i0k1)
   if(out->next!=NULL)
     {
       if(filename)
-        gal_checkset_dataset_name(filename, hdu);
+        source=gal_checkset_dataset_name(filename, hdu);
       else
         source="standard-input";
       error(EXIT_FAILURE, 0, "%s: more than one column in input table mached "
diff --git a/bin/cosmiccal/Makefile.am b/bin/cosmiccal/Makefile.am
index 96cafdd..3021844 100644
--- a/bin/cosmiccal/Makefile.am
+++ b/bin/cosmiccal/Makefile.am
@@ -29,7 +29,7 @@ AM_CPPFLAGS = -I\$(top_srcdir)/bootstrapped/lib 
-I\$(top_srcdir)/lib
 bin_PROGRAMS = astcosmiccal
 
 ## Reason for linking with `libgnu' described in `bin/TEMPLATE/Makefile.am'.
-astcosmiccal_LDADD = $(top_builddir)/bootstrapped/lib/libgnu.la -lgnuastro
+astcosmiccal_LDADD = $(top_builddir)/bootstrapped/lib/libgnu.la -lgnuastro 
$(CONFIG_LDADD)
 
 astcosmiccal_SOURCES = main.c ui.c cosmiccal.c
 
diff --git a/bin/cosmiccal/args.h b/bin/cosmiccal/args.h
index e7359cb..d241ca0 100644
--- a/bin/cosmiccal/args.h
+++ b/bin/cosmiccal/args.h
@@ -45,6 +45,20 @@ struct argp_option program_options[] =
       GAL_OPTIONS_NOT_SET
     },
     {
+      "obsline",
+      UI_KEY_OBSLINE,
+      "STR,FLT",
+      0,
+      "Redshift from line and observed wavelength.",
+      GAL_OPTIONS_GROUP_INPUT,
+      &p->obsline,
+      GAL_TYPE_STRING,
+      GAL_OPTIONS_RANGE_ANY,
+      GAL_OPTIONS_NOT_MANDATORY,
+      GAL_OPTIONS_NOT_SET,
+      ui_parse_obsline
+    },
+    {
       "H0",
       UI_KEY_H0,
       "FLT",
@@ -106,6 +120,20 @@ struct argp_option program_options[] =
       UI_GROUP_SPECIFIC
     },
     {
+      "usedredshift",
+      UI_KEY_USEDREDSHIFT,
+      0,
+      0,
+      "Used redshift in this run.",
+      UI_GROUP_SPECIFIC,
+      &p->specific,
+      GAL_OPTIONS_NO_ARG_TYPE,
+      GAL_OPTIONS_RANGE_0_OR_1,
+      GAL_OPTIONS_NOT_MANDATORY,
+      GAL_OPTIONS_NOT_SET,
+      ui_add_to_single_value,
+    },
+    {
       "agenow",
       UI_KEY_AGENOW,
       0,
diff --git a/bin/cosmiccal/cosmiccal.c b/bin/cosmiccal/cosmiccal.c
index e58a834..9d52a29 100644
--- a/bin/cosmiccal/cosmiccal.c
+++ b/bin/cosmiccal/cosmiccal.c
@@ -167,6 +167,11 @@ cosmiccal(struct cosmiccalparams *p)
       for(tmp=p->specific;tmp!=NULL;tmp=tmp->next)
         switch(tmp->v)
           {
+          case UI_KEY_USEDREDSHIFT:
+            printf("%g ",
+                   p->redshift==MAIN_REDSHIFT_ZERO ? 0.0f: p->redshift);
+            break;
+
           case UI_KEY_AGENOW:
             printf("%f ", gal_cosmology_age(0.0f, p->H0, p->olambda,
                                             p->omatter, p->oradiation));
diff --git a/bin/cosmiccal/main.h b/bin/cosmiccal/main.h
index e6aff26..958a8db 100644
--- a/bin/cosmiccal/main.h
+++ b/bin/cosmiccal/main.h
@@ -33,7 +33,7 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 #define PROGRAM_EXEC   "astcosmiccal"     /* Program executable name. */
 #define PROGRAM_STRING PROGRAM_NAME" (" PACKAGE_NAME ") " PACKAGE_VERSION
 
-
+#define MAIN_REDSHIFT_ZERO 1e-20
 
 
 
@@ -51,6 +51,7 @@ struct cosmiccalparams
   double               olambda; /* Current cosmological constant dens.  */
   double               omatter; /* Current matter density.              */
   double            oradiation; /* Current radiation density.           */
+  gal_data_t          *obsline; /* Observed wavelength of a line.       */
 
   /* Outputs. */
   gal_list_i32_t     *specific; /* Codes for single row calculations.   */
diff --git a/bin/cosmiccal/ui.c b/bin/cosmiccal/ui.c
index e52842b..32f4008 100644
--- a/bin/cosmiccal/ui.c
+++ b/bin/cosmiccal/ui.c
@@ -26,11 +26,14 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 #include <errno.h>
 #include <error.h>
 #include <stdio.h>
+#include <string.h>
 
 #include <gsl/gsl_const_mksa.h>
 
 #include <gnuastro/fits.h>
 #include <gnuastro/table.h>
+#include <gnuastro/speclines.h>
+#include <gnuastro/cosmology.h>
 
 #include <gnuastro-internal/timing.h>
 #include <gnuastro-internal/options.h>
@@ -231,6 +234,97 @@ ui_add_to_single_value(struct argp_option *option, char 
*arg,
 
 
 
+/* Parse the observed line properties: LINE,OBSERVED_WAVELENGHT. */
+void *
+ui_parse_obsline(struct argp_option *option, char *arg,
+                 char *filename, size_t lineno, void *junk)
+{
+  size_t nc, two=2;
+  char *c, *linename;
+  gal_data_t *obsline, *tobsline;
+  double *dptr, *tdptr, manualwl=NAN;
+  char *str, sstr[GAL_OPTIONS_STATIC_MEM_FOR_VALUES];
+
+  /* We want to print the stored values. */
+  if(lineno==-1)
+    {
+      /* Set the value pointer to `obsline'. */
+      obsline=*(gal_data_t **)(option->value);
+      dptr = obsline->array;
+
+      /* First write the line name into the output string. */
+      nc=0;
+      linename=gal_speclines_line_name(obsline->status);
+      nc += sprintf(sstr+nc, "%s,", linename);
+
+      /* Write the observed wavelength. */
+      sprintf(sstr+nc, "%g", dptr[0]);
+
+      /* Copy the string into a dynamically allocated space, because it
+         will be freed later.*/
+      gal_checkset_allocate_copy(sstr, &str);
+      return str;
+    }
+  else
+    {
+      /* The first part of `arg' (before the first comma) is not
+         necessarily a number. So we need to separate the first part from
+         the rest.*/
+      linename=arg;
+      c=arg; while(*c!='\0' && *c!=',') ++c;
+      arg = (*c=='\0') ? NULL : c+1;
+      *c='\0';
+
+      /* Read the parameters. */
+      obsline=gal_options_parse_list_of_numbers(arg, filename, lineno);
+
+      /* Only one number must be given as second argument. */
+      if(obsline->size!=1)
+        error(EXIT_FAILURE, 0, "too many values (%zu) given to `--obsline'. "
+              "Only two values (line name/wavelengh, and observed wavelengh) "
+              "must be given", obsline->size+1);
+
+      /* If a wavelength is given directly as a number (not a name), then
+         put that number in a second element of the array. */
+      dptr=&manualwl;
+      if( gal_type_from_string((void **)(&dptr), linename, GAL_TYPE_FLOAT64) )
+        { /* `linename' isn't a number. */
+          obsline->status=gal_speclines_line_code(linename);
+          if(obsline->status==GAL_SPECLINES_INVALID)
+            error(EXIT_FAILURE, 0, "`%s' not recognized as a standard spectral 
"
+                  "line name", linename);
+        }
+      else
+        { /* `linename' is a number. */
+
+          /* Allocate the new space. */
+          tobsline=gal_data_alloc(NULL, GAL_TYPE_FLOAT64, 1, &two, NULL,
+                                  0, -1, NULL, NULL, NULL);
+          tobsline->status=GAL_SPECLINES_INVALID;
+
+          /* Write the values into tptr. */
+          dptr=obsline->array;
+          tdptr=tobsline->array;
+          tdptr[0]=dptr[0];
+          tdptr[1]=manualwl;
+
+          /* Free the old dataset and use the new one. */
+          gal_data_free(obsline);
+          obsline=tobsline;
+        }
+
+      /* Point `option->value' to the dataset. */
+      *(gal_data_t **)(option->value) = obsline;
+
+      /* Our job is done, return NULL. */
+      return NULL;
+    }
+}
+
+
+
+
+
 
 
 
@@ -263,6 +357,11 @@ ui_read_check_only_options(struct cosmiccalparams *p)
           "The cosmological constant (`olambda'), matter (`omatter') "
           "and radiation (`oradiation') densities are given as %.8f, %.8f, "
           "%.8f", sum, p->olambda, p->omatter, p->oradiation);
+
+  /* Make sure that `--redshift' and `--obsline' aren't called together. */
+  if(!isnan(p->redshift) && p->obsline)
+    error(EXIT_FAILURE, 0, "`--redshift' and `--obsline' cannot be called "
+          "together");
 }
 
 
@@ -290,6 +389,21 @@ ui_read_check_only_options(struct cosmiccalparams *p)
 static void
 ui_preparations(struct cosmiccalparams *p)
 {
+  double *obsline = p->obsline ? p->obsline->array : NULL;
+
+  /* If `--obsline' has been given, set the redshift based on it. */
+  if(p->obsline)
+    p->redshift = ( (p->obsline->status==GAL_SPECLINES_INVALID)
+                    ? gal_speclines_line_redshift(obsline[0], obsline[1])
+                    : gal_speclines_line_redshift_code(obsline[0],
+                                                       p->obsline->status) );
+
+  /* Currently GSL will fail for z=0. So if a value of zero is given (bug
+     #56299). As a work-around, in such cases, we'll change it to an
+     extremely small value. NOTE: This has to be after the `obsline'
+     check.*/
+  if(p->redshift==0.0f) p->redshift=MAIN_REDSHIFT_ZERO;
+
   /* The list is filled out in a first-in-last-out order. By the time
      control reaches here, the list is finalized. So we should just reverse
      it so the user gets values in the same order they requested them. */
diff --git a/bin/cosmiccal/ui.h b/bin/cosmiccal/ui.h
index f59a5c6..dcc57f9 100644
--- a/bin/cosmiccal/ui.h
+++ b/bin/cosmiccal/ui.h
@@ -42,18 +42,20 @@ enum program_args_groups
 
 /* Available letters for short options:
 
-   e f i j k n p t w x y
-   B E J O Q R W X Y
+   f i j k n p t w x y
+   B E J Q R W X Y
 */
 enum option_keys_enum
 {
   /* With short-option version. */
   UI_KEY_REDSHIFT            = 'z',
+  UI_KEY_OBSLINE             = 'O',
   UI_KEY_H0                  = 'H',
   UI_KEY_OLAMBDA             = 'l',
   UI_KEY_OMATTER             = 'm',
   UI_KEY_ORADIATION          = 'r',
 
+  UI_KEY_USEDREDSHIFT        = 'e',
   UI_KEY_AGENOW              = 'G',
   UI_KEY_CRITICALDENSITYNOW  = 'C',
   UI_KEY_PROPERDISTANCE      = 'd',
diff --git a/bin/crop/Makefile.am b/bin/crop/Makefile.am
index e6a86a2..168cf97 100644
--- a/bin/crop/Makefile.am
+++ b/bin/crop/Makefile.am
@@ -29,7 +29,7 @@ AM_CPPFLAGS = -I\$(top_srcdir)/bootstrapped/lib 
-I\$(top_srcdir)/lib
 bin_PROGRAMS = astcrop
 
 ## Reason for linking with `libgnu' described in `bin/TEMPLATE/Makefile.am'.
-astcrop_LDADD = $(top_builddir)/bootstrapped/lib/libgnu.la -lgnuastro
+astcrop_LDADD = $(top_builddir)/bootstrapped/lib/libgnu.la -lgnuastro 
$(CONFIG_LDADD)
 
 astcrop_SOURCES = main.c ui.c crop.c wcsmode.c onecrop.c
 
diff --git a/bin/fits/Makefile.am b/bin/fits/Makefile.am
index 8d7d0e8..0f00d00 100644
--- a/bin/fits/Makefile.am
+++ b/bin/fits/Makefile.am
@@ -29,7 +29,7 @@ AM_CPPFLAGS = -I\$(top_srcdir)/bootstrapped/lib 
-I\$(top_srcdir)/lib
 bin_PROGRAMS = astfits
 
 ## Reason for linking with `libgnu' described in `bin/TEMPLATE/Makefile.am'.
-astfits_LDADD = $(top_builddir)/bootstrapped/lib/libgnu.la -lgnuastro
+astfits_LDADD = $(top_builddir)/bootstrapped/lib/libgnu.la -lgnuastro 
$(CONFIG_LDADD)
 
 astfits_SOURCES = main.c ui.c extension.c fits.c keywords.c
 
diff --git a/bin/fits/keywords.c b/bin/fits/keywords.c
index 61bb435..f7346ff 100644
--- a/bin/fits/keywords.c
+++ b/bin/fits/keywords.c
@@ -351,7 +351,7 @@ keywords_copykeys(struct fitsparams *p, char *inkeys, 
size_t numinkeys)
   if(p->copykeysrange[0]>=numinkeys)
     error(EXIT_FAILURE, 0, "%s (hdu %s): first keyword number give to "
           "`--copykeys' (%ld) is larger than the number of keywords in this "
-          "header (%ld, including the `END' keyword)", p->filename, p->cp.hdu,
+          "header (%zu, including the `END' keyword)", p->filename, p->cp.hdu,
           p->copykeysrange[0], numinkeys);
 
   /* If the user wanted to count from the end (by giving a negative value),
@@ -374,7 +374,7 @@ keywords_copykeys(struct fitsparams *p, char *inkeys, 
size_t numinkeys)
   if(p->copykeysrange[1]>=numinkeys)
     error(EXIT_FAILURE, 0, "%s (hdu %s): second keyword number give to "
           "`--copykeys' (%ld) is larger than the number of keywords in this "
-          "header (%ld, including the `END' keyword)", p->filename, p->cp.hdu,
+          "header (%zu, including the `END' keyword)", p->filename, p->cp.hdu,
           p->copykeysrange[1], numinkeys);
 
 
@@ -424,7 +424,7 @@ keywords_date_to_seconds(struct fitsparams *p, fitsfile 
*fptr)
       printf("(To suppress verbose output, run with `-q')\n");
     }
   else
-    printf("%ld%s\n", seconds, subsecstr);
+    printf("%zu%s\n", seconds, subsecstr);
 }
 
 
diff --git a/bin/match/Makefile.am b/bin/match/Makefile.am
index c11c58d..28ab4fa 100644
--- a/bin/match/Makefile.am
+++ b/bin/match/Makefile.am
@@ -29,7 +29,7 @@ AM_CPPFLAGS = -I\$(top_srcdir)/bootstrapped/lib 
-I\$(top_srcdir)/lib
 bin_PROGRAMS = astmatch
 
 ## Reason for linking with `libgnu' described in `bin/TEMPLATE/Makefile.am'.
-astmatch_LDADD = $(top_builddir)/bootstrapped/lib/libgnu.la -lgnuastro
+astmatch_LDADD = $(top_builddir)/bootstrapped/lib/libgnu.la -lgnuastro 
$(CONFIG_LDADD)
 
 astmatch_SOURCES = main.c ui.c match.c
 
diff --git a/bin/match/match.c b/bin/match/match.c
index 7dca0ab..d60c39e 100644
--- a/bin/match/match.c
+++ b/bin/match/match.c
@@ -353,7 +353,7 @@ match_catalog(struct matchparams *p)
   uint32_t *u, *uf;
   gal_data_t *tmp, *mcols;
   gal_data_t *a=NULL, *b=NULL;
-  size_t nummatched, *acolmatch, *bcolmatch;
+  size_t nummatched, *acolmatch=NULL, *bcolmatch=NULL;
 
   /* Find the matching coordinates. We are doing the processing in
      place, */
diff --git a/bin/match/ui.c b/bin/match/ui.c
index af1206e..20aa669 100644
--- a/bin/match/ui.c
+++ b/bin/match/ui.c
@@ -119,7 +119,6 @@ ui_initialize_options(struct matchparams *p,
           break;
         case GAL_OPTIONS_KEY_TYPE:
         case GAL_OPTIONS_KEY_NUMTHREADS:
-        case GAL_OPTIONS_KEY_STDINTIMEOUT:
           cp->coptions[i].flags=OPTION_HIDDEN;
           break;
         }
@@ -322,7 +321,10 @@ ui_set_mode(struct matchparams *p)
       p->mode = (tin1 == IMAGE_HDU) ? MATCH_MODE_WCS : MATCH_MODE_CATALOG;
     }
   else
-    p->mode=MATCH_MODE_CATALOG;
+    {
+      tin1=ASCII_TBL; /* For "uninitialized" warning, irrelevant here. */
+      p->mode=MATCH_MODE_CATALOG;
+    }
 
 
   /* Necessary sanity checks. */
@@ -1074,11 +1076,14 @@ ui_free_report(struct matchparams *p, struct timeval 
*t1)
 {
   /* Free the allocated arrays: */
   free(p->cp.hdu);
+  free(p->aperture);
   free(p->out1name);
   free(p->out2name);
   free(p->cp.output);
   gal_data_free(p->ccol1);
   gal_data_free(p->ccol2);
+  gal_list_data_free(p->cols1);
+  gal_list_data_free(p->cols2);
   gal_list_str_free(p->stdinlines, 1);
 
   /* Print the final message.
diff --git a/bin/mkcatalog/Makefile.am b/bin/mkcatalog/Makefile.am
index b834dff..0797e92 100644
--- a/bin/mkcatalog/Makefile.am
+++ b/bin/mkcatalog/Makefile.am
@@ -29,7 +29,7 @@ AM_CPPFLAGS = -I\$(top_srcdir)/bootstrapped/lib 
-I\$(top_srcdir)/lib
 bin_PROGRAMS = astmkcatalog
 
 ## Reason for linking with `libgnu' described in `bin/TEMPLATE/Makefile.am'.
-astmkcatalog_LDADD = $(top_builddir)/bootstrapped/lib/libgnu.la -lgnuastro
+astmkcatalog_LDADD = $(top_builddir)/bootstrapped/lib/libgnu.la -lgnuastro 
$(CONFIG_LDADD)
 
 astmkcatalog_SOURCES = main.c ui.c mkcatalog.c columns.c upperlimit.c parse.c
 
diff --git a/bin/mkcatalog/args.h b/bin/mkcatalog/args.h
index b08a2ac..1a2ad60 100644
--- a/bin/mkcatalog/args.h
+++ b/bin/mkcatalog/args.h
@@ -1302,7 +1302,7 @@ struct argp_option program_options[] =
       UI_KEY_SEMIMAJOR,
       0,
       0,
-      "Flux weighted semi-major axis.",
+      "RMS along major axis (in pixels).",
       UI_GROUP_COLUMNS_MORPHOLOGY,
       0,
       GAL_TYPE_INVALID,
@@ -1316,7 +1316,7 @@ struct argp_option program_options[] =
       UI_KEY_SEMIMINOR,
       0,
       0,
-      "Flux weighted semi-minor axis.",
+      "RMS along minor axis (in pixels).",
       UI_GROUP_COLUMNS_MORPHOLOGY,
       0,
       GAL_TYPE_INVALID,
@@ -1358,7 +1358,7 @@ struct argp_option program_options[] =
       UI_KEY_GEOSEMIMAJOR,
       0,
       0,
-      "Geometric semi-major axis.",
+      "RMS along major axis (ignoring value).",
       UI_GROUP_COLUMNS_MORPHOLOGY,
       0,
       GAL_TYPE_INVALID,
@@ -1372,7 +1372,7 @@ struct argp_option program_options[] =
       UI_KEY_GEOSEMIMINOR,
       0,
       0,
-      "Geometric semi-minor axis.",
+      "RMS along minor axis (ignoring value).",
       UI_GROUP_COLUMNS_MORPHOLOGY,
       0,
       GAL_TYPE_INVALID,
diff --git a/bin/mknoise/Makefile.am b/bin/mknoise/Makefile.am
index 6f09968..4573434 100644
--- a/bin/mknoise/Makefile.am
+++ b/bin/mknoise/Makefile.am
@@ -29,7 +29,7 @@ AM_CPPFLAGS = -I\$(top_srcdir)/bootstrapped/lib 
-I\$(top_srcdir)/lib
 bin_PROGRAMS = astmknoise
 
 ## Reason for linking with `libgnu' described in `bin/TEMPLATE/Makefile.am'.
-astmknoise_LDADD = $(top_builddir)/bootstrapped/lib/libgnu.la -lgnuastro
+astmknoise_LDADD = $(top_builddir)/bootstrapped/lib/libgnu.la -lgnuastro 
$(CONFIG_LDADD)
 
 astmknoise_SOURCES = main.c ui.c mknoise.c
 
diff --git a/bin/mkprof/Makefile.am b/bin/mkprof/Makefile.am
index cfaa9ea..e0d2a51 100644
--- a/bin/mkprof/Makefile.am
+++ b/bin/mkprof/Makefile.am
@@ -29,7 +29,7 @@ AM_CPPFLAGS = -I\$(top_srcdir)/bootstrapped/lib 
-I\$(top_srcdir)/lib
 bin_PROGRAMS = astmkprof
 
 ## Reason for linking with `libgnu' described in `bin/TEMPLATE/Makefile.am'.
-astmkprof_LDADD = $(top_builddir)/bootstrapped/lib/libgnu.la -lgnuastro
+astmkprof_LDADD = $(top_builddir)/bootstrapped/lib/libgnu.la -lgnuastro 
$(CONFIG_LDADD)
 
 astmkprof_SOURCES = main.c ui.c mkprof.c oneprofile.c profiles.c
 
diff --git a/bin/noisechisel/Makefile.am b/bin/noisechisel/Makefile.am
index 873a112..2651026 100644
--- a/bin/noisechisel/Makefile.am
+++ b/bin/noisechisel/Makefile.am
@@ -29,7 +29,7 @@ AM_CPPFLAGS = -I\$(top_srcdir)/bootstrapped/lib 
-I\$(top_srcdir)/lib
 bin_PROGRAMS = astnoisechisel
 
 ## Reason for linking with `libgnu' described in `bin/TEMPLATE/Makefile.am'.
-astnoisechisel_LDADD = $(top_builddir)/bootstrapped/lib/libgnu.la -lgnuastro
+astnoisechisel_LDADD = $(top_builddir)/bootstrapped/lib/libgnu.la -lgnuastro 
$(CONFIG_LDADD)
 
 astnoisechisel_SOURCES = main.c ui.c detection.c noisechisel.c sky.c     \
   threshold.c
diff --git a/bin/noisechisel/detection.c b/bin/noisechisel/detection.c
index 9104055..cd9e69c 100644
--- a/bin/noisechisel/detection.c
+++ b/bin/noisechisel/detection.c
@@ -519,13 +519,6 @@ detection_sn_write_to_file(struct noisechiselparams *p, 
gal_data_t *sn,
                 : "SKY_PSEUDODET_SN" );
   threshold_write_sn_table(p, sn, snind, str, comments, extname);
   gal_list_str_free(comments, 1);
-
-
-  /* Abort NoiseChisel if the user asked for it. */
-  if(s0d1D2==2 && !p->continueaftercheck)
-    ui_abort_after_check(p, p->detsn_s_name, p->detsn_d_name,
-                         "pseudo-detection and grown/final detection S/N "
-                         "values in a table");
 }
 
 
@@ -867,23 +860,19 @@ detection_final_remove_small_sn(struct noisechiselparams 
*p,
   size_t i;
   int8_t *b;
   float *snarr;
-  gal_data_t *sn, *snind;
+  gal_data_t *sn;
   int32_t *l, *lf, curlab=1;
-  gal_list_str_t *comments=NULL;
-  char *extname="GROWN_DETECTION_SN";
   int32_t *newlabs=gal_pointer_allocate(GAL_TYPE_INT32, num+1, 1, __func__,
                                         "newlabs");
 
   /* Get the Signal to noise ratio of all detections. */
   sn=detection_sn(p, p->olabel, num, 2, "DILATED");
 
-
   /* Only keep the objects with an S/N above the pseudo-detection limit. */
   snarr=sn->array;
   for(i=1;i<num+1;++i)
     newlabs[i] = snarr[i] > p->detsnthresh ? curlab++ : 0;
 
-
   /* Go over the labeled image and correct the labels. */
   b=workbin->array;
   lf=(l=p->olabel->array)+p->olabel->size;
@@ -899,32 +888,6 @@ detection_final_remove_small_sn(struct noisechiselparams 
*p,
     }
   else do *b++ = (*l=newlabs[ *l ]) > 0; while(++l<lf);
 
-
-  /* Save the S/N values if the user asked for them. */
-  if(p->detsn_D_name)
-    {
-      /* Make the S/N index array. */
-      snind=gal_data_alloc(NULL, GAL_TYPE_INT32, 1, &num, NULL, 0,
-                           p->cp.minmapsize, NULL, NULL, NULL);
-
-      /* Fill in the indexs. Note that the S/N array had num+1 elements, so
-         we also want to shift them back by one element, so we also need to
-         correct its size. */
-      l=snind->array;
-      sn->size = sn->dsize[0] = num;
-      for(i=0;i<num;++i) { l[i]=i+1; snarr[i]=snarr[i+1]; }
-
-      /* Make the comments, then write the table. */
-      gal_list_str_add(&comments, "See also: `DILATED' "
-                       "HDU of output with `--checkdetection'.", 1);
-      gal_list_str_add(&comments, "S/N of finally grown detections.", 1);
-      threshold_write_sn_table(p, sn, snind, p->detsn_D_name, comments,
-                               extname);
-      gal_list_str_free(comments, 1);
-
-    }
-
-
   /* Clean up and return. */
   free(newlabs);
   gal_data_free(sn);
diff --git a/bin/noisechisel/threshold.c b/bin/noisechisel/threshold.c
index 4fe408a..9f09dc3 100644
--- a/bin/noisechisel/threshold.c
+++ b/bin/noisechisel/threshold.c
@@ -203,12 +203,6 @@ threshold_write_sn_table(struct noisechiselparams *p, 
gal_data_t *insn,
       sn=gal_data_copy(insn);
       gal_blank_remove(ind);
       gal_blank_remove(sn);
-
-      /* A small sanity check. */
-      if(ind->size==0 || sn->size==0)
-        error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at %s to fix "
-              "the problem. For some reason, all the elements in `ind' or "
-              "`sn' are blank", __func__, PACKAGE_BUGREPORT);
     }
   else
     {
diff --git a/bin/script/sort-by-night.in b/bin/script/sort-by-night.in
index 31c4d26..41bde36 100644
--- a/bin/script/sort-by-night.in
+++ b/bin/script/sort-by-night.in
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/sh
 
 # Separate input datasets into multiple nights, run with `--help', or see
 # description under `print_help' (below) for more.
@@ -60,11 +60,13 @@ This script is part of GNU Astronomy Utilities $version.
 
 This script will look into a HDU/extension for a header keyword in the
 given FITS files and interpret the value as a date. The inputs will be
-separated by "night"s. It will then print a list of all the input files
-along with the following two columns: night number and file number in that
-night (sorted by time). With '--link' a symbolic link (one for each input)
-will be made with names including the night classifier. With '--copy'
-instead of a link, a copy of the inputs will be made.
+separated by "night"s. The definition a "nights" is set with the '--hour'
+option (just note that the FITS time may be recorded in UTC, not local
+time)! It will then print a list of all the input files along with the
+following two columns: night number and file number in that night (sorted
+by time). With '--link' a symbolic link (one for each input) will be made
+with names including the night classifier. With '--copy' instead of a link,
+a copy of the inputs will be made.
 
 For more information, please run any of the following commands. In
 particular the first contains a very comprehensive explanation of this
@@ -84,6 +86,7 @@ $scriptname options:
   -h, --hdu=STR           HDU/extension of all input FITS files.
   -k, --key=STR           Header keyword specifying date to use.
   -H, --hour=FLT          Hour in next day to be included in night.
+                          Be aware of time zones whith this argument!
 
  Output:
   -l, --link              list of inputs with night and file number.
@@ -127,7 +130,7 @@ EOF
 
 
 # Functions to check option values and complain if necessary.
-function on_off_option_error() {
+on_off_option_error() {
     if [ "x$2" = x ]; then
         echo "$scriptname: '$1' doesn't take any values."
     else
@@ -136,7 +139,7 @@ function on_off_option_error() {
     exit 1
 }
 
-function check_v() {
+check_v() {
     if [ x"$2" = x ]; then
         echo "$scriptname: option '$1' requires an argument."
         echo "Try '$scriptname --help' for more information."
@@ -172,7 +175,7 @@ function check_v() {
 #   if a value is appended to the short format it should crash. So in the
 #   second test for these (`-l*') will account for both the case where we
 #   have an equal sign and where we don't.
-while [[ $# -gt 0 ]]
+while [ $# -gt 0 ]
 do
     case "$1" in
         # Input parameters.
@@ -241,9 +244,9 @@ fi
 # since 1970-01-01,00:00:00) and keep that with the filename.
 list=$(for f in $inputs; do
            astfits $f --datetosec=$key --hdu=$hdu -q \
-               | awk '{h='$hour'; d=int($1/86400);   \
-                       print "'$f'", $1,             \
-                       int($1)%86400<(h*3600) ? d-1 : d }';
+               | awk '{h='$hour'; d=int($1/86400); \
+                       if(int($1)%86400<(h*3600)) n=d-1; else n=d; \
+                       print "'$f'", $1, n }'
        done)
 
 
@@ -299,5 +302,5 @@ echo "$unique" | while read l; do
     done
 
     # Increment the night-counter.
-    ((counter++))
+    counter=$((counter+1))
 done
diff --git a/bin/segment/Makefile.am b/bin/segment/Makefile.am
index ea56135..6b1c4ec 100644
--- a/bin/segment/Makefile.am
+++ b/bin/segment/Makefile.am
@@ -29,7 +29,7 @@ AM_CPPFLAGS = -I\$(top_srcdir)/bootstrapped/lib 
-I\$(top_srcdir)/lib
 bin_PROGRAMS = astsegment
 
 ## Reason for linking with `libgnu' described in `bin/TEMPLATE/Makefile.am'.
-astsegment_LDADD = $(top_builddir)/bootstrapped/lib/libgnu.la -lgnuastro
+astsegment_LDADD = $(top_builddir)/bootstrapped/lib/libgnu.la -lgnuastro 
$(CONFIG_LDADD)
 
 astsegment_SOURCES = main.c ui.c segment.c clumps.c
 
diff --git a/bin/statistics/Makefile.am b/bin/statistics/Makefile.am
index 972cc54..07b03db 100644
--- a/bin/statistics/Makefile.am
+++ b/bin/statistics/Makefile.am
@@ -29,7 +29,7 @@ AM_CPPFLAGS = -I\$(top_srcdir)/bootstrapped/lib 
-I\$(top_srcdir)/lib
 bin_PROGRAMS = aststatistics
 
 ## Reason for linking with `libgnu' described in `bin/TEMPLATE/Makefile.am'.
-aststatistics_LDADD = $(top_builddir)/bootstrapped/lib/libgnu.la -lgnuastro
+aststatistics_LDADD = $(top_builddir)/bootstrapped/lib/libgnu.la -lgnuastro 
$(CONFIG_LDADD)
 
 aststatistics_SOURCES = main.c ui.c sky.c statistics.c
 
diff --git a/bin/statistics/args.h b/bin/statistics/args.h
index 7fbd64b..3eaed38 100644
--- a/bin/statistics/args.h
+++ b/bin/statistics/args.h
@@ -305,6 +305,63 @@ struct argp_option program_options[] =
       GAL_OPTIONS_NOT_SET,
       ui_add_to_single_value
     },
+    {
+      "sigclip-number",
+      UI_KEY_SIGCLIPNUMBER,
+      0,
+      0,
+      "Number of elements after sigma-clipping.",
+      UI_GROUP_SINGLE_VALUE,
+      &p->singlevalue,
+      GAL_OPTIONS_NO_ARG_TYPE,
+      GAL_OPTIONS_RANGE_0_OR_1,
+      GAL_OPTIONS_NOT_MANDATORY,
+      GAL_OPTIONS_NOT_SET,
+      ui_add_to_single_value
+    },
+    {
+      "sigclip-median",
+      UI_KEY_SIGCLIPMEDIAN,
+      0,
+      0,
+      "Sigma-clipped median.",
+      UI_GROUP_SINGLE_VALUE,
+      &p->singlevalue,
+      GAL_OPTIONS_NO_ARG_TYPE,
+      GAL_OPTIONS_RANGE_0_OR_1,
+      GAL_OPTIONS_NOT_MANDATORY,
+      GAL_OPTIONS_NOT_SET,
+      ui_add_to_single_value
+    },
+    {
+      "sigclip-mean",
+      UI_KEY_SIGCLIPMEAN,
+      0,
+      0,
+      "Sigma-clipped mean.",
+      UI_GROUP_SINGLE_VALUE,
+      &p->singlevalue,
+      GAL_OPTIONS_NO_ARG_TYPE,
+      GAL_OPTIONS_RANGE_0_OR_1,
+      GAL_OPTIONS_NOT_MANDATORY,
+      GAL_OPTIONS_NOT_SET,
+      ui_add_to_single_value
+    },
+    {
+      "sigclip-std",
+      UI_KEY_SIGCLIPSTD,
+      0,
+      0,
+      "Sigma-clipped standard deviation.",
+      UI_GROUP_SINGLE_VALUE,
+      &p->singlevalue,
+      GAL_OPTIONS_NO_ARG_TYPE,
+      GAL_OPTIONS_RANGE_0_OR_1,
+      GAL_OPTIONS_NOT_MANDATORY,
+      GAL_OPTIONS_NOT_SET,
+      ui_add_to_single_value
+    },
+
 
 
 
diff --git a/bin/statistics/statistics.c b/bin/statistics/statistics.c
index 333b432..30686d9 100644
--- a/bin/statistics/statistics.c
+++ b/bin/statistics/statistics.c
@@ -95,12 +95,13 @@ statistics_print_one_row(struct statisticsparams *p)
   double arg, *d;
   gal_list_i32_t *tmp;
   size_t dsize=1, counter;
-  gal_data_t *tmpv, *out=NULL, *num=NULL, *min=NULL, *max=NULL;
   gal_data_t *sum=NULL, *med=NULL, *meanstd=NULL, *modearr=NULL;
+  gal_data_t *tmpv, *sclip=NULL, *out=NULL, *num=NULL, *min=NULL, *max=NULL;
 
   /* The user can ask for any of the operators more than once, also some
      operators might return more than one usable value (like mode). So we
-     will calculate the desired values once, and then print them. */
+     will calculate the desired values once, and then print them any number
+     of times. */
   for(tmp=p->singlevalue; tmp!=NULL; tmp=tmp->next)
     switch(tmp->v)
       {
@@ -125,11 +126,21 @@ statistics_print_one_row(struct statisticsparams *p)
       case UI_KEY_MODEQUANT:
       case UI_KEY_MODESYM:
       case UI_KEY_MODESYMVALUE:
-        modearr = ( modearr ? modearr
+        modearr = ( modearr
+                    ? modearr
                     : gal_statistics_mode(p->sorted, p->mirrordist, 0) );
         d=modearr->array;
         if(d[2]<GAL_STATISTICS_MODE_GOOD_SYM) d[0]=d[1]=NAN;
         break;
+      case UI_KEY_SIGCLIPSTD:
+      case UI_KEY_SIGCLIPMEAN:
+      case UI_KEY_SIGCLIPNUMBER:
+      case UI_KEY_SIGCLIPMEDIAN:
+        sclip = ( sclip
+                  ? sclip
+                  : gal_statistics_sigma_clip(p->sorted, p->sclipparams[0],
+                                              p->sclipparams[1], 0, 1) );
+        break;
 
       /* Will be calculated as printed. */
       case UI_KEY_QUANTILE:
@@ -172,6 +183,14 @@ statistics_print_one_row(struct statisticsparams *p)
           out=statistics_pull_out_element(modearr, 2); mustfree=1; break;
         case UI_KEY_MODESYMVALUE:
           out=statistics_pull_out_element(modearr, 3); mustfree=1; break;
+        case UI_KEY_SIGCLIPSTD:
+          out=statistics_pull_out_element(sclip,   3); mustfree=1; break;
+        case UI_KEY_SIGCLIPMEAN:
+          out=statistics_pull_out_element(sclip,   2); mustfree=1; break;
+        case UI_KEY_SIGCLIPMEDIAN:
+          out=statistics_pull_out_element(sclip,   1); mustfree=1; break;
+        case UI_KEY_SIGCLIPNUMBER:
+          out=statistics_pull_out_element(sclip,   0); mustfree=1; break;
 
         /* Not previously calculated. */
         case UI_KEY_QUANTILE:
@@ -213,6 +232,7 @@ statistics_print_one_row(struct statisticsparams *p)
   if(max)     gal_data_free(max);
   if(sum)     gal_data_free(sum);
   if(med)     gal_data_free(med);
+  if(sclip)   gal_data_free(sclip);
   if(meanstd) gal_data_free(meanstd);
   if(modearr) gal_data_free(modearr);
 }
diff --git a/bin/statistics/ui.c b/bin/statistics/ui.c
index 662c0df..a85881d 100644
--- a/bin/statistics/ui.c
+++ b/bin/statistics/ui.c
@@ -249,9 +249,11 @@ ui_add_to_single_value(struct argp_option *option, char 
*arg,
     {
       /* Read the string of numbers. */
       inputs=gal_options_parse_list_of_numbers(arg, filename, lineno);
-      d=inputs->array;
+      if(inputs->size==0)
+        error(EXIT_FAILURE, 0, "`--%s' needs a value", option->name);
 
       /* Do the appropriate operations with the  */
+      d=inputs->array;
       switch(option->key)
         {
         case UI_KEY_QUANTILE:
@@ -460,6 +462,18 @@ ui_read_check_only_options(struct statisticsparams *p)
           error(EXIT_FAILURE, 0, "`--mirrordist' is required for the "
                 "mode-related single measurements (`--mode', `--modequant', "
                 "`--modesym', and `--modesymvalue')");
+        break;
+      case UI_KEY_SIGCLIPSTD:
+      case UI_KEY_SIGCLIPMEAN:
+      case UI_KEY_SIGCLIPNUMBER:
+      case UI_KEY_SIGCLIPMEDIAN:
+        if( isnan(p->sclipparams[0]) )
+          error(EXIT_FAILURE, 0, "`--sclipparams' is necessary with "
+                "sigma-clipping measurements.\n\n"
+                "`--sclipparams' takes two values (separated by a comma) for "
+                "defining the sigma-clip: the multiple of sigma, and tolerance 
"
+                "(<1) or number of clips (>1).");
+        break;
       }
 
 
@@ -665,6 +679,10 @@ ui_make_sorted_if_necessary(struct statisticsparams *p)
       case UI_KEY_MEDIAN:
       case UI_KEY_QUANTILE:
       case UI_KEY_QUANTFUNC:
+      case UI_KEY_SIGCLIPSTD:
+      case UI_KEY_SIGCLIPMEAN:
+      case UI_KEY_SIGCLIPNUMBER:
+      case UI_KEY_SIGCLIPMEDIAN:
         is_necessary=1;
         break;
       }
diff --git a/bin/statistics/ui.h b/bin/statistics/ui.h
index de4782c..8b2422b 100644
--- a/bin/statistics/ui.h
+++ b/bin/statistics/ui.h
@@ -100,6 +100,10 @@ enum option_keys_enum
   UI_KEY_CHECKSKY,
   UI_KEY_IGNOREBLANKINTILES,
   UI_KEY_SCLIPPARAMS,
+  UI_KEY_SIGCLIPNUMBER,
+  UI_KEY_SIGCLIPMEDIAN,
+  UI_KEY_SIGCLIPMEAN,
+  UI_KEY_SIGCLIPSTD,
 };
 
 
diff --git a/bin/table/Makefile.am b/bin/table/Makefile.am
index f3313a2..ccc5036 100644
--- a/bin/table/Makefile.am
+++ b/bin/table/Makefile.am
@@ -29,11 +29,11 @@ AM_CPPFLAGS = -I\$(top_srcdir)/bootstrapped/lib 
-I\$(top_srcdir)/lib
 bin_PROGRAMS = asttable
 
 ## Reason for linking with `libgnu' described in `bin/TEMPLATE/Makefile.am'.
-asttable_LDADD = $(top_builddir)/bootstrapped/lib/libgnu.la -lgnuastro
+asttable_LDADD = $(top_builddir)/bootstrapped/lib/libgnu.la -lgnuastro 
$(CONFIG_LDADD)
 
-asttable_SOURCES = main.c ui.c table.c
+asttable_SOURCES = main.c ui.c arithmetic.c table.c
 
-EXTRA_DIST = main.h authors-cite.h args.h ui.h table.h
+EXTRA_DIST = main.h authors-cite.h args.h ui.h arithmetic.h table.h
 
 
 
diff --git a/bin/table/args.h b/bin/table/args.h
index 4c151d1..144616c 100644
--- a/bin/table/args.h
+++ b/bin/table/args.h
@@ -44,6 +44,32 @@ struct argp_option program_options[] =
       GAL_OPTIONS_NOT_MANDATORY,
       GAL_OPTIONS_NOT_SET
     },
+    {
+      "wcsfile",
+      UI_KEY_WCSFILE,
+      "STR",
+      0,
+      "File with WCS if conversion is requested.",
+      GAL_OPTIONS_GROUP_INPUT,
+      &p->wcsfile,
+      GAL_TYPE_STRING,
+      GAL_OPTIONS_RANGE_ANY,
+      GAL_OPTIONS_NOT_MANDATORY,
+      GAL_OPTIONS_NOT_SET
+    },
+    {
+      "wcshdu",
+      UI_KEY_WCSHDU,
+      "STR",
+      0,
+      "HDU in file with WCS for conversion.",
+      GAL_OPTIONS_GROUP_INPUT,
+      &p->wcshdu,
+      GAL_TYPE_STRING,
+      GAL_OPTIONS_RANGE_ANY,
+      GAL_OPTIONS_NOT_MANDATORY,
+      GAL_OPTIONS_NOT_SET
+    },
 
 
 
@@ -116,6 +142,32 @@ struct argp_option program_options[] =
       GAL_OPTIONS_NOT_MANDATORY,
       GAL_OPTIONS_NOT_SET
     },
+    {
+      "head",
+      UI_KEY_HEAD,
+      "INT",
+      0,
+      "Only output given number of top rows.",
+      GAL_OPTIONS_GROUP_OUTPUT,
+      &p->head,
+      GAL_TYPE_SIZE_T,
+      GAL_OPTIONS_RANGE_GE_0,
+      GAL_OPTIONS_NOT_MANDATORY,
+      GAL_OPTIONS_NOT_SET
+    },
+    {
+      "tail",
+      UI_KEY_TAIL,
+      "INT",
+      0,
+      "Only output given number of bottom rows.",
+      GAL_OPTIONS_GROUP_OUTPUT,
+      &p->tail,
+      GAL_TYPE_SIZE_T,
+      GAL_OPTIONS_RANGE_GE_0,
+      GAL_OPTIONS_NOT_MANDATORY,
+      GAL_OPTIONS_NOT_SET
+    },
 
 
 
diff --git a/bin/table/arithmetic.c b/bin/table/arithmetic.c
new file mode 100644
index 0000000..3ed15dc
--- /dev/null
+++ b/bin/table/arithmetic.c
@@ -0,0 +1,672 @@
+/*********************************************************************
+Table - View and manipulate a FITS table structures.
+Table is part of GNU Astronomy Utilities (Gnuastro) package.
+
+Original author:
+     Mohammad Akhlaghi <mohammad@akhlaghi.org>
+Contributing author(s):
+Copyright (C) 2019, 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 <string.h>
+#include <stdlib.h>
+
+#include <gnuastro/wcs.h>
+
+#include <gnuastro-internal/checkset.h>
+
+#include "main.h"
+#include "arithmetic.h"
+
+
+
+
+/*********************************************************************/
+/********************       List operations      *********************/
+/*********************************************************************/
+static struct arithmetic_token *
+arithmetic_add_new_to_end(struct arithmetic_token **list)
+{
+  struct arithmetic_token *tmp, *node;
+
+  /* Allocate a new node. */
+  errno=0;
+  node=malloc(sizeof *node);
+  if(node==NULL)
+    error(EXIT_FAILURE, errno, "%s: couldn't allocate new node (%zu bytes)",
+          __func__, sizeof *node);
+
+  /* Initialize its elements. */
+  node->next=NULL;
+  node->constant=NULL;
+  node->index=GAL_BLANK_SIZE_T;
+  node->operator=GAL_ARITHMETIC_OP_INVALID;
+
+  /* If the list already has elements, go to the last node in the list and
+     add this node. */
+  if(*list)
+    {
+      for(tmp=*list;tmp->next!=NULL;tmp=tmp->next) {}
+      tmp->next=node;
+    }
+  else
+    *list=node;
+
+  /* Return a pointer to this node (to use temporarily). */
+  return node;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/*********************************************************************/
+/********************       User-interface       *********************/
+/*********************************************************************/
+static char *
+arithmetic_operator_name(int operator)
+{
+  char *out=gal_arithmetic_operator_string(operator);
+
+  /* If the operator wasn't in the library, see if it was defined here. */
+  if(out==NULL)
+    switch(operator)
+      {
+      case ARITHMETIC_TABLE_OP_WCSTOIMG: out="wcstoimg"; break;
+      case ARITHMETIC_TABLE_OP_IMGTOWCS: out="imgtowcs"; break;
+      default:
+        error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at %s to fix "
+              "the problem. %d is not a recognized operator code", __func__,
+              PACKAGE_BUGREPORT, operator);
+      }
+
+  return out;
+}
+
+
+
+
+
+static void
+arithmetic_init_wcs(struct tableparams *p, char *operator)
+{
+  /* If a WCS hasn't been read yet, read it.*/
+  if(p->wcs==NULL)
+    {
+      /* A small sanity check. */
+      if(p->wcsfile==NULL || p->wcshdu==NULL)
+        error(EXIT_FAILURE, 0, "`--wcsfile' and `--wcshdu' are necessary "
+              "for the `%s' operator", operator);
+
+      /* Read the WCS. */
+      p->wcs=gal_wcs_read(p->wcsfile, p->wcshdu, 0, 0, &p->nwcs);
+      if(p->wcs==NULL)
+        error(EXIT_FAILURE, 0, "%s (hdu: %s): no WCS could be read by "
+              "WCSLIB", p->wcsfile, p->wcshdu);
+    }
+}
+
+
+
+
+
+/* Set the operator code from the given string. */
+static int
+arithmetic_set_operator(struct tableparams *p, char *string,
+                        size_t *num_operands)
+{
+  int op=gal_arithmetic_set_operator(string, num_operands);;
+
+  /* Set the operator and number of operands. */
+  if( op==GAL_ARITHMETIC_OP_INVALID )
+    {
+      if(      !strncmp(string, "wcstoimg", 8))
+        { op=ARITHMETIC_TABLE_OP_WCSTOIMG;   *num_operands=0; }
+      else if (!strncmp(string, "imgtowcs", 8))
+        { op=ARITHMETIC_TABLE_OP_IMGTOWCS;   *num_operands=0; }
+      else
+        { op=GAL_ARITHMETIC_OP_INVALID; *num_operands=GAL_BLANK_INT; }
+    }
+
+  /* Operator specific operations. */
+  switch(op)
+    {
+    case ARITHMETIC_TABLE_OP_WCSTOIMG:
+    case ARITHMETIC_TABLE_OP_IMGTOWCS:
+      arithmetic_init_wcs(p, string);
+      break;
+    }
+
+  /* Return the operator. */
+  return op;
+}
+
+
+
+
+
+/* Initialize each column from an arithmetic operation. */
+void
+arithmetic_init(struct tableparams *p, struct arithmetic_token **arith,
+                gal_list_str_t **toread, size_t *totcalled, char *expression)
+{
+  void *num;
+  size_t one=1;
+  uint8_t ntype;
+  char *str, *delimiter=" \t";
+  struct arithmetic_token *node=NULL;
+  char *token=NULL, *lasttoken=NULL, *saveptr;
+
+  /* Parse all the given tokens. */
+  token=strtok_r(expression, delimiter, &saveptr);
+  while(token!=NULL)
+    {
+      /* Allocate and initialize this arithmetic token. */
+      lasttoken=token;
+      node=arithmetic_add_new_to_end(arith);
+
+      /* See if the token is an operator, if not check other cases.  */
+      node->operator=arithmetic_set_operator(p, token, &node->num_operands);
+      if(node->operator==GAL_ARITHMETIC_OP_INVALID)
+        {
+          /* Token is a single number.*/
+          if( (num=gal_type_string_to_number(token, &ntype)) )
+            node->constant=gal_data_alloc(num, ntype, 1, &one, NULL, 0, -1,
+                                          NULL, NULL, NULL);
+
+          /* Token is a column operand (column number or name). */
+          else
+            {
+              str = ( (token[0]=='c' && isdigit(token[1]))
+                      ? &token[1]   /* Column number (starting with `c'). */
+                      : token );    /* Column name, just add it.          */
+              gal_list_str_add(toread, str, 1);
+              node->index=*totcalled;
+              *totcalled+=1;
+            }
+        }
+
+      /* Go to the next token. */
+      token=strtok_r(NULL, delimiter, &saveptr);
+    }
+
+  /* A small sanity check: the last added token must be an operator. */
+  if( node==NULL || node->operator==GAL_ARITHMETIC_OP_INVALID )
+    error(EXIT_FAILURE, 0, "last token in arithmetic column (`%s') is not a "
+          "recognized operator", lasttoken);
+}
+
+
+
+
+
+/* Set the final index of each package of columns (possibly containing
+   processing columns that will change in number and contents).  */
+void
+arithmetic_indexs_final(struct tableparams *p, size_t *colmatch)
+{
+  size_t startind;
+  size_t i, numcols;
+  struct column_pack *tmp;
+  struct arithmetic_token *atmp;
+
+  /* Set the column array that will allow removal of some read columns
+     (where operations will be done). */
+  p->colarray=gal_list_data_to_array_ptr(p->table, &p->numcolarray);
+
+  /* go over each package of columns. */
+  for(tmp=p->outcols;tmp!=NULL;tmp=tmp->next)
+    {
+      /* If we are on an arithmetic operation. */
+      if(tmp->tokens)
+        {
+          for(atmp=tmp->tokens;atmp!=NULL;atmp=atmp->next)
+            if(atmp->index!=GAL_BLANK_SIZE_T)
+              {
+                /* Small sanity check. */
+                if(colmatch[atmp->index]!=1)
+                  error(EXIT_FAILURE, 0, "arithmetic operands can (currently) "
+                        "only correspond to a single column");
+
+                /* Update the index in the full list of read columns. */
+                numcols=0; for(i=0;i<atmp->index;++i) numcols+=colmatch[i];
+                atmp->index=numcols;
+              }
+        }
+      /* A simple column. */
+      else
+        {
+          /* See where the starting column for this patch of simple columns
+             is. */
+          startind=0;
+          for(i=0;i<tmp->start;++i) startind+=colmatch[i];
+
+          /* How many of the read columns are associated with the this
+             patch of columns. */
+          numcols=0;
+          for(i=0;i<tmp->numsimple;++i) numcols+=colmatch[tmp->start+i];
+
+          /* Update the values. */
+          tmp->start=startind;
+          tmp->numsimple=numcols;
+        }
+
+    }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/*********************************************************************/
+/********************       Low-level tools      *********************/
+/*********************************************************************/
+static gal_data_t *
+arithmetic_stack_pop(gal_data_t **stack, int operator)
+{
+  gal_data_t *out=*stack;
+
+  /* Update the stack. */
+  if(*stack)
+    *stack=(*stack)->next;
+  else
+    error(EXIT_FAILURE, 0, "not enough operands for `%s'",
+          arithmetic_operator_name(operator));
+
+  /* Remove the `next' element to break from the stack and return. */
+  out->next=NULL;
+  return out;
+}
+
+
+
+
+
+/* Set the converted column metadata. */
+static void
+arithmetic_update_metadata(gal_data_t *col, char *name, char *unit,
+                           char *comment)
+{
+  if(col)
+    {
+      if(col->name)    free(col->name);
+      if(col->unit)    free(col->unit);
+      if(col->comment) free(col->comment);
+      gal_checkset_allocate_copy(name, &col->name);
+      gal_checkset_allocate_copy(unit, &col->unit);
+      gal_checkset_allocate_copy(comment, &col->comment);
+    }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/*********************************************************************/
+/********************          Operations        *********************/
+/*********************************************************************/
+static void
+arithmetic_wcs(struct tableparams *p, gal_data_t **stack, int operator)
+{
+  gal_data_t *tmp;
+  struct wcsprm *wcs=p->wcs;
+  size_t i, ndim=p->wcs->naxis;
+  gal_data_t *coord[3]={NULL, NULL, NULL};
+
+  /* Pop all the necessary datasets and make sure they are
+     double-precision. NOTE: the top dataset on the stack is the
+     highest-dimensional dataset. */
+  for(i=0;i<ndim;++i)
+    {
+      tmp=arithmetic_stack_pop(stack, operator);
+      tmp=gal_data_copy_to_new_type_free(tmp, GAL_TYPE_FLOAT64);
+      coord[ndim-i-1]=tmp;
+    }
+
+  /* Define the list of coordinates. */
+  if(coord[1]) coord[0]->next=coord[1];
+  if(coord[2]) coord[1]->next=coord[2];
+
+
+  /* Final preparations. */
+  if(operator==ARITHMETIC_TABLE_OP_WCSTOIMG)
+    {
+      /* Do the conversion. */
+      gal_wcs_world_to_img(coord[0], wcs, 1);
+
+      /* For image coordinates, we don't need much precision. */
+      for(i=0;i<ndim;++i)
+        coord[i]=gal_data_copy_to_new_type_free(coord[i], GAL_TYPE_FLOAT32);
+
+      /* Set the names, units and comments for each dataset. */
+      arithmetic_update_metadata(coord[0],"X","pixel","Converted from WCS");
+      arithmetic_update_metadata(coord[1],"Y","pixel","Converted from WCS");
+      arithmetic_update_metadata(coord[2],"Z","pixel","Converted from WCS");
+    }
+  else
+    {
+      gal_wcs_img_to_world(coord[0], wcs, 1);
+      arithmetic_update_metadata(coord[0], wcs->ctype[0], wcs->cunit[0],
+                                 "Converted from pixel coordinates");
+      arithmetic_update_metadata(coord[1], coord[1]?wcs->ctype[1]:NULL,
+                                 coord[1]?wcs->cunit[1]:NULL,
+                                 "Converted from pixel coordinates");
+      arithmetic_update_metadata(coord[2], coord[2]?wcs->ctype[2]:NULL,
+                                 coord[2]?wcs->cunit[2]:NULL,
+                                 "Converted from pixel coordinates");
+    }
+
+  /* Reverse the column orders and put them on the stack. */
+  for(i=0;i<ndim;++i)
+    {
+      coord[i]->next=NULL;
+      gal_list_data_add(stack, coord[i]);
+    }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/*********************************************************************/
+/********************          Operations        *********************/
+/*********************************************************************/
+static void
+arithmetic_placeholder_name(gal_data_t *col)
+{
+  static size_t counter=0;
+
+  /* Increment counter next time this function is called. */
+  ++counter;
+
+  /* Free any possibly existing metadata. */
+  if(col->name)    free(col->name);
+  if(col->unit)    free(col->unit);
+  if(col->comment) free(col->comment);
+
+  /* Set the new meta-data. */
+  errno=0;
+  if( asprintf(&col->name, "ARITH_%zu", counter)==-1 )
+    error(EXIT_FAILURE, errno, "%s: asprintf error for name", __func__);
+  if( asprintf(&col->unit, "arith_unit_%zu", counter)==-1)
+    error(EXIT_FAILURE, errno, "%s: asprintf error for unit", __func__);
+  if( asprintf(&col->comment, "Column from arithmetic operation %zu",
+               counter)==-1 )
+    error(EXIT_FAILURE, errno, "%s: asprintf error for comment", __func__);
+}
+
+
+
+
+
+static void
+arithmetic_operator_run(struct tableparams *p, gal_data_t **stack,
+                        int operator, size_t num_operands)
+{
+  gal_data_t *d1=NULL, *d2=NULL, *d3=NULL;
+  int flags = ( GAL_ARITHMETIC_INPLACE | GAL_ARITHMETIC_FREE
+                | GAL_ARITHMETIC_NUMOK );
+
+  /* When `num_operands!=0', the operator is in the library. */
+  if(num_operands)
+    {
+      /* Pop the necessary number of operators. Note that the
+         operators are poped from a linked list (which is
+         last-in-first-out). So for the operators which need a
+         specific order, the first poped operand is actally the
+         last (right most, in in-fix notation) input operand.*/
+      switch(num_operands)
+        {
+        case 1:
+          d1=arithmetic_stack_pop(stack, operator);
+          break;
+
+        case 2:
+          d2=arithmetic_stack_pop(stack, operator);
+          d1=arithmetic_stack_pop(stack, operator);
+          break;
+
+        case 3:
+          d3=arithmetic_stack_pop(stack, operator);
+          d2=arithmetic_stack_pop(stack, operator);
+          d1=arithmetic_stack_pop(stack, operator);
+          break;
+
+        case -1:
+          error(EXIT_FAILURE, 0, "operators with a variable number of "
+                "operands are not yet implemented. Please contact us at "
+                "%s to include them", PACKAGE_BUGREPORT);
+          break;
+
+        default:
+          error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at %s to fix "
+                "the problem. `%zu' is not recognized as an operand "
+                "counter (with `%s')", __func__, PACKAGE_BUGREPORT,
+                num_operands, arithmetic_operator_name(operator));
+        }
+
+      /* Run the arithmetic operation. Note that `gal_arithmetic' is a
+         variable argument function (like printf). So the number of
+         arguments it uses depend on the operator. In other words, when the
+         operator doesn't need three operands, the extra arguments will be
+         ignored. */
+      gal_list_data_add(stack, gal_arithmetic(operator, p->cp.numthreads,
+                                              flags, d1, d2, d3));
+
+      /* Reset the meta-data for the element that was just put on the
+         stack. */
+      arithmetic_placeholder_name(*stack);
+    }
+
+  /* This operator is specific to this program (Table). */
+  else
+    {
+      switch(operator)
+        {
+        case ARITHMETIC_TABLE_OP_WCSTOIMG:
+        case ARITHMETIC_TABLE_OP_IMGTOWCS:
+          arithmetic_wcs(p, stack, operator);
+          break;
+
+        default:
+          error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at %s to "
+                "fix the problem. The operator code %d is not recognized",
+                __func__, PACKAGE_BUGREPORT, operator);
+        }
+    }
+}
+
+
+
+
+
+/* Apply reverse polish mechanism for this column. */
+static void
+arithmetic_reverse_polish(struct tableparams *p, struct column_pack *outpack)
+{
+  gal_data_t *single, *stack=NULL;
+  struct arithmetic_token *token;
+
+  /* Go through all the tokens given to this element. */
+  for(token=outpack->tokens;token!=NULL;token=token->next)
+    {
+      /* We are on an operator. */
+      if(token->operator!=GAL_ARITHMETIC_OP_INVALID)
+        arithmetic_operator_run(p, &stack, token->operator,
+                                token->num_operands);
+
+      /* Constant number: just put it ontop of the stack. */
+      else if(token->constant)
+        {
+          gal_list_data_add(&stack, token->constant);
+          token->constant=NULL;
+        }
+
+      /* A column from the table. */
+      else if(token->index!=GAL_BLANK_SIZE_T)
+        gal_list_data_add(&stack, p->colarray[token->index]);
+
+      /* Un-recognized situation. */
+      else
+        error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at %s to "
+              "fix the problem. The token can't be identified as an "
+              "operator, constant or column", __func__, PACKAGE_BUGREPORT);
+    }
+
+  /* Put everything that remains in the stack (reversed) into the final
+     table. Just note that `gal_list_data_add' behaves differently for
+     lists, so we'll add have to manually set the `next' element to NULL
+     before adding the column to the final table. */
+  gal_list_data_reverse(&stack);
+  while(stack!=NULL)
+    {
+      /* Keep the top element in `single' and move `stack' to the next
+         element. */
+      single=stack;
+      stack=stack->next;
+
+      /* A small sanity check. */
+      if(single->size==1 && p->table && single->size!=p->table->size)
+        error(EXIT_FAILURE, 0, "the arithmetic operation resulted in a "
+              "a single value, but other columns have also been requested "
+              "which have more elements/rows");
+
+      /* Set `single->next' to NULL so it isn't treated as a list and
+         remove all metadata */
+      single->next=NULL;
+      gal_list_data_add(&p->table, single);
+    }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/*********************************************************************/
+/********************         High-level         *********************/
+/*********************************************************************/
+void
+arithmetic_operate(struct tableparams *p)
+{
+  size_t i;
+  struct column_pack *outpack;
+
+
+  /* From now on, we will be looking for columns from the index in
+     `colarray', so to keep things clean, we'll set all the `next' elements
+     to NULL. */
+  for(i=0;i<p->numcolarray;++i) p->colarray[i]->next=NULL;
+
+  /* We'll also reset the output table pointer, to fill it in as we
+     progress. */
+  p->table=NULL;
+
+  /* Go over each package of columns. */
+  for(outpack=p->outcols;outpack!=NULL;outpack=outpack->next)
+    {
+      if(outpack->tokens)
+        arithmetic_reverse_polish(p, outpack);
+      else
+        {
+          for(i=0;i<outpack->numsimple;++i)
+            gal_list_data_add(&p->table, p->colarray[outpack->start+i]);
+        }
+    }
+
+  /* Reverse the final output to be in the proper order. Note that all the
+     column contents have either been moved into the new table, or have
+     already been freed. */
+  gal_list_data_reverse(&p->table);
+}
diff --git a/bin/table/ui.h b/bin/table/arithmetic.h
similarity index 55%
copy from bin/table/ui.h
copy to bin/table/arithmetic.h
index da7fce7..dc75d61 100644
--- a/bin/table/ui.h
+++ b/bin/table/arithmetic.h
@@ -5,7 +5,7 @@ Table is part of GNU Astronomy Utilities (Gnuastro) package.
 Original author:
      Mohammad Akhlaghi <mohammad@akhlaghi.org>
 Contributing author(s):
-Copyright (C) 2016-2019, Free Software Foundation, Inc.
+Copyright (C) 2019, 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
@@ -20,46 +20,41 @@ 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 UI_H
-#define UI_H
+#ifndef ARITHMETIC_H
+#define ARITHMETIC_H
 
-/* For common options groups. */
-#include <gnuastro-internal/options.h>
 
+#include <gnuastro/arithmetic.h>
 
 
+/* Basic constants. */
+#define ARITHMETIC_CALL "arith "
+#define ARITHMETIC_CALL_LENGTH strlen(ARITHMETIC_CALL)
 
 
-/* Available letters for short options:
-
-   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
+/* Operators used for arithmetic on columns. */
+enum arithmetic_operators
 {
-  /* With short-option version. */
-  UI_KEY_COLUMN          = 'c',
-  UI_KEY_INFORMATION     = 'i',
-  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). */
+ ARITHMETIC_TABLE_OP_WCSTOIMG = GAL_ARITHMETIC_OP_LAST_CODE,
+ ARITHMETIC_TABLE_OP_IMGTOWCS,
 };
 
 
 
 
 
+
+
+/* Functions */
 void
-ui_read_check_inputs_setup(int argc, char *argv[], struct tableparams *p);
+arithmetic_init(struct tableparams *p, struct arithmetic_token **arith,
+                gal_list_str_t **toread, size_t *totcalled, char *expression);
 
 void
-ui_list_range_free(struct list_range *list, int freevalue);
+arithmetic_indexs_final(struct tableparams *p, size_t *colmatch);
 
 void
-ui_free_report(struct tableparams *p);
+arithmetic_operate(struct tableparams *p);
+
 
 #endif
diff --git a/bin/table/asttable.conf b/bin/table/asttable.conf
index a7a1a97..4660480 100644
--- a/bin/table/asttable.conf
+++ b/bin/table/asttable.conf
@@ -18,3 +18,6 @@
 # permitted in any medium without royalty provided the copyright notice and
 # this notice are preserved.  This file is offered as-is, without any
 # warranty.
+
+# Inputs
+ wcshdu        1
\ No newline at end of file
diff --git a/bin/table/main.h b/bin/table/main.h
index f3e4bb7..44694f6 100644
--- a/bin/table/main.h
+++ b/bin/table/main.h
@@ -36,13 +36,31 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 
 
 
-
+/* Basic structure. */
 struct list_range
 {
   gal_data_t           *v;
   struct list_range *next;
 };
 
+struct arithmetic_token
+{
+  /* First layer elements. */
+  int            operator;  /* OPERATOR: Code of operator.                */
+  size_t     num_operands;  /* OPERATOR: Number of required operands.     */
+  size_t            index;  /* OPERAND: Index in requested columns.       */
+  gal_data_t    *constant;  /* OPERAND: a constant/single number.         */
+  struct arithmetic_token *next;  /* Pointer to next token.               */
+};
+
+struct column_pack
+{
+  size_t                    start; /* Starting ind. in requested columns. */
+  size_t                numsimple; /* Number of simple columns.           */
+  struct arithmetic_token *tokens; /* Arithmetic tokens to use.           */
+  struct column_pack        *next; /* Next output column.                 */
+};
+
 
 
 
@@ -53,15 +71,22 @@ struct tableparams
   /* From command-line */
   struct gal_options_common_params cp; /* Common parameters.            */
   char              *filename;  /* Input filename.                      */
+  char               *wcsfile;  /* File with WCS.                       */
+  char                *wcshdu;  /* HDU in file with WCS.                */
   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.    */
+  size_t                 head;  /* Output only the no. of top rows.     */
+  size_t                 tail;  /* Output only the no. of bottom rows.  */
 
   /* Internal. */
+  struct column_pack *outcols;  /* Output column packages.              */
   gal_data_t           *table;  /* Linked list of output table columns. */
+  struct wcsprm          *wcs;  /* WCS structure for conversion.        */
+  int                    nwcs;  /* Number of WCS structures.            */
   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.            */
@@ -69,6 +94,14 @@ struct tableparams
   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.        */
+  gal_data_t       **colarray;  /* Array of columns, with arithmetic.   */
+  size_t          numcolarray;  /* Number of elements in `colarray'.    */
+
+  /* For arithmetic operators. */
+  gal_list_str_t  *wcstoimg_p;  /* Pointer to the node.                 */
+  gal_list_str_t  *imgtowcs_p;  /* Pointer to the node.                 */
+  size_t             wcstoimg;  /* Output column no, for conversion.    */
+  size_t             imgtowcs;  /* Output column no, for conversion.    */
 };
 
 #endif
diff --git a/bin/table/table.c b/bin/table/table.c
index 7577064..97bd560 100644
--- a/bin/table/table.c
+++ b/bin/table/table.c
@@ -31,9 +31,11 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 
 #include <gsl/gsl_heapsort.h>
 
+#include <gnuastro/wcs.h>
 #include <gnuastro/fits.h>
 #include <gnuastro/table.h>
 #include <gnuastro/qsort.h>
+#include <gnuastro/pointer.h>
 #include <gnuastro/arithmetic.h>
 #include <gnuastro/statistics.h>
 #include <gnuastro/permutation.h>
@@ -41,7 +43,9 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 #include <gnuastro-internal/checkset.h>
 
 #include "main.h"
+
 #include "ui.h"
+#include "arithmetic.h"
 
 
 
@@ -78,7 +82,7 @@ table_range(struct tableparams *p)
   double *rarr;
   gal_data_t *mask;
   struct list_range *tmp;
-  gal_data_t *ref, *perm, *range;
+  gal_data_t *ref, *perm, *range, *blmask;
   size_t i, g, b, *s, *sf, one=1, ngood=0;
   gal_data_t *min, *max, *ltmin, *gemax, *sum;
 
@@ -107,11 +111,18 @@ table_range(struct tableparams *p)
       /* 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. */
+      /* Find all the bad elements (smaller than the minimum, larger than
+         the maximum or blank) so we can flag them. */
       ltmin=gal_arithmetic(GAL_ARITHMETIC_OP_LT, 1, numok,   ref,   min);
       gemax=gal_arithmetic(GAL_ARITHMETIC_OP_GE, 1, numok,   ref,   max);
+      blmask = ( gal_blank_present(ref, 1)
+                 ? gal_arithmetic(GAL_ARITHMETIC_OP_ISBLANK, 1, 0, ref)
+                 : NULL );
+
+      /* Merge all the flags into one array. */
       ltmin=gal_arithmetic(GAL_ARITHMETIC_OP_OR, 1, inplace, ltmin, gemax);
+      if(blmask)
+        ltmin=gal_arithmetic(GAL_ARITHMETIC_OP_OR, 1, inplace, ltmin, blmask);
 
       /* Add these flags to all previous flags. */
       mask=gal_arithmetic(GAL_ARITHMETIC_OP_OR, 1, inplace, mask, ltmin);
@@ -267,6 +278,54 @@ table_sort(struct tableparams *p)
 
 
 
+static void
+table_head_tail(struct tableparams *p)
+{
+  char **strarr;
+  gal_data_t *col;
+  size_t i, start, end;
+
+  /* Go over all the columns and make the necessary corrections. */
+  for(col=p->table;col!=NULL;col=col->next)
+    {
+      /* If we are dealing with strings, we'll need to free the strings
+         that the columns that will not be used point to (outside the
+         allocated array directly `gal_data_t'). We don't have to worry
+         about the space for the actual pointers (they will be free'd by
+         `free' in any case, since they are in the initially allocated
+         array).*/
+      if(col->type==GAL_TYPE_STRING)
+        {
+          /* Set the start and ending indexs. */
+          start = p->head!=GAL_BLANK_SIZE_T ? p->head        : 0;
+          end   = p->head!=GAL_BLANK_SIZE_T ? p->table->size : p->tail;
+
+          /* Free their allocated spaces. */
+          strarr=col->array;
+          for(i=start; i<end; ++i) { free(strarr[i]); strarr[i]=NULL; }
+        }
+
+      /* For `--tail', we'll need to bring the last columns to the
+         start. Note that we are using `memmove' because we want to be safe
+         with overlap. */
+      if(p->tail!=GAL_BLANK_SIZE_T)
+        memmove(col->array,
+                gal_pointer_increment(col->array, col->size - p->tail,
+                                      col->type),
+                p->tail*gal_type_sizeof(col->type));
+
+      /* In any case (head or tail), the new number of column elements is
+         the given value. */
+      col->size = col->dsize[0] = ( p->head!=GAL_BLANK_SIZE_T
+                                    ? p->head
+                                    : p->tail );
+    }
+}
+
+
+
+
+
 /**************************************************************/
 /***************       Top function         *******************/
 /**************************************************************/
@@ -279,6 +338,14 @@ table(struct tableparams *p)
   /* Sort it (if required). */
   if(p->sort) table_sort(p);
 
+  /* If the output number of rows is limited, apply them. */
+  if(p->head!=GAL_BLANK_SIZE_T || p->tail!=GAL_BLANK_SIZE_T)
+    table_head_tail(p);
+
+  /* If any operations are needed, do them. */
+  if(p->outcols)
+    arithmetic_operate(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 3431f76..2259c5b 100644
--- a/bin/table/ui.c
+++ b/bin/table/ui.c
@@ -28,6 +28,7 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 #include <stdio.h>
 #include <string.h>
 
+#include <gnuastro/wcs.h>
 #include <gnuastro/fits.h>
 #include <gnuastro/table.h>
 #include <gnuastro/pointer.h>
@@ -41,6 +42,7 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 #include "main.h"
 
 #include "ui.h"
+#include "arithmetic.h"
 #include "authors-cite.h"
 
 
@@ -115,6 +117,10 @@ ui_initialize_options(struct tableparams *p,
   cp->program_authors    = PROGRAM_AUTHORS;
   cp->coptions           = gal_commonopts_options;
 
+  /* Program-specific initialization. */
+  p->head                = GAL_BLANK_SIZE_T;
+  p->tail                = GAL_BLANK_SIZE_T;
+
   /* Modify common options. */
   for(i=0; !gal_options_is_last(&cp->coptions[i]); ++i)
     {
@@ -240,6 +246,11 @@ ui_read_check_only_options(struct tableparams *p)
           error(EXIT_FAILURE, 0, "first value (%g) given to `--range' must "
                 "be smaller than the second (%g)", darr[0], darr[1]);
       }
+
+  /* Make sure `--head' and `--tail' aren't given together. */
+  if(p->head!=GAL_BLANK_SIZE_T && p->tail!=GAL_BLANK_SIZE_T)
+    error(EXIT_FAILURE, 0, "`--head' and `--tail' options cannot be "
+          "called together");
 }
 
 
@@ -373,6 +384,81 @@ ui_list_range_free(struct list_range *list, int freevalue)
 
 
 
+
+
+/**************************************************************/
+/***************      Packaged columns      *******************/
+/**************************************************************/
+/* Return the last outcols element. */
+static struct column_pack *
+ui_outcols_last(struct column_pack *list)
+{
+  if(list)
+    {
+      while(list->next!=NULL) list=list->next;
+      return list;
+    }
+  else return NULL;
+}
+
+
+
+
+
+/* Allocate a clean `out_columns' structure and put it at the top of the
+   list. */
+static struct column_pack *
+ui_outcols_add_new_to_end(struct column_pack **list)
+{
+  struct column_pack *last, *node;
+
+  /* Allocate a new node. */
+  errno=0;
+  node=malloc(sizeof *node);
+  if(node==NULL)
+    error(EXIT_FAILURE, errno, "%s: couldn't allocate new node (%zu bytes)",
+          __func__, sizeof *node);
+
+  /* Initialize its elements. */
+  node->next=NULL;
+  node->numsimple=0;
+  node->tokens=NULL;
+  node->start=GAL_BLANK_SIZE_T;
+
+  /* If the list already has elements, go to the last node in the list and
+     add this node. */
+  if(*list)
+    {
+      last=ui_outcols_last(*list);
+      last->next=node;
+    }
+  else
+    *list=node;
+
+  /* Return a pointer to this node (to use temporarily). */
+  return node;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
 /**************************************************************/
 /***************       Preparations         *******************/
 /**************************************************************/
@@ -430,10 +516,11 @@ ui_print_info_exit(struct tableparams *p)
 static void
 ui_columns_prepare(struct tableparams *p)
 {
-  size_t i;
   char **strarr;
   gal_data_t *strs;
-  gal_list_str_t *tmp, *new=NULL;
+  size_t i, totcalled=0;
+  struct column_pack *node, *last;
+  gal_list_str_t *tmp, *toread=NULL;
 
   /* Go over the whole original list (where each node may have more than
      one value separated by a comma. */
@@ -444,10 +531,69 @@ ui_columns_prepare(struct tableparams *p)
       strs=gal_options_parse_csv_strings_raw(tmp->v, NULL, 0);
       strarr=strs->array;
 
-      /* Go over all the elements and add them to the `new' list. */
+      /* Go over all the given colum names/numbers. */
       for(i=0;i<strs->size;++i)
         {
-          gal_list_str_add(&new, strarr[i], 0);
+          /* See if this is an arithmetic column to be processed, or the
+             contents should just be printed. */
+          if(!strncmp(strarr[i], ARITHMETIC_CALL, ARITHMETIC_CALL_LENGTH))
+            {
+              /* If this is the first arithmetic operation and the user has
+                 already asked for some columns, we'll need to put all
+                 previously requested simply-printed columns into an
+                 `outcols' structure, then add this arithmetic operation's
+                 `outcols'. */
+              if(p->outcols==NULL && toread)
+                {
+                  /* Allocate an empty structure and set the necessary
+                     pointers. */
+                  node=ui_outcols_add_new_to_end(&p->outcols);
+                  node->start=0;
+                  node->numsimple=gal_list_str_number(toread);
+                  totcalled=node->numsimple;
+                }
+
+              /* Add a new column pack, then read all the tokens (while
+                 specifying which columns it needs). */
+              node=ui_outcols_add_new_to_end(&p->outcols);
+              arithmetic_init(p, &node->tokens, &toread, &totcalled,
+                              strarr[i]+ARITHMETIC_CALL_LENGTH);
+              free(strarr[i]);
+            }
+          /* This is a simple column (no change in values). */
+          else
+            {
+              /* Add this column to the list of columns to read. */
+              gal_list_str_add(&toread, strarr[i], 0);
+
+              /* See if we have packaged the output columns. */
+              if(p->outcols)
+                {
+                  /* If the previous column package was an arithmetic
+                     operation, allocate a new node. */
+                  last=ui_outcols_last(p->outcols);
+                  if(last->tokens)
+                    {
+                      node=ui_outcols_add_new_to_end(&p->outcols);
+                      node->start=totcalled;
+                      node->numsimple=1;
+                    }
+
+                  /* The previous package of columns are simple (we don't
+                     need to change their value), so we can just increment
+                     the number of columns there and don't need to allocate
+                     a new one. */
+                  else
+                    last->numsimple+=1;
+                }
+
+              /* Increment the total number of called columns. */
+              totcalled+=1;
+            }
+
+          /* The pointer allocated string is either being used (and later
+             freed) else, or has already been freed. So its necessary to
+             set it to NULL. */
           strarr[i]=NULL;
         }
 
@@ -455,12 +601,39 @@ ui_columns_prepare(struct tableparams *p)
       gal_data_free(strs);
     }
 
-  /* Delete the old list. */
-  gal_list_str_free(p->columns, 1);
+  /* For a check
+  if(p->outcols)
+    {
+      struct column_pack *tmp;
+      struct arithmetic_token *atmp;
+      for(tmp=p->outcols;tmp!=NULL;tmp=tmp->next)
+        {
+          if(tmp->tokens)
+            for(atmp=tmp->tokens;atmp!=NULL;atmp=atmp->next)
+              {
+                printf("Arithmetic: ");
+                if(atmp->constant) printf("Constant number\n");
+                else if(atmp->index) printf("Called column: %zu\n",
+                                            atmp->index);
+                else if(atmp->operator!=ARITHMETIC_TABLE_OP_INVALID)
+                  printf("Operator: %d\n", atmp->operator);
+                else
+                  error(EXIT_FAILURE, 0, "%s: UNKNOWN SITUATION!",
+                        __func__);
+              }
+          else
+            printf("Simple: start: %zu, num: %zu\n", tmp->start,
+                   tmp->numsimple);
+        }
+    }
+  */
+
 
-  /* Reverse the new list, then put it into `p->columns'. */
-  gal_list_str_reverse(&new);
-  p->columns=new;
+  /* Delete the old list, then reverse the `toread' list, and put it into
+     `p->columns'. */
+  gal_list_str_free(p->columns, 1);
+  gal_list_str_reverse(&toread);
+  p->columns=toread;
 }
 
 
@@ -759,6 +932,7 @@ ui_check_range_sort_after(struct tableparams *p, size_t 
nrange,
 static void
 ui_preparations(struct tableparams *p)
 {
+  size_t *colmatch;
   gal_list_str_t *lines;
   size_t nrange=0, origoutncols=0;
   struct gal_options_common_params *cp=&p->cp;
@@ -784,10 +958,19 @@ ui_preparations(struct tableparams *p)
                                &rangeindout);
 
 
+  /* If we have any arithmetic operations, we need to make sure how many
+     columns match every given column name. */
+  colmatch = ( p->outcols
+               ? gal_pointer_allocate(GAL_TYPE_SIZE_T,
+                                      gal_list_str_number(p->columns), 1,
+                                      __func__, "colmatch")
+               : NULL);
+
+
   /* Read the necessary columns. */
   p->table=gal_table_read(p->filename, cp->hdu, lines, p->columns,
                           cp->searchin, cp->ignorecase, cp->minmapsize,
-                          NULL);
+                          colmatch);
   if(p->filename==NULL) p->filename="stdin";
   gal_list_str_free(lines, 1);
 
@@ -806,6 +989,11 @@ ui_preparations(struct tableparams *p)
           "non-blank lines)", p->filename);
 
 
+  /* Set the final indexs. */
+  if(p->outcols)
+    arithmetic_indexs_final(p, colmatch);
+
+
   /* Now that the data columns are ready, we can free the string linked
      list. */
   gal_list_str_free(p->columns, 1);
@@ -816,7 +1004,20 @@ ui_preparations(struct tableparams *p)
   gal_checkset_writable_remove(p->cp.output, 0, p->cp.dontdelete);
 
 
+  /* If the head or tail values are given and are larger than the number of
+     rows, just set them to the number of rows (print the all the final
+     rows). This is how the `head' and `tail' programs of GNU Coreutils
+     operate. */
+  p->head = ( ((p->head!=GAL_BLANK_SIZE_T) && (p->head > p->table->size))
+              ? p->table->size
+              : p->head );
+  p->tail = ( ((p->tail!=GAL_BLANK_SIZE_T) && (p->tail > p->table->size))
+              ? p->table->size
+              : p->tail );
+
+
   /* Clean up. */
+  free(colmatch);
   if(rangeindout) free(rangeindout);
 }
 
@@ -923,4 +1124,5 @@ ui_free_report(struct tableparams *p)
   free(p->cp.hdu);
   free(p->cp.output);
   gal_list_data_free(p->table);
+  if(p->colarray) free(p->colarray);
 }
diff --git a/bin/table/ui.h b/bin/table/ui.h
index da7fce7..37f61a3 100644
--- a/bin/table/ui.h
+++ b/bin/table/ui.h
@@ -32,18 +32,22 @@ 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 t u v w x y z
-   A B C E G H J L O Q R W X Y
+   a b d e f g j k l m n p t u v x y z
+   A B C E G H J L O Q R X Y
 */
 enum option_keys_enum
 {
   /* With short-option version. */
+  UI_KEY_WCSFILE         = 'w',
+  UI_KEY_WCSHDU          = 'W',
   UI_KEY_COLUMN          = 'c',
   UI_KEY_INFORMATION     = 'i',
   UI_KEY_COLINFOINSTDOUT = 'O',
   UI_KEY_RANGE           = 'r',
   UI_KEY_SORT            = 's',
   UI_KEY_DESCENDING      = 'd',
+  UI_KEY_HEAD            = 'H',
+  UI_KEY_TAIL            = 't',
 
   /* Only with long version (start with a value 1000, the rest will be set
      automatically). */
diff --git a/bin/warp/Makefile.am b/bin/warp/Makefile.am
index b7c0a7f..898b986 100644
--- a/bin/warp/Makefile.am
+++ b/bin/warp/Makefile.am
@@ -29,7 +29,7 @@ AM_CPPFLAGS = -I\$(top_srcdir)/bootstrapped/lib 
-I\$(top_srcdir)/lib
 bin_PROGRAMS = astwarp
 
 ## Reason for linking with `libgnu' described in `bin/TEMPLATE/Makefile.am'.
-astwarp_LDADD = $(top_builddir)/bootstrapped/lib/libgnu.la -lgnuastro
+astwarp_LDADD = $(top_builddir)/bootstrapped/lib/libgnu.la -lgnuastro 
$(CONFIG_LDADD)
 
 astwarp_SOURCES = main.c ui.c warp.c
 
diff --git a/bin/warp/ui.c b/bin/warp/ui.c
index d778a33..0e11d19 100644
--- a/bin/warp/ui.c
+++ b/bin/warp/ui.c
@@ -224,6 +224,9 @@ ui_add_to_modular_warps_ll(struct argp_option *option, char 
*arg,
   gal_data_t *new;
   struct warpparams *p=(struct warpparams *)params;
 
+  /* Make sure we actually have a string to parse. */
+  if(*arg=='\0')
+    error(EXIT_FAILURE, 0, "empty string given to `--%s'", option->name);
 
   /* Parse the (possible) arguments. */
   if(option->key==UI_KEY_ALIGN)
diff --git a/bootstrap.conf b/bootstrap.conf
index 8814be2..9275622 100644
--- a/bootstrap.conf
+++ b/bootstrap.conf
@@ -223,11 +223,14 @@ gnulib_modules="
     stdint
     strtod
     mktime
+    havelib
+    memmove
     getline
     strcase
     gendocs
     gpl-3.0
     mbstok_r
+    strtok_r
     inttypes
     sys_time
     strptime
diff --git a/configure.ac b/configure.ac
index ee6654a..8fab48d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -50,7 +50,7 @@ AC_CONFIG_MACRO_DIRS([bootstrapped/m4])
 
 # Library version, see the GNU Libtool manual ("Library interface versions"
 # section for the exact definition of each) for
-GAL_CURRENT=7
+GAL_CURRENT=8
 GAL_REVISION=0
 GAL_AGE=0
 GAL_LT_VERSION="${GAL_CURRENT}:${GAL_REVISION}:${GAL_AGE}"
@@ -193,6 +193,10 @@ AC_CHECK_SIZEOF([long])
 AC_SUBST(SIZEOF_LONG, [$ac_cv_sizeof_long])
 AC_DEFINE_UNQUOTED([GAL_CONFIG_SIZEOF_LONG], [$ac_cv_sizeof_long],
                    [On 32bit will be 4, on 64 bit, will be 8])
+AC_CHECK_SIZEOF([int])
+AC_SUBST(SIZEOF_INT, [$ac_cv_sizeof_int])
+AC_DEFINE_UNQUOTED([GAL_CONFIG_SIZEOF_INT], [$ac_cv_sizeof_int],
+                   [It may be 16bit or 32bit])
 
 
 
@@ -262,12 +266,23 @@ has_cfitsio=yes
 has_gslcblas=yes
 missing_mandatory=no
 missing_optional_lib=no
-AC_SEARCH_LIBS(sqrt, m, [],
-               [missing_mandatory=yes; has_cmath=no])
-AC_SEARCH_LIBS([cblas_sdsdot], [gslcblas], [],
-               [missing_mandatory=yes; has_gslcblas=no])
-AC_SEARCH_LIBS([gsl_integration_qng], [gsl], [],
-               [missing_mandatory=yes; has_gsl=no])
+
+# Order is important here.
+AC_LIB_HAVE_LINKFLAGS([m], [], [#include <math.h>])
+AS_IF([test "x$LIBM" = x],
+      [missing_mandatory=yes; has_cmath=no],
+      [LDADD="$LIBM $LDADD"])
+
+AC_LIB_HAVE_LINKFLAGS([gsl], [gslcblas], [
+#include <gsl/gsl_rng.h>
+void junk(void) { gsl_rng_env_setup(); } ])
+AS_IF([test "x$LIBGSL" = x],
+      [missing_mandatory=yes; has_gsl=no; has_gslcblas=no],
+      [LDADD="$LIBGSL $LDADD"])
+
+
+
+
 
 # Since version 0.42, if `libcurl' is installed, CFITSIO will link with it
 # and thus it will be necessary to explicitly link with libcurl also. If it
@@ -282,20 +297,64 @@ AC_SEARCH_LIBS([gsl_integration_qng], [gsl], [],
 # librtmp, libldap). So if you intend to make Gnuastro statically, then
 # build Libcurl in static-only mode so you won't have to check for all
 # these extra libraries here.
-AC_SEARCH_LIBS([deflateInit_], [z], [], [])
-AC_SEARCH_LIBS([curl_global_init], [curl], [], [])
-AC_SEARCH_LIBS([ffopen], [cfitsio], [],
-               [missing_mandatory=yes; has_cfitsio=no])
-AC_SEARCH_LIBS([wcspih], [wcs], [],
-               [missing_mandatory=yes; has_wcslib=no])
+AC_LIB_HAVE_LINKFLAGS([z], [], [#include <zlib.h>])
+AS_IF([test "x$LIBZ" = x], [], [LDADD="$LIBZ $LDADD"])
+
+AC_LIB_HAVE_LINKFLAGS([curl], [], [#include <curl/curl.h>])
+AS_IF([test "x$LIBCURL" = x], [], [LDADD="$LIBCURL $LDADD"])
+
+# CFITSIO can depend on libcurl (which may not exist on some
+# systems). Also, `AC_LIB_HAVE_LINKFLAGS' puts the value in its second
+# argument in single-quotes. So its not easy to set a conditional linking
+# dependency. Therefore, we need to temporarily put LDADD within LIBS so
+# the compiler knows what to link with.
+origlibs="$LIBS"
+LIBS="$LIBS $LDADD"
+AC_LIB_HAVE_LINKFLAGS([cfitsio], [], [
+#include <fitsio.h>
+void junk(void) {
+int status;
+fitsfile *f;
+ffopen(&f, "junk", READONLY, &status);} ])
+AS_IF([test "x$LIBCFITSIO" = x],
+      [missing_mandatory=yes; has_cfitsio=no],
+      [LDADD="$LIBCFITSIO $LDADD"])
+LIBS="$origlibs"
+
+AC_LIB_HAVE_LINKFLAGS([wcs], [], [
+#include <wcslib/wcshdr.h>
+void junk(void) {
+int nreject, nwcs;
+struct wcsprm *wcs;
+char *header="JUNK";
+wcspih(header, 1, 0, 0, &nreject, &nwcs, &wcs);
+} ])
+AS_IF([test "x$LIBWCS" = x],
+      [missing_mandatory=yes; has_wcslib=no],
+      [LDADD="$LIBWCS $LDADD"])
+
+
+
+
 
 # These are secondary tests for more fine-grained control in libraries that
-# have already been checked. We don't need to add them to the LIBS
-# variable, so we are using AC_CHECK_LIB for these tests.
-AC_CHECK_DECLS(gsl_interp_steffen,
-               [ gsl_version_old=no                   ],
-               [ gsl_version_old=yes; anywarnings=yes ],
-               [[#include <gsl/gsl_interp.h>]])
+# have already been checked.
+
+# GSL's `gsl_interp_steffen' isn't a function. So we'll need to use
+# `AC_LINK_IFELSE'. However, AC_LINK_IFELSE doesn't use `LDADD', so we'll
+# have to temporarily add `LDADD' to LIBS, then set it back to the
+# original.
+origlibs="$LIBS"
+LIBS="$LIBS $LDADD"
+AC_MSG_CHECKING(if GSL supports Steffen splines)
+AC_LINK_IFELSE([AC_LANG_PROGRAM(
+                   [[#include <gsl/gsl_interp.h>]],
+                   [[const gsl_interp_type *itype=gsl_interp_steffen;]])],
+               [AC_MSG_RESULT(yes)
+                gsl_version_old=no],
+               [AC_MSG_RESULT(no)
+                gsl_version_old=yes; anywarnings=yes;])
+LIBS="$origlibs"
 
 # If the CFITSIO library has the `fits_is_reentrant' function (it was added
 # since version 3.30 of April 2012).
@@ -335,8 +394,18 @@ AM_CONDITIONAL([COND_HASHELP2MAN], [test "x$has_help2man" 
= "xyes"])
 
 
 # Check libjpeg:
-AC_SEARCH_LIBS([jpeg_stdio_dest], [jpeg],
-               [has_libjpeg=yes], [has_libjpeg=no; missing_optional_lib=yes])
+AC_LIB_HAVE_LINKFLAGS([jpeg], [], [
+#include <stdio.h>
+#include <stdlib.h>
+#include <jpeglib.h>
+void junk(void) {
+  struct jpeg_decompress_struct cinfo;
+  jpeg_create_decompress(&cinfo);
+}  ])
+AS_IF([test "x$LIBJPEG" = x],
+      [missing_optional_lib=yes; has_libjpeg=no],
+      [has_libjpeg=yes; LDADD="$LIBJPEG $LDADD"])
+
 AS_IF([test "x$has_libjpeg" = "xyes"],
       [AC_DEFINE([HAVE_LIBJPEG], [], [Has libjpeg])],
       [anywarnings=yes])
@@ -351,9 +420,16 @@ AM_CONDITIONAL([COND_HASLIBJPEG], [test "x$has_libjpeg" = 
"xyes"])
 # the LZMA library. But if libtiff hasn't been linked with it and its
 # present, there is no problem, the linker will just pass over it. So we
 # don't need to stop the build if this fails.
-AC_SEARCH_LIBS([lzma_stream_decoder], [lzma], [], [])
-AC_SEARCH_LIBS([TIFFOpen], [tiff],
-               [has_libtiff=yes], [has_libtiff=no; missing_optional_lib=yes])
+AC_LIB_HAVE_LINKFLAGS([lzma], [], [#include <lzma.h>])
+AS_IF([test "x$LIBLZMA" = x], [], [LDADD="$LIBLZMA $LDADD"])
+
+AC_LIB_HAVE_LINKFLAGS([tiff], [], [
+#include <tiffio.h>
+void junk(void) {TIFF *tif=TIFFOpen("junk", "r");}
+])
+AS_IF([test "x$LIBTIFF" = x],
+      [missing_optional_lib=yes; has_libtiff=no],
+      [has_libtiff=yes; LDADD="$LIBTIFF $LDADD"])
 AS_IF([test "x$has_libtiff" = "xyes"],
       [AC_DEFINE([HAVE_LIBTIFF], [], [Has libtiff])],
       [anywarnings=yes])
@@ -363,9 +439,15 @@ AM_CONDITIONAL([COND_HASLIBTIFF], [test "x$has_libtiff" = 
"xyes"])
 
 
 
-# Check libgit2:
-AC_SEARCH_LIBS([git_libgit2_init], [git2],
-               [has_libgit2=1], [has_libgit2=0; missing_optional_lib=yes])
+# Check libgit2. Note that very old versions of libgit2 don't have the
+# `git_libgit2_init' function.
+AC_LIB_HAVE_LINKFLAGS([git2], [], [
+#include <git2.h>
+void junk(void) {git_libgit2_init();}
+])
+AS_IF([test "x$LIBGIT2" = x],
+      [missing_optional_lib=yes; has_libgit2=0],
+      [has_libgit2=1; LDADD="$LIBGIT2 $LDADD"])
 AC_DEFINE_UNQUOTED([GAL_CONFIG_HAVE_LIBGIT2], [$has_libgit2],
                    [libgit2 is installed on the system])
 AS_IF([test "x$has_libgit2" = "x1"], [], [anywarnings=yes])
@@ -848,7 +930,16 @@ AC_CONFIG_COMMANDS([man page directory], [$MKDIR_P 
doc/man])
 
 
 
-# Make the Makefiles:
+# Set the linker-necessary parameters.
+AC_SUBST(CONFIG_LDADD, [$LDADD])
+AC_DEFINE_UNQUOTED([LDADD], ["$LDADD"],
+                   [Linking information, primarily for BuildProgram])
+
+
+
+
+
+# Prepare the Makefiles.
 AC_OUTPUT
 
 
diff --git a/doc/announce-acknowledge.txt b/doc/announce-acknowledge.txt
index 97a8052..1c554bd 100644
--- a/doc/announce-acknowledge.txt
+++ b/doc/announce-acknowledge.txt
@@ -1,5 +1,11 @@
 Alphabetically ordered list to acknowledge in the next release.
 
+Hamed Altafi
+Leindert Boogaard
+Bruno Haible
+Raul Infante-Sainz
+Lee Kelvin
+Elham Saremi
 David Valls-Gabaud
 
 
diff --git a/doc/gnuastro.texi b/doc/gnuastro.texi
index f4f3c62..93b6e45 100644
--- a/doc/gnuastro.texi
+++ b/doc/gnuastro.texi
@@ -377,6 +377,7 @@ ConvertType
 
 Table
 
+* Column arithmetic::           How to do operations on table columns.
 * Invoking asttable::           Options and arguments to Table.
 
 Data manipulation
@@ -600,6 +601,7 @@ Gnuastro library
 * Convolution functions::       Library functions to do convolution.
 * Interpolation::               Interpolate (over blank values possibly).
 * Git wrappers::                Wrappers for functions in libgit2.
+* Spectral lines library::
 * Cosmology library::           Cosmological calculations.
 
 Multithreaded programming (@file{threads.h})
@@ -1700,10 +1702,10 @@ character, enabling you to use multiple lines to write 
your commands.
 
 Gnuastro would not have been possible without scholarships and grants from
 several funding institutions. We thus ask that if you used Gnuastro in any
-of your papers/reports, please add the proper citation and acknowledge this
-instrumental support. For details of which papers to cite (may be different
-for different programs) and get the acknowledgment statement to include in
-your paper, please run the relevant programs with the common
+of your papers/reports, please add the proper citation and acknowledge the
+funding agencies/projects. For details of which papers to cite (may be
+different for different programs) and get the acknowledgment statement to
+include in your paper, please run the relevant programs with the common
 @option{--cite} option like the example commands below (for more on
 @option{--cite}, please see @ref{Operating mode options}).
 
@@ -1888,23 +1890,22 @@ use in the example codes through the book, please see 
@ref{Conventions}.
 @cindex Azophi
 @cindex Abd al-rahman Sufi
 @cindex Sufi, Abd al-rahman
-It is the year 953 A.D.  and Sufi@footnote{Abd al-rahman Sufi (903 --
-986 A.D.), also known in Latin as Azophi was an Iranian
+It is the year 953 A.D. and Abd al-rahman Sufi (903 -- 986
+A.D.)@footnote{In Latin Sufi is known as Azophi. He was an Iranian
 astronomer. His manuscript ``Book of fixed stars'' contains the first
-recorded observations of the Andromeda galaxy, the Large Magellanic
-Cloud and seven other non-stellar or `nebulous' objects.}  is in
-Shiraz as a guest astronomer. He had come there to use the advanced
-123 centimeter astrolabe for his studies on the Ecliptic. However,
-something was bothering him for a long time. While mapping the
-constellations, there were several non-stellar objects that he had
-detected in the sky, one of them was in the Andromeda
-constellation. During a trip he had to Yemen, Sufi had seen another
-such object in the southern skies looking over the Indian ocean. He
-wasn't sure if such cloud-like non-stellar objects (which he was the
-first to call `Sah@={a}bi' in Arabic or `nebulous') were real
-astronomical objects or if they were only the result of some bias in
-his observations. Could such diffuse objects actually be detected at
-all with his detection technique?
+recorded observations of the Andromeda galaxy, the Large Magellanic Cloud
+and seven other non-stellar or `nebulous' objects.}  is in Shiraz as a
+guest astronomer. He had come there to use the advanced 123 centimeter
+astrolabe for his studies on the Ecliptic. However, something was bothering
+him for a long time. While mapping the constellations, there were several
+non-stellar objects that he had detected in the sky, one of them was in the
+Andromeda constellation. During a trip he had to Yemen, Sufi had seen
+another such object in the southern skies looking over the Indian ocean. He
+wasn't sure if such cloud-like non-stellar objects (which he was the first
+to call `Sah@={a}bi' in Arabic or `nebulous') were real astronomical
+objects or if they were only the result of some bias in his
+observations. Could such diffuse objects actually be detected at all with
+his detection technique?
 
 @cindex Almagest
 @cindex Claudius Ptolemy
@@ -2027,10 +2028,11 @@ Using all the information above, he creates the catalog 
of mock profiles he
 wants in a file named @file{cat.txt} (short for catalog) using his favorite
 text editor and stores it in a directory named @file{simulationtest} in his
 home directory. [The @command{cat} command prints the contents of a file,
-short for concatenation. So please copy-paste the lines after
+short for ``concatenation''. So please copy-paste the lines after
 ``@command{cat cat.txt}'' into @file{cat.txt} when the editor opens in the
 steps above it, note that there are 7 lines, first one starting with
-@key{#}]:
+@key{#}. Also be careful when copying from the PDF format, the Info, web,
+or text formats shouldn't have any problem]:
 
 @example
 $ mkdir ~/simulationtest
@@ -2104,6 +2106,7 @@ Convolve started on Mon Apr  6 16:35:32 953
   - Multiplied in the frequency domain.                0.040659 seconds
   - Converted back to the spatial domain.              3.465344 seconds
   - Padded parts removed.                              0.016767 seconds
+  - Output: cat_convolved.fits
 Convolve finished in:  10.422161 seconds
 
 $ls
@@ -2116,9 +2119,9 @@ and showed the effect of convolution to his student and 
explained to him
 how a PSF with a larger FWHM would make the points even wider. With the
 convolved image ready, they were prepared to re-sample it to the original
 pixel scale Sufi had planned [from the @command{$ astmkprof -P} command
-above, recall that MakeProfiles had over-sampled the image by 5 times]. Sufi
-explained the basic concepts of warping the image to his student and ran
-Warp with the following command:
+above, recall that MakeProfiles had over-sampled the image by 5
+times]. Sufi explained the basic concepts of warping the image to his
+student and ran Warp with the following command:
 
 @example
 $ astwarp --scale=1/5 --centeroncorner cat_convolved.fits
@@ -2141,12 +2144,12 @@ NAXIS2  =                  526 / length of data axis 2
 @end example
 
 @noindent
-@file{cat_convolved_warped.fits} now has the correct pixel scale. However,
+@file{cat_convolved_scaled.fits} now has the correct pixel scale. However,
 the image is still larger than what we had wanted, it is 526
 (@mymath{500+13+13}) by 526 pixels. The student is slightly confused, so
-Sufi also re-samples the PSF with the same scale and shows him that it is 27
-(@mymath{2\times13+1}) by 27 pixels. Sufi goes on to explain how frequency
-space convolution will dim the edges and that is why he added the
+Sufi also re-samples the PSF with the same scale and shows him that it is
+27 (@mymath{2\times13+1}) by 27 pixels. Sufi goes on to explain how
+frequency space convolution will dim the edges and that is why he added the
 @option{--prepforconv} option to MakeProfiles, see @ref{If convolving
 afterwards}. Now that convolution is done, Sufi can remove those extra
 pixels using Crop with the command below. Crop's @option{--section} option
@@ -2155,7 +2158,7 @@ standard), so the crop's first pixel has to be 14, not 13.
 
 @example
 $ astcrop cat_convolved_scaled.fits --section=14:*-13,14:*-13    \
-          --zeroisnotblank
+          --mode=img --zeroisnotblank
 Crop started on Sat Oct  6 17:03:24 953
   - Read metadata of 1 image.                          0.001304 seconds
   ---- ...nvolved_scaled_cropped.fits created: 1 input.
@@ -2179,7 +2182,7 @@ ran MakeNoise:
 
 @example
 $ astmknoise --zeropoint=18 --background=7 --output=out.fits    \
-             cat_convolved_warped_crop.fits
+             cat_convolved_scaled_crop.fits
 MakeNoise started on Mon Apr  6 17:05:06 953
   - Generator type: mt19937
   - Generator seed: 1428318100
@@ -2250,12 +2253,11 @@ He used this chance to remind the student of the 
importance of comments in
 code or shell scripts: when writing the code, you have a good mental
 picture of what you are doing, so writing comments might seem superfluous
 and excessive. However, in one month when you want to re-use the script,
-you have lost that mental picture and rebuilding it is can be
-time-consuming and frustrating. The importance of comments is further
-amplified when you want to share the script with a friend/colleague. So it
-is good to accompany any script/code with useful comments while you are
-writing it (have a good mental picture of what/why you are doing
-something).
+you have lost that mental picture and remembering it can be time-consuming
+and frustrating. The importance of comments is further amplified when you
+want to share the script with a friend/colleague. So it is good to
+accompany any script/code with useful comments while you are writing it
+(create a good mental picture of what/why you are doing something).
 
 @cindex Gedit
 @cindex GNU Emacs
@@ -2807,9 +2809,9 @@ main(void)
 @noindent
 To greatly simplify the compilation, linking and running of simple C
 programs like this that use Gnuastro's library, Gnuastro has
-@ref{BuildProgram}. This program designed to manage Gnuastro's
+@ref{BuildProgram}. This program is designed to manage Gnuastro's
 dependencies, compile and link the program and then run the new program. To
-build and run the program above, simply run the following command:
+build, @emph{and run} the program above, use the following command:
 
 @example
 $ astbuildprog myprogram.c
@@ -2827,11 +2829,11 @@ $ ./myprogram
 @end example
 
 The efficiency of @file{myprogram} compared to CosmicCalculator is because
-the requested processing is faster/comparable to the overheads necessary
-for each processing. For other programs that take large input datasets
-(images for example), the overhead is usually negligible compared to the
-processing. In such cases, the libraries are only useful if you want a
-different/new processing compared to the functionalities in Gnuastro's
+in the latter, the requested processing is comparable to the necessary
+overheads. For other programs that take large input datasets and do
+complicated processing on them, the overhead is usually negligible compared
+to the processing. In such cases, the libraries are only useful if you want
+a different/new processing compared to the functionalities in Gnuastro's
 existing programs.
 
 Gnuastro has a large library which is heavily used by all the programs. In
@@ -2853,18 +2855,19 @@ above, it completed its processing and printed results. 
So where did the
 come from?  The values come from the command-line or a configuration file
 (see @ref{Configuration file precedence}).
 
-CosmicCalculator has a limited set of parameters and doesn't need any
-particular file inputs. Therefore, we'll use it to discuss configuration
-files which are an important part of all Gnuastro's programs (see
-@ref{Configuration files}).
+CosmicCalculator has a small set of parameters/options. Therefore, let's
+use it to discuss configuration files (see @ref{Configuration
+files}). Configuration files are an important part of all Gnuastro's
+programs, especially the ones with a large number of options, so its
+important to understand this part well .
 
 Once you get comfortable with configuration files, you can easily do the
-same for the options of all Gnuastro programs. For example, NoiseChisel has
-the largest number of options in the programs. Therefore configuration
-files will be useful for it when you use different datasets (with different
-noise properties or in different research contexts). The configuration of
-each program (besides its version) is vital for the reproducibility of your
-results, so it is important to manage them properly.
+same for the options of all Gnuastro programs (for example,
+NoiseChisel). Therefore configuration files will be useful for it when you
+use different datasets (with different noise properties or in different
+research contexts). The configuration of each program (besides its version)
+is vital for the reproducibility of your results, so it is important to
+manage them properly.
 
 As we saw above, the full list of the options in all Gnuastro programs can
 be seen with the @option{--help} option. Try calling it with
@@ -3972,11 +3975,11 @@ $ ds9 -mecube seg/xdf-f160w.fits -zscale -zoom to fit   
 \
 In conclusion, we hope this extended tutorial has been a good starting
 point to help in your exciting research. If this book or any of the
 programs in Gnuastro have been useful for your research, please cite the
-respective papers and share your thoughts and suggestions with us (it can
-be very encouraging). All Gnuastro programs have a @option{--cite} option
-to help you cite the authors' work more easily. Just note that it may be
+respective papers, and acknowledge the funding agencies that made all of
+this possible. All Gnuastro programs have a @option{--cite} option to
+facilitate the citation and acknowledgement. Just note that it may be
 necessary to cite additional papers for different programs, so please try
-it out for any program you used.
+it out on all the programs that you used, for example:
 
 @example
 $ astmkcatalog --cite
@@ -3990,8 +3993,6 @@ $ astnoisechisel --cite
 
 
 
-
-
 @node Detecting large extended targets, Hubble visually checks and classifies 
his catalog, General program usage tutorial, Tutorials
 @section Detecting large extended targets
 
@@ -4641,12 +4642,12 @@ usage tutorial} and @ref{Segment} for more on using 
Segment, producing
 catalogs with MakeCatalog and using those catalogs.
 
 Finally, if this book or any of the programs in Gnuastro have been useful
-for your research, please cite the respective papers and share your
-thoughts and suggestions with us (it can be very encouraging). All Gnuastro
-programs have a @option{--cite} option to help you cite the authors' work
-more easily. Just note that it may be necessary to cite additional papers
-for different programs, so please use @option{--cite} with any program that
-has been useful in your work.
+for your research, please cite the respective papers, and acknowledge the
+funding agencies that made all of this possible. All Gnuastro programs have
+a @option{--cite} option to facilitate the citation and
+acknowledgement. Just note that it may be necessary to cite additional
+papers for different programs, so please try it out on all the programs
+that you used, for example:
 
 @example
 $ astmkcatalog --cite
@@ -4679,6 +4680,17 @@ can't be modeled (like stars that are always a point) 
easily. So there
 is no better way to distinguish them than to visually inspect them and
 see if it is possible to classify these nebulae or not.
 
+@cartouche
+@noindent
+@strong{No default dataset in this tutorial:} Unfortunately there is no
+input dataset for this tutorial. We will add a dataset and corresponding
+table to smoothly run this tutorial later. But until then, you can use the
+final catalog that you produced in @ref{General program usage
+tutorial}. The start of this tutorial has some overlaps with the ending of
+@ref{General program usage tutorial}. You can just select some of the
+brighter sources to make it shorter and more managable.
+@end cartouche
+
 Hubble has stored all the FITS images of the objects he wants to visually
 inspect in his @file{/mnt/data/images} directory. He has also stored his
 catalog of extra-galactic nebulae in
@@ -5087,6 +5099,7 @@ $ ./testprog > testprog.lis
 $ diff testprog.lis testprog.out    # Should have no output
 $ cmp testprog.fit testprog.std     # Should have no output
 $ rm cookbook fitscopy imcopy smem speed testprog
+$ make shared
 $ sudo make install
 @end example
 
@@ -5613,7 +5626,7 @@ found, then configure Gnuastro like the command below 
(correcting
 @file{/path/to/lib}). For more, see @ref{Known issues} and
 @ref{Installation directory}.
 @example
-$ ./configure LDFLAGS="-I/path/to/lib"
+$ ./configure LDFLAGS="-L/path/to/lib"
 @end example
 @end cartouche
 
@@ -7106,7 +7119,7 @@ sure it is added to the list of directories, add the 
following line to your
 (non-standard) directories.
 
 @example
-export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib
+export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/local/lib"
 @end example
 
 You can also add more directories by using a colon `@code{:}' to separate
@@ -9487,8 +9500,8 @@ table (the first one, with nothing but the column number 
is redundant):
 
 @example
 # Column 5:
-# Column 1: ID [,i] The Clump ID.
-# Column 3: mag_f160w [AB mag, f] Magnitude from the F160W filter
+# Column 1: ID [,i8] The Clump ID.
+# Column 3: mag_f160w [AB mag, f32] Magnitude from the F160W filter
 @end example
 
 @noindent
@@ -9527,7 +9540,7 @@ manually later. If only one of the leading or trailing 
white spaces is
 important for your work, you can only use one of the `@key{|}'s.
 
 @example
-# Column 1: ID [label, uc]
+# Column 1: ID [label, u8]
 # Column 2: Notes [no unit, str50]
 1    leading and trailing white space is ignored here    2.3442e10
 2   |         but they will be preserved here        |   8.2964e11
@@ -10819,6 +10832,26 @@ The hour that defines the next ``night''. By default, 
all times before
 sub-hour value is necessary, it should be given in units of hours, for
 example @option{--hour=9.5} corresponds to 9:30a.m.
 
+@cartouche
+@noindent
+@cindex Time zone
+@cindex UTC (Universal time coordinate)
+@cindex Universal time coordinate (UTC)
+@strong{Dealing with time zones:} the time that is recorded in
+@option{--key} may be in UTC (Universal Time Coordinate). However, the
+organization of the images taken during the night depends on the local
+time. It is possible to take this into account by setting the
+@option{--hour} option to the local time in UTC.
+
+For example, consider a set of images taken in Auckland (New Zeland,
+UTC+12) during different nights. If you want to classify these images by
+night, you have to know at which time (in UTC time) the Sun rises (or any
+other separator/definition of a different night). In this particular
+example, you can use @option{--hour=21}. Because in Auckland, a night
+finishes (roughly) at the local time of 9:00, which corresponds to 21:00
+UTC.
+@end cartouche
+
 @item -l
 @itemx --link
 Create a symbolic link for each input FITS file. This option cannot be used
@@ -10883,8 +10916,6 @@ the files (in that directory) will all start with 
@file{img-}.
 
 
 
-
-
 @node ConvertType, Table, Sort FITS files by night, Data containers
 @section ConvertType
 
@@ -11576,10 +11607,108 @@ higher-level processing, see the examples in 
@ref{Invoking asttable} for
 some simple examples.
 
 @menu
+* Column arithmetic::           How to do operations on table columns.
 * Invoking asttable::           Options and arguments to Table.
 @end menu
 
-@node Invoking asttable,  , Table, Table
+@node Column arithmetic, Invoking asttable, Table, Table
+@subsection Column arithmetic
+
+After reading the requested columns from the input table, you can also do
+operations/arithmetic on the columns and save the resulting values as new
+column(s) in the output table (possibly in between other requested
+columns). To enable column arithmetic, the first 6 characters of the value
+to @option{--column} (@code{-c}) should be the arithmetic activation word
+`@option{arith }' (note the space character in the end, after
+`@code{arith}').
+
+After the activation word, you can use the reverse polish notation to
+identify the operators and their operands, see @ref{Reverse polish
+notation}. Just note that white-space characters are used between the
+tokens of the arithmetic expression and that they are meaningful to the
+command-line environment. Therefore the whole expression (including the
+activation word) has to be quoted on the command-line or in a shell script
+(see the examples below).
+
+To identify a column you can directly use its name, or specify its number
+(counting from one, see @ref{Selecting table columns}). When you are giving
+a column number, it is necessary to prefix it with a @code{c} (otherwise it
+is not distinguisable from a constant number to use in the arithmetic
+operation).
+
+For example with the command below, the first two columns of
+@file{table.fits} will be printed along with a third column that is the
+result of multiplying the first column with @mymath{10^{10}} (for example
+to convert wavelength from Meters to Angstroms). Note how without the
+`@key{c}', it is not possible to distinguish between @key{1} as a
+column-counter, or as a constant number to use in the arithmetic operation.
+
+@example
+$ asttable table.fits -c1,2 -c"arith c1 1e10 x"
+@end example
+
+Alternatively, if the columns have meta-data and the first two are
+respectively called @code{AWAV} and @code{SPECTRUM}, the command above is
+equivalent to the command below. Note that the @key{c} is no longer
+necessary in this scenario.
+
+@example
+$ asttable table.fits -cAWAV,SPECTRUM -c"arith AWAV 1e10 x"
+@end example
+
+Comparison of the two commands above clearly shows why it is recommended to
+use column names instead of numbers. When the columns have clear names, the
+command/script actually becomes much more readable, describing the intent
+of the operation. It is also independent of the low-level table structure:
+for the second command, the position of the @code{AWAV} and @code{SPECTRUM}
+columns in @file{table.fits} is irrelevant.
+
+Finally, since the arithmetic expressions are a value to @option{--column},
+it doesn't necessarily have to be a separate option, so the commands above
+are also identical to the command below (note that this only has one
+@option{-c} option). Just be very careful with the quoting!
+
+@example
+$ asttable table.fits -cAWAV,SPECTRUM,"arith AWAV 1e10 x"
+@end example
+
+Almost all the arithmetic operators of @ref{Arithmetic operators} are also
+supported for column arithmetic in Table. In particular, the few that are
+not present in the Gnuastro library aren't yet supported. For a list of the
+Gnuastro library arithmetic operators, please see the macros starting with
+@code{GAL_ARITHMETIC_OP} and ending with the operator name in
+@ref{Arithmetic on datasets}. Besides the operators in @ref{Arithmetic
+operators}, several operators are only available in Table to use on table
+columns.
+
+@cindex WCS: World Coordinate System
+@cindex World Coordinate System (WCS)
+@table @code
+@item wcstoimg
+Convert the given WCS positions to image/dataset coordinates based on the
+number of dimensions in the WCS structure of @option{--wcshdu}
+extension/HDU in @option{--wcsfile}. It will output the same number of
+columns. The first poppoed operand is the last FITS dimension.
+
+For example the two commands below (which have the same output) will
+produce 5 columns. The first three columns are the input table's ID, RA and
+Dec columns. The fourth and fifth columns will be the pixel positions in
+@file{image.fits} that correspond to each RA and Dec.
+
+@example
+$ asttable table.fits -cID,RA,DEC,"arith RA DEC wcstoimg" \
+           --wcsfile=image.fits
+$ asttable table.fits -cID,RA -cDEC \
+           -c"arith RA DEC wcstoimg" --wcsfile=image.fits
+@end example
+
+@item imgtowcs
+Similar to @code{wcstoimg}, except that image/dataset coordinates are
+converted to WCS coordinates.
+@end table
+
+
+@node Invoking asttable,  , Column arithmetic, Table
 @subsection Invoking Table
 
 Table will read/write, select, convert, or show the information of the
@@ -11613,26 +11742,19 @@ $ asttable bintab.fits -cRA,DEC,/^MAG_/ --sort=Z_PHOT
 ## 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:
-$ asttable bintab.fits -c2,5 | awk '@{print $1, 5*$2@}'
-
 ## Only print rows with a value in the 10th column above 100000:
-$ asttable bintab.fits | awk '$10>10e5 @{print@}'
+$ asttable bintab.fits --range=10,10e5,inf
 
-## Sort the output columns by the third column, save output:
-$ asttable bintab.fits | 'sort -nk3 > output.txt
+## Only print the 2nd column, and the third column multiplied by 5,
+## Save the resulting two columns in `table.txt'
+$ asttable bintab.fits -c2,"arith c2 5 x" -otable.fits
 
-## Subtract the first column from the second in `cat.txt' and keep the
-## third and fourth columns. Feed the columns to Table to write as a
-## FITS table.
-$ awk '!/^#/@{print $2-$1, $3, $4@}' cat.txt | asttable -ocat.fits
+## Sort the output columns by the third column, save output:
+$ asttable bintab.fits --sort=3 -ooutput.txt
 
-## Convert a plain text table to a binary FITS table:
-$ asttable plaintext.txt --output=table.fits --tabletype=fits-binary
+## Subtract the first column from the second in `cat.txt' (can also
+## be a FITS table) and keep the third and fourth columns.
+$ awk cat.txt -c"arith c2 c1 -",3,4 -ocat.fits
 @end example
 
 Table's input dataset can be given either as a file or from Standard input
@@ -11685,20 +11807,37 @@ last command with all the previously typed columns 
present, delete
 @cindex GNU AWK
 @item -c STR/INT
 @itemx --column=STR/INT
-Specify the columns to read, see @ref{Selecting table columns} for a
-thorough explanation on how the value to this option is interpreted. There
-are two ways to specify multiple columns: 1) multiple calls to this option,
-2) using a comma between each column specifier in one call to this
-option. These different solutions may be mixed in one call to Table: for
-example, @option{-cRA,DEC -cMAG}, or @option{-cRA -cDEC -cMAG} are both
-equivalent to @option{-cRA -cDEC -cMAG}. The order of the output columns
-will be the same order given to the option or in the configuration files
-(see @ref{Configuration file precedence}).
+Set the output columns either by specifying the column number, or name. For
+more on selecting columns, see @ref{Selecting table columns}. If a value of
+this option starts with `@code{arith }', this option will do the requested
+operations/arithmetic on the specified columns and output the result in
+that place (among other requested columns). For more on column arithmetic
+see @ref{Column arithmetic}.
+
+To ask for multiple columns this option can be used in two way: 1) multiple
+calls to this option, 2) using a comma between each column specifier in one
+call to this option. These different solutions may be mixed in one call to
+Table: for example, @option{-cRA,DEC -cMAG}, or @option{-cRA -cDEC -cMAG}
+are both equivalent to @option{-cRA -cDEC -cMAG}. The order of the output
+columns will be the same order given to the option or in the configuration
+files (see @ref{Configuration file precedence}).
 
 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.
 
+@item -w STR
+@itemx --wcsfile=STR
+FITS file that contains the WCS to be used in the @code{wcstoimg} and
+@code{imgtowcs} operators of @option{--column} (see above). The extension
+name/number within the FITS file can be specified with @option{--wcshdu}.
+
+@item -W STR
+@itemx --wcshdu=STR
+FITS extension/HDU that contains the WCS to be used in the @code{wcstoimg}
+and @code{imgtowcs} operators of @option{--column} (see above). The FITS
+file name can be specified with @option{--wcsfile}.
+
 @item -O
 @itemx --colinfoinstdout
 @cindex Standard output
@@ -11722,6 +11861,9 @@ 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.
 
+For one example of using this option, see the example under
+@option{--sigclip-median} in @ref{Invoking aststatistics}.
+
 @item -s STR
 @item --sort=STR
 Sort the output rows based on the values in the @code{STR} column (can be a
@@ -11736,6 +11878,25 @@ column anymore afterwards.
 @itemx --descending
 When called with @option{--sort}, rows will be sorted in descending order.
 
+@item -H INT
+@itemx --head=INT
+Only print the given number of rows from the @emph{top} of the final
+table. Note that this option only affects the @emph{output} table. For
+example if you use @option{--sort}, or @option{--range}, the printed rows
+are the first @emph{after} applying the sort sorting, or selecting a range
+of the full input.
+
+@cindex GNU Coreutils
+If the given value to @option{--head} is 0, the output columns won't have
+any rows and if its larger than the number of rows in the input table, all
+the rows are printed (this option is effectively ignored). This behavior is
+taken from the @command{head} program in GNU Coreutils.
+
+@item -t INT
+@itemx --tail=INT
+Only print the given number of rows from the @emph{bottom} of the final
+table. See @option{--head} for more.
+
 @end table
 
 
@@ -12514,14 +12675,15 @@ The most common notation for arithmetic operations is 
the
 @url{https://en.wikipedia.org/wiki/Infix_notation, infix notation} where
 the operator goes between the two operands, for example @mymath{4+5}. While
 the infix notation is the preferred way in most programming languages,
-currently Arithmetic does not use it since it will require parenthesis
-which can complicate the implementation of the code. In the near future we
-do plan to adopt this
+currently the Gnuastro's program (in particular Arithmetic and Table, when
+doing column arithmetic) do not use it. This is because it will require
+parenthesis which can complicate the implementation of the code. In the
+near future we do plan to also allow this
 notation@footnote{@url{https://savannah.gnu.org/task/index.php?13867}}, but
-for the time being (due to time constraints on the developers), Arithmetic
-uses the post-fix or
+for the time being (due to time constraints on the developers), arithmetic
+operations can only be done in the post-fix notation (also known as
 @url{https://en.wikipedia.org/wiki/Reverse_Polish_notation, reverse polish
-notation}. The Wikipedia article provides some excellent explanation on
+notation}). The Wikipedia article provides some excellent explanation on
 this notation but here we will give a short summary here for
 self-sufficiency.
 
@@ -12529,22 +12691,24 @@ In the post-fix notation, the operator is placed 
after the operands, as we
 will see below this removes the need to define parenthesis for most
 ordinary operators. For example, instead of writing @command{5+6}, we write
 @command{5 6 +}. To easily understand how this notation works, you can
-think of each operand as a node in a first-in-first-out stack. Every time
-an operator is confronted, it pops the number of operands it needs from the
-top of the stack (so they don't exist in the stack any more), does its
-operation and pushes the result back on top of the stack. So if you want
-the average of 5 and 6, you would write: @command{5 6 + 2 /}. The
-operations that are done are:
+think of each operand as a node in a ``last-in-first-out'' stack. Every
+time an operator is confronted, the operator pops the number of operands it
+needs from the top of the stack (so they don't exist in the stack any
+more), does its operation and pushes the result back on top of the
+stack. So if you want the average of 5 and 6, you would write: @command{5 6
++ 2 /}. The operations that are done are:
 
 @enumerate
 @item
-@command{5} is an operand, so it is pushed to the top of the stack.
+@command{5} is an operand, so it is pushed to the top of the stack (which
+is initially empty).
 @item
 @command{6} is an operand, so it is pushed to the top of the stack.
 @item
-@command{+} is a binary operator, so pull the top two elements of the stack
-and perform addition on them (the order is @mymath{5+6} in the example
-above). The result is @command{11}, push it on top of the stack.
+@command{+} is a @emph{binary} operator, so it will pop the top two
+elements of the stack out of it, and perform addition on them (the order is
+@mymath{5+6} in the example above). The result is @command{11} which is
+pushed to the top of the stack.
 @item
 @command{2} is an operand so push it onto the top of the stack.
 @item
@@ -12553,14 +12717,17 @@ the stack (top-most is @command{2}, then 
@command{11}) and divide the
 second one by the first.
 @end enumerate
 
-In the Arithmetic program, the operands can be FITS images or numbers. As
-you can see, very complicated procedures can be created without the need
-for parenthesis or worrying about precedence. Even functions which take an
-arbitrary number of arguments can be defined in this notation. This is a
-very powerful notation and is used in languages like Postscript
+In the Arithmetic program, the operands can be FITS images or numbers (see
+@ref{Invoking astarithmetic}). In Table's column arithmetic, they can be
+any column or a number (see @ref{Column arithmetic}).
+
+With this notation, very complicated procedures can be created without the
+need for parenthesis or worrying about precedence. Even functions which
+take an arbitrary number of arguments can be defined in this notation. This
+is a very powerful notation and is used in languages like Postscript
 @footnote{See the EPS and PDF part of @ref{Recognized file formats} for a
-little more on the Postscript language.}  (the programming language in
-Postscript and compiled into PDF files) uses this notation.
+little more on the Postscript language.} which produces PDF files when
+compiled.
 
 
 
@@ -12663,6 +12830,9 @@ to @command{minvalue}.
 
 @cindex NaN
 @item min
+For each pixel, find the minimum value in all given datasets. The output
+will have the same type as the input.
+
 The first popped operand to this operator must be a positive integer number
 which specifies how many further operands should be popped from the
 stack. All the subsequently popped operands must have the same type and
@@ -12698,37 +12868,50 @@ conversion will be used.
 @end itemize
 
 @item max
-Similar to @command{min}, but the pixels of the output will contain
-the maximum of the respective pixels in all operands in the stack.
+For each pixel, find the maximum value in all given datasets. The output
+will have the same type as the input. This operator is called similar to
+the @command{min} operator, please see there for more.
 
 @item number
-Similar to @command{min}, but the pixels of the output will contain the
-number of the respective non-blank pixels in all input operands.
+For each pixel count the number of non-blank pixels in all given
+datasets. The output will be an unsigned 32-bit integer datatype (see
+@ref{Numeric data types}). This operator is called similar to the
+@command{min} operator, please see there for more.
 
 @item sum
-Similar to @command{min}, but the pixels of the output will contain the sum
-of the respective pixels in all input operands.
+For each pixel, calculate the sum in all given datasets. The output will
+have the a single-precision (32-bit) floating point type. This operator is
+called similar to the @command{min} operator, please see there for more.
 
 @item mean
-Similar to @command{min}, but the pixels of the output will contain the
-mean (average) of the respective pixels in all operands in the stack.
+For each pixel, calculate the mean in all given datasets. The output will
+have the a single-precision (32-bit) floating point type. This operator is
+called similar to the @command{min} operator, please see there for more.
 
 @item std
-Similar to @command{min}, but the pixels of the output will contain the
-standard deviation of the respective pixels in all operands in the stack.
+For each pixel, find the standard deviation in all given datasets. The
+output will have the a single-precision (32-bit) floating point type. This
+operator is called similar to the @command{min} operator, please see there
+for more.
 
 @item median
-Similar to @command{min}, but the pixels of the output will contain
-the median of the respective pixels in all operands in the stack.
+For each pixel, find the median in all given datasets. The output will have
+the a single-precision (32-bit) floating point type. This operator is
+called similar to the @command{min} operator, please see there for more.
 
 @item sigclip-number
-Combine the specified number of inputs into a single output that contains
-the number of remaining elements after @mymath{\sigma}-clipping on each
-element/pixel (for more on @mymath{\sigma}-clipping, see @ref{Sigma
-clipping}). This operator is very similar to @command{min}, with the
-exception that it expects two operands (parameters for sigma-clipping)
-before the total number of inputs. The first popped operand is the
-termination criteria and the second is the multiple of @mymath{\sigma}.
+For each pixel, find the sigma-clipped number (after removing outliers) in
+all given datasets. The output will have the an unsigned 32-bit integer
+type (see @ref{Numeric data types}).
+
+This operator will combine the specified number of inputs into a single
+output that contains the number of remaining elements after
+@mymath{\sigma}-clipping on each element/pixel (for more on
+@mymath{\sigma}-clipping, see @ref{Sigma clipping}). This operator is very
+similar to @command{min}, with the exception that it expects two operands
+(parameters for sigma-clipping) before the total number of inputs. The
+first popped operand is the termination criteria and the second is the
+multiple of @mymath{\sigma}.
 
 For example in the command below, the first popped operand (@command{0.2})
 is the sigma clipping termination criteria. If the termination criteria is
@@ -12744,19 +12927,22 @@ astarithmetic a.fits b.fits c.fits 3 5 0.2 
sigclip-number
 @end example
 
 @item sigclip-median
-Combine the specified number of inputs into a single output that contains
-the @emph{median} after @mymath{\sigma}-clipping on each element/pixel. For
-more see @command{sigclip-number}.
+For each pixel, find the sigma-clipped median in all given datasets. The
+output will have the a single-precision (32-bit) floating point type. This
+operator is called similar to the @command{sigclip-number} operator, please
+see there for more.
 
 @item sigclip-mean
-Combine the specified number of inputs into a single output that contains
-the @emph{mean} after @mymath{\sigma}-clipping on each element/pixel. For
-more see @command{sigclip-number}.
+For each pixel, find the sigma-clipped mean in all given datasets. The
+output will have the a single-precision (32-bit) floating point type. This
+operator is called similar to the @command{sigclip-number} operator, please
+see there for more.
 
 @item sigclip-std
-Combine the specified number of inputs into a single output that contains
-the @emph{standard deviation} after @mymath{\sigma}-clipping on each
-element/pixel. For more see @command{sigclip-number}.
+For each pixel, find the sigma-clipped standard deviation in all given
+datasets. The output will have the a single-precision (32-bit) floating
+point type. This operator is called similar to the @command{sigclip-number}
+operator, please see there for more.
 
 @item filter-mean
 Apply mean filtering (or @url{https://en.wikipedia.org/wiki/Moving_average,
@@ -12907,6 +13093,15 @@ Similar to @option{collapse-sum}, but the returned 
dataset will have the
 same numeric type as the input and will contain the maximum value for each
 pixel along the collapsed dimension.
 
+@item unique
+Remove all duplicate (and blank) elements from the first popped
+operand. The unique elements of the dataset will be stored in a
+single-dimensional dataset.
+
+Recall that by default, single-dimensional datasets are stored as a table
+column in the output. But you can use @option{--onedasimage} to store them
+as a single-dimensional FITS array/image.
+
 @item erode
 @cindex Erosion
 Erode the foreground pixels (with value @code{1}) of the input dataset
@@ -15750,11 +15945,11 @@ iteration:
 @itemize
 @item
 When a certain number of iterations has taken place (second value to the
-@option{--sigclip} option is larger than 1).
+@option{--sclipparams} option is larger than 1).
 @item
 When the new measured standard deviation is within a certain tolerance
-level of the old one (second value to the @option{--sigclip} option is less
-than 1). The tolerance level is defined by:
+level of the old one (second value to the @option{--sclipparams} option is
+less than 1). The tolerance level is defined by:
 
 @dispmath{\sigma_{old}-\sigma_{new} \over \sigma_{new}}
 
@@ -15952,7 +16147,7 @@ the histogram bin-widths. Generally, the mode of a 
distribution also shifts
 as signal is added. Therefore, even if it is accurately measured, the mode
 is a biased measure for the Sky value.
 
-@cindex sigma-clipping
+@cindex Sigma-clipping
 @item
 Another approach was to iteratively clip the brightest pixels in the image
 (which is known as @mymath{\sigma}-clipping). See @ref{Sigma clipping} for
@@ -16398,6 +16593,86 @@ distributions are no longer symmetric, see 
@option{--mode} and Appendix C
 of @url{https://arxiv.org/abs/1505.01664, Akhlaghi and Ichikawa 2015} for
 more.
 
+@item --sigclip-number
+Number of elements after applying @mymath{\sigma}-clipping (see @ref{Sigma
+clipping}). @mymath{\sigma}-clipping configuration is done with the
+@option{--sigclipparams} option.
+
+@item --sigclip-median
+Median after applying @mymath{\sigma}-clipping (see @ref{Sigma
+clipping}). @mymath{\sigma}-clipping configuration is done with the
+@option{--sigclipparams} option.
+
+@cindex Outlier
+Here is one scenario where this can be useful: assume you have a table and
+you would like to remove the rows that are outliers (not within the
+@mymath{\sigma}-clipping range). Let's assume your table is called
+@file{table.fits} and you only want to keep the rows that have a value in
+@code{COLUMN} within the @mymath{\sigma}-clipped range (to
+@mymath{3\sigma}, with a tolerance of 0.1). This command will return the
+@mymath{\sigma}-clipped median and standard deviation (used to define the
+range later).
+
+@example
+$ aststatistics table.fits -cCOLUMN --sclipparams=3,0.1 \
+                --sigclip-median --sigclip-std
+@end example
+
+@cindex GNU AWK
+You can then use the @option{--range} option of Table (see @ref{Table}) to
+select the proper rows. But for that, you need the actual starting and
+ending values of the range (@mymath{m\pm s\sigma}; where @mymath{m} is the
+median and @mymath{s} is the multiple of sigma to define an
+outlier). Therefore, the raw outputs of Statistics in the command above
+aren't enough.
+
+To get the starting and ending values of the non-outlier range (and put a
+`@key{,}' between them, ready to be used in @option{--range}), pipe the
+result into AWK. But in AWK, we'll also need the multiple of
+@mymath{\sigma}, so we'll define it as a shell variable (@code{s}) before
+calling Statistics (note how @code{$s} is used two times now):
+
+@example
+$ s=3
+$ aststatistics table.fits -cCOLUMN --sclipparams=$s,0.1 \
+                --sigclip-median --sigclip-std           \
+     | awk '@{s='$s'; printf("%f,%f\n", $1-s*$2, $1+s*$2)@}'
+@end example
+
+To pass it onto Table, we'll need to keep the printed output from the
+command above in another shell variable (@code{r}), not print it. In Bash,
+can do this by putting the whole statement within a @code{$()}:
+
+@example
+$ s=3
+$ r=$(aststatistics table.fits -cCOLUMN --sclipparams=$s,0.1 \
+                    --sigclip-median --sigclip-std           \
+        | awk '@{s='$s'; printf("%f,%f\n", $1-s*$2, $1+s*$2)@}')
+$ echo $r      # Just to confirm.
+@end example
+
+Now you can use Table with the @option{--range} option to only print the
+rows that have a value in @code{COLUMN} within the desired range:
+
+@example
+$ asttable table.fits --range=COLUMN,$r
+@end example
+
+To save the resulting table (that is clean of outliers) in another file
+(for example named @file{cleaned.fits}, it can also have a @file{.txt}
+suffix), just add @option{--output=cleaned.fits} to the command above.
+
+
+@item --sigclip-mean
+Mean after applying @mymath{\sigma}-clipping (see @ref{Sigma
+clipping}). @mymath{\sigma}-clipping configuration is done with the
+@option{--sigclipparams} option.
+
+@item --sigclip-std
+Standard deviation after applying @mymath{\sigma}-clipping (see @ref{Sigma
+clipping}). @mymath{\sigma}-clipping configuration is done with the
+@option{--sigclipparams} option.
+
 @end table
 
 The list of options below are for those statistical operations that output
@@ -16684,8 +16959,8 @@ it is interpreted as tolerance and if it is larger than 
one it is a
 specific number. Hence, in the latter case the value must be an integer.
 
 @item --outliersclip=FLT,FLT
-Sigma-clipping parameters for the outlier rejection of the Sky value
-(similar to @option{--sclipparams}).
+@mymath{\sigma}-clipping parameters for the outlier rejection of the Sky
+value (similar to @option{--sclipparams}).
 
 Outlier rejection is useful when the dataset contains a large and diffuse
 (almost flat within each tile) signal. The flatness of the profile will
@@ -17026,9 +17301,8 @@ results, but it can also increase the NoiseChisel run 
time (depending on
 the given value and input size).
 
 @item
-@option{--cleangrowndet}: A process to further clean/remove the possibility
-of false detections, see the descriptions under this option in
-@ref{Detection options}.
+@option{--cleangrowndet}: Further clean/remove false detections after
+growth, see the descriptions under this option in @ref{Detection options}.
 
 @end itemize
 
@@ -17384,8 +17658,8 @@ quantile is between 0.49 and 0.51 (recall that the 
median's quantile is
 0.5) will be used.
 
 @item --outliersclip=FLT,FLT
-Sigma-clipping parameters for the outlier rejection of the quantile
-threshold. The format of the given values is similar to
+@mymath{\sigma}-clipping parameters for the outlier rejection of the
+quantile threshold. The format of the given values is similar to
 @option{--sigmaclip} below. In NoiseChisel, outlier rejection on tiles is
 used when identifying the quantile thresholds (@option{--qthresh},
 @option{--noerodequant}, and @option{detgrowquant}).
@@ -18482,9 +18756,9 @@ options}). Please see the descriptions there for more.
 The quantile of the signal-to-noise ratio distribution of clumps in
 undetected regions, used to define true clumps. After identifying all the
 usable clumps in the undetected regions of the dataset, the given quantile
-of their signal-to-noise ratios is used to define a the signal-to-noise
-ratio of a ``true'' clump. Effectively, this can be seen as an inverse
-p-value measure. See Figure 9 and Section 3.2.1 of
+of their signal-to-noise ratios is used to define the signal-to-noise ratio
+of a ``true'' clump. Effectively, this can be seen as an inverse p-value
+measure. See Figure 9 and Section 3.2.1 of
 @url{https://arxiv.org/abs/1505.01664, Akhlaghi and Ichikawa [2015]} for a
 complete explanation. The full distribution of clump signal-to-noise ratios
 over the undetected areas can be saved into a table with @option{--checksn}
@@ -19143,9 +19417,9 @@ derivations with some added explanations for easier 
reading.
 
 @cindex Moments
 Let's begin with one dimension for simplicity: Assume we have a set of
-@mymath{N} values @mymath{B_i} (keeping the spatial distribution of
-brightness for example), each at position @mymath{x_i}. The simplest
-parameter we can define is the geometric center of the object
+@mymath{N} values @mymath{B_i} (for example showing the spatial
+distribution of a target's brightness), each at position @mymath{x_i}. The
+simplest parameter we can define is the geometric center of the object
 (@mymath{x_g}) (ignoring the brightness values):
 @mymath{x_g=(\sum_ix_i)/N}. @emph{Moments} are defined to incorporate both
 the value (brightness) and position of the data. The first moment can be
@@ -20077,11 +20351,11 @@ than the minimum, a value of @code{-inf} is reported.
 
 @item --upperlimitskew
 @cindex Skewness
-This column contains the non-parametric skew of the sigma-clipped random
-distribution that was used to estimate the upper-limit magnitude. Taking
-@mymath{\mu} as the mean, @mymath{\nu} as the median and @mymath{\sigma} as
-the standard deviation, the traditional definition of skewness is defined
-as: @mymath{(\mu-\nu)/\sigma}.
+This column contains the non-parametric skew of the @mymath{\sigma}-clipped
+random distribution that was used to estimate the upper-limit
+magnitude. Taking @mymath{\mu} as the mean, @mymath{\nu} as the median and
+@mymath{\sigma} as the standard deviation, the traditional definition of
+skewness is defined as: @mymath{(\mu-\nu)/\sigma}.
 
 This can be a good measure to see how much you can trust the random
 measurements, or in other words, how accurately the regions with signal
@@ -20158,13 +20432,15 @@ projection onto the first two dimensions would be a 
narrow-band image.
 
 @item -A
 @itemx --semimajor
-The pixel-value weighted semi-major axis of the profile (assuming it is an
-ellipse) in units of pixels. See @ref{Measuring elliptical parameters}.
+The pixel-value weighted root mean square (RMS) along the semi-major axis
+of the profile (assuming it is an ellipse) in units of pixels. See
+@ref{Measuring elliptical parameters}.
 
 @item -B
 @itemx --semiminor
-The pixel-value weighted semi-minor axis of the profile (assuming it is an
-ellipse) in units of pixels. See @ref{Measuring elliptical parameters}.
+The pixel-value weighted root mean square (RMS) along the semi-minor axis
+of the profile (assuming it is an ellipse) in units of pixels. See
+@ref{Measuring elliptical parameters}.
 
 @item --axisratio
 The pixel-value weighted axis ratio (semi-minor/semi-major) of the object
@@ -20176,12 +20452,14 @@ The pixel-value weighted angle of the semi-major axis 
with the first FITS
 axis in degrees. See @ref{Measuring elliptical parameters}.
 
 @item --geosemimajor
-The geometric (ignoring pixel values) semi-major axis of the profile,
-assuming it is an ellipse.
+The geometric (ignoring pixel values) root mean square (RMS) along the
+semi-major axis of the profile, assuming it is an ellipse, in units of
+pixels.
 
 @item --geosemiminor
-The geometric (ignoring pixel values) semi-minor axis of the profile,
-assuming it is an ellipse.
+The geometric (ignoring pixel values) root mean square (RMS) along the
+semi-minor axis of the profile, assuming it is an ellipse, in units of
+pixels.
 
 @item --geoaxisratio
 The geometric (ignoring pixel values) axis ratio of the profile, assuming
@@ -22823,6 +23101,10 @@ $ astcosmiccal -z2.5
 ## Only print Comoving volume over 4pi stradian to z (Mpc^3):
 $ astcosmiccal --redshift=0.8 --volume
 
+## Print redshift and age of universe when Lyman-alpha line is
+## at 6000 angstrom (another way to specify redshift).
+$ astcosmiccal --obsline=lyalpha,6000 --age
+
 ## Print luminosity distance, angular diameter distance and age
 ## of universe in one row at redshift 0.4
 $ astcosmiccal -z0.4 -LAg
@@ -22861,7 +23143,7 @@ The inputs to CosmicCalculator can be specified with 
the following options:
 
 @item -z FLT
 @itemx --redshift=FLT
-The redshift of interest.
+The redshift of interest. This cannot be called with @option{--obsline}.
 
 @item -H FLT
 @itemx --H0=FLT
@@ -22881,6 +23163,132 @@ density in the current Universe 
(@mymath{\Omega_{m,0}}).
 @itemx --oradiation=FLT
 Radiation density divided by the critical density in the current Universe
 (@mymath{\Omega_{r,0}}).
+
+@item -O STR/FLT,FLT
+@itemx --obsline=STR/FLT,FLT
+@cindex Rest-frame wavelength
+@cindex Wavelength, rest-frame
+Find the redshift to use in next steps based on the rest-frame and observed
+wavelengths of a line. Wavelenghts are assumed to be in Angstroms. The
+first argument identifies the line. It can be one of the standard names
+below, or any rest-frame wavelengh in Angestroms. The second argument is
+the observed wavelength of that line. For example
+@option{--obsline=lyalpha,6000} is the same as
+@option{--obsline=1215.64,6000}.
+
+The accepted names are listed below, sorted from red (longer wavelengh) to
+blue (shorter wavelengh).
+
+@table @code
+@item siired
+[6731@AA{}] SII doublet's redder line.
+
+@item sii
+@cindex Doublet: SII
+@cindex SII doublet
+[6724@AA{}] SII doublet's mean center at .
+
+@item siiblue
+[6717@AA{}] SII doublet's bluer line.
+
+@item niired
+[6584@AA{}] NII doublet's redder line.
+
+@item nii
+@cindex Doublet: NII
+@cindex NII doublet
+[6566@AA{}] NII doublet's mean center.
+
+@item halpha
+@cindex H-alpha
+[6562.8@AA{}] H-@mymath{\alpha} line.
+
+@item niiblue
+[6548@AA{}] NII doublet's bluer line.
+
+@item oiiired
+[5007@AA{}] OIII doublet's redder line.
+
+@item oiii
+@cindex Doublet: OIII
+@cindex OIII doublet
+[4983@AA{}] OIII doublet's mean center.
+
+@item oiiiblue
+[4959@AA{}] OIII doublet's bluer line.
+
+@item hbeta
+@cindex H-beta
+[4861.36@AA{}] H-@mymath{\beta} line.
+
+@item heiired
+[4686@AA{}] HeII doublet's redder line.
+
+@item hgamma
+@cindex H-gamma
+[4340.46@AA{}] H-@mymath{\gamma} line.
+
+@item hdelta
+@cindex H-delta
+[4101.74@AA{}] H-@mymath{\delta} line.
+
+@item hepsilon
+@cindex H-epsilon
+[3970.07@AA{}] H-@mymath{\epsilon} line.
+
+@item neiii
+[3869@AA{}] NEIII line.
+
+@item oiired
+[3729@AA{}] OII doublet's redder line.
+
+@item oii
+@cindex Doublet: OII
+@cindex OII doublet
+[3727.5@AA{}] OII doublet's mean center.
+
+@item oiiblue
+[3726@AA{}] OII doublet's bluer line.
+
+@item blimit
+@cindex Balmer limit
+[3646@AA{}] Balmer limit.
+
+@item mgiired
+[2803@AA{}] MgII doublet's redder line.
+
+@item mgii
+@cindex Doublet: MgII
+@cindex MgII doublet
+[2799.5@AA{}] MgII doublet's mean center.
+
+@item mgiiblue
+[2796@AA{}] MgII doublet's bluer line.
+
+@item ciiired
+[1909@AA{}] CIII doublet's redder line.
+
+@item ciii
+@cindex Doublet: CIII
+@cindex CIII doublet
+[1908@AA{}] CIII doublet's mean center.
+
+@item ciiiblue
+[1907@AA{}] CIII doublet's bluer line.
+
+@item heiiblue
+[1640@AA{}] HeII doublet's bluer line.
+
+@item lyalpha
+@cindex Lyman-alpha
+[1215.67@AA{}] Lyman-@mymath{\alpha} line.
+
+@item lylimit
+@cindex Lyman limit
+[912@AA{}] Lyman limit.
+
+@end table
+
 @end table
 
 
@@ -22952,6 +23360,15 @@ option which has the units along with a short 
description.
 
 @table @option
 
+@item -e
+@itemx --usedredshift
+The redshift that was used in this run. In many cases this is the main
+input parameter to CosmicCalculator, but it is useful in others. For
+example in combination with @option{--obsline} (where you give an observed
+and restframe wavelength and would like to know the redshift), or if you
+want to run CosmicCalculator in a loop while changing the redshift and you
+want to keep the redshift value.
+
 @item -G
 @itemx --agenow
 The current age of the universe (given the input parameters) in Ga (Giga
@@ -23965,6 +24382,7 @@ documentation will correspond to your installed version.
 * Convolution functions::       Library functions to do convolution.
 * Interpolation::               Interpolate (over blank values possibly).
 * Git wrappers::                Wrappers for functions in libgit2.
+* Spectral lines library::
 * Cosmology library::           Cosmological calculations.
 @end menu
 
@@ -24510,11 +24928,11 @@ out = gal_type_to_string(&string, GAL_TYPE_STRING, 1);
 @end deftypefun
 
 @deftypefun int gal_type_from_string (void @code{**out}, char @code{*string}, 
uint8_t @code{type})
-Read a string as a given data type and put a the pointer to it in
+Read a string as a given data type and put a pointer to it in
 @code{*out}. When @code{*out!=NULL}, then it is assumed to be already
-allocated and the value will be simply put the memory. If
-@code{*out==NULL}, then space will be allocated for the given type and the
-string will be read into that type.
+allocated and the value will be simply put there. If @code{*out==NULL},
+then space will be allocated for the given type and the string will be read
+into that type.
 
 Note that when we are dealing with a string type, @code{*out} should be
 interpreted as @code{char **} (one element in an array of pointers to
@@ -24695,6 +25113,16 @@ Blank value for an unsigned, 64-bit integer.
 Blank value for a signed, 64-bit integer.
 @end deffn
 
+@deffn {Global integer}  GAL_BLANK_INT
+Blank value for @code{int} type (@code{int16_t} or @code{int32_t} depending
+on the system.
+@end deffn
+
+@deffn {Global integer}  GAL_BLANK_UINT
+Blank value for @code{int} type (@code{int16_t} or @code{int32_t} depending
+on the system.
+@end deffn
+
 @deffn {Global integer}  GAL_BLANK_LONG
 Blank value for @code{long} type (@code{int32_t} or @code{int64_t} in
 32-bit or 64-bit systems).
@@ -25630,6 +26058,10 @@ pointer.
 Return the number of nodes in @code{list}.
 @end deftypefun
 
+@deftypefun size_t gal_list_str_last (gal_list_str_t @code{*list})
+Return a pointer to the last node in @code{list}.
+@end deftypefun
+
 @deftypefun void gal_list_str_print (gal_list_str_t @code{*list})
 Print the strings within each node of @code{*list} on the standard output
 in the same order that they are stored. Each string is printed on one
@@ -25706,6 +26138,10 @@ also change @code{list} to point to the next node in 
the list. If
 Return the number of nodes in @code{list}.
 @end deftypefun
 
+@deftypefun size_t gal_list_i32_last (gal_list_i32_t @code{*list})
+Return a pointer to the last node in @code{list}.
+@end deftypefun
+
 @deftypefun void gal_list_i32_print (gal_list_i32_t @code{*list})
 Print the integers within each node of @code{*list} on the standard output
 in the same order that they are stored. Each integer is printed on one
@@ -25807,6 +26243,10 @@ also change @code{list} to point to the next node in 
the list. If
 Return the number of nodes in @code{list}.
 @end deftypefun
 
+@deftypefun size_t gal_list_sizet_last (gal_list_sizet_t @code{*list})
+Return a pointer to the last node in @code{list}.
+@end deftypefun
+
 @deftypefun void gal_list_sizet_print (gal_list_sizet_t @code{*list})
 Print the values within each node of @code{*list} on the standard output in
 the same order that they are stored. Each integer is printed on one
@@ -25892,6 +26332,10 @@ also change @code{list} to point to the next node in 
the list. If
 Return the number of nodes in @code{list}.
 @end deftypefun
 
+@deftypefun size_t gal_list_f32_last (gal_list_f32_t @code{*list})
+Return a pointer to the last node in @code{list}.
+@end deftypefun
+
 @deftypefun void gal_list_f32_print (gal_list_f32_t @code{*list})
 Print the values within each node of @code{*list} on the standard output in
 the same order that they are stored. Each floating point number is printed
@@ -25980,6 +26424,10 @@ also change @code{list} to point to the next node in 
the list. If
 Return the number of nodes in @code{list}.
 @end deftypefun
 
+@deftypefun size_t gal_list_f64_last (gal_list_f64_t @code{*list})
+Return a pointer to the last node in @code{list}.
+@end deftypefun
+
 @deftypefun void gal_list_f64_print (gal_list_f64_t @code{*list})
 Print the values within each node of @code{*list} on the standard output in
 the same order that they are stored. Each floating point number is printed
@@ -26074,6 +26522,10 @@ also change @code{list} to point to the next node in 
the list. If
 Return the number of nodes in @code{list}.
 @end deftypefun
 
+@deftypefun size_t gal_list_void_last (gal_list_void_t @code{*list})
+Return a pointer to the last node in @code{list}.
+@end deftypefun
+
 @deftypefun void gal_list_void_reverse (gal_list_void_t @code{**list})
 Reverse the order of the list such that the top node in the list before
 calling this function becomes the bottom node after it.
@@ -26259,10 +26711,21 @@ Reverse the order of the list such that the top node 
in the list before
 calling this function becomes the bottom node after it.
 @end deftypefun
 
+@deftypefun {gal_data_t **} gal_list_data_to_array_ptr (gal_data_t 
@code{*list}, size_t @code{*num})
+Allocate and return an array of @code{gal_data_t *} pointers with the same
+number of elements as the nodes in @code{list}. The pointers will be put in
+the same order that the list is parsed. Hence the N-th element in the array
+will point to the same dataset that the N-th node in the list points to.
+@end deftypefun
+
 @deftypefun size_t gal_list_data_number (gal_data_t @code{*list})
 Return the number of nodes in @code{list}.
 @end deftypefun
 
+@deftypefun size_t gal_list_data_last (gal_data_t @code{*list})
+Return a pointer to the last node in @code{list}.
+@end deftypefun
+
 @deftypefun void gal_list_data_free (gal_data_t @code{*list})
 Free all the datasets in @code{list} along with all the allocated spaces in
 each.
@@ -27987,11 +28450,18 @@ Unary operand absolute-value operator.
 @deffnx Macro GAL_ARITHMETIC_OP_MEDIAN
 Multi-operand statistical operations. When @code{gal_arithmetic} is called
 with any of these operators, it will expect only a single operand that will
-be interpreted as a list of datasets (see @ref{List of gal_data_t}. The
-output will be a single dataset with each of its elements replaced by the
-respective statistical operation on the whole list. These operators can
-work on multiple threads using the @code{numthreads} argument. See the
-discussion under the @code{min} operator in @ref{Arithmetic operators}.
+be interpreted as a list of datasets (see @ref{List of gal_data_t}). These
+operators can work on multiple threads using the @code{numthreads}
+argument. See the discussion under the @code{min} operator in
+@ref{Arithmetic operators}.
+
+The output will be a single dataset with each of its elements replaced by
+the respective statistical operation on the whole list. The type of the
+output is determined from the operator (irrespective of the input type):
+for @code{GAL_ARITHMETIC_OP_MIN} and @code{GAL_ARITHMETIC_OP_MAX}, it will
+be the same type as the input, for @code{GAL_ARITHMETIC_OP_NUMBER}, the
+output will be @code{GAL_TYPE_UINT32} and for the rest, it will be
+@code{GAL_TYPE_FLOAT32}.
 @end deffn
 
 @deffn  Macro GAL_ARITHMETIC_OP_SIGCLIP_STD
@@ -28001,9 +28471,11 @@ discussion under the @code{min} operator in 
@ref{Arithmetic operators}.
 Similar to the operands above (including @code{GAL_ARITHMETIC_MIN}), except
 that when @code{gal_arithmetic} is called with these operators, it requires
 two arguments. The first is the list of datasets like before, and the
-second is the 2-element list of sigma-clipping parameters. The first
+second is the 2-element list of @mymath{\sigma}-clipping parameters. The first
 element in the parameters list is the multiple of sigma and the second is
-the termination criteria (see @ref{Sigma clipping}).
+the termination criteria (see @ref{Sigma clipping}). The output type of
+@code{GAL_ARITHMETIC_OP_SIGCLIP_NUMBER} will be @code{GAL_TYPE_UINT32} and
+for the rest it will be @code{GAL_TYPE_FLOAT32}.
 @end deffn
 
 @deffn Macro GAL_ARITHMETIC_OP_POW
@@ -28088,6 +28560,25 @@ necessary arguments to @code{gal_arithmetic}) are 
described above under
 each operator.
 @end deftypefun
 
+@deftypefun int gal_arithmetic_set_operator (char @code{*string}, size_t 
@code{*num_operands})
+Return the operator macro/code that corresponds to @code{string}. The
+number of operands that it needs are written into the space that
+@code{*num_operands} points to. If the string couldn't be interpretted as
+an operator, this function will return @code{GAL_ARITHMETIC_OP_INVALID}.
+
+This function will check @code{string} with the fixed human-readable names
+(using @code{strcmp}) for the operators and return the two numbers. Note
+that @code{string} must only contain the single operator name and nothing
+else (not even any extra white space).
+@end deftypefun
+
+@deftypefun {char *} gal_arithmetic_operator_string (int @code{operator})
+Return the human-readable standard string that corresponds to the given
+operator. For example when the input is @code{GAL_ARITHMETIC_OP_PLUS} or
+@code{GAL_ARITHMETIC_OP_MEAN}, the strings @code{+} or @code{mean} will be
+returned.
+@end deftypefun
+
 @node Tessellation library, Bounding box, Arithmetic on datasets, Gnuastro 
library
 @subsection Tessellation library (@file{tile.h})
 
@@ -28702,7 +29193,7 @@ Free all the allocated arrays within @code{tl}.
 @node Bounding box, Polygons, Tessellation library, Gnuastro library
 @subsection Bounding box (@file{box.h})
 
-Functions related to reporting a the bounding box of certain inputs are
+Functions related to reporting the bounding box of certain inputs are
 declared in @file{gnuastro/box.h}. All coordinates in this header are in
 the FITS format (first axis is the horizontal and the second axis is
 vertical).
@@ -29172,7 +29663,7 @@ container}.
 @deffn  Macro GAL_STATISTICS_SIG_CLIP_MAX_CONVERGE
 The maximum number of clips, when @mymath{\sigma}-clipping should be done
 by convergence. If the clipping does not converge before making this many
-clips, all sigma-clipping outputs will be NaN.
+clips, all @mymath{\sigma}-clipping outputs will be NaN.
 @end deffn
 
 @deffn  Macro GAL_STATISTICS_MODE_GOOD_SYM
@@ -29535,50 +30026,55 @@ moves the window as a separate line with several 
columns. The first column
 is the value, the second (in square brackets) is the sorted index, the
 third is the distance of this element from the previous one. The Fourth and
 fifth (in parenthesis) are the median and standard deviation of the
-sigma-clipped distribution within the window and the last column is the
-difference between the third and fourth, divided by the fifth.
+@mymath{\sigma}-clipped distribution within the window and the last column
+is the difference between the third and fourth, divided by the fifth.
 
 @end deftypefun
 
-@deftypefun {gal_data_t *} gal_statistics_outlier_flat_cfp (gal_data_t 
@code{*input}, size_t @code{dist}, float @code{thresh}, float @code{width}, int 
@code{inplace}, int @code{quiet}, size_t @code{*index})
+@deftypefun {gal_data_t *} gal_statistics_outlier_flat_cfp (gal_data_t 
@code{*input}, size_t @code{numprev}, float @code{sigclip_multip}, float 
@code{sigclip_param}, float @code{thresh}, size_t @code{numcontig}, int 
@code{inplace}, int @code{quiet}, size_t @code{*index})
 
 Return the first element in the given dataset where the cumulative
-frequency plot first becomes flat (below a given threshold on the slope)
-for a sufficient width (percentage of whole dataset's range). The returned
-dataset only has one element (with the same type as the input). If
-@code{index!=NULL}, the index (counting from zero, after sorting dataset
-and removing any blanks) is written in the space that @code{index} points
-to. If no sufficiently flat portion is found, the returned pointer will be
-@code{NULL}.
-
-The operation of this function can be best visualized using the cumulative
-frequency plot (CFP, see @ref{Histogram and Cumulative Frequency
-Plot}). Imagine setting the horizontal axis of the input's CFP to a range
-of 0 to 100, and finding the first part where its slope is
-constantly/contiguously flat for a certain fraction/width of the whole
-dataset's range. Below we'll describe this in more detail.
-
-This function will first remove all the blank elements and sort the
-remaining elements. If @code{inplace} is non-zero this step will be done in
-place: re-organizing/permuting the input dataset. Using @code{inplace} can
-result in faster processing and less RAM consumption, but only when the
-input dataset is no longer needed in its original permutation.
-
-The input dataset will then be internally scaled from 0 to 100 (so
-@code{thresh} and @code{width} can be in units of percent). For each
-element, this function will then estimate the slope of the cumulative
-distribution function by using the @code{dist} elements before and after
-it. In other words, if @mymath{d} is the value of @code{dist}, then the
-slope over the @mymath{i}'th element (@mymath{a_i}) is estimated using this
-formula: @mymath{1/(a_{i+d}-a_{i-d})}. Therefore, when this slope is larger
-than 1, the distance between the two checked points is smaller than
-@mymath{1\%} of the dataset's range.
-
-All points that have a slope less than @code{thresh} are then marked. The
-first (parsing from the smallest to the largest values) contiguous patch of
-marked elements that is larger than @code{width} wide (in units of
-percentage of the dataset's range) will be considered as the boundary
-region of outliers and the first element in that patch will be returned.
+frequency plot first becomes significantly flat for a sufficient number of
+elements. The returned dataset only has one element (with the same type as
+the input). If @code{index!=NULL}, the index (counting from zero, after
+sorting the dataset and removing any blanks) is written in the space that
+@code{index} points to. If no sufficiently flat portion is found, the
+returned pointer will be @code{NULL}.
+
+@cindex Sigma-clipping
+The flatness on the cumulative frequency plot is defined like this (see
+@ref{Histogram and Cumulative Frequency Plot}): on the sorted dataset, for
+every point (@mymath{a_i}), we calculate @mymath{d_i=a_{i+2}-a_{i-2}}. This
+done on the first @mymath{N} elements (value of @code{numprev}). After
+element @mymath{a_{N+2}}, we start estimating the flatness as follows: for
+every element we use the @mymath{N}, @mymath{d_i} measurements before it as
+the reference. Let's call this set @mymath{D_i} for element @mymath{i}. The
+@mymath{\sigma}-clipped median (@mymath{m}) and standard deviation
+(@mymath{s}) of @mymath{D_i} are then calculated. The
+@mymath{\sigma}-clipping can be configured with the two
+@code{sigclip_param} and @code{sigclip_multip} arguments.
+
+Taking @mymath{t} as the significance threshold (value to @code{thresh}), a
+point is considered flat when @mymath{a_i>m+t\sigma}. But a single point
+satisfying this condition will probably just be due to noise. To make a
+more robust estimate, this significance/condition has to hold for
+@code{numcontig} contiguous elements after @mymath{a_i}. When this is
+satisfied, @mymath{a_i} is retured as the point where the distribution's
+cumulative frequency plot becomes flat.
+
+To get a good estimate of @mymath{m} and @mymath{s}, it is thus recommended
+to set @code{numprev} as large as possible. However, be careful not to set
+it too high: the checks in the paragraph above are not done on the first
+@code{numprev} elements and this function assumes the flatness occures
+after them. Also, be sure that the value to @code{numcontig} is much less
+than @code{numprev}, otherwise @mymath{\sigma}-clipping may not be able to
+remove the immediate outliers in @mymath{D_i} near the boundary of the flat
+region.
+
+When @code{quiet==0}, the basic measurements done on each element are
+printed on the command-line (good for finding the best parameters). When
+@code{inplace!=0}, the sorting and removal of blank elements is done on the
+input dataset, so the input may be altered after this function.
 @end deftypefun
 
 
@@ -30317,7 +30813,7 @@ blank. To see if any blank (non-interpolated) elements 
remain, you can use
 @end deftypefun
 
 
-@node Git wrappers, Cosmology library, Interpolation, Gnuastro library
+@node Git wrappers, Spectral lines library, Interpolation, Gnuastro library
 @subsection Git wrappers (@file{git.h})
 
 @cindex Git
@@ -30353,8 +30849,164 @@ not installed or the program calling this function is 
not within a version
 controlled directory, then the output will be the @code{NULL} pointer.
 @end deftypefun
 
+@node Spectral lines library, Cosmology library, Git wrappers, Gnuastro library
+@subsection Spectral lines library (@file{speclines.h})
+
+Gnuastro's library has the following macros and functions for dealing with
+spectral lines. All these functions are declared in
+@file{gnuastro/spectra.h}.
+
+@cindex H-alpha
+@cindex H-beta
+@cindex H-gamma
+@cindex H-delta
+@cindex H-epsilon
+@cindex OII doublet
+@cindex SII doublet
+@cindex Lyman-alpha
+@cindex Lyman limit
+@cindex NII doublet
+@cindex Doublet: NII
+@cindex Doublet: OII
+@cindex Doublet: SII
+@cindex OIII doublet
+@cindex MgII doublet
+@cindex CIII doublet
+@cindex Balmer limit
+@cindex Doublet: OIII
+@cindex Doublet: MgII
+@cindex Doublet: CIII
+@deffn  Macro GAL_SPECLINES_INVALID
+@deffnx Macro GAL_SPECLINES_SIIRED
+@deffnx Macro GAL_SPECLINES_SII
+@deffnx Macro GAL_SPECLINES_SIIBLUE
+@deffnx Macro GAL_SPECLINES_NIIRED
+@deffnx Macro GAL_SPECLINES_NII
+@deffnx Macro GAL_SPECLINES_HALPHA
+@deffnx Macro GAL_SPECLINES_NIIBLUE
+@deffnx Macro GAL_SPECLINES_OIIIRED
+@deffnx Macro GAL_SPECLINES_OIII
+@deffnx Macro GAL_SPECLINES_OIIIBLUE
+@deffnx Macro GAL_SPECLINES_HBETA
+@deffnx Macro GAL_SPECLINES_HEIIRED
+@deffnx Macro GAL_SPECLINES_HGAMMA
+@deffnx Macro GAL_SPECLINES_HDELTA
+@deffnx Macro GAL_SPECLINES_HEPSILON
+@deffnx Macro GAL_SPECLINES_NEIII
+@deffnx Macro GAL_SPECLINES_OIIRED
+@deffnx Macro GAL_SPECLINES_OII
+@deffnx Macro GAL_SPECLINES_OIIBLUE
+@deffnx Macro GAL_SPECLINES_BLIMIT
+@deffnx Macro GAL_SPECLINES_MGIIRED
+@deffnx Macro GAL_SPECLINES_MGII
+@deffnx Macro GAL_SPECLINES_MGIIBLUE
+@deffnx Macro GAL_SPECLINES_CIIIRED
+@deffnx Macro GAL_SPECLINES_CIII
+@deffnx Macro GAL_SPECLINES_CIIIBLUE
+@deffnx Macro GAL_SPECLINES_HEIIBLUE
+@deffnx Macro GAL_SPECLINES_LYALPHA
+@deffnx Macro GAL_SPECLINES_LYLIMIT
+Internal values/identifiers for specific spectral lines as is clear from
+their names.
+@end deffn
+
+@deffn  Macro GAL_SPECLINES_ANGSTROM_SIIRED
+@deffnx Macro GAL_SPECLINES_ANGSTROM_SII
+@deffnx Macro GAL_SPECLINES_ANGSTROM_SIIBLUE
+@deffnx Macro GAL_SPECLINES_ANGSTROM_NIIRED
+@deffnx Macro GAL_SPECLINES_ANGSTROM_NII
+@deffnx Macro GAL_SPECLINES_ANGSTROM_HALPHA
+@deffnx Macro GAL_SPECLINES_ANGSTROM_NIIBLUE
+@deffnx Macro GAL_SPECLINES_ANGSTROM_OIIIRED
+@deffnx Macro GAL_SPECLINES_ANGSTROM_OIII
+@deffnx Macro GAL_SPECLINES_ANGSTROM_OIIIBLUE
+@deffnx Macro GAL_SPECLINES_ANGSTROM_HBETA
+@deffnx Macro GAL_SPECLINES_ANGSTROM_HEIIRED
+@deffnx Macro GAL_SPECLINES_ANGSTROM_HGAMMA
+@deffnx Macro GAL_SPECLINES_ANGSTROM_HDELTA
+@deffnx Macro GAL_SPECLINES_ANGSTROM_HEPSILON
+@deffnx Macro GAL_SPECLINES_ANGSTROM_NEIII
+@deffnx Macro GAL_SPECLINES_ANGSTROM_OIIRED
+@deffnx Macro GAL_SPECLINES_ANGSTROM_OII
+@deffnx Macro GAL_SPECLINES_ANGSTROM_OIIBLUE
+@deffnx Macro GAL_SPECLINES_ANGSTROM_BLIMIT
+@deffnx Macro GAL_SPECLINES_ANGSTROM_MGIIRED
+@deffnx Macro GAL_SPECLINES_ANGSTROM_MGII
+@deffnx Macro GAL_SPECLINES_ANGSTROM_MGIIBLUE
+@deffnx Macro GAL_SPECLINES_ANGSTROM_CIIIRED
+@deffnx Macro GAL_SPECLINES_ANGSTROM_CIII
+@deffnx Macro GAL_SPECLINES_ANGSTROM_CIIIBLUE
+@deffnx Macro GAL_SPECLINES_ANGSTROM_HEIIBLUE
+@deffnx Macro GAL_SPECLINES_ANGSTROM_LYALPHA
+@deffnx Macro GAL_SPECLINES_ANGSTROM_LYLIMIT
+Wavelengh (in Angstroms) of the named lines.
+@end deffn
+
+@deffn  Macro GAL_SPECLINES_NAME_SIIRED
+@deffnx Macro GAL_SPECLINES_NAME_SII
+@deffnx Macro GAL_SPECLINES_NAME_SIIBLUE
+@deffnx Macro GAL_SPECLINES_NAME_NIIRED
+@deffnx Macro GAL_SPECLINES_NAME_NII
+@deffnx Macro GAL_SPECLINES_NAME_HALPHA
+@deffnx Macro GAL_SPECLINES_NAME_NIIBLUE
+@deffnx Macro GAL_SPECLINES_NAME_OIIIRED
+@deffnx Macro GAL_SPECLINES_NAME_OIII
+@deffnx Macro GAL_SPECLINES_NAME_OIIIBLUE
+@deffnx Macro GAL_SPECLINES_NAME_HBETA
+@deffnx Macro GAL_SPECLINES_NAME_HEIIRED
+@deffnx Macro GAL_SPECLINES_NAME_HGAMMA
+@deffnx Macro GAL_SPECLINES_NAME_HDELTA
+@deffnx Macro GAL_SPECLINES_NAME_HEPSILON
+@deffnx Macro GAL_SPECLINES_NAME_NEIII
+@deffnx Macro GAL_SPECLINES_NAME_OIIRED
+@deffnx Macro GAL_SPECLINES_NAME_OII
+@deffnx Macro GAL_SPECLINES_NAME_OIIBLUE
+@deffnx Macro GAL_SPECLINES_NAME_BLIMIT
+@deffnx Macro GAL_SPECLINES_NAME_MGIIRED
+@deffnx Macro GAL_SPECLINES_NAME_MGII
+@deffnx Macro GAL_SPECLINES_NAME_MGIIBLUE
+@deffnx Macro GAL_SPECLINES_NAME_CIIIRED
+@deffnx Macro GAL_SPECLINES_NAME_CIII
+@deffnx Macro GAL_SPECLINES_NAME_CIIIBLUE
+@deffnx Macro GAL_SPECLINES_NAME_HEIIBLUE
+@deffnx Macro GAL_SPECLINES_NAME_LYALPHA
+@deffnx Macro GAL_SPECLINES_NAME_LYLIMIT
+Names (as literal stings without any space, all in small-caps) that can be
+used to refer to the lines in your program and converted to and from line
+identifiers using the functions below.
+@end deffn
+
+@deftypefun {char *} gal_speclines_line_name (int @code{linecode})
+Return the literal string of the given spectral line identifier Macro (for
+example @code{GAL_SPECLINES_HALPHA} or @code{GAL_SPECLINES_LYLIMIT}).
+@end deftypefun
+
+@deftypefun int gal_speclines_line_code (char @code{*name})
+Return the spectral line identifier of the given standard name (for example
+@code{GAL_SPECLINES_NAME_HALPHA} or @code{GAL_SPECLINES_NAME_LYLIMIT}).
+@end deftypefun
+
+@deftypefun double gal_speclines_line_angstrom (int @code{linecode})
+Return the wavelengh (in Angstroms) of the given line.
+@end deftypefun
+
+@deftypefun double gal_speclines_line_redshift (double @code{obsline}, double 
@code{restline})
+@cindex Rest-frame
+Return the redshift where the observed wavelength (@code{obsline}) was
+emitted from (if its restframe wavelength was @code{restline}).
+@end deftypefun
+
+@deftypefun double gal_speclines_line_redshift_code (double @code{obsline}, 
int @code{linecode})
+Return the redshift where the observed wavelength (@code{obsline}) was
+emitted from (assuming its a specific spectra line, identified with
+@code{linecode}).
+@end deftypefun
+
+
+
+
 
-@node Cosmology library,  , Git wrappers, Gnuastro library
+@node Cosmology library,  , Spectral lines library, Gnuastro library
 @subsection Cosmology library (@file{cosmology.h})
 
 This library does the main cosmological calculations that are commonly
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 6677a96..17d88e8 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -43,7 +43,7 @@ AM_CPPFLAGS = -I\$(top_srcdir)/bootstrapped/lib            \
 # features. This also avoids the need for the programs to link separately
 # with Gnulib, they only need to link with the Gnuastro library.
 lib_LTLIBRARIES = libgnuastro.la
-libgnuastro_la_LDFLAGS = -version-info $(GAL_LT_VERSION)
+libgnuastro_la_LDFLAGS = -version-info $(GAL_LT_VERSION) $(CONFIG_LDADD)
 libgnuastro_la_LIBADD = $(top_builddir)/bootstrapped/lib/libgnu.la
 
 
@@ -59,9 +59,9 @@ libgnuastro_la_SOURCES = arithmetic.c arithmetic-and.c 
arithmetic-bitand.c \
   arithmetic-or.c arithmetic-plus.c array.c binary.c blank.c box.c         \
   checkset.c convolve.c cosmology.c data.c eps.c fits.c git.c              \
   interpolate.c jpeg.c label.c list.c match.c options.c pdf.c              \
-  permutation.c pointer.c polygon.c qsort.c dimension.c statistics.c       \
-  table.c tableintern.c threads.c tiff.c tile.c tile-internal.c timing.c   \
-  txt.c type.c wcs.c
+  permutation.c pointer.c polygon.c qsort.c dimension.c speclines.c        \
+  statistics.c table.c tableintern.c threads.c tiff.c tile.c               \
+  tile-internal.c timing.c txt.c type.c wcs.c
 
 
 
@@ -79,9 +79,10 @@ pkginclude_HEADERS = gnuastro/config.h 
$(headersdir)/arithmetic.h          \
   $(headersdir)/jpeg.h $(headersdir)/label.h $(headersdir)/list.h          \
   $(headersdir)/match.h $(headersdir)/pdf.h $(headersdir)/permutation.h    \
   $(headersdir)/pointer.h $(headersdir)/polygon.h $(headersdir)/qsort.h    \
-  $(headersdir)/statistics.h $(headersdir)/table.h $(headersdir)/threads.h \
-  $(headersdir)/tiff.h $(headersdir)/tile.h $(headersdir)/txt.h            \
-  $(headersdir)/type.h $(headersdir)/wcs.h
+  $(headersdir)/speclines.h $(headersdir)/statistics.h                     \
+  $(headersdir)/table.h $(headersdir)/threads.h $(headersdir)/tiff.h       \
+  $(headersdir)/tile.h $(headersdir)/txt.h $(headersdir)/type.h            \
+  $(headersdir)/wcs.h
 
 
 
diff --git a/lib/arithmetic.c b/lib/arithmetic.c
index dfdfabb..0bd8cb8 100644
--- a/lib/arithmetic.c
+++ b/lib/arithmetic.c
@@ -25,6 +25,7 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 #include <errno.h>
 #include <error.h>
 #include <stdio.h>
+#include <string.h>
 #include <stdlib.h>
 #include <stdarg.h>
 
@@ -686,8 +687,8 @@ struct multioperandparams
 
 
 #define MULTIOPERAND_MIN(TYPE) {                                        \
-    TYPE t, max;                                                        \
     size_t n, j=0;                                                      \
+    TYPE t, max, *o=p->out->array;                                      \
     gal_type_max(p->list->type, &max);                                  \
                                                                         \
     /* Go over all the pixels assigned to this thread. */               \
@@ -716,8 +717,8 @@ struct multioperandparams
 
 
 #define MULTIOPERAND_MAX(TYPE) {                                        \
-    TYPE t, min;                                                        \
     size_t n, j=0;                                                      \
+    TYPE t, min, *o=p->out->array;                                      \
     gal_type_min(p->list->type, &min);                                  \
                                                                         \
     /* Go over all the pixels assigned to this thread. */               \
@@ -748,6 +749,7 @@ struct multioperandparams
 #define MULTIOPERAND_NUM {                                              \
     int use;                                                            \
     size_t n, j;                                                        \
+    uint32_t *o=p->out->array;                                          \
                                                                         \
     /* Go over all the pixels assigned to this thread. */               \
     for(tind=0; tprm->indexs[tind] != GAL_BLANK_SIZE_T; ++tind)         \
@@ -780,6 +782,7 @@ struct multioperandparams
     int use;                                                            \
     double sum;                                                         \
     size_t n, j;                                                        \
+    float *o=p->out->array;                                             \
                                                                         \
     /* Go over all the pixels assigned to this thread. */               \
     for(tind=0; tprm->indexs[tind] != GAL_BLANK_SIZE_T; ++tind)         \
@@ -813,6 +816,7 @@ struct multioperandparams
     int use;                                                            \
     double sum;                                                         \
     size_t n, j;                                                        \
+    float *o=p->out->array;                                             \
                                                                         \
     /* Go over all the pixels assigned to this thread. */               \
     for(tind=0; tprm->indexs[tind] != GAL_BLANK_SIZE_T; ++tind)         \
@@ -846,6 +850,7 @@ struct multioperandparams
     int use;                                                            \
     size_t n, j;                                                        \
     double sum, sum2;                                                   \
+    float *o=p->out->array;                                             \
                                                                         \
     /* Go over all the pixels assigned to this thread. */               \
     for(tind=0; tprm->indexs[tind] != GAL_BLANK_SIZE_T; ++tind)         \
@@ -883,6 +888,7 @@ struct multioperandparams
 #define MULTIOPERAND_MEDIAN(TYPE, QSORT_F) {                            \
     int use;                                                            \
     size_t n, j;                                                        \
+    float *o=p->out->array;                                             \
     TYPE *pixs=gal_pointer_allocate(p->list->type, p->dnum, 0,          \
                                     __func__, "pixs");                  \
                                                                         \
@@ -926,9 +932,10 @@ struct multioperandparams
 
 
 #define MULTIOPERAND_SIGCLIP(TYPE) {                                    \
-    float *sarr;                                                        \
     size_t n, j;                                                        \
     gal_data_t *sclip;                                                  \
+    uint32_t *N=p->out->array;                                          \
+    float *sarr, *o=p->out->array;                                      \
     TYPE *pixs=gal_pointer_allocate(p->list->type, p->dnum, 0,          \
                                     __func__, "pixs");                  \
     gal_data_t *cont=gal_data_alloc(pixs, p->list->type, 1, &p->dnum,   \
@@ -954,7 +961,7 @@ struct multioperandparams
               case GAL_ARITHMETIC_OP_SIGCLIP_STD:    o[j]=sarr[3]; break;\
               case GAL_ARITHMETIC_OP_SIGCLIP_MEAN:   o[j]=sarr[2]; break;\
               case GAL_ARITHMETIC_OP_SIGCLIP_MEDIAN: o[j]=sarr[1]; break;\
-              case GAL_ARITHMETIC_OP_SIGCLIP_NUMBER: o[j]=sarr[0]; break;\
+              case GAL_ARITHMETIC_OP_SIGCLIP_NUMBER: N[j]=sarr[0]; break;\
               default:                                                  \
                 error(EXIT_FAILURE, 0, "%s: a bug! the code %d is not " \
                       "valid for sigma-clipping results", __func__,     \
@@ -979,9 +986,9 @@ struct multioperandparams
 
 
 #define MULTIOPERAND_TYPE_SET(TYPE, QSORT_F) {                          \
+    TYPE b, **a;                                                        \
     gal_data_t *tmp;                                                    \
     size_t i=0, tind;                                                   \
-    TYPE b, **a, *o=p->out->array;                                      \
                                                                         \
     /* Allocate space to keep the pointers to the arrays of each. */    \
     /* Input data structure. The operators will increment these */      \
@@ -1110,9 +1117,9 @@ static gal_data_t *
 arithmetic_multioperand(int operator, int flags, gal_data_t *list,
                         gal_data_t *params, size_t numthreads)
 {
-  uint8_t *hasblank;
   size_t i=0, dnum=1;
   float p1=NAN, p2=NAN;
+  uint8_t *hasblank, otype;
   struct multioperandparams p;
   gal_data_t *out, *tmp, *ttmp;
 
@@ -1160,11 +1167,31 @@ arithmetic_multioperand(int operator, int flags, 
gal_data_t *list,
     }
 
 
+  /* Set the output dataset type */
+  switch(operator)
+    {
+    case GAL_ARITHMETIC_OP_MIN:            otype=list->type;       break;
+    case GAL_ARITHMETIC_OP_MAX:            otype=list->type;       break;
+    case GAL_ARITHMETIC_OP_NUMBER:         otype=GAL_TYPE_UINT32;  break;
+    case GAL_ARITHMETIC_OP_SUM:            otype=GAL_TYPE_FLOAT32; break;
+    case GAL_ARITHMETIC_OP_MEAN:           otype=GAL_TYPE_FLOAT32; break;
+    case GAL_ARITHMETIC_OP_STD:            otype=GAL_TYPE_FLOAT32; break;
+    case GAL_ARITHMETIC_OP_MEDIAN:         otype=GAL_TYPE_FLOAT32; break;
+    case GAL_ARITHMETIC_OP_SIGCLIP_STD:    otype=GAL_TYPE_FLOAT32; break;
+    case GAL_ARITHMETIC_OP_SIGCLIP_MEAN:   otype=GAL_TYPE_FLOAT32; break;
+    case GAL_ARITHMETIC_OP_SIGCLIP_MEDIAN: otype=GAL_TYPE_FLOAT32; break;
+    case GAL_ARITHMETIC_OP_SIGCLIP_NUMBER: otype=GAL_TYPE_UINT32;  break;
+    default:
+      error(EXIT_FAILURE, 0, "%s: operator code %d isn't recognized",
+            __func__, operator);
+    }
+
+
   /* Set the output data structure. */
-  if(flags & GAL_ARITHMETIC_INPLACE)
+  if( (flags & GAL_ARITHMETIC_INPLACE) && otype==list->type)
     out = list;                 /* The top element in the list. */
   else
-    out = gal_data_alloc(NULL, list->type, list->ndim, list->dsize,
+    out = gal_data_alloc(NULL, otype, list->ndim, list->dsize,
                          list->wcs, 0, list->minmapsize, NULL, NULL, NULL);
 
 
@@ -1530,6 +1557,144 @@ arithmetic_binary_function_flt(int operator, int flags, 
gal_data_t *l,
 /**********************************************************************/
 /****************         High-level functions        *****************/
 /**********************************************************************/
+/* Order is the same as in the manual. */
+int
+gal_arithmetic_set_operator(char *string, size_t *num_operands)
+{
+  int op;
+
+  /* Simple arithmetic operators. */
+  if      (!strcmp(string, "+" ))
+    { op=GAL_ARITHMETIC_OP_PLUS;              *num_operands=2;  }
+  else if (!strcmp(string, "-" ))
+    { op=GAL_ARITHMETIC_OP_MINUS;             *num_operands=2;  }
+  else if (!strcmp(string, "x" ))
+    { op=GAL_ARITHMETIC_OP_MULTIPLY;          *num_operands=2;  }
+  else if (!strcmp(string, "/" ))
+    { op=GAL_ARITHMETIC_OP_DIVIDE;            *num_operands=2;  }
+  else if (!strcmp(string, "%" ))
+    { op=GAL_ARITHMETIC_OP_MODULO;            *num_operands=2;  }
+
+  /* Mathematical Operators. */
+  else if (!strcmp(string, "abs"))
+    { op=GAL_ARITHMETIC_OP_ABS;               *num_operands=1;  }
+  else if (!strcmp(string, "pow"))
+    { op=GAL_ARITHMETIC_OP_POW;               *num_operands=2;  }
+  else if (!strcmp(string, "sqrt"))
+    { op=GAL_ARITHMETIC_OP_SQRT;              *num_operands=1;  }
+  else if (!strcmp(string, "log"))
+    { op=GAL_ARITHMETIC_OP_LOG;               *num_operands=1;  }
+  else if (!strcmp(string, "log10"))
+    { op=GAL_ARITHMETIC_OP_LOG10;             *num_operands=1;  }
+
+  /* Statistical/higher-level operators. */
+  else if (!strcmp(string, "minvalue"))
+    { op=GAL_ARITHMETIC_OP_MINVAL;            *num_operands=1;  }
+  else if (!strcmp(string, "maxvalue"))
+    { op=GAL_ARITHMETIC_OP_MAXVAL;            *num_operands=1;  }
+  else if (!strcmp(string, "numbervalue"))
+    { op=GAL_ARITHMETIC_OP_NUMBERVAL;         *num_operands=1;  }
+  else if (!strcmp(string, "sumvalue"))
+    { op=GAL_ARITHMETIC_OP_SUMVAL;            *num_operands=1;  }
+  else if (!strcmp(string, "meanvalue"))
+    { op=GAL_ARITHMETIC_OP_MEANVAL;           *num_operands=1;  }
+  else if (!strcmp(string, "stdvalue"))
+    { op=GAL_ARITHMETIC_OP_STDVAL;            *num_operands=1;  }
+  else if (!strcmp(string, "medianvalue"))
+    { op=GAL_ARITHMETIC_OP_MEDIANVAL;         *num_operands=1;  }
+  else if (!strcmp(string, "min"))
+    { op=GAL_ARITHMETIC_OP_MIN;               *num_operands=-1; }
+  else if (!strcmp(string, "max"))
+    { op=GAL_ARITHMETIC_OP_MAX;               *num_operands=-1; }
+  else if (!strcmp(string, "number"))
+    { op=GAL_ARITHMETIC_OP_NUMBER;            *num_operands=-1; }
+  else if (!strcmp(string, "sum"))
+    { op=GAL_ARITHMETIC_OP_SUM;               *num_operands=-1; }
+  else if (!strcmp(string, "mean"))
+    { op=GAL_ARITHMETIC_OP_MEAN;              *num_operands=-1; }
+  else if (!strcmp(string, "std"))
+    { op=GAL_ARITHMETIC_OP_STD;               *num_operands=-1; }
+  else if (!strcmp(string, "median"))
+    { op=GAL_ARITHMETIC_OP_MEDIAN;            *num_operands=-1; }
+  else if (!strcmp(string, "sigclip-number"))
+    { op=GAL_ARITHMETIC_OP_SIGCLIP_NUMBER;    *num_operands=-1; }
+  else if (!strcmp(string, "sigclip-mean"))
+    { op=GAL_ARITHMETIC_OP_SIGCLIP_MEAN;      *num_operands=-1; }
+  else if (!strcmp(string, "sigclip-median"))
+    { op=GAL_ARITHMETIC_OP_SIGCLIP_MEDIAN;    *num_operands=-1; }
+  else if (!strcmp(string, "sigclip-std"))
+    { op=GAL_ARITHMETIC_OP_SIGCLIP_STD;       *num_operands=-1; }
+
+  /* Conditional operators. */
+  else if (!strcmp(string, "lt" ))
+    { op=GAL_ARITHMETIC_OP_LT;                *num_operands=2;  }
+  else if (!strcmp(string, "le"))
+    { op=GAL_ARITHMETIC_OP_LE;                *num_operands=2;  }
+  else if (!strcmp(string, "gt" ))
+    { op=GAL_ARITHMETIC_OP_GT;                *num_operands=2;  }
+  else if (!strcmp(string, "ge"))
+    { op=GAL_ARITHMETIC_OP_GE;                *num_operands=2;  }
+  else if (!strcmp(string, "eq"))
+    { op=GAL_ARITHMETIC_OP_EQ;                *num_operands=2;  }
+  else if (!strcmp(string, "ne"))
+    { op=GAL_ARITHMETIC_OP_NE;                *num_operands=2;  }
+  else if (!strcmp(string, "and"))
+    { op=GAL_ARITHMETIC_OP_AND;               *num_operands=2;  }
+  else if (!strcmp(string, "or"))
+    { op=GAL_ARITHMETIC_OP_OR;                *num_operands=2;  }
+  else if (!strcmp(string, "not"))
+    { op=GAL_ARITHMETIC_OP_NOT;               *num_operands=1;  }
+  else if (!strcmp(string, "isblank"))
+    { op=GAL_ARITHMETIC_OP_ISBLANK;           *num_operands=1;  }
+  else if (!strcmp(string, "where"))
+    { op=GAL_ARITHMETIC_OP_WHERE;             *num_operands=3;  }
+
+  /* Bitwise operators. */
+  else if (!strcmp(string, "bitand"))
+    { op=GAL_ARITHMETIC_OP_BITAND;            *num_operands=2;  }
+  else if (!strcmp(string, "bitor"))
+    { op=GAL_ARITHMETIC_OP_BITOR;             *num_operands=2;  }
+  else if (!strcmp(string, "bitxor"))
+    { op=GAL_ARITHMETIC_OP_BITXOR;            *num_operands=2;  }
+  else if (!strcmp(string, "lshift"))
+    { op=GAL_ARITHMETIC_OP_BITLSH;            *num_operands=2;  }
+  else if (!strcmp(string, "rshift"))
+    { op=GAL_ARITHMETIC_OP_BITRSH;            *num_operands=2;  }
+  else if (!strcmp(string, "bitnot"))
+    { op=GAL_ARITHMETIC_OP_BITNOT;            *num_operands=1;  }
+
+  /* Type conversion. */
+  else if (!strcmp(string, "uint8"))
+    { op=GAL_ARITHMETIC_OP_TO_UINT8;          *num_operands=1;  }
+  else if (!strcmp(string, "int8"))
+    { op=GAL_ARITHMETIC_OP_TO_INT8;           *num_operands=1;  }
+  else if (!strcmp(string, "uint16"))
+    { op=GAL_ARITHMETIC_OP_TO_UINT16;         *num_operands=1;  }
+  else if (!strcmp(string, "int16"))
+    { op=GAL_ARITHMETIC_OP_TO_INT16;          *num_operands=1;  }
+  else if (!strcmp(string, "uint32"))
+    { op=GAL_ARITHMETIC_OP_TO_UINT32;         *num_operands=1;  }
+  else if (!strcmp(string, "int32"))
+    { op=GAL_ARITHMETIC_OP_TO_INT32;          *num_operands=1;  }
+  else if (!strcmp(string, "uint64"))
+    { op=GAL_ARITHMETIC_OP_TO_UINT64;         *num_operands=1;  }
+  else if (!strcmp(string, "int64"))
+    { op=GAL_ARITHMETIC_OP_TO_INT64;          *num_operands=1;  }
+  else if (!strcmp(string, "float32"))
+    { op=GAL_ARITHMETIC_OP_TO_FLOAT32;        *num_operands=1;  }
+  else if (!strcmp(string, "float64"))
+    { op=GAL_ARITHMETIC_OP_TO_FLOAT64;        *num_operands=1;  }
+
+  /* Operator not defined. */
+  else
+    { op=GAL_ARITHMETIC_OP_INVALID; *num_operands=GAL_BLANK_INT; }
+  return op;
+}
+
+
+
+
+
 char *
 gal_arithmetic_operator_string(int operator)
 {
@@ -1597,14 +1762,8 @@ gal_arithmetic_operator_string(int operator)
     case GAL_ARITHMETIC_OP_TO_FLOAT32:      return "float32";
     case GAL_ARITHMETIC_OP_TO_FLOAT64:      return "float64";
 
-    default:
-      error(EXIT_FAILURE, 0, "%s: operator code %d not recognized",
-            __func__, operator);
+    default:                                return NULL;
     }
-
-  error(EXIT_FAILURE, 0, "%s: a bug! Please contact us to fix the problem. "
-        "Control has reached the end of this function. This should not have "
-        "happened", __func__);
   return NULL;
 }
 
diff --git a/lib/cosmology.c b/lib/cosmology.c
index 3d3a65c..b8d243b 100644
--- a/lib/cosmology.c
+++ b/lib/cosmology.c
@@ -152,7 +152,7 @@ cosmology_integrand_comoving_volume(double z, void *params)
 
 
 /**************************************************************/
-/************          Final functions            *************/
+/************      Basic cosmology functions      *************/
 /**************************************************************/
 /* Age of the universe (in Gyrs). H0 is in units of (km/sec/Mpc) and the
    fractional densities must add up to 1. */
diff --git a/lib/eps.c b/lib/eps.c
index 997fc09..8c95e88 100644
--- a/lib/eps.c
+++ b/lib/eps.c
@@ -46,14 +46,18 @@ int
 gal_eps_name_is_eps(char *name)
 {
   size_t len;
-  len=strlen(name);
-  if ( ( len>=3 && strcmp(&name[len-3], "eps") == 0 )
-       || ( len>=3 && strcmp(&name[len-3], "EPS") == 0 )
-       || ( len>=4 && strcmp(&name[len-4], "epsf") == 0 )
-       || ( len>=4 && strcmp(&name[len-4], "epsi") == 0 ) )
-    return 1;
-  else
-    return 0;
+  if(name)
+    {
+      len=strlen(name);
+      if ( ( len>=3 && strcmp(&name[len-3], "eps") == 0 )
+           || ( len>=3 && strcmp(&name[len-3], "EPS") == 0 )
+           || ( len>=4 && strcmp(&name[len-4], "epsf") == 0 )
+           || ( len>=4 && strcmp(&name[len-4], "epsi") == 0 ) )
+        return 1;
+      else
+        return 0;
+    }
+  else return 0;
 }
 
 
@@ -63,13 +67,17 @@ gal_eps_name_is_eps(char *name)
 int
 gal_eps_suffix_is_eps(char *name)
 {
-  if (strcmp(name, "eps") == 0 || strcmp(name, ".eps") == 0
-      || strcmp(name, "EPS") == 0 || strcmp(name, ".EPS") == 0
-      || strcmp(name, "epsf") == 0 || strcmp(name, ".epsf") == 0
-      || strcmp(name, "epsi") == 0 || strcmp(name, ".epsi") == 0)
-    return 1;
-  else
-    return 0;
+  if(name)
+    {
+      if (strcmp(name, "eps") == 0 || strcmp(name, ".eps") == 0
+          || strcmp(name, "EPS") == 0 || strcmp(name, ".EPS") == 0
+          || strcmp(name, "epsf") == 0 || strcmp(name, ".epsf") == 0
+          || strcmp(name, "epsi") == 0 || strcmp(name, ".epsi") == 0)
+        return 1;
+      else
+        return 0;
+    }
+  else return 0;
 }
 
 
diff --git a/lib/fits.c b/lib/fits.c
index dd2d3bf..fbbea32 100644
--- a/lib/fits.c
+++ b/lib/fits.c
@@ -101,16 +101,21 @@ int
 gal_fits_name_is_fits(char *name)
 {
   size_t len;
-  len=strlen(name);
-  if ( (    len>=3 && strcmp(&name[len-3], "fit"     ) == 0 )
-       || ( len>=4 && strcmp(&name[len-4], "fits"    ) == 0 )
-       || ( len>=7 && strcmp(&name[len-7], "fits.gz" ) == 0 )
-       || ( len>=6 && strcmp(&name[len-6], "fits.Z"  ) == 0 )
-       || ( len>=3 && strcmp(&name[len-3], "imh"     ) == 0 )
-       || ( len>=7 && strcmp(&name[len-7], "fits.fz" ) == 0 ) )
-    return 1;
-  else
-    return 0;
+
+  if(name)
+    {
+      len=strlen(name);
+      if ( (    len>=3 && strcmp(&name[len-3], "fit"     ) == 0 )
+           || ( len>=4 && strcmp(&name[len-4], "fits"    ) == 0 )
+           || ( len>=7 && strcmp(&name[len-7], "fits.gz" ) == 0 )
+           || ( len>=6 && strcmp(&name[len-6], "fits.Z"  ) == 0 )
+           || ( len>=3 && strcmp(&name[len-3], "imh"     ) == 0 )
+           || ( len>=7 && strcmp(&name[len-7], "fits.fz" ) == 0 ) )
+        return 1;
+      else
+        return 0;
+    }
+  else return 0;
 }
 
 
@@ -124,16 +129,22 @@ gal_fits_name_is_fits(char *name)
 int
 gal_fits_suffix_is_fits(char *suffix)
 {
-  char *nodot = suffix[0]=='.' ? (suffix+1) : suffix;
-  if ( strcmp(   nodot, "fit"     ) == 0
-       || strcmp(nodot, "fits"    ) == 0
-       || strcmp(nodot, "fits.gz" ) == 0
-       || strcmp(nodot, "fits.Z"  ) == 0
-       || strcmp(nodot, "imh"     ) == 0
-       || strcmp(nodot, "fits.fz" ) == 0 )
-    return 1;
-  else
-    return 0;
+  char *nodot;
+
+  if(suffix)
+    {
+      nodot=suffix[0]=='.' ? (suffix+1) : suffix;
+      if ( strcmp(   nodot, "fit"     ) == 0
+           || strcmp(nodot, "fits"    ) == 0
+           || strcmp(nodot, "fits.gz" ) == 0
+           || strcmp(nodot, "fits.Z"  ) == 0
+           || strcmp(nodot, "imh"     ) == 0
+           || strcmp(nodot, "fits.fz" ) == 0 )
+        return 1;
+      else
+        return 0;
+    }
+  else return 0;
 }
 
 
diff --git a/lib/gnuastro/arithmetic.h b/lib/gnuastro/arithmetic.h
index a1922c8..ce529ff 100644
--- a/lib/gnuastro/arithmetic.h
+++ b/lib/gnuastro/arithmetic.h
@@ -140,7 +140,11 @@ enum gal_arithmetic_operators
   GAL_ARITHMETIC_OP_LAST_CODE,    /* Last code of the library operands.    */
 };
 
+char *
+gal_arithmetic_operator_string(int operator);
 
+int
+gal_arithmetic_set_operator(char *string, size_t *num_operands);
 
 gal_data_t *
 gal_arithmetic(int operator, size_t numthreads, int flags, ...);
diff --git a/lib/gnuastro/blank.h b/lib/gnuastro/blank.h
index 2e2490d..0bb67da 100644
--- a/lib/gnuastro/blank.h
+++ b/lib/gnuastro/blank.h
@@ -89,6 +89,14 @@ __BEGIN_C_DECLS  /* From C++ preparations */
 #define GAL_BLANK_ULONG GAL_BLANK_UINT64
 #endif
 
+#if GAL_CONFIG_SIZEOF_INT == 4
+#define GAL_BLANK_INT  GAL_BLANK_INT32
+#define GAL_BLANK_UINT GAL_BLANK_UINT32
+#elif GAL_CONFIG_SIZEOF_INT == 2
+#define GAL_BLANK_INT  GAL_BLANK_INT16
+#define GAL_BLANK_UINT GAL_BLANK_UINT16
+#endif
+
 
 /* Functions. */
 void
diff --git a/lib/gnuastro/cosmology.h b/lib/gnuastro/cosmology.h
index b7568ad..b64ed0c 100644
--- a/lib/gnuastro/cosmology.h
+++ b/lib/gnuastro/cosmology.h
@@ -88,9 +88,6 @@ double
 gal_cosmology_to_absolute_mag(double z, double H0, double o_lambda_0,
                               double o_matter_0, double o_radiation_0);
 
-
-
-
 __END_C_DECLS    /* From C++ preparations */
 
 #endif           /* __GAL_COSMOLOGY_H__ */
diff --git a/lib/gnuastro/list.h b/lib/gnuastro/list.h
index e0f790e..9a164c9 100644
--- a/lib/gnuastro/list.h
+++ b/lib/gnuastro/list.h
@@ -68,6 +68,9 @@ gal_list_str_pop(gal_list_str_t **list);
 size_t
 gal_list_str_number(gal_list_str_t *list);
 
+gal_list_str_t *
+gal_list_str_last(gal_list_str_t *list);
+
 void
 gal_list_str_print(gal_list_str_t *list);
 
@@ -99,6 +102,9 @@ gal_list_i32_pop(gal_list_i32_t **list);
 size_t
 gal_list_i32_number(gal_list_i32_t *list);
 
+gal_list_i32_t *
+gal_list_i32_last(gal_list_i32_t *list);
+
 void
 gal_list_i32_print(gal_list_i32_t *list);
 
@@ -133,6 +139,9 @@ gal_list_sizet_pop(gal_list_sizet_t **list);
 size_t
 gal_list_sizet_number(gal_list_sizet_t *list);
 
+gal_list_sizet_t *
+gal_list_sizet_last(gal_list_sizet_t *list);
+
 void
 gal_list_sizet_print(gal_list_sizet_t *list);
 
@@ -167,6 +176,9 @@ gal_list_f32_pop(gal_list_f32_t **list);
 size_t
 gal_list_f32_number(gal_list_f32_t *list);
 
+gal_list_f32_t *
+gal_list_f32_last(gal_list_f32_t *list);
+
 void
 gal_list_f32_reverse(gal_list_f32_t **list);
 
@@ -201,6 +213,9 @@ gal_list_f64_pop(gal_list_f64_t **list);
 size_t
 gal_list_f64_number(gal_list_f64_t *list);
 
+gal_list_f64_t *
+gal_list_f64_last(gal_list_f64_t *list);
+
 void
 gal_list_f64_print(gal_list_f64_t *list);
 
@@ -235,6 +250,9 @@ gal_list_void_pop(gal_list_void_t **list);
 size_t
 gal_list_void_number(gal_list_void_t *list);
 
+gal_list_void_t *
+gal_list_void_last(gal_list_void_t *list);
+
 void
 gal_list_void_reverse(gal_list_void_t **list);
 
@@ -322,9 +340,15 @@ gal_list_data_pop(gal_data_t **list);
 void
 gal_list_data_reverse(gal_data_t **list);
 
+gal_data_t **
+gal_list_data_to_array_ptr(gal_data_t *list, size_t *num);
+
 size_t
 gal_list_data_number(gal_data_t *list);
 
+gal_data_t *
+gal_list_data_last(gal_data_t *list);
+
 void
 gal_list_data_free(gal_data_t *list);
 
diff --git a/lib/gnuastro/speclines.h b/lib/gnuastro/speclines.h
new file mode 100644
index 0000000..add541d
--- /dev/null
+++ b/lib/gnuastro/speclines.h
@@ -0,0 +1,180 @@
+/*********************************************************************
+Spectral lines.
+This is part of GNU Astronomy Utilities (Gnuastro) package.
+
+Original author:
+     Mohammad Akhlaghi <mohammad@akhlaghi.org>
+Contributing author(s):
+Copyright (C) 2019, 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/>.
+**********************************************************************/
+#ifndef __GAL_SPECLINES_H__
+#define __GAL_SPECLINES_H__
+
+/* Include other headers if necessary here. Note that other header files
+   must be included before the C++ preparations below */
+
+
+
+/* C++ Preparations */
+#undef __BEGIN_C_DECLS
+#undef __END_C_DECLS
+#ifdef __cplusplus
+# define __BEGIN_C_DECLS extern "C" {
+# define __END_C_DECLS }
+#else
+# define __BEGIN_C_DECLS                /* empty */
+# define __END_C_DECLS                  /* empty */
+#endif
+/* End of C++ preparations */
+
+
+
+/* Actual header contants (the above were for the Pre-processor). */
+__BEGIN_C_DECLS  /* From C++ preparations */
+
+
+/* Spectral line internal codes. */
+enum gal_speclines_line_codes
+{
+  GAL_SPECLINES_INVALID=0,
+  GAL_SPECLINES_SIIRED,
+  GAL_SPECLINES_SII,
+  GAL_SPECLINES_SIIBLUE,
+  GAL_SPECLINES_NIIRED,
+  GAL_SPECLINES_NII,
+  GAL_SPECLINES_HALPHA,
+  GAL_SPECLINES_NIIBLUE,
+  GAL_SPECLINES_OIIIRED,
+  GAL_SPECLINES_OIII,
+  GAL_SPECLINES_OIIIBLUE,
+  GAL_SPECLINES_HBETA,
+  GAL_SPECLINES_HEIIRED,
+  GAL_SPECLINES_HGAMMA,
+  GAL_SPECLINES_HDELTA,
+  GAL_SPECLINES_HEPSILON,
+  GAL_SPECLINES_NEIII,
+  GAL_SPECLINES_OIIRED,
+  GAL_SPECLINES_OII,
+  GAL_SPECLINES_OIIBLUE,
+  GAL_SPECLINES_BLIMIT,
+  GAL_SPECLINES_MGIIRED,
+  GAL_SPECLINES_MGII,
+  GAL_SPECLINES_MGIIBLUE,
+  GAL_SPECLINES_CIIIRED,
+  GAL_SPECLINES_CIII,
+  GAL_SPECLINES_CIIIBLUE,
+  GAL_SPECLINES_HEIIBLUE,
+  GAL_SPECLINES_LYALPHA,
+  GAL_SPECLINES_LYLIMIT,
+};
+
+
+/* Spectral lines wavelengths in Angstroms. */
+#define GAL_SPECLINES_ANGSTROM_SIIRED    6731
+#define GAL_SPECLINES_ANGSTROM_SII       6724
+#define GAL_SPECLINES_ANGSTROM_SIIBLUE   6717
+#define GAL_SPECLINES_ANGSTROM_NIIRED    6584
+#define GAL_SPECLINES_ANGSTROM_NII       6566
+#define GAL_SPECLINES_ANGSTROM_HALPHA    6562.8
+#define GAL_SPECLINES_ANGSTROM_NIIBLUE   6548
+#define GAL_SPECLINES_ANGSTROM_OIIIRED   5007
+#define GAL_SPECLINES_ANGSTROM_OIII      4983
+#define GAL_SPECLINES_ANGSTROM_OIIIBLUE  4959
+#define GAL_SPECLINES_ANGSTROM_HBETA     4861.36
+#define GAL_SPECLINES_ANGSTROM_HEIIRED   4686
+#define GAL_SPECLINES_ANGSTROM_HGAMMA    4340.46
+#define GAL_SPECLINES_ANGSTROM_HDELTA    4101.74
+#define GAL_SPECLINES_ANGSTROM_HEPSILON  3970.07
+#define GAL_SPECLINES_ANGSTROM_NEIII     3869
+#define GAL_SPECLINES_ANGSTROM_OIIRED    3729
+#define GAL_SPECLINES_ANGSTROM_OII       3727.5
+#define GAL_SPECLINES_ANGSTROM_OIIBLUE   3726
+#define GAL_SPECLINES_ANGSTROM_BLIMIT    3646
+#define GAL_SPECLINES_ANGSTROM_MGIIRED   2803
+#define GAL_SPECLINES_ANGSTROM_MGII      2799.5
+#define GAL_SPECLINES_ANGSTROM_MGIIBLUE  2796
+#define GAL_SPECLINES_ANGSTROM_CIIIRED   1909
+#define GAL_SPECLINES_ANGSTROM_CIII      1908
+#define GAL_SPECLINES_ANGSTROM_CIIIBLUE  1907
+#define GAL_SPECLINES_ANGSTROM_HEIIBLUE  1640
+#define GAL_SPECLINES_ANGSTROM_LYALPHA   1215.67
+#define GAL_SPECLINES_ANGSTROM_LYLIMIT   912
+
+
+/* Spectral line name strings. */
+#define GAL_SPECLINES_NAME_SIIRED    "siired"
+#define GAL_SPECLINES_NAME_SII       "sii"
+#define GAL_SPECLINES_NAME_SIIBLUE   "siiblue"
+#define GAL_SPECLINES_NAME_NIIRED    "niired"
+#define GAL_SPECLINES_NAME_NII       "nii"
+#define GAL_SPECLINES_NAME_HALPHA    "halpha"
+#define GAL_SPECLINES_NAME_NIIBLUE   "niiblue"
+#define GAL_SPECLINES_NAME_OIIIRED   "oiiired"
+#define GAL_SPECLINES_NAME_OIII      "oiii"
+#define GAL_SPECLINES_NAME_OIIIBLUE  "oiiiblue"
+#define GAL_SPECLINES_NAME_HBETA     "hbeta"
+#define GAL_SPECLINES_NAME_HEIIRED   "heiired"
+#define GAL_SPECLINES_NAME_HGAMMA    "hgamma"
+#define GAL_SPECLINES_NAME_HDELTA    "hdelta"
+#define GAL_SPECLINES_NAME_HEPSILON  "hepsilon"
+#define GAL_SPECLINES_NAME_NEIII     "neiii"
+#define GAL_SPECLINES_NAME_OIIRED    "oiired"
+#define GAL_SPECLINES_NAME_OII       "oii"
+#define GAL_SPECLINES_NAME_OIIBLUE   "oiiblue"
+#define GAL_SPECLINES_NAME_BLIMIT    "blimit"
+#define GAL_SPECLINES_NAME_MGIIRED   "mgiired"
+#define GAL_SPECLINES_NAME_MGII      "mgii"
+#define GAL_SPECLINES_NAME_MGIIBLUE  "mgiiblue"
+#define GAL_SPECLINES_NAME_CIIIRED   "ciiired"
+#define GAL_SPECLINES_NAME_CIII      "ciii"
+#define GAL_SPECLINES_NAME_CIIIBLUE  "ciiiblue"
+#define GAL_SPECLINES_NAME_HEIIBLUE  "heiiblue"
+#define GAL_SPECLINES_NAME_LYALPHA   "lyalpha"
+#define GAL_SPECLINES_NAME_LYLIMIT   "lylimit"
+
+
+
+
+
+/*********************************************************************/
+/*************        Internal names and codes         ***************/
+/*********************************************************************/
+char *
+gal_speclines_line_name(int linecode);
+
+int
+gal_speclines_line_code(char *name);
+
+double
+gal_speclines_line_angstrom(int linecode);
+
+
+
+
+
+/*********************************************************************/
+/*************             Redshifted lines            ***************/
+/*********************************************************************/
+double
+gal_speclines_line_redshift(double obsline, double restline);
+
+double
+gal_speclines_line_redshift_code(double obsline, int linecode);
+
+
+__END_C_DECLS    /* From C++ preparations */
+
+#endif           /* __GAL_COSMOLOGY_H__ */
diff --git a/lib/gnuastro/statistics.h b/lib/gnuastro/statistics.h
index 7eeff6a..9dcf35a 100644
--- a/lib/gnuastro/statistics.h
+++ b/lib/gnuastro/statistics.h
@@ -179,9 +179,10 @@ gal_statistics_outlier_positive(gal_data_t *input, size_t 
window_size,
                                 float sigclip_param, int inplace, int quiet);
 
 gal_data_t *
-gal_statistics_outlier_flat_cfp(gal_data_t *input, size_t dist, float thresh,
-                                float width, int inplace, int quiet,
-                                size_t *index);
+gal_statistics_outlier_flat_cfp(gal_data_t *input, size_t numprev,
+                                float sigclip_multip, float sigclip_param,
+                                float thresh, size_t numcontig, int inplace,
+                                int quiet, size_t *index);
 
 
 
diff --git a/lib/jpeg.c b/lib/jpeg.c
index 34dc71b..2e86e60 100644
--- a/lib/jpeg.c
+++ b/lib/jpeg.c
@@ -48,18 +48,23 @@ int
 gal_jpeg_name_is_jpeg(char *name)
 {
   size_t len;
-  len=strlen(name);
-  if ( ( len>=3 && strcmp(&name[len-3], "jpg") == 0 )
-       || ( len>=3 && strcmp(&name[len-3], "JPG") == 0 )
-       || ( len>=4 && strcmp(&name[len-4], "jpeg") == 0 )
-       || ( len>=4 && strcmp(&name[len-4], "JPEG") == 0 )
-       || ( len>=3 && strcmp(&name[len-3], "jpe") == 0 )
-       || ( len>=3 && strcmp(&name[len-3], "jif") == 0 )
-       || ( len>=4 && strcmp(&name[len-4], "jfif") == 0 )
-       || ( len>=3 && strcmp(&name[len-3], "jfi") == 0 ) )
-    return 1;
-  else
-    return 0;
+
+  if(name)
+    {
+      len=strlen(name);
+      if ( ( len>=3 && strcmp(&name[len-3], "jpg") == 0 )
+           || ( len>=3 && strcmp(&name[len-3], "JPG") == 0 )
+           || ( len>=4 && strcmp(&name[len-4], "jpeg") == 0 )
+           || ( len>=4 && strcmp(&name[len-4], "JPEG") == 0 )
+           || ( len>=3 && strcmp(&name[len-3], "jpe") == 0 )
+           || ( len>=3 && strcmp(&name[len-3], "jif") == 0 )
+           || ( len>=4 && strcmp(&name[len-4], "jfif") == 0 )
+           || ( len>=3 && strcmp(&name[len-3], "jfi") == 0 ) )
+        return 1;
+      else
+        return 0;
+    }
+  else return 0;
 }
 
 
@@ -69,17 +74,21 @@ gal_jpeg_name_is_jpeg(char *name)
 int
 gal_jpeg_suffix_is_jpeg(char *name)
 {
-  if (strcmp(name, "jpg") == 0   || strcmp(name, ".jpg") == 0
-      || strcmp(name, "JPG") == 0 || strcmp(name, ".JPG") == 0
-      || strcmp(name, "jpeg") == 0 || strcmp(name, ".jpeg") == 0
-      || strcmp(name, "JPEG") == 0 || strcmp(name, ".JPEG") == 0
-      || strcmp(name, "jpe") == 0 || strcmp(name, ".jpe") == 0
-      || strcmp(name, "jif") == 0 || strcmp(name, ".jif") == 0
-      || strcmp(name, "jfif") == 0 || strcmp(name, ".jfif") == 0
-      || strcmp(name, "jfi") == 0 || strcmp(name, ".jfi") == 0)
-    return 1;
-  else
-    return 0;
+  if(name)
+    {
+      if (strcmp(name, "jpg") == 0   || strcmp(name, ".jpg") == 0
+          || strcmp(name, "JPG") == 0 || strcmp(name, ".JPG") == 0
+          || strcmp(name, "jpeg") == 0 || strcmp(name, ".jpeg") == 0
+          || strcmp(name, "JPEG") == 0 || strcmp(name, ".JPEG") == 0
+          || strcmp(name, "jpe") == 0 || strcmp(name, ".jpe") == 0
+          || strcmp(name, "jif") == 0 || strcmp(name, ".jif") == 0
+          || strcmp(name, "jfif") == 0 || strcmp(name, ".jfif") == 0
+          || strcmp(name, "jfi") == 0 || strcmp(name, ".jfi") == 0)
+        return 1;
+      else
+        return 0;
+    }
+  else return 0;
 }
 
 
diff --git a/lib/list.c b/lib/list.c
index 1c84a7c..c28b845 100644
--- a/lib/list.c
+++ b/lib/list.c
@@ -102,6 +102,21 @@ gal_list_str_number(gal_list_str_t *list)
 
 
 
+gal_list_str_t *
+gal_list_str_last(gal_list_str_t *list)
+{
+  if(list)
+    {
+      while(list->next!=NULL) list=list->next;
+      return list;
+    }
+  else return NULL;
+}
+
+
+
+
+
 void
 gal_list_str_print(gal_list_str_t *list)
 {
@@ -225,6 +240,21 @@ gal_list_i32_number(gal_list_i32_t *list)
 
 
 
+gal_list_i32_t *
+gal_list_i32_last(gal_list_i32_t *list)
+{
+  if(list)
+    {
+      while(list->next!=NULL) list=list->next;
+      return list;
+    }
+  else return NULL;
+}
+
+
+
+
+
 void
 gal_list_i32_print(gal_list_i32_t *list)
 {
@@ -374,6 +404,22 @@ gal_list_sizet_number(gal_list_sizet_t *list)
 
 
 
+
+gal_list_sizet_t *
+gal_list_sizet_last(gal_list_sizet_t *list)
+{
+  if(list)
+    {
+      while(list->next!=NULL) list=list->next;
+      return list;
+    }
+  else return NULL;
+}
+
+
+
+
+
 void
 gal_list_sizet_print(gal_list_sizet_t *list)
 {
@@ -524,6 +570,21 @@ gal_list_f32_number(gal_list_f32_t *list)
 
 
 
+gal_list_f32_t *
+gal_list_f32_last(gal_list_f32_t *list)
+{
+  if(list)
+    {
+      while(list->next!=NULL) list=list->next;
+      return list;
+    }
+  else return NULL;
+}
+
+
+
+
+
 void
 gal_list_f32_reverse(gal_list_f32_t **list)
 {
@@ -681,6 +742,21 @@ gal_list_f64_number(gal_list_f64_t *list)
 
 
 
+gal_list_f64_t *
+gal_list_f64_last(gal_list_f64_t *list)
+{
+  if(list)
+    {
+      while(list->next!=NULL) list=list->next;
+      return list;
+    }
+  else return NULL;
+}
+
+
+
+
+
 void
 gal_list_f64_print(gal_list_f64_t *list)
 {
@@ -836,6 +912,22 @@ gal_list_void_number(gal_list_void_t *list)
 
 
 
+
+gal_list_void_t *
+gal_list_void_last(gal_list_void_t *list)
+{
+  if(list)
+    {
+      while(list->next!=NULL) list=list->next;
+      return list;
+    }
+  else return NULL;
+}
+
+
+
+
+
 void
 gal_list_void_reverse(gal_list_void_t **list)
 {
@@ -1273,6 +1365,32 @@ gal_list_data_reverse(gal_data_t **list)
 
 
 
+gal_data_t **
+gal_list_data_to_array_ptr(gal_data_t *list, size_t *num)
+{
+  size_t i, n;
+  gal_data_t *tmp, **out;
+
+  /* Count how many columns are necessary. */
+  n=*num=gal_list_data_number(list);
+
+  /* Allocate space for the array. */
+  errno=0;
+  out=malloc(n * sizeof *out);
+  if(out==NULL)
+    error(EXIT_FAILURE, 0, "%s: couldn't allocate %zu bytes", __func__,
+          n * sizeof *out);
+
+  /* Fill up the array with the pointers and return. */
+  i=0;
+  for(tmp=list;tmp!=NULL;tmp=tmp->next) out[i++]=tmp;
+  return out;
+}
+
+
+
+
+
 size_t
 gal_list_data_number(gal_data_t *list)
 {
@@ -1288,6 +1406,21 @@ gal_list_data_number(gal_data_t *list)
 
 
 
+
+gal_data_t *
+gal_list_data_last(gal_data_t *list)
+{
+  if(list)
+    {
+      while(list->next!=NULL) list=list->next;
+      return list;
+    }
+  else return NULL;
+}
+
+
+
+
 void
 gal_list_data_free(gal_data_t *list)
 {
diff --git a/lib/options.c b/lib/options.c
index fd6623a..529a88c 100644
--- a/lib/options.c
+++ b/lib/options.c
@@ -516,7 +516,7 @@ void *
 gal_options_read_interpmetric(struct argp_option *option, char *arg,
                               char *filename, size_t lineno, void *junk)
 {
-  char *str;
+  char *str=NULL;
   if(lineno==-1)
     {
       switch(*(uint8_t *)(option->value))
@@ -575,12 +575,14 @@ gal_options_parse_list_of_numbers(char *string, char 
*filename, size_t lineno)
   gal_list_f64_t *list=NULL, *tdll;
   double numerator=NAN, denominator=NAN, tmp;
 
-
   /* The nature of the arrays/numbers read here is very small, so since
      `p->cp.minmapsize' might not have been read yet, we will set it to -1
      (largest size_t number), so the values are kept in memory. */
   size_t minmapsize=-1;
 
+  /* If we have an empty string, just return NULL. */
+  if(*string=='\0') return NULL;
+
   /* Go through the input character by character. */
   while(string && *c!='\0')
     {
diff --git a/lib/pdf.c b/lib/pdf.c
index 29628c8..c3b71ee 100644
--- a/lib/pdf.c
+++ b/lib/pdf.c
@@ -44,12 +44,17 @@ int
 gal_pdf_name_is_pdf(char *name)
 {
   size_t len;
-  len=strlen(name);
-  if (strcmp(&name[len-3], "pdf") == 0
-      || strcmp(&name[len-3], "PDF") == 0)
-    return 1;
-  else
-    return 0;
+
+  if(name)
+    {
+      len=strlen(name);
+      if (strcmp(&name[len-3], "pdf") == 0
+          || strcmp(&name[len-3], "PDF") == 0)
+        return 1;
+      else
+        return 0;
+    }
+  else return 0;
 }
 
 
@@ -59,11 +64,15 @@ gal_pdf_name_is_pdf(char *name)
 int
 gal_pdf_suffix_is_pdf(char *name)
 {
-  if (strcmp(name, "pdf") == 0 || strcmp(name, ".pdf") == 0
-      || strcmp(name, "PDF") == 0 || strcmp(name, ".PDF") == 0)
-    return 1;
-  else
-    return 0;
+  if(name)
+    {
+      if (strcmp(name, "pdf") == 0 || strcmp(name, ".pdf") == 0
+          || strcmp(name, "PDF") == 0 || strcmp(name, ".PDF") == 0)
+        return 1;
+      else
+        return 0;
+    }
+  else return 0;
 }
 
 
diff --git a/lib/speclines.c b/lib/speclines.c
new file mode 100644
index 0000000..c98c212
--- /dev/null
+++ b/lib/speclines.c
@@ -0,0 +1,231 @@
+/*********************************************************************
+Spectral lines.
+This is part of GNU Astronomy Utilities (Gnuastro) package.
+
+Original author:
+     Mohammad Akhlaghi <mohammad@akhlaghi.org>
+Contributing author(s):
+Copyright (C) 2019, 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 <math.h>
+#include <stdio.h>
+#include <errno.h>
+#include <error.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <gnuastro/speclines.h>
+
+
+/*********************************************************************/
+/*************        Internal names and codes         ***************/
+/*********************************************************************/
+/* Return line's name as literal string. */
+char *
+gal_speclines_line_name(int linecode)
+{
+  switch(linecode)
+    {
+    case GAL_SPECLINES_SIIRED:           return GAL_SPECLINES_NAME_SIIRED;
+    case GAL_SPECLINES_SII:              return GAL_SPECLINES_NAME_SII;
+    case GAL_SPECLINES_SIIBLUE:          return GAL_SPECLINES_NAME_SIIBLUE;
+    case GAL_SPECLINES_NIIRED:           return GAL_SPECLINES_NAME_NIIRED;
+    case GAL_SPECLINES_NII:              return GAL_SPECLINES_NAME_NII;
+    case GAL_SPECLINES_HALPHA:           return GAL_SPECLINES_NAME_HALPHA;
+    case GAL_SPECLINES_NIIBLUE:          return GAL_SPECLINES_NAME_NIIBLUE;
+    case GAL_SPECLINES_OIIIRED:          return GAL_SPECLINES_NAME_OIIIRED;
+    case GAL_SPECLINES_OIII:             return GAL_SPECLINES_NAME_OIII;
+    case GAL_SPECLINES_OIIIBLUE:         return GAL_SPECLINES_NAME_OIIIBLUE;
+    case GAL_SPECLINES_HBETA:            return GAL_SPECLINES_NAME_HBETA;
+    case GAL_SPECLINES_HEIIRED:          return GAL_SPECLINES_NAME_HEIIRED;
+    case GAL_SPECLINES_HGAMMA:           return GAL_SPECLINES_NAME_HGAMMA;
+    case GAL_SPECLINES_HDELTA:           return GAL_SPECLINES_NAME_HDELTA;
+    case GAL_SPECLINES_HEPSILON:         return GAL_SPECLINES_NAME_HEPSILON;
+    case GAL_SPECLINES_NEIII:            return GAL_SPECLINES_NAME_NEIII;
+    case GAL_SPECLINES_OIIRED:           return GAL_SPECLINES_NAME_OIIRED;
+    case GAL_SPECLINES_OII:              return GAL_SPECLINES_NAME_OII;
+    case GAL_SPECLINES_OIIBLUE:          return GAL_SPECLINES_NAME_OIIBLUE;
+    case GAL_SPECLINES_BLIMIT:           return GAL_SPECLINES_NAME_BLIMIT;
+    case GAL_SPECLINES_MGIIRED:          return GAL_SPECLINES_NAME_MGIIRED;
+    case GAL_SPECLINES_MGII:             return GAL_SPECLINES_NAME_MGII;
+    case GAL_SPECLINES_MGIIBLUE:         return GAL_SPECLINES_NAME_MGIIBLUE;
+    case GAL_SPECLINES_CIIIRED:          return GAL_SPECLINES_NAME_CIIIRED;
+    case GAL_SPECLINES_CIII:             return GAL_SPECLINES_NAME_CIII;
+    case GAL_SPECLINES_CIIIBLUE:         return GAL_SPECLINES_NAME_CIIIBLUE;
+    case GAL_SPECLINES_HEIIBLUE:         return GAL_SPECLINES_NAME_HEIIBLUE;
+    case GAL_SPECLINES_LYALPHA:          return GAL_SPECLINES_NAME_LYALPHA;
+    case GAL_SPECLINES_LYLIMIT:          return GAL_SPECLINES_NAME_LYLIMIT;
+    default:                           return NULL;
+    }
+  return NULL;
+}
+
+
+
+
+
+/* Return the code of the given line name. */
+int
+gal_speclines_line_code(char *name)
+{
+  if( !strcmp(name, GAL_SPECLINES_NAME_SIIRED) )
+    return GAL_SPECLINES_SIIRED;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_SII) )
+    return GAL_SPECLINES_SII;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_SIIBLUE) )
+    return GAL_SPECLINES_SIIBLUE;
+  if( !strcmp(name, GAL_SPECLINES_NAME_NIIRED) )
+    return GAL_SPECLINES_NIIRED;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_NII) )
+    return GAL_SPECLINES_NII;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_HALPHA) )
+    return GAL_SPECLINES_HALPHA;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_NIIBLUE) )
+    return GAL_SPECLINES_NIIBLUE;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_OIIIRED) )
+    return GAL_SPECLINES_OIIIRED;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_OIII) )
+    return GAL_SPECLINES_OIII;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_OIIIBLUE) )
+    return GAL_SPECLINES_OIIIBLUE;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_HBETA) )
+    return GAL_SPECLINES_HBETA;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_HEIIRED) )
+    return GAL_SPECLINES_HEIIRED;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_HGAMMA) )
+    return GAL_SPECLINES_HGAMMA;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_HDELTA) )
+    return GAL_SPECLINES_HDELTA;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_HEPSILON) )
+    return GAL_SPECLINES_HEPSILON;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_NEIII) )
+    return GAL_SPECLINES_NEIII;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_OIIRED) )
+    return GAL_SPECLINES_OIIRED;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_OII) )
+    return GAL_SPECLINES_OII;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_OIIBLUE) )
+    return GAL_SPECLINES_OIIBLUE;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_BLIMIT) )
+    return GAL_SPECLINES_BLIMIT;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_MGIIRED) )
+    return GAL_SPECLINES_MGIIRED;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_MGII) )
+    return GAL_SPECLINES_MGII;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_MGIIBLUE) )
+    return GAL_SPECLINES_MGIIBLUE;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_CIIIRED) )
+    return GAL_SPECLINES_CIIIRED;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_CIII) )
+    return GAL_SPECLINES_CIII;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_CIIIBLUE) )
+    return GAL_SPECLINES_CIIIBLUE;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_HEIIBLUE) )
+    return GAL_SPECLINES_HEIIBLUE;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_LYALPHA) )
+    return GAL_SPECLINES_LYALPHA;
+  else if( !strcmp(name, GAL_SPECLINES_NAME_LYLIMIT) )
+    return GAL_SPECLINES_LYLIMIT;
+  else return GAL_SPECLINES_INVALID;
+  return GAL_SPECLINES_INVALID;
+}
+
+
+
+
+
+/* Return the wavelength (in Angstroms) of given line. */
+double
+gal_speclines_line_angstrom(int linecode)
+{
+  switch(linecode)
+    {
+    case GAL_SPECLINES_SIIRED:        return GAL_SPECLINES_ANGSTROM_SIIRED;
+    case GAL_SPECLINES_SII:           return GAL_SPECLINES_ANGSTROM_SII;
+    case GAL_SPECLINES_SIIBLUE:       return GAL_SPECLINES_ANGSTROM_SIIBLUE;
+    case GAL_SPECLINES_NIIRED:        return GAL_SPECLINES_ANGSTROM_NIIRED;
+    case GAL_SPECLINES_NII:           return GAL_SPECLINES_ANGSTROM_NII;
+    case GAL_SPECLINES_HALPHA:        return GAL_SPECLINES_ANGSTROM_HALPHA;
+    case GAL_SPECLINES_NIIBLUE:       return GAL_SPECLINES_ANGSTROM_NIIBLUE;
+    case GAL_SPECLINES_OIIIRED:       return GAL_SPECLINES_ANGSTROM_OIIIRED;
+    case GAL_SPECLINES_OIII:          return GAL_SPECLINES_ANGSTROM_OIII;
+    case GAL_SPECLINES_OIIIBLUE:      return GAL_SPECLINES_ANGSTROM_OIIIBLUE;
+    case GAL_SPECLINES_HBETA:         return GAL_SPECLINES_ANGSTROM_HBETA;
+    case GAL_SPECLINES_HEIIRED:       return GAL_SPECLINES_ANGSTROM_HEIIRED;
+    case GAL_SPECLINES_HGAMMA:        return GAL_SPECLINES_ANGSTROM_HGAMMA;
+    case GAL_SPECLINES_HDELTA:        return GAL_SPECLINES_ANGSTROM_HDELTA;
+    case GAL_SPECLINES_HEPSILON:      return GAL_SPECLINES_ANGSTROM_HEPSILON;
+    case GAL_SPECLINES_NEIII:         return GAL_SPECLINES_ANGSTROM_NEIII;
+    case GAL_SPECLINES_OIIRED:        return GAL_SPECLINES_ANGSTROM_OIIRED;
+    case GAL_SPECLINES_OII:           return GAL_SPECLINES_ANGSTROM_OII;
+    case GAL_SPECLINES_OIIBLUE:       return GAL_SPECLINES_ANGSTROM_OIIBLUE;
+    case GAL_SPECLINES_BLIMIT:        return GAL_SPECLINES_ANGSTROM_BLIMIT;
+    case GAL_SPECLINES_MGIIRED:       return GAL_SPECLINES_ANGSTROM_MGIIRED;
+    case GAL_SPECLINES_MGII:          return GAL_SPECLINES_ANGSTROM_MGII;
+    case GAL_SPECLINES_MGIIBLUE:      return GAL_SPECLINES_ANGSTROM_MGIIBLUE;
+    case GAL_SPECLINES_CIIIRED:       return GAL_SPECLINES_ANGSTROM_CIIIRED;
+    case GAL_SPECLINES_CIII:          return GAL_SPECLINES_ANGSTROM_CIII;
+    case GAL_SPECLINES_CIIIBLUE:      return GAL_SPECLINES_ANGSTROM_CIIIBLUE;
+    case GAL_SPECLINES_HEIIBLUE:      return GAL_SPECLINES_ANGSTROM_HEIIBLUE;
+    case GAL_SPECLINES_LYALPHA:       return GAL_SPECLINES_ANGSTROM_LYALPHA;
+    case GAL_SPECLINES_LYLIMIT:       return GAL_SPECLINES_ANGSTROM_LYLIMIT;
+    default:
+      error(EXIT_FAILURE, 0, "%s: `%d' not recognized line identifier",
+            __func__, linecode);
+    }
+  return NAN;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/*********************************************************************/
+/*************             Redshifted lines            ***************/
+/*********************************************************************/
+double
+gal_speclines_line_redshift(double obsline, double restline)
+{
+  return (obsline/restline)-1;
+}
+
+
+
+
+
+double
+gal_speclines_line_redshift_code(double obsline, int linecode)
+{
+  double restline=gal_speclines_line_angstrom(linecode);
+  return (obsline/restline)-1;
+}
diff --git a/lib/statistics.c b/lib/statistics.c
index bbf1c56..f65bf4e 100644
--- a/lib/statistics.c
+++ b/lib/statistics.c
@@ -1398,13 +1398,12 @@ gal_statistics_no_blank_sorted(gal_data_t *input, int 
inplace)
         }
       else noblank=contig;
 
-      /* If there are any non-blank elements, make sure the array is
-         sorted. After this step, we won't be dealing with `noblank' any
-         more but with `sorted'. */
+      /* Make sure the array is sorted. After this step, we won't be
+         dealing with `noblank' any more but with `sorted'. */
       if(noblank->size)
         {
           if( gal_statistics_is_sorted(noblank, 1) )
-            sorted=noblank;
+            sorted = inplace ? noblank : gal_data_copy(noblank);
           else
             {
               if(inplace) sorted=noblank;
@@ -2214,56 +2213,93 @@ gal_statistics_outlier_positive(gal_data_t *input, 
size_t window_size,
 
 
 
-/* Find the outliers using the first flat portion of the cumulative
-   frequency plot. A good value for window and thresh are 5 and 1.0. */
+/* Find the outliers using the average distance of the neighboring
+   points. */
 #define OUTLIER_FLAT_CFP_BYTYPE(IT) {                                   \
-    IT m, n, *a=nbs->array, *p=a+dist, *pp=a+nbs->size-dist;            \
-    min=a[0]; max=a[nbs->size-1];                                       \
+    IT diff, *pr=prev->array;                                           \
+    IT *a=nbs->array, *p=a+d, *pp=a+nbs->size-d;                        \
+                                                                        \
     do                                                                  \
       {                                                                 \
-        m=( *(p-dist)-min ) / (max-min) * 100.0f;                       \
-        n=( *(p+dist)-min ) / (max-min) * 100.0f;                       \
-        check=1/(n-m);                                                  \
-        if(!quiet) printf("%-6zu%-15g%-15g\n", p-a, (float)(*p), check); \
-        if( check<thresh && start==GAL_BLANK_SIZE_T )                   \
-          { start=p-a; if(!quiet) printf("\t---start\n"); }             \
-        if( check>thresh && start!=GAL_BLANK_SIZE_T )                   \
+        diff=*(p+d)-*(p-d);                                             \
+        if(p-a-d<numprev)                                               \
           {                                                             \
-             widthcheck=100.0 * (double)(*p-a[start])/(max-min);        \
-             if(!quiet) printf("\t----end: %f\n", widthcheck);          \
-             if( widthcheck > width ) { flatind=start; break; }         \
-             start=GAL_BLANK_SIZE_T;                                    \
+            pr[p-a-d]=diff;                                             \
+            if(!quiet) printf("%-6zu%-15g%-15g\n", p-a, (float)(*p),    \
+                              (float)diff);                             \
+          }                                                             \
+        else                                                            \
+          {                                                             \
+            /* Sigma-clipped median and std for a check. */             \
+            prev->flag=0;                                               \
+            prev->size=prev->dsize[0]=numprev;                          \
+            sclip=gal_statistics_sigma_clip(prev, sigclip_multip,       \
+                                            sigclip_param, 1, 1);       \
+                                                                        \
+            sarr=sclip->array;                                          \
+            check = (diff - sarr[1]) / sarr[3];                         \
+                                                                        \
+            /* If requested, print the values. */                       \
+            if(!quiet) printf("%-6zu%-15g%-15g%-15g (%g,%g)\n", p-a,    \
+                              (float)(*p), (float)diff, check, sarr[1], \
+                              sarr[3]);                                 \
+                                                                        \
+            /* When values are equal, std will be roughly zero */       \
+            if(sarr[3]>1e-6 && check>thresh)                            \
+              {                                                         \
+                if(flatind==GAL_BLANK_SIZE_T)                           \
+                  {                                                     \
+                    ++counter;                                          \
+                    flatind=p-a;                                        \
+                  }                                                     \
+                else                                                    \
+                  {                                                     \
+                    if(flatind==p-a-counter)                            \
+                      { /* First element above thresh is 0, so for */   \
+                        /* counting, when counting the number of */     \
+                        /* contiguous elements, we have to add 1. */    \
+                        if(counter+1==numcontig)                        \
+                          {gal_data_free(sclip); break;}                \
+                        else ++counter;                                 \
+                      }                                                 \
+                    else { flatind=GAL_BLANK_SIZE_T; counter=0; }       \
+                  }                                                     \
+              }                                                         \
+            else { flatind=GAL_BLANK_SIZE_T; counter=0; }               \
+            pr[(p-a-d)%numprev]=diff;                                   \
+            gal_data_free(sclip);                                       \
           }                                                             \
       }                                                                 \
     while(++p<pp);                                                      \
-    if( pp==p && start!=GAL_BLANK_SIZE_T )                              \
-      {                                                                 \
-        widthcheck=100.0 * (double)(*(p-1)-a[start])/(max-min);         \
-        if(!quiet) printf("\t----end: %f\n", widthcheck);               \
-        if( widthcheck > width ) flatind=start;                         \
-      }                                                                 \
+    if(counter+1!=numcontig) flatind=GAL_BLANK_SIZE_T;                    \
   }
 
 gal_data_t *
-gal_statistics_outlier_flat_cfp(gal_data_t *input, size_t dist,
-                                float thresh, float width, int inplace,
+gal_statistics_outlier_flat_cfp(gal_data_t *input, size_t numprev,
+                                float sigclip_multip, float sigclip_param,
+                                float thresh, size_t numcontig, int inplace,
                                 int quiet, size_t *index)
 {
-  gal_data_t  *nbs, *out=NULL;
-  double min, max, check, widthcheck;
-  size_t one=1, flatind=GAL_BLANK_SIZE_T, start=GAL_BLANK_SIZE_T;
+  float *sarr;
+  double check;
+  gal_data_t  *nbs, *prev, *out=NULL, *sclip;
+  size_t d=2, counter=0, one=1, flatind=GAL_BLANK_SIZE_T;
 
   /* Sanity checks. */
-  if(thresh<=0 || width<=0)
-    error(EXIT_FAILURE, 0, "%s: the values to `thresh' (%g) and `width' (%g) "
-          "must be positive", __func__, thresh, width);
-  if(width==0)
-    error(EXIT_FAILURE, 0, "%s: `dist' (%zu) cannot be zero", __func__,
-          dist);
+  if(thresh<=0)
+    error(EXIT_FAILURE, 0, "%s: the value of `thresh' (%g) must be "
+          "positive", __func__, thresh);
+  if(numprev==0)
+    error(EXIT_FAILURE, 0, "%s: `numprev' (%zu) cannot be zero", __func__,
+          numprev);
 
   /* Remove all blanks and sort the dataset. */
   nbs=gal_statistics_no_blank_sorted(input, inplace);
 
+  /* Keep previous slopes. */
+  prev=gal_data_alloc(NULL, GAL_TYPE_FLOAT64, 1, &numprev, NULL, 0, -1,
+                      NULL, NULL, NULL);
+
   /* Find the index where the distribution becomes sufficiently flat. */
   switch(nbs->type)
     {
@@ -2282,7 +2318,8 @@ gal_statistics_outlier_flat_cfp(gal_data_t *input, size_t 
dist,
             __func__, nbs->type);
     }
 
-  /* Write the output dataset. */
+  /* Write the output dataset: if no point flat part was found, return
+     NULL. */
   if(flatind!=GAL_BLANK_SIZE_T)
     {
       out=gal_data_alloc(NULL, input->type, 1, &one, NULL, 0, -1,
@@ -2295,5 +2332,6 @@ gal_statistics_outlier_flat_cfp(gal_data_t *input, size_t 
dist,
   /* Clean up and return. */
   if(nbs!=input) gal_data_free(nbs);
   if(index) *index=flatind;
+  gal_data_free(prev);
   return out;
 }
diff --git a/lib/tableintern.c b/lib/tableintern.c
index f1c8e8b..25a1c24 100644
--- a/lib/tableintern.c
+++ b/lib/tableintern.c
@@ -62,7 +62,7 @@ gal_tableintern_error_col_selection(char *filename, char *hdu,
                    filename, hdu)<0 )
         error(EXIT_FAILURE, 0, "%s: asprintf allocation", __func__);
     }
-  else command=name=filename;
+  else command=name=filename?filename:"stdin";
 
   /* Abort with with the proper error. */
   error(EXIT_FAILURE, 0, "%s: %s\n\nFor more information on selecting "
diff --git a/lib/tiff.c b/lib/tiff.c
index 3e9894b..a853746 100644
--- a/lib/tiff.c
+++ b/lib/tiff.c
@@ -52,14 +52,19 @@ int
 gal_tiff_name_is_tiff(char *name)
 {
   size_t len;
-  len=strlen(name);
-  if ( ( len>=3 && strcmp(&name[len-3], "tif") == 0 )
-       || ( len>=3 && strcmp(&name[len-3], "TIF") == 0 )
-       || ( len>=4 && strcmp(&name[len-4], "tiff") == 0 )
-       || ( len>=4 && strcmp(&name[len-4], "TIFF") == 0 ) )
-    return 1;
-  else
-    return 0;
+
+  if(name)
+    {
+      len=strlen(name);
+      if ( ( len>=3 && strcmp(&name[len-3], "tif") == 0 )
+           || ( len>=3 && strcmp(&name[len-3], "TIF") == 0 )
+           || ( len>=4 && strcmp(&name[len-4], "tiff") == 0 )
+           || ( len>=4 && strcmp(&name[len-4], "TIFF") == 0 ) )
+        return 1;
+      else
+        return 0;
+    }
+  else return 0;
 }
 
 
@@ -69,13 +74,17 @@ gal_tiff_name_is_tiff(char *name)
 int
 gal_tiff_suffix_is_tiff(char *name)
 {
-  if (strcmp(name, "tif") == 0   || strcmp(name, ".tif") == 0
-      || strcmp(name, "TIF") == 0 || strcmp(name, ".TIF") == 0
-      || strcmp(name, "tiff") == 0 || strcmp(name, ".tiff") == 0
-      || strcmp(name, "TIFF") == 0 || strcmp(name, ".TIFF") == 0 )
-    return 1;
-  else
-    return 0;
+  if(name)
+    {
+    if (strcmp(name, "tif") == 0   || strcmp(name, ".tif") == 0
+        || strcmp(name, "TIF") == 0 || strcmp(name, ".TIF") == 0
+        || strcmp(name, "tiff") == 0 || strcmp(name, ".tiff") == 0
+        || strcmp(name, "TIFF") == 0 || strcmp(name, ".TIFF") == 0 )
+      return 1;
+    else
+      return 0;
+    }
+  else return 0;
 }
 
 
diff --git a/lib/txt.c b/lib/txt.c
index 4404e2f..96d2027 100644
--- a/lib/txt.c
+++ b/lib/txt.c
@@ -153,16 +153,29 @@ txt_trim_space(char *str)
   be before column 7.
 */
 static void
-txt_info_from_comment(char *line, gal_data_t **datall, char *comm_start)
+txt_info_from_comment(char *in_line, gal_data_t **datall, char *comm_start,
+                      int inplace)
 {
-  char *tailptr;
   gal_data_t *tmp;
   int index, strw=0;
+  char *line, *aline, *tailptr;
   size_t len=strlen(comm_start);
   int type=GAL_TYPE_FLOAT64;                     /* Default type. */
   char *number=NULL, *name=NULL, *comment=NULL;
   char *inbrackets=NULL, *unit=NULL, *typestr=NULL, *blank=NULL;
 
+  /* Make a copy of the input line if `inplace==0'. */
+  if(inplace) line=aline=in_line;
+  else
+    {
+      /* Because the `line' pointer will change, we need a pointer to the
+         start of the originally allocated lines. This is the purpose of
+         `aline' (allocated-line). */
+      gal_checkset_allocate_copy(in_line, &aline);
+      line=aline;
+    }
+
+
   /* Only read this comment line if it follows the convention: */
   if( !strncmp(line, comm_start, len) )
     {
@@ -276,6 +289,9 @@ txt_info_from_comment(char *line, gal_data_t **datall, char 
*comm_start)
          final column, we are just collecting information now. */
       gal_tableintern_read_blank(*datall, txt_trim_space(blank));
     }
+
+  /* Clean up. */
+  if(in_line!=aline) free(aline);
 }
 
 
@@ -539,7 +555,7 @@ txt_get_info_line(char *line, gal_data_t **datall, char 
*comm_start,
     {
       /* Line is a comment, see if it has formatted information. */
     case GAL_TXT_LINESTAT_COMMENT:
-      txt_info_from_comment(line, datall, comm_start);
+      txt_info_from_comment(line, datall, comm_start, inplace);
       break;
 
       /* Line is actual data, use it to fill in the gaps.  */
@@ -808,7 +824,7 @@ txt_read_token(gal_data_t *data, gal_data_t *info, char 
*token,
 static void
 txt_fill(char *in_line, char **tokens, size_t maxcolnum, gal_data_t *info,
          gal_data_t *out, size_t rowind, char *filename, size_t lineno,
-         int inplace)
+         int inplace, int format)
 {
   size_t i, n=0;
   gal_data_t *data;
@@ -838,8 +854,10 @@ txt_fill(char *in_line, char **tokens, size_t maxcolnum, 
gal_data_t *info,
       if(n>maxcolnum) break;
 
       /* Set the pointer to the start of this token/column. See
-         explanations in `txt_info_from_first_row'. */
-      if( info[n-1].type == GAL_TYPE_STRING )
+         explanations in `txt_info_from_first_row'. Note that an image has
+         a single `info' element for the whole array, while a table has one
+         for each column. */
+      if( info[format==TXT_FORMAT_TABLE ? n-1 : 0].type == GAL_TYPE_STRING )
         {
           /* Remove any delimiters and stop at the first non-delimiter. If
              we have reached the end of the line then its an error, because
@@ -1016,7 +1034,7 @@ txt_read(char *filename, gal_list_str_t *lines, size_t 
*dsize,
           ++lineno;
           if( gal_txt_line_stat(line) == GAL_TXT_LINESTAT_DATAROW )
             txt_fill(line, tokens, maxcolnum, info, out, rowind++,
-                     filename, lineno, 1);
+                     filename, lineno, 1, format);
         }
 
       /* Clean up and close the file. */
@@ -1032,7 +1050,7 @@ txt_read(char *filename, gal_list_str_t *lines, size_t 
*dsize,
         ++lineno;
         if( gal_txt_line_stat(tmp->v) == GAL_TXT_LINESTAT_DATAROW )
           txt_fill(tmp->v, tokens, maxcolnum, info, out, rowind++,
-                   filename, lineno, 0);
+                   filename, lineno, 0, format);
       }
 
   /* Clean up and return. */
diff --git a/tests/Makefile.am b/tests/Makefile.am
index ed58445..cc9a6b4 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -235,11 +235,11 @@ export check_with_program=$(MAYBE_CHECK_WITH_PROGRAM);
 # `../lib/Makefile.am' and is only meant for outside users (to be tested
 # here). Thus (unlike the programs, which use `config.h') we need to add
 # the top build directory to the include search directories (`-I').
+LDADD = -lgnuastro $(CONFIG_LDADD)
 AM_LDFLAGS = -L\$(top_builddir)/lib
 AM_CPPFLAGS = -I\$(top_srcdir)/lib -I\$(top_builddir)/lib
 
 # Rest of library check settings.
-LDADD = -lgnuastro
 check_PROGRAMS = multithread $(MAYBE_CXX_PROGS)
 multithread_SOURCES = lib/multithread.c
 lib/multithread.sh: mkprof/mosaic1.sh.log



reply via email to

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