gnuastro-commits
[Top][All Lists]
Advanced

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

[gnuastro-commits] master e2c7fff 054/125: Option values now usable in p


From: Mohammad Akhlaghi
Subject: [gnuastro-commits] master e2c7fff 054/125: Option values now usable in program
Date: Sun, 23 Apr 2017 22:36:36 -0400 (EDT)

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

    Option values now usable in program
    
    The option values can now be used in the programs. There is still some
    small amount of work to complete task #14300 ("Option management using new
    root data structure."), but fortunately most of it is done. The only
    remaining parts are writing the printed paramters to configuration files
    when the `set*conf' options are given. Also, some polishing of the normal
    parameter printing function (print comments, and the extra information).
    
    The book was also updated to fit some of the parts, but one full reading
    over the text has not been done yet to make it nice and homogenous.
    
    To do this, the following changes were also made:
    
     - Most of the `uiparams' elements have been removed.
    
     - The option keys are now enumerator types. This allows easy checking of
       option array elements, instead of having to use `strcmp' on the names.
    
     - The citation printing is also now complete: each program has its own
       `bibtex' variable which should keep the BibTeX record(s).
---
 bin/table/args.h          |  40 ++--
 bin/table/cite.h          |  20 +-
 bin/table/main.h          |   9 +-
 bin/table/ui.c            | 111 ++++++---
 doc/gnuastro.texi         | 174 ++++++++++----
 lib/commonopts.h          |  44 ++--
 lib/fixedstringmacros.h   |  24 --
 lib/gnuastro/linkedlist.h |  26 ++-
 lib/linkedlist.c          | 106 ++++++++-
 lib/options.c             | 574 +++++++++++++++++++++++++++++++++++++++++-----
 lib/options.h             |  50 +++-
 11 files changed, 936 insertions(+), 242 deletions(-)

diff --git a/bin/table/args.h b/bin/table/args.h
index 3a87e7a..17f45a2 100644
--- a/bin/table/args.h
+++ b/bin/table/args.h
@@ -68,13 +68,24 @@ const char doc[] =
 /* Available letters for short options:
 
    a b d e f g j k l m n p r u v w x y z
-   A B C E F G H J L M O Q R T U W X Y Z
+   A B C E F G H J L M O Q R T U W X Y Z  */
+enum option_keys_enum
+{
+  /* With short-option version. */
+  ARGS_OPTION_COLUMN_KEY      = 'c',
+  ARGS_OPTION_SEARCHIN_KEY    = 's',
+  ARGS_OPTION_IGNORECASE_KEY  = 'I',
+  ARGS_OPTION_TABLETYPE_KEY   = 't',
+  ARGS_OPTION_INFORMATION_KEY = 'i',
+
+  /* Only with long version. */
+};
+
+
 
-   Number keys used (larger than 1000): 1000
 
-   Options with keys (second structure element) larger than 500 do not
-   have a short version.
- */
+
+/* Array of acceptable options. */
 struct argp_option options[] =
   {
     {
@@ -84,7 +95,7 @@ struct argp_option options[] =
     },
     {
       "column",
-      'c',
+      ARGS_OPTION_COLUMN_KEY,
       "STR",
       0,
       "Column number (counting from 1) or search string.",
@@ -93,7 +104,7 @@ struct argp_option options[] =
     },
     {
       "searchin",
-      's',
+      ARGS_OPTION_SEARCHIN_KEY,
       "STR",
       0,
       "Search in column `name', `units', or `comments'.",
@@ -102,7 +113,7 @@ struct argp_option options[] =
     },
     {
       "ignorecase",
-      'I',
+      ARGS_OPTION_IGNORECASE_KEY,
       0,
       0,
       "Ignore case when matching column information.",
@@ -120,7 +131,7 @@ struct argp_option options[] =
     },
     {
       "tabletype",
-      't',
+      ARGS_OPTION_TABLETYPE_KEY,
       "STR",
       0,
       "Output table type: `fits-ascii', `fits-binary'.",
@@ -138,7 +149,7 @@ struct argp_option options[] =
     },
     {
       "information",
-      'i',
+      ARGS_OPTION_INFORMATION_KEY,
       0,
       0,
       "Only print table and column information.",
@@ -185,15 +196,6 @@ parse_opt(int key, char *arg, struct argp_state *state)
       break;
 
 
-    /* The command line options and arguments are finished. */
-    case ARGP_KEY_END:
-      if(p->cp.setdirconf==0 && p->cp.setusrconf==0
-         && p->cp.printparams==0)
-        if(state->arg_num==0)
-          argp_error(state, "no argument given");
-      break;
-
-
     /* This is an option, set its value. */
     default:
       return gal_options_set_from_key(key, arg, options);
diff --git a/bin/table/cite.h b/bin/table/cite.h
index de9ab4f..6eaee12 100644
--- a/bin/table/cite.h
+++ b/bin/table/cite.h
@@ -23,16 +23,14 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 #ifndef CITE_H
 #define CITE_H
 
-#define TABLEBIBTEX ""
-
-#define PRINTCITEABORT {                                                \
-    printf("\nWe hope %s has been useful for your research.\n"          \
-           "Citations are vital for the continued work on %s.\n"        \
-           "Thank you for citing it in your research paper.\n"          \
-           "\nPlease cite as \"%s\":\n\n%s\n\n%s",                      \
-           SPACK_NAME, SPACK_NAME, SPACK_STRING,                        \
-           GAL_STRINGS_MAIN_BIBTEX, TABLEBIBTEX);                       \
-    exit(EXIT_SUCCESS);                                                 \
-  }
+/* When any specific citation is necessary, please add its BibTeX (from ADS
+   hopefully) to this variable a long with a title decribing what this
+   paper/book does for the progarm in a short line. In the following line
+   put a row of `-' with the same length and then put the BibTeX.
+
+   See the `gnuastro_bibtex' variable in `lib/options' (from the top
+   Gnuastro source code directory as an example.*/
+
+char *bibtex="";
 
 #endif
diff --git a/bin/table/main.h b/bin/table/main.h
index bb4e25a..2b54865 100644
--- a/bin/table/main.h
+++ b/bin/table/main.h
@@ -23,6 +23,7 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 #ifndef MAIN_H
 #define MAIN_H
 
+/* Include necessary headers */
 #include <gnuastro/data.h>
 
 #include <options.h>
@@ -40,15 +41,7 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 struct uiparams
 {
   char              *filename;
-  char             *tabletype;
   gal_data_t      *allcolinfo;
-  char              *searchin;
-
-  /* If values are set: */
-  int          informationset;
-  int           ignorecaseset;
-  int            tabletypeset;
-  int             searchinset;
 };
 
 
diff --git a/bin/table/ui.c b/bin/table/ui.c
index 752ecce..f00f70f 100644
--- a/bin/table/ui.c
+++ b/bin/table/ui.c
@@ -43,8 +43,9 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 
 #include "main.h"
 
-#include "ui.h"                  /* Needs main.h                   */
-#include "args.h"                /* Needs main.h, includes argp.h. */
+#include "ui.h"
+#include "args.h"
+#include "cite.h"
 
 
 /* Set the file names of the places where the default parameters are
@@ -66,14 +67,75 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 /**************************************************************/
 /***************       Sanity Check         *******************/
 /**************************************************************/
+static void
+ui_option_is_mandatory(char *name)
+{
+  error(EXIT_FAILURE, 0, "`%s' option is mandatory", name);
+}
+
+
+
+
+
 void
 fill_params_from_options(struct tableparams *p)
 {
+  size_t i;
 
-
-  /* Free all the allocated spaces in the option structures. */
-  gal_options_free(options);
-  gal_options_free(gal_commonopts_options);
+  /* Put the program's option values into the structure. */
+  for(i=0; !gal_options_is_last(&options[i]); ++i)
+    if( options[i].key && options[i].name )
+      switch(options[i].key)
+        {
+        /* Inputs */
+        case ARGS_OPTION_COLUMN_KEY:
+          gal_linked_list_copy_stll(options[i].value, &p->columns);
+          break;
+
+        case ARGS_OPTION_SEARCHIN_KEY:
+          if(options[i].value)
+            p->searchin=gal_table_string_to_searchin(options[i].value);
+          else ui_option_is_mandatory((char *)options[i].name);
+          break;
+
+        case ARGS_OPTION_IGNORECASE_KEY:
+          p->ignorecase = *(unsigned char *)options[i].value;
+          break;
+
+
+        /* Output */
+        case ARGS_OPTION_TABLETYPE_KEY:
+
+          /* Set the tabletype parameter. */
+          if(options[i].value)
+            p->tabletype=gal_table_string_to_type(options[i].value);
+          else if( gal_fits_name_is_fits(p->cp.output) )
+            ui_option_is_mandatory((char *)options[i].name);
+
+
+          /* If the output name was set and is a FITS file, make sure that
+             the type of the table is not a `txt'. */
+          if( p->cp.output && gal_fits_name_is_fits(p->cp.output)
+              && ( p->tabletype !=GAL_TABLE_TYPE_AFITS
+                   && p->tabletype !=GAL_TABLE_TYPE_BFITS ) )
+            error(EXIT_FAILURE, 0, "desired output file `%s' is a FITS "
+                  "file, but `tabletype' is not a FITS table type. "
+                  "Please set it to `fits-ascii', or `fits-binary'",
+                  p->cp.output);
+          break;
+
+
+        /* Operating mode */
+        case ARGS_OPTION_INFORMATION_KEY:
+          if(options[i].value)
+            p->information = *(unsigned char *)options[i].value;
+          break;
+
+
+        default:
+          error(EXIT_FAILURE, 0, "option key %d not recognized in "
+                "`fill_params_from_options'", options[i].key);
+        }
 }
 
 
@@ -83,27 +145,8 @@ fill_params_from_options(struct tableparams *p)
 void
 sanitycheck(struct tableparams *p)
 {
-  struct uiparams *up=&p->up;
-
-  /* Set the searchin integer value. */
-  p->searchin=gal_table_string_to_searchin(p->up.searchin);
-
-
-  /* If the outtabletype option was given, then convert it to an easiy
-     usable integer. Note we cannot do this in the output filename check
-     below, since it is also necessary when there is an output file.*/
-  if(up->tabletypeset)
-    p->tabletype=gal_table_string_to_type(up->tabletype);
 
 
-  /* If the output name was set and is a FITS file, make sure that the type
-     of the table is not a `txt'. */
-  if( p->cp.output && gal_fits_name_is_fits(p->cp.output)
-      && ( p->tabletype !=GAL_TABLE_TYPE_AFITS
-           && p->tabletype !=GAL_TABLE_TYPE_BFITS ) )
-        error(EXIT_FAILURE, 0, "desired output file `%s' is a FITS file, "
-              "but `tabletype' is set to `%s'. Please set it to "
-              "`fits-ascii', or `fits-binary'", p->cp.output, up->tabletype);
 }
 
 
@@ -243,19 +286,28 @@ setparams(int argc, char *argv[], struct tableparams *p)
     error(EXIT_FAILURE, errno, "parsing arguments");
 
   /* Read the configuration files. */
-  gal_options_config_files(PROG_EXEC, options, gal_commonopts_options);
+  gal_options_config_files(PROG_EXEC, PROG_NAME, options,
+                           gal_commonopts_options, &p->cp);
 
   /* Fill the parameters from the options. */
   fill_params_from_options(p);
 
-  printf("\n--- back in `ui.c' ---\n");
-  exit(0);
 
   /* Do a sanity check. */
   sanitycheck(p);
 
-  /* Make the array of input images. */
+  /* Print the necessary information if asked. Note that this needs to be
+     done after the sanity check so un-sane values are not printed in the
+     output state. */
+  gal_options_print_state(PROG_NAME, bibtex, options,
+                          gal_commonopts_options);
+
+  /* Read/allocate all the necessary starting arrays */
   preparearrays(p);
+
+  /* Free all the allocated spaces in the option structures. */
+  gal_options_free(options);
+  gal_options_free(gal_commonopts_options);
 }
 
 
@@ -286,6 +338,5 @@ freeandreport(struct tableparams *p)
   /* Free the allocated arrays: */
   free(p->cp.hdu);
   free(p->cp.output);
-  free(p->up.searchin);
   gal_data_free_ll(p->table);
 }
diff --git a/doc/gnuastro.texi b/doc/gnuastro.texi
index ba84e4b..ab146d8 100644
--- a/doc/gnuastro.texi
+++ b/doc/gnuastro.texi
@@ -4413,6 +4413,14 @@ devoted to Gnuastro will be published, see @ref{GNU 
Astronomy Utilities
 Print the final values used for all the parameters and abort. See
 @ref{Final parameter values} for more details.
 
address@hidden --config
+(@option{=STR}) Read the file given to this option as a configuration file
+before any of the other configuration files. Multiple instances of this
+option are acceptable, allowing specification of multiple configuration
+files will be parsed before the default ones in the same order that this
+option was called on the command line. This option is only relevant on the
+command-line, within a configuration file, it is ignored.
+
 @item -S
 @itemx --setdirconf
 Update the current directory configuration file from the given command
@@ -4439,33 +4447,68 @@ the program will not run).
 Update the user configuration file from the command-line options and
 quit. See explanation under @option{--setdirconf} for more details.
 
address@hidden --onlydirconf
-Only read the current (local) directory configuration file and ignore the
-rest of the configuration files, see @ref{Configuration file precedence}
-and @ref{Current directory and User wide}. This can be very useful when you
-want your results to be exactly reproducible. All the configuration files
-can be put in the hidden @file{./.gnuastro/} directory in the current
-directory, or the hidden directory can be a symbolic link to the directory
-containing the configuration files. Then with this option you can ensure
-that no other configuration file is read. So if your local configuration
-file lacks some parameters, which ever Gnuastro program you are using will
-will warn you and abort, enabling you to exactly set all the necessary
-parameters without unknowingly relying on some user or system wide option
-values.
address@hidden --lastconfig
+This is the last configuration file. When this option is confronted in a
+configuration file (or even on the command-line), no other configuration
+file will be parsed, see @ref{Configuration file precedence} and
address@hidden directory and User wide}. On the command-line this option
+doesn't take any values, but in a configuration file, it takes the values
+of @option{0} or @option{1}, see @ref{Configuration file format}. If it is
+present in a configuration file (and has a value of @option{0}), then all
+later occurances of this option will be ignored).
 
address@hidden can also be used in the configuration files (with
-a value of @option{0} or @option{1}), see @ref{Configuration file
-format}. If it is present in the local configuration file, other
-configuration files will not be read. In the other configuration
-files, it is irrelevant.
 
 @item --onlyversion
 (@option{=STR}) Only run the program if its version is equal with the
-string of characters given to this option. Note that it is not
-compared as a number, but as a string of characters, so @option{0}, or
address@hidden and @option{0.00} are different. This is useful if you
-want your results to be exactly reproducible and not mistakenly run
-with an updated or older version of the program.
+string of characters given to this option. Note that it is not compared as
+a number, but as a string of characters, so @option{0}, or @option{0.0} and
address@hidden are different. This option will report an error and abort as
+soon as it is confronted by the command-line or configuration file parser.
+
+This is useful if you want your results to be exactly reproducible and not
+mistakenly run with an updated/newer or older version of the
+program. Besides internal algorithmic/behavior changes in programs, the
+existence of options or their names might change between versions
+(especially in these earlier versions of Gnuastro).
+
+Hence, when using this option (probably in a script or in a configuration
+file), be sure to call it before other options. The benefit is that, when
+the version differs, the other options won't be parsed and you, or your
+collaborators/users, won't get errors saying an option in your
+configuration doesn't exist in the running version of the program.
+
+Here is one example of how this option can be used in conjunction with the
address@hidden option. Let's assume that you were satisfied with the
+results of this command: @command{astnoisechisel image.fits
+--detquant=0.95} (along with various options set in various configuration
+files). You can save the state of NoiseChisel and reproduce that exact
+result on @file{image.fits} later by following these steps (the the extra
+spaces are only for easy readability, if you want to try it out, only one
+space between each token is enough).
+
address@hidden
+$ echo "onlyversion X.XX"                         > reproducible.conf
+$ echo "lastconfig 1"                            >> reproducible.conf
+$ astnoisechisel image.fits --detquant=0.95 -P   >> reproducible.conf
address@hidden example
+
address@hidden was available from Gnuastro 0.0, so putting it
+immediately at the start of a configuration file will ensure that later,
+you (or others using different version) won't get a non-recognized option
+error. Through the @option{--lastconfig} option will informing the other
+NoiseChisel to not parse any other configuration files. Finally, in the
+third command with the @option{-P} (short for @option{--printparams})
+option, NoiseChisel will print all the option values visible to it (in all
+the configuration files). Hence, you don't have to worry about remembering
+the (possibly) different options in the different configuration
+files. Afterwards, if you run NoiseChisel as shown below (telling it to
+read this configuration files), you can be sure that there will either be
+an error (for version mis-match) or it will produce exactly the same result
+that you got before.
+
address@hidden
+$ astnoisechisel --config=reproducible.conf
address@hidden example
 
 @item --nolog
 For programs which generate Log files, if this option is called, no
@@ -4588,45 +4631,78 @@ more understandable.
 @cindex Configuration file precedence
 @cindex Configuration file directories
 @cindex Precedence, configuration files
-The parameter values in all the programs of Gnuastro will be filled
-in the following order. Such that if a parameter is assigned a value
-in an earlier step, any value for that parameter in a later step will
-be ignored.
+The parameter values in all the programs of Gnuastro will be filled in the
+following order. Such that if a parameter is assigned a value in an earlier
+step, any value for that parameter in a later step will be ignored. Note
+that if the @option{lastconfig} option is specified in any step below, all
+later files will be ignored (see @ref{Operating modes}).
 
 @enumerate
 @item
 Command-line options, for this particular execution.
 
 @item
-Current directory, for all executions in the directory from which any
-of the programs is run (@file{./.gnuastro/}).
+Any file(s) given to the @option{--config} option (in the same order that
+this option was called, see @ref{Operating modes}).
+
address@hidden
+Program-specific configuration file in current directory, for example
address@hidden/astnoisechisel.conf}, or @file{.gnuastro/astimgcrop.conf}.
+
address@hidden
+General configuration file in current directory:
address@hidden/gnuastro.conf}.
+
address@hidden
+Program-specific configuration file in your home directory
+(@file{$HOME/.local/etc/}), see below). For example
address@hidden/.local/etc/astnoisechisel.conf}. For any Gnuastro program you
+run as this user.
 
 @item
-The user's home directory, for all the executions of a particular
-user: (@file{$HOME/.local/etc/}, see below). It is only read if
address@hidden is not called, see @ref{Operating modes}.
+General Gnuastro configuration file in your home directory:
address@hidden/.local/etc/gnuastro.conf}, see bellow.
 
 @item
-In a system wide directory for any user on that computer
-(@file{prefix/etc/}, see @ref{Installation directory} for the value of
address@hidden). It is only read if @option{--onlydirconf} is not
-called, see @ref{Operating modes}.
+Program-specific configuration file in a system wide directory for any user
+on that computer (@file{prefix/etc/}, see @ref{Installation directory} for
+the value of @file{prefix}). For example
address@hidden/etc/astnoisechisel.conf}.
+
address@hidden
+General Gnuastro configuration file in a system wide directory:
address@hidden/etc/gnuastro.conf}
 @end enumerate
 @noindent
 
+The @file{gnuastro.conf} configuration files should only contain common
+options (see @ref{Common options}), otherwise there will be un-recognized
+option errors and the programs will abort, or give unexpected behavior if
+the option has different behavior in another program. On the other hand,
+there is no problem with program-specific configuration files containing
+common options.
+
 The basic idea behind setting this progressive state of checking for
 parameter values is that separate users of a computer or separate
 folders in a user's file system might need different values for some
-parameters and the same values for others. For example raw telescope
-images usually have their main image extension in the second FITS
-extension, while processed FITS images usually only have one
-extension. If your system wide default input extension is 0 (the
-first), then when you want to work with the former group of data you
-have to explicitly mention it to the programs every time. With this
-progressive state of default values to check, you can set different
-default values for the different directories that you would like to
-run Gnuastro in for your different purposes, so you won't have to
-worry about this issue any more.
+parameters and the same values for others.
+
+For example raw telescope images usually have their main image extension in
+the second FITS extension, while processed FITS images usually only have
+one extension. If your system-wide default input extension is 0 (the
+first), then when you want to work with the former group of data you have
+to explicitly mention it to the programs every time. With this progressive
+state of default values to check, you can set different default values for
+the different directories that you would like to run Gnuastro in for your
+different purposes, so you won't have to worry about this issue any
+more.
+
+The same can be said about the @file{gnuastro.conf} files: by specifying a
+behavior in this single file, all Gnuastro programs in the respective
+directory, user, or system-wide steps will behave similarly. For example to
+keep the input's directory when no specific output is given (see
address@hidden output}), or to not delete an existing file if it has the
+same name as a given output (see @ref{Input output}).
 
 
 @node Current directory and User wide, System wide, Configuration file 
precedence, Configuration files
@@ -17847,9 +17923,9 @@ problem. The most efficient way to manage the actions 
is such that only
 identified for it in series (one after the other). This way your CPU will
 get all the actions done with minimal overhead.
 
-The purpose of this function is to do do what we explained above: each row
-in the @code{outthrds} array contains the indexs of actions which must be
-done by one thread. @code{outthrds} contains @code{outthrdcols} columns. In
+The purpose of this function is to do what we explained above: each row in
+the @code{outthrds} array contains the indexs of actions which must be done
+by one thread. @code{outthrds} contains @code{outthrdcols} columns. In
 using @code{outthrds}, you don't have to know the number of columns. The
 @code{GAL_THREADS_NON_THRD_INDEX} macro has a role very similar to a
 string's @code{\0}: every row finishes with this macro, so can easily stop
diff --git a/lib/commonopts.h b/lib/commonopts.h
index 1e79102..ec188af 100644
--- a/lib/commonopts.h
+++ b/lib/commonopts.h
@@ -32,26 +32,14 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
      libraries, and in particular `options.c'. Because we want each program
      to have its own allocation of the common options structure. If it is
      included in options.c, then it will be shared between all the
-     programs.
-
-
-   Free letters (-V which is used by GNU is also removed):
-
-   a b c d e f g i j k l m n p r s t u v w x y z
-   A B C E F G H I J L M O Q R T U W X Y Z
-
-   Used numbers <= 1004
-
-   You can use this above list to set short options for the different
-   utilities.
- */
+     programs. */
 struct argp_option gal_commonopts_options[] =
   {
     /* Input/output. */
 #ifndef NOT_COMMON_HDU_PARSER
     {                           /* Some utilities need to parse `hdu' them-*/
       "hdu",                    /* selves. In this case, they will define  */
-      'h',                      /* `NOT_COMMON_HDU_PARSER' and set their   */
+      GAL_OPTIONS_HDU_KEY,      /* `NOT_COMMON_HDU_PARSER' and set their   */
       "STR",                    /* own `hdu' option structure. */
       0,
       "Extension name or number of input data.",
@@ -61,7 +49,7 @@ struct argp_option gal_commonopts_options[] =
 #endif
     {
       "output",
-      'o',
+      GAL_OPTIONS_OUTPUT_KEY,
       "STR",
       0,
       "Output file or directory name.",
@@ -70,7 +58,7 @@ struct argp_option gal_commonopts_options[] =
     },
     {
       "dontdelete",
-      'D',
+      GAL_OPTIONS_DONTDELETE_KEY,
       0,
       0,
       "Don't delete output if it exists.",
@@ -79,7 +67,7 @@ struct argp_option gal_commonopts_options[] =
     },
     {
       "keepinputdir",
-      'K',
+      GAL_OPTIONS_KEEPINPUTDIR_KEY,
       0,
       0,
       "Keep input directory for automatic output.",
@@ -92,7 +80,7 @@ struct argp_option gal_commonopts_options[] =
     /* Operating mode. */
     {
       "quiet",
-      'q',
+      GAL_OPTIONS_QUIET_KEY,
       0,
       0,
       "Only report errors, remain quiet about steps.",
@@ -101,7 +89,7 @@ struct argp_option gal_commonopts_options[] =
     },
     {
       "numthreads",
-      'N',
+      GAL_OPTIONS_NUMTHREADS_KEY,
       "INT",
       0,
       "Number of CPU threads to use.",
@@ -110,7 +98,7 @@ struct argp_option gal_commonopts_options[] =
     },
     {
       "minmapsize",
-      1004,
+      GAL_OPTIONS_MINMAPSIZE_KEY,
       "INT",
       0,
       "Minimum no. bytes to map arrays to hdd/ssd.",
@@ -119,7 +107,7 @@ struct argp_option gal_commonopts_options[] =
     },
     {
       "log",
-      1003,
+      GAL_OPTIONS_LOG_KEY,
       0,
       0,
       "No log file for programs which make one.",
@@ -132,7 +120,7 @@ struct argp_option gal_commonopts_options[] =
     /* Internal (before control goes back to the program). */
     {
       "cite",
-      1000,
+      GAL_OPTIONS_CITE_KEY,
       0,
       0,
       "BibTeX citation for this program.",
@@ -141,7 +129,7 @@ struct argp_option gal_commonopts_options[] =
     },
     {
       "printparams",
-      'P',
+      GAL_OPTIONS_PRINTPARAMS_KEY,
       0,
       0,
       "Print parameter values to be used and abort.",
@@ -150,7 +138,7 @@ struct argp_option gal_commonopts_options[] =
     },
     {
       "config",
-      1005,
+      GAL_OPTIONS_CONFIG_KEY,
       "STR",
       0,
       "Read file STR before default configuration files.",
@@ -159,7 +147,7 @@ struct argp_option gal_commonopts_options[] =
     },
     {
       "setdirconf",
-      'S',
+      GAL_OPTIONS_SETDIRCONF_KEY,
       0,
       0,
       "Set default values for this directory and abort.",
@@ -168,7 +156,7 @@ struct argp_option gal_commonopts_options[] =
     },
     {
       "setusrconf",
-      'U',
+      GAL_OPTIONS_SETUSRCONF_KEY,
       0,
       0,
       "Set default values for this user and abort.",
@@ -177,7 +165,7 @@ struct argp_option gal_commonopts_options[] =
     },
     {
       "lastconfig",
-      1001,
+      GAL_OPTIONS_LASTCONFIG_KEY,
       0,
       0,
       "Do not parse any more configuration files.",
@@ -186,7 +174,7 @@ struct argp_option gal_commonopts_options[] =
     },
     {
       "onlyversion",
-      1002,
+      GAL_OPTIONS_ONLYVERSION_KEY,
       "STR",
       0,
       "Only run if the program version is STR.",
diff --git a/lib/fixedstringmacros.h b/lib/fixedstringmacros.h
index 70d01e1..5d8cf72 100644
--- a/lib/fixedstringmacros.h
+++ b/lib/fixedstringmacros.h
@@ -62,30 +62,6 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
   PROG_NAME" options:"                                                  \
 
 
-
-#define GAL_STRINGS_MAIN_BIBTEX                                         \
-  "@ARTICLE{noisechisel,\n"                                             \
-  "   author = {{Akhlaghi}, M. and {Ichikawa}, T.},\n"                  \
-  "    title = \"{Noise-based Detection and Segmentation of Nebulous "  \
-  "Objects}\",\n"                                                       \
-  "  journal = {\\apjs},\n"                                             \
-  "archivePrefix = \"arXiv\",\n"                                        \
-  "   eprint = {1505.01664},\n"                                         \
-  " primaryClass = \"astro-ph.IM\",\n"                                  \
-  " keywords = {galaxies: irregular, galaxies: photometry, "            \
-  "galaxies: structure, methods: data analysis, "                       \
-  "techniques: image processing, techniques: photometric},\n"           \
-  "     year = 2015,\n"                                                 \
-  "    month = sep,\n"                                                  \
-  "   volume = 220,\n"                                                  \
-  "      eid = {1},\n"                                                  \
-  "    pages = {1},\n"                                                  \
-  "      doi = {10.1088/0067-0049/220/1/1},\n"                          \
-  "   adsurl = {http://adsabs.harvard.edu/abs/2015ApJS..220....1A},\n";  \
-  "  adsnote = {Provided by the SAO/NASA Astrophysics Data System}\n"   \
-  "}"
-
-
 /* This can be used in the end of error messages related to option
    values. */
 #define GAL_STRINGS_HOW_TO_CHECK_VALUES                                 \
diff --git a/lib/gnuastro/linkedlist.h b/lib/gnuastro/linkedlist.h
index df1c9b4..00c8894 100644
--- a/lib/gnuastro/linkedlist.h
+++ b/lib/gnuastro/linkedlist.h
@@ -122,8 +122,12 @@ struct gal_linkedlist_stll
 };
 
 void
-gal_linkedlist_add_to_stll(struct gal_linkedlist_stll **list, char *value,
-                           int allocate);
+gal_linkedlist_add_to_stll(struct gal_linkedlist_stll **list,
+                           char *value, int allocate);
+
+void
+gal_linked_list_copy_stll(struct gal_linkedlist_stll *from,
+                          struct gal_linkedlist_stll **to);
 
 void
 gal_linkedlist_pop_from_stll(struct gal_linkedlist_stll **list,
@@ -177,6 +181,24 @@ gal_linkedlist_free_sll(struct gal_linkedlist_sll *list);
 
 
 
+/******************* int: */
+struct gal_linkedlist_ill
+{
+    int v;
+    struct gal_linkedlist_ill *next;
+};
+
+void
+gal_linkedlist_add_to_ill(struct gal_linkedlist_ill **list, int value);
+
+void
+gal_linkedlist_pop_from_ill(struct gal_linkedlist_ill **list, int *value);
+
+void
+gal_linkedlist_reverse_ill(struct gal_linkedlist_ill **list);
+
+void
+gal_linkedlist_print_ill(struct gal_linkedlist_ill *list);
 
 
 
diff --git a/lib/linkedlist.c b/lib/linkedlist.c
index 0feb159..a278b2a 100644
--- a/lib/linkedlist.c
+++ b/lib/linkedlist.c
@@ -306,8 +306,8 @@ gal_linkedlist_free_tdll(struct gal_linkedlist_tdll *list)
  *****************           string          ********************
  ****************************************************************/
 void
-gal_linkedlist_add_to_stll(struct gal_linkedlist_stll **list, char *value,
-                           int allocate)
+gal_linkedlist_add_to_stll(struct gal_linkedlist_stll **list,
+                           char *value, int allocate)
 {
   struct gal_linkedlist_stll *newnode;
 
@@ -331,6 +331,23 @@ gal_linkedlist_add_to_stll(struct gal_linkedlist_stll 
**list, char *value,
 
 
 void
+gal_linked_list_copy_stll(struct gal_linkedlist_stll *from,
+                          struct gal_linkedlist_stll **to)
+{
+  struct gal_linkedlist_stll *tmp, *out=NULL;
+
+  for(tmp=from; tmp!=NULL; tmp=tmp->next)
+    gal_linkedlist_add_to_stll(&out, tmp->v, 1);
+
+  gal_linkedlist_reverse_stll(&out);
+  *to=out;
+}
+
+
+
+
+
+void
 gal_linkedlist_pop_from_stll(struct gal_linkedlist_stll **list, char **value)
 {
   struct gal_linkedlist_stll *tmp;
@@ -569,6 +586,91 @@ gal_linkedlist_free_sll(struct gal_linkedlist_sll *list)
 
 
 /****************************************************************
+ *****************            int            ********************
+ ****************************************************************/
+void
+gal_linkedlist_add_to_ill(struct gal_linkedlist_ill **list, int value)
+{
+  struct gal_linkedlist_ill *newnode;
+
+  errno=0;
+  newnode=malloc(sizeof *newnode);
+  if(newnode==NULL)
+    error(EXIT_FAILURE, errno,
+          "linkedlist: New element in gal_linkedlist_ill");
+
+  newnode->v=value;
+  newnode->next=*list;
+  *list=newnode;
+}
+
+
+
+
+
+void
+gal_linkedlist_pop_from_ill(struct gal_linkedlist_ill **list, int *value)
+{
+  struct gal_linkedlist_ill *tmp;
+  tmp=*list;
+  *value=tmp->v;
+  *list=tmp->next;
+  free(tmp);
+}
+
+
+
+
+
+void
+gal_linkedlist_reverse_ill(struct gal_linkedlist_ill **list)
+{
+  int thisnum;
+  struct gal_linkedlist_ill *correctorder=NULL;
+
+  if( *list && (*list)->next )
+    {
+      while(*list!=NULL)
+        {
+          gal_linkedlist_pop_from_ill(list, &thisnum);
+          gal_linkedlist_add_to_ill(&correctorder, thisnum);
+        }
+      *list=correctorder;
+    }
+}
+
+
+
+
+
+void
+gal_linkedlist_print_ill(struct gal_linkedlist_ill *list)
+{
+  struct gal_linkedlist_ill *tmp;
+  for(tmp=list; tmp!=NULL; tmp=tmp->next)
+    printf("%d\n", tmp->v);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/****************************************************************
  ******************        Ordered SLL       ********************
  *****************           size_t          ********************
  ****************************************************************/
diff --git a/lib/options.c b/lib/options.c
index 48dd62b..de51b05 100644
--- a/lib/options.c
+++ b/lib/options.c
@@ -32,7 +32,7 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 #include <gnuastro/linkedlist.h>
 
 #include <options.h>
-
+#include <checkset.h>
 
 
 
@@ -104,6 +104,105 @@ gal_options_free(struct argp_option *options)
 
 
 /**********************************************************************/
+/************              Option actions               ***************/
+/**********************************************************************/
+
+static void
+options_check_version(char *version_string)
+{
+  if( strcmp(version_string, PACKAGE_VERSION) )
+    error(EXIT_FAILURE, 0, "version mis-match: you are running GNU "
+          "Astronomy Utilities version %s, but this program was configured "
+          "to run with version %s (value to the `onlyversion' option, "
+          "either in a configuration file or on the command-line). This was "
+          "probably done for reproducibility. Therefore, removing, or "
+          "changing, the option value might produce errors or unexpected "
+          "results. It is hence strongly advised to build GNU Astronomy "
+          "Utilities version %s and re-run this command/script",
+          PACKAGE_VERSION, version_string, version_string);
+}
+
+
+
+
+
+static void
+options_print_citation_exit(char *prog_name, char *prog_bibtex)
+{
+  char *gnuastro_bibtex=
+    "Gnuastro package/infrastructure\n"
+    "-------------------------------\n"
+    "  @ARTICLE{noisechisel-gnuastro,\n"
+    "     author = {{Akhlaghi}, M. and {Ichikawa}, T.},\n"
+    "      title = \"{Noise-based Detection and Segmentation of Nebulous "
+    "Objects}\",\n"
+    "    journal = {\\apjs},\n"
+    "  archivePrefix = \"arXiv\",\n"
+    "     eprint = {1505.01664},\n"
+    "   primaryClass = \"astro-ph.IM\",\n"
+    "   keywords = {galaxies: irregular, galaxies: photometry, "
+    "galaxies: structure, methods: data analysis, "
+    "techniques: image processing, techniques: photometric},\n"
+    "       year = 2015,\n"
+    "      month = sep,\n"
+    "     volume = 220,\n"
+    "        eid = {1},\n"
+    "      pages = {1},\n"
+    "        doi = {10.1088/0067-0049/220/1/1},\n"
+    "     adsurl = {http://adsabs.harvard.edu/abs/2015ApJS..220....1A},\n";
+    "    adsnote = {Provided by the SAO/NASA Astrophysics Data System}\n"
+    "  }";
+
+
+  /* Print the statements. */
+  printf("\nThank you for using %s (%s) %s.\n\n", prog_name, PACKAGE_NAME,
+         PACKAGE_VERSION);
+  printf("Citations are vital for the continued work on Gnuastro.\n\n"
+         "Please cite these BibTeX record(s) in your paper(s).\n\n%s\n\n",
+         gnuastro_bibtex);
+
+  /* Only print the citation for the program if one exists. */
+  if(prog_bibtex[0]!='\0') printf("%s\n\n", prog_bibtex);
+
+
+  printf("                                               ,\n"
+         "                                              {|'--.\n"
+         "                                             {{\\    \\\n"
+         "      Many thanks from all                   |/`'--./=.\n"
+         "      Gnuastro developers!                   `\\.---' `\\\\\n"
+         "                                                  |\\  ||\n"
+         "                                                  | |//\n"
+         "                                                   \\//_/|\n"
+         "                                                   //\\__/\n"
+         "                                                  //\n"
+         "                   (http://www.chris.com/ascii/) |/\n");
+
+
+
+  /* Exit the program. */
+  exit(EXIT_SUCCESS);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/**********************************************************************/
 /************            Command-line options           ***************/
 /**********************************************************************/
 /* Set the value given to the command-line, where we have the integer `key'
@@ -123,6 +222,13 @@ gal_options_set_from_key(int key, char *arg, struct 
argp_option *options)
       /* Check if the key corresponds to this option. */
       if(options[i].key==key)
         {
+          /* If this is the only version option, we need to check and
+             (possibly) abort immediately, because the other options might
+             not exist in later versions and we don't want to confuse the
+             user with an unknown option error. */
+          if( options[i].key == GAL_OPTIONS_ONLYVERSION_KEY )
+              options_check_version(arg);
+
           /* When options are read from keys, they are read from the
              command-line. On the commandline, the last invokation of the
              option is important. Especially in contexts like scripts, this
@@ -269,7 +375,7 @@ gal_options_common_argp_parse(int key, char *arg, struct 
argp_state *state)
 /* Read the option and the argument from the line and return.*/
 static void
 options_read_name_arg(char *line, char *filename, size_t lineno,
-                        char **name, char **arg)
+                      char **name, char **arg)
 {
   int notyetfinished=1, inword=0, inquote=0;
 
@@ -370,6 +476,14 @@ options_set_from_name(char *name, char *arg, struct 
argp_option *options,
           if(options[i].value && !gal_data_is_linked_list(options[i].type))
             return 0;
 
+          /* If this is the `onlyversion' option, we need to check and
+             (possibly) abort immediately. The other options might not
+             exist in the running version and we don't want to confuse the
+             user with an unknown option error (while it is present in the
+             proper version). */
+          if( options[i].key == GAL_OPTIONS_ONLYVERSION_KEY )
+              options_check_version(arg);
+
           /* For strings, `gal_data_string_to_type' is going to return an
              allocated pointer to an allocated string (`char **'). In this
              context, we are just dealing with one string, and arrays of
@@ -422,7 +536,7 @@ options_set_from_name(char *name, char *arg, struct 
argp_option *options,
 
 static void
 options_parse_file(char *filename,  struct argp_option *poptions,
-                   struct argp_option *coptions)
+                   struct argp_option *coptions, int enoent_abort)
 {
   FILE *fp;
   char *line, *name, *arg;
@@ -435,7 +549,7 @@ options_parse_file(char *filename,  struct argp_option 
*poptions,
   fp=fopen(filename, "r");
   if(fp==NULL)
     {
-      if(errno==ENOENT)
+      if(errno==ENOENT && enoent_abort==0)
         return;
       else
         error(EXIT_FAILURE, errno, "%s: to read as a configuration file",
@@ -515,9 +629,10 @@ static void
 gal_options_parse_config_files(char *progexec, struct argp_option *poptions,
                                struct argp_option *coptions)
 {
+  char *home;
   char *filename;
-  size_t i, last_config_index;
   struct gal_linkedlist_stll *tmp;
+  size_t i, last_config_index=-1, config_index=-1;
 
 
 
@@ -531,98 +646,439 @@ gal_options_parse_config_files(char *progexec, struct 
argp_option *poptions,
 
 
 
-  /* Set the index of the `lastconfig' option. It is important to check
-     this option after every configuration file. Thus, to avoid having to
-     loop through all the options on every check, we'll find the index and
-     just check it each time.
+  /* Things to do before starting to go into the configuration files.
 
-     Although very unlikely, it might happen that the user calls this on
-     the command-line (to avoid any configuration files). So, also check if
-     we should continue with this function or not. */
-  for(i=0; gal_options_is_last(&coptions[i])==0; ++i)
-    if(!strcmp(coptions[i].name, "lastconfig"))
-      {
-        last_config_index=i;
-        if(OPTIONS_THIS_IS_LASTCONFIG) return;
-        break;
-      }
+     - Get the index of the `lastconfig' option in the array, since it
+       should be checked multiple times during this function.
+
+     - Parse any specific configuration files that the user might have
+       specified before going over the standard ones.  */
+  for(i=0; !gal_options_is_last(&coptions[i]); ++i)
+    {
+      if( coptions[i].key == GAL_OPTIONS_LASTCONFIG_KEY )
+        {
+          /* Index of `lastconfig' in the options array for later. */
+          last_config_index=i;
+
+          /* Although very unlikely, it might happen that the user calls
+             this on the command-line (to avoid any configuration
+             files). So, also check if we should continue with this
+             function or not. */
+          if(OPTIONS_THIS_IS_LASTCONFIG) return;
+        }
 
+      else if( coptions[i].key == GAL_OPTIONS_CONFIG_KEY )
+        {
+          /* Index of `config' in the options array for later. */
+          config_index=i;
 
+          /* Reverse the linked list so the configuration files are in the
+             same order that the user specified on the command-line. */
+          gal_linkedlist_reverse_stll(
+              (struct gal_linkedlist_stll **)(&coptions[i].value) );
 
-  /* Before doing anything, see if the user specified any configuration
-     files to parse before the standard ones. */
-  for(i=0; gal_options_is_last(&coptions[i])==0; ++i)
-    if(!strcmp(coptions[i].name, "config"))
-      {
-        /* When more than one configuration file is given, reverse the list
-           so it comes into the same order that the user specified on the
-           command-line. */
-        gal_linkedlist_reverse_stll(
-                (struct gal_linkedlist_stll **)(&coptions[i].value) );
-
-        /* Go through all the configuration files and fill in the values. */
-        for(tmp=coptions[i].value; tmp!=NULL; tmp=tmp->next)
-          {
-            options_parse_file(tmp->v, poptions, coptions);
-            if( OPTIONS_THIS_IS_LASTCONFIG ) return;
-          }
-        break;
-      }
+          /* Go through the configuration files and fill in the values.
 
+             Note that if there are any other calls to the `config' option
+             they will be ignored. This is because they will be added to
+             the top of the list which is no longer parsed, */
+          for(tmp=coptions[i].value; tmp!=NULL; tmp=tmp->next)
+            {
+              options_parse_file(tmp->v, poptions, coptions, 1);
+              if( OPTIONS_THIS_IS_LASTCONFIG ) return;
+            }
+        }
+    }
+  if( last_config_index == -1 || config_index == -1 )
+    error(EXIT_FAILURE, 0, "a bug! The common options array doesn't "
+          "contain an entry for the `lastconfig' or `config' options. "
+          "Please contact us at %s so we can address the problem",
+          PACKAGE_BUGREPORT);
 
 
   /* The program's current directory configuration file. */
   asprintf(&filename, ".%s/%s.conf", PACKAGE, progexec);
-  options_parse_file(filename, poptions, coptions);
+  options_parse_file(filename, poptions, coptions, 0);
   if( OPTIONS_THIS_IS_LASTCONFIG ) return;
   free(filename);
 
   /* General Gnuastro configuration file. */
   asprintf(&filename, ".%s/%s.conf", PACKAGE, PACKAGE);
-  printf("%s\n", filename);
-  options_parse_file(filename, poptions, coptions);
+  options_parse_file(filename, poptions, coptions, 0);
   if( OPTIONS_THIS_IS_LASTCONFIG ) return;
   free(filename);
 
-  /* User level configuration files. */
-  asprintf(&filename, "%s/%s.conf", USERCONFIG_DIR, progexec);
-  printf("%s\n", filename);
-  options_parse_file(filename, poptions, coptions);
+  /* Read the home environment variable. */
+  home=getenv("HOME");
+  if(home==NULL)
+    error(EXIT_FAILURE, 0, "the HOME environment variable "
+          "is not defined");
+
+  /* User wide configuration files. */
+  asprintf(&filename, "%s/%s/%s.conf", home, USERCONFIG_DIR, progexec);
+  options_parse_file(filename, poptions, coptions, 0);
   if( OPTIONS_THIS_IS_LASTCONFIG ) return;
   free(filename);
 
-  /* User level general Gnuastro configuration file. */
-  asprintf(&filename, "%s/%s.conf", USERCONFIG_DIR, PACKAGE);
-  printf("%s\n", filename);
-  options_parse_file(filename, poptions, coptions);
+  /* User wide general Gnuastro configuration file. */
+  asprintf(&filename, "%s/%s/%s.conf", home, USERCONFIG_DIR, PACKAGE);
+  options_parse_file(filename, poptions, coptions, 0);
   if( OPTIONS_THIS_IS_LASTCONFIG ) return;
   free(filename);
 
-  /* User level configuration files. */
+  /* System wide configuration files. */
   asprintf(&filename, "%s/%s.conf", SYSCONFIG_DIR, progexec);
-  printf("%s\n", filename);
-  options_parse_file(filename, poptions, coptions);
+  options_parse_file(filename, poptions, coptions, 0);
   if( OPTIONS_THIS_IS_LASTCONFIG ) return;
   free(filename);
 
-  /* User level general Gnuastro configuration file. */
+  /* System wide general Gnuastro configuration file. */
   asprintf(&filename, "%s/%s.conf", SYSCONFIG_DIR, PACKAGE);
-  printf("%s\n", filename);
-  options_parse_file(filename, poptions, coptions);
+  options_parse_file(filename, poptions, coptions, 0);
   if( OPTIONS_THIS_IS_LASTCONFIG ) return;
   free(filename);
+
+
+
+  /* Free the config option's (possible) list of file names since it is no
+     longer needed. */
+  gal_linkedlist_free_stll(coptions[last_config_index].value, 1);
 }
 
 
 
 
 
+static void
+options_reverse_lists(struct argp_option *options)
+{
+  size_t i;
+
+  for(i=0; !gal_options_is_last(&options[i]); ++i)
+    if(options[i].value && gal_data_is_linked_list(options[i].type) )
+      switch(options[i].type)
+        {
+        case GAL_DATA_TYPE_STRLL:
+          gal_linkedlist_reverse_stll(
+                 (struct gal_linkedlist_stll **)(&options[i].value) );
+          break;
+
+        default:
+          error(EXIT_FAILURE, 0, "type code %d isn't recognized as a "
+                "linked list in `options_reverse_lists'", options[i].type);
+        }
+}
+
+
+
+
+
+
 void
-gal_options_config_files(char *progexec, struct argp_option *poptions,
-                         struct argp_option *coptions)
+gal_options_config_files(char *prog_exec, char *prog_name,
+                         struct argp_option *poptions,
+                         struct argp_option *coptions,
+                         struct gal_options_common_params *cp)
 {
+  size_t i;
+
   /* Parse all the configuration files. */
-  gal_options_parse_config_files(progexec, poptions, coptions);
+  gal_options_parse_config_files(prog_exec, poptions, coptions);
+
+
+  /* Reverse the order of all linked list type options so the popping order
+     is the same as the user's input order. We need to do this here because
+     when printing those options, their order matters.*/
+  options_reverse_lists(poptions);
+  options_reverse_lists(coptions);
+
+
+  /* Put the common option values into the structure. */
+  for(i=0; !gal_options_is_last(&coptions[i]); ++i)
+    if( coptions[i].key && coptions[i].name )
+      switch(coptions[i].key)
+        {
+        case GAL_OPTIONS_HDU_KEY:
+          gal_checkset_allocate_copy(coptions[i].value, &cp->hdu);
+          break;
+
+        case GAL_OPTIONS_OUTPUT_KEY:
+          gal_checkset_allocate_copy(coptions[i].value, &cp->output);
+          break;
+
+        case GAL_OPTIONS_DONTDELETE_KEY:
+          if(coptions[i].value)
+            cp->dontdelete=*(unsigned char *)coptions[i].value;
+          break;
+
+        case GAL_OPTIONS_KEEPINPUTDIR_KEY:
+          if(coptions[i].value)
+            cp->keepinputdir=*(unsigned char *)coptions[i].value;
+          break;
+
+        case GAL_OPTIONS_QUIET_KEY:
+          if(coptions[i].value)
+            cp->quiet=*(unsigned char *)coptions[i].value;
+          break;
+
+        case GAL_OPTIONS_NUMTHREADS_KEY:
+          if(coptions[i].value)
+            cp->numthreads=*(unsigned long *)coptions[i].value;
+          break;
+
+        case GAL_OPTIONS_MINMAPSIZE_KEY:
+          if(coptions[i].value)
+            cp->minmapsize=*(unsigned long *)coptions[i].value;
+          break;
+
+        case GAL_OPTIONS_LOG_KEY:
+          if(coptions[i].value)
+            cp->log=*(unsigned char *)coptions[i].value;
+          break;
+        }
+}
+
+
+
+
 
-  /* Do the necessary checks (printing, saving and etc). */
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/**********************************************************************/
+/************            After sanity check            ***************/
+/**********************************************************************/
+static int
+options_max_name_length(struct argp_option *poptions,
+                        struct argp_option *coptions)
+{
+  int i, maxlen=0;
+
+  for(i=0; !gal_options_is_last(&poptions[i]); ++i)
+    if(poptions[i].name && strlen(poptions[i].name)>maxlen)
+      maxlen=strlen(poptions[i].name);
+
+  for(i=0; !gal_options_is_last(&coptions[i]); ++i)
+    if(coptions[i].name && strlen(coptions[i].name)>maxlen)
+      maxlen=strlen(coptions[i].name);
+
+  return maxlen;
+}
+
+
+
+
+
+static void
+options_print_any_type(void *ptr, int type)
+{
+  char *c;
+  switch(type)
+    {
+    /* For a string we need to make sure it has no white space characters,
+       if it does, it should be printed it within quotation signs. */
+    case GAL_DATA_TYPE_STRING:
+      c=ptr; while(*c!='\0') if(isspace(*c++)) break;
+      if(*c=='\0') printf("%s\n", (char *)ptr);
+      else         printf("\"%s\"\n", (char *)ptr);
+      break;
+
+    case GAL_DATA_TYPE_UCHAR:
+      printf("%u\n", *(unsigned char *)ptr);
+      break;
+
+    case GAL_DATA_TYPE_CHAR:
+      printf("%d\n", *(char *)ptr);
+      break;
+
+    case GAL_DATA_TYPE_USHORT:
+      printf("%u\n", *(unsigned short *)ptr);
+      break;
+
+    case GAL_DATA_TYPE_SHORT:
+      printf("%d\n", *(short *)ptr);
+      break;
+
+    case GAL_DATA_TYPE_UINT:
+      printf("%u\n", *(unsigned int *)ptr);
+      break;
+
+    case GAL_DATA_TYPE_INT:
+      printf("%d\n", *(int *)ptr);
+      break;
+
+    case GAL_DATA_TYPE_ULONG:
+      printf("%lu\n", *(unsigned long *)ptr);
+      break;
+
+    case GAL_DATA_TYPE_LONG:
+      printf("%ld\n", *(long *)ptr);
+      break;
+
+    case GAL_DATA_TYPE_LONGLONG:
+      printf("%lld\n", *(LONGLONG *)ptr);
+      break;
+
+    case GAL_DATA_TYPE_FLOAT:
+      printf("%.6f\n", *(float *)ptr);
+      break;
+
+    case GAL_DATA_TYPE_DOUBLE:
+      printf("%.14f\n", *(double *)ptr);
+      break;
+
+    default:
+      error(EXIT_FAILURE, 0, "type code %d not recognized in "
+            "`options_print_any_type'", type);
+    }
+}
+
+
+
+
+
+static void
+options_print_all_in_group(struct argp_option *options, int groupint,
+                           int maxlen)
+{
+  size_t i;
+  int namewidth=maxlen+2;
+  struct gal_linkedlist_stll *tmp;
+
+  for(i=0; !gal_options_is_last(&options[i]); ++i)
+    if( options[i].group == groupint && options[i].name && options[i].value )
+      {
+        /* Don't print the values of configuration specific options. */
+        switch(options[i].key)
+          {
+          case GAL_OPTIONS_CITE_KEY:
+          case GAL_OPTIONS_PRINTPARAMS_KEY:
+          case GAL_OPTIONS_CONFIG_KEY:
+          case GAL_OPTIONS_SETDIRCONF_KEY:
+          case GAL_OPTIONS_SETUSRCONF_KEY:
+          case GAL_OPTIONS_LASTCONFIG_KEY:
+            return;
+          }
+
+        /* Print the option name and value */
+        if(gal_data_is_linked_list(options[i].type))
+          {
+            /* A small sanity check. */
+            if(options[i].type!=GAL_DATA_TYPE_STRLL)
+              error(EXIT_FAILURE, 0, "`options_print_all_in_group' "
+                    "currently only supports string linked lists");
+
+            /* Print every element of the list as a separate option. */
+            for(tmp=options[i].value; tmp!=NULL; tmp=tmp->next)
+              {
+                printf(" %-*s ", namewidth, options[i].name);
+                options_print_any_type(tmp->v, GAL_DATA_TYPE_STRING);
+              }
+          }
+        else
+          {
+            printf(" %-*s ", namewidth, options[i].name);
+            options_print_any_type(options[i].value, options[i].type);
+          }
+      }
+}
+
+
+
+
+
+static void
+options_print_all(struct argp_option *poptions,
+                  struct argp_option *coptions, char *filename)
+{
+  size_t i;
+  char *topicstr;
+  int groupint, maxlen;
+  struct gal_linkedlist_ill *group=NULL;
+  struct gal_linkedlist_stll *topic=NULL;
+
+  /* First, parse all the options with a title, note that the title options
+     must only be in the `poptions'. We will only be dealing with the
+     `topics' linked list in this function and the strings in `poption' are
+     statically allocated, so its fine to not waste CPU cycles allocating
+     and freeing.*/
+  for(i=0; !gal_options_is_last(&poptions[i]); ++i)
+    if(poptions[i].name==NULL && poptions[i].key==0 && poptions[i].doc)
+      {
+        /* The `(char *)' is because `.doc' is a constant and this helps
+           remove the compiler warning. */
+        gal_linkedlist_add_to_ill(&group, poptions[i].group);
+        gal_linkedlist_add_to_stll(&topic, (char *)poptions[i].doc, 0);
+      }
+
+  /* Reverse the linked lists to get the same input order. */
+  gal_linkedlist_reverse_stll(&topic);
+  gal_linkedlist_reverse_ill(&group);
+
+  /* Get the maximum width of all the names. */
+  maxlen=options_max_name_length(poptions, coptions);
+
+  /* Go over each topic and print every option that is in this group. */
+  while(topic)
+    {
+      /* Pop the nodes from the linked list. */
+      gal_linkedlist_pop_from_ill(&group, &groupint);
+      gal_linkedlist_pop_from_stll(&topic, &topicstr);
+
+      /* First print the topic, */
+      printf("\n# %s\n", topicstr);
+
+      /* Then, print all the options that are in this group. */
+      options_print_all_in_group(coptions, groupint, maxlen);
+      options_print_all_in_group(poptions, groupint, maxlen);
+    }
+
+  /* Exit the program successfully */
+  exit(EXIT_SUCCESS);
+}
+
+
+
+
+
+#define OPTIONS_UCHARVAL *(unsigned char *)(coptions[i].value)
+void
+gal_options_print_state(char *prog_name, char *prog_bibtex,
+                        struct argp_option *poptions,
+                        struct argp_option *coptions)
+{
+  size_t i;
+
+  /* Do the necessary checks (printing, saving and etc). Note that if they
+     were called (with a value of 1 or 0), they should be checked, so
+     before checking an option's name, check if its `value' pointer isn't
+     NULL.*/
+  for(i=0; !gal_options_is_last(&coptions[i]); ++i)
+    if(coptions[i].value)
+      switch(coptions[i].key)
+        {
+        /* Print citation. */
+        case GAL_OPTIONS_CITE_KEY:
+          if(OPTIONS_UCHARVAL)
+            options_print_citation_exit(prog_name, prog_bibtex);
+          break;
+
+        /* Print configuration parameters and abort. */
+        case GAL_OPTIONS_PRINTPARAMS_KEY:
+          if(OPTIONS_UCHARVAL)
+            options_print_all(poptions, coptions, NULL);
+          break;
+    }
 }
diff --git a/lib/options.h b/lib/options.h
index 52e83ad..86ad8b7 100644
--- a/lib/options.h
+++ b/lib/options.h
@@ -44,6 +44,37 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 extern struct argp_option gal_commonopts_options[];
 
 
+/* Key values for the common options, the free alphabetical keys are listed
+   below. You can use any of the free letters for an option in a
+   program. Note that `-V', which is used by GNU and implemented by Argp,
+   is also removed.
+
+   a b c d e f g i j k l m n p r s t u v w x y z
+   A B C E F G H I J L M O Q R T U W X Y Z
+*/
+enum options_option_keys
+{
+  /* With short-option version */
+  GAL_OPTIONS_HDU_KEY          = 'h',
+  GAL_OPTIONS_OUTPUT_KEY       = 'o',
+  GAL_OPTIONS_DONTDELETE_KEY   = 'D',
+  GAL_OPTIONS_KEEPINPUTDIR_KEY = 'K',
+  GAL_OPTIONS_QUIET_KEY        = 'q',
+  GAL_OPTIONS_NUMTHREADS_KEY   = 'N',
+  GAL_OPTIONS_PRINTPARAMS_KEY  = 'P',
+  GAL_OPTIONS_SETDIRCONF_KEY   = 'S',
+  GAL_OPTIONS_SETUSRCONF_KEY   = 'U',
+
+  /* Only long option (integers for keywords). */
+  GAL_OPTIONS_MINMAPSIZE_KEY   = 500,
+  GAL_OPTIONS_LOG_KEY,
+  GAL_OPTIONS_CITE_KEY,
+  GAL_OPTIONS_CONFIG_KEY,
+  GAL_OPTIONS_LASTCONFIG_KEY,
+  GAL_OPTIONS_ONLYVERSION_KEY,
+};
+
+
 /* The structure keeping all the values of the common options in Gnuastro's
    programs. */
 struct gal_options_common_params
@@ -59,14 +90,6 @@ struct gal_options_common_params
   size_t  numthreads;     /* Number of threads to use.                   */
   size_t  minmapsize;     /* The minimum bytes necessary to use mmap.    */
   int            log;     /* Make a log file.                            */
-
-  /* Internal (before control goes back to the program). */
-  int           cite;     /* BibTeX citation for program and abort.      */
-  int    printparams;     /* Print all option values and abort.          */
-  int     setdirconf;     /* Set default values for this dir and abort.  */
-  int     setusrconf;     /* Set default values for this user and abort. */
-  int    onlydirconf;     /* Only read current directory config file.    */
-  int    onlyversion;     /* Only run program with this version.         */
 };
 
 
@@ -106,8 +129,15 @@ gal_options_common_argp_parse(int key, char *arg, struct 
argp_state *state);
 /************            Configuration files            ***************/
 /**********************************************************************/
 void
-gal_options_config_files(char *progname, struct argp_option *poptions,
-                         struct argp_option *coptions);
+gal_options_config_files(char *prog_exec, char *prog_name,
+                         struct argp_option *poptions,
+                         struct argp_option *coptions,
+                         struct gal_options_common_params *cp);
+
+void
+gal_options_print_state(char *prog_name, char *prog_bibtex,
+                        struct argp_option *poptions,
+                        struct argp_option *coptions);
 
 
 #endif



reply via email to

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