gnuastro-commits
[Top][All Lists]
Advanced

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

[gnuastro-commits] master 26cdc23: More clear names for functions in `ty


From: Mohammad Akhlaghi
Subject: [gnuastro-commits] master 26cdc23: More clear names for functions in `type.h'
Date: Sat, 29 Apr 2017 21:09:02 -0400 (EDT)

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

    More clear names for functions in `type.h'
    
    Some of the functions in `type.h' have been renamed to be more clear, for
    example `gal_type_to_string' has been renamed to `gal_type_name', so it
    doesn't get confused with converting a given number to a string. Generally,
    the functions in this header have been managed better and as discussed
    below, some `data.h' functions have been moved to `type.h'.
    
    Until now, the there were several extra functions in `data.h' to do with a
    single element on a dataset's array. But they were out of place there since
    that header is for very basic operations on a whole dataset. While writing
    the manual, I they were moved to the `type.h' header because they fit
    better there (these functions were at a lower level). Also the
    `gal_data_copy_element_same_type' was removed and in the few places that it
    was used, we are now using `memcpy' along with `gal_data_ptr_increment'.
    
    Also, the old `gal_data_copy_to_new_type_to_allocated' has been removed
    since it was actually never used! Its functionality has been moved to
    `gal_data_copy_to_allocated'.
---
 bin/arithmetic/arithmetic.c |   2 +-
 bin/convertt/ui.c           |   6 +-
 bin/crop/ui.c               |   6 +-
 bin/fits/fits.c             |   2 +-
 bin/mkcatalog/ui.c          |   6 +-
 bin/noisechisel/detection.c |   2 +-
 bin/noisechisel/sky.c       |   2 +-
 bin/statistics/statistics.c |  12 +-
 bin/statistics/ui.c         |   2 +-
 doc/gnuastro.texi           | 156 ++++++++++++++---
 lib/arithmetic-onlyint.c    |   2 +-
 lib/arithmetic.c            |   6 +-
 lib/binary.c                |   6 +-
 lib/blank.c                 |   2 +-
 lib/convolve.c              |   3 +-
 lib/data.c                  | 408 ++++++--------------------------------------
 lib/fits.c                  |   8 +-
 lib/gnuastro/data.h         |  34 +---
 lib/gnuastro/type.h         |  28 ++-
 lib/options.c               |  20 +--
 lib/statistics.c            |  37 ++--
 lib/table.c                 |   8 +-
 lib/txt.c                   |  10 +-
 lib/type.c                  | 280 +++++++++++++++++++++++++++++-
 24 files changed, 567 insertions(+), 481 deletions(-)

diff --git a/bin/arithmetic/arithmetic.c b/bin/arithmetic/arithmetic.c
index 95ddf58..ed00325 100644
--- a/bin/arithmetic/arithmetic.c
+++ b/bin/arithmetic/arithmetic.c
@@ -152,7 +152,7 @@ reversepolish(struct imgarithparams *p)
          operation on them. */
       if(gal_fits_name_is_fits(token->v))
         add_operand(p, token->v, NULL);
-      else if( (d1=gal_data_string_to_number(token->v)) )
+      else if( (d1=gal_data_copy_string_to_number(token->v)) )
         add_operand(p, NULL, d1);
       else
         {
diff --git a/bin/convertt/ui.c b/bin/convertt/ui.c
index 01dbd40..053947f 100644
--- a/bin/convertt/ui.c
+++ b/bin/convertt/ui.c
@@ -244,7 +244,7 @@ ui_read_check_only_options(struct converttparams *p)
      is indeed smaller than fluxhigh. */
   if(p->fluxlowstr)
     {
-      p->fluxlow=gal_data_string_to_number(p->fluxlowstr);
+      p->fluxlow=gal_data_copy_string_to_number(p->fluxlowstr);
       if(p->fluxlow==NULL)
         error(EXIT_FAILURE, 0, "value to the `--fluxlow' (`-L', %s) "
               "couldn't be read as a number", p->fluxlowstr);
@@ -252,7 +252,7 @@ ui_read_check_only_options(struct converttparams *p)
 
   if(p->fluxhighstr)
     {
-      p->fluxhigh=gal_data_string_to_number(p->fluxhighstr);
+      p->fluxhigh=gal_data_copy_string_to_number(p->fluxhighstr);
       if(p->fluxhigh==NULL)
         error(EXIT_FAILURE, 0, "value to the `--fluxhigh' (`-H', %s) "
               "couldn't be read as a number", p->fluxhighstr);
@@ -337,7 +337,7 @@ ui_make_change_struct(char *arg)
         {
           /* Read the number and increment the counter. */
           ++counter;
-          data=gal_data_string_to_number(p);
+          data=gal_data_copy_string_to_number(p);
           if(data==NULL)
             error(EXIT_FAILURE, 0, "`%s' (input number %zu to the "
                   "`--change' option) couldn't be read as a number", p,
diff --git a/bin/crop/ui.c b/bin/crop/ui.c
index 0142e9b..f5371fa 100644
--- a/bin/crop/ui.c
+++ b/bin/crop/ui.c
@@ -713,9 +713,9 @@ ui_preparations(struct cropparams *p)
                   "information (press `SPACE' for going down and `q' to "
                   "return to the command-line):\n\n"
                   "    $ info Arithmetic\n",
-                  img->name, gal_type_to_string(p->type, 1),
-                  gal_type_to_string(firsttype, 1), img->name,
-                  gal_type_to_string(p->type, 1));
+                  img->name, gal_type_name(p->type, 1),
+                  gal_type_name(firsttype, 1), img->name,
+                  gal_type_name(p->type, 1));
         }
 
       /* In WCS mode, Check resolution and get the first pixel
diff --git a/bin/fits/fits.c b/bin/fits/fits.c
index 7a3c5d4..1d3d649 100644
--- a/bin/fits/fits.c
+++ b/bin/fits/fits.c
@@ -139,7 +139,7 @@ fits_print_extension_info(struct fitsparams *p)
         {
         case IMAGE_HDU:
           gal_fits_img_info(fptr, &type, &ndim, &dsize);
-          tstr=gal_type_to_string(type , 1);
+          tstr=gal_type_name(type , 1);
           break;
 
         case ASCII_TBL:
diff --git a/bin/mkcatalog/ui.c b/bin/mkcatalog/ui.c
index 1541bd1..0fc988e 100644
--- a/bin/mkcatalog/ui.c
+++ b/bin/mkcatalog/ui.c
@@ -463,12 +463,12 @@ ui_preparations_read_inputs(struct mkcatalogparams *p)
         asprintf(&namestypes, "However, `%s' (hdu: %s) and `%s' (hdu: %s) "
                  "have types of `%s' and `%s' respectively", objectsfile,
                  p->objectshdu, clumpsfile, p->clumpshdu,
-                 gal_type_to_string(p->objects->type, 1),
-                 gal_type_to_string(p->clumps->type, 1) );
+                 gal_type_name(p->objects->type, 1),
+                 gal_type_name(p->clumps->type, 1) );
       else
         asprintf(&namestypes, "However, %s (hdu: %s) has a type of %s",
                  objectsfile, p->objectshdu,
-                 gal_type_to_string(p->objects->type, 1));
+                 gal_type_name(p->objects->type, 1));
       error(EXIT_FAILURE, 0, "labeled images (for objects or clumps) must "
             "have an integer datatype. %s.\n\n"
             "If you are sure the images contain only integer values but "
diff --git a/bin/noisechisel/detection.c b/bin/noisechisel/detection.c
index fc7aaaf..f528927 100644
--- a/bin/noisechisel/detection.c
+++ b/bin/noisechisel/detection.c
@@ -449,7 +449,7 @@ detection_sn(struct noisechiselparams *p, gal_data_t 
*worklab, size_t num,
   /* Sanity check. */
   if(p->input->type!=GAL_TYPE_FLOAT32)
     error(EXIT_FAILURE, 0, "%s: the input dataset must be float32 type, "
-          "it is %s", __func__, gal_type_to_string(p->input->type, 1));
+          "it is %s", __func__, gal_type_name(p->input->type, 1));
   if(!isnan(GAL_BLANK_FLOAT32))
     error(EXIT_FAILURE, 0, "%s: only a NaN value is recognized for blank "
           "floating point data types, the blank value is defined to be %f",
diff --git a/bin/noisechisel/sky.c b/bin/noisechisel/sky.c
index 96e6f24..92ee414 100644
--- a/bin/noisechisel/sky.c
+++ b/bin/noisechisel/sky.c
@@ -242,7 +242,7 @@ sky_subtract(struct noisechiselparams *p)
   if(p->sky->type!=GAL_TYPE_FLOAT32)
     error(EXIT_FAILURE, 0, "%s: only `float32' type is acceptable "
           "for sky values. but `p->sky' has type `%s'", __func__,
-          gal_type_to_string(p->sky->type, 1));
+          gal_type_name(p->sky->type, 1));
 
   /* Go over all the tiles. */
   for(tid=0; tid<p->cp.tl.tottiles; ++tid)
diff --git a/bin/statistics/statistics.c b/bin/statistics/statistics.c
index 3502157..a873d32 100644
--- a/bin/statistics/statistics.c
+++ b/bin/statistics/statistics.c
@@ -60,7 +60,9 @@ statistics_pull_out_element(gal_data_t *input, size_t index)
   size_t dsize=1;
   gal_data_t *out=gal_data_alloc(NULL, input->type, 1, &dsize,
                                  NULL, 1, -1, NULL, NULL, NULL);
-  gal_data_copy_element_same_type(input, index, out->array);
+  memcpy( out->array,
+          gal_data_ptr_increment(input->array, index, input->type),
+          gal_type_sizeof(input->type) );
   return out;
 }
 
@@ -187,7 +189,7 @@ statistics_print_one_row(struct statisticsparams *p)
         }
 
       /* Print the number. */
-      toprint=gal_data_write_to_string(out->array, out->type, 0);
+      toprint=gal_type_to_string(out->array, out->type, 0);
       printf("%s ", toprint);
       free(toprint);
 
@@ -767,14 +769,14 @@ print_basics(struct statisticsparams *p)
 
   /* Minimum: */
   tmp=gal_statistics_minimum(p->input);
-  str=gal_data_write_to_string(tmp->array, tmp->type, 0);
+  str=gal_type_to_string(tmp->array, tmp->type, 0);
   printf("  %-*s %s\n", namewidth, "Minimum:", str);
   gal_data_free(tmp);
   free(str);
 
   /* Maximum: */
   tmp=gal_statistics_maximum(p->input);
-  str=gal_data_write_to_string(tmp->array, tmp->type, 0);
+  str=gal_type_to_string(tmp->array, tmp->type, 0);
   printf("  %-*s %s\n", namewidth, "Maximum:", str);
   gal_data_free(tmp);
   free(str);
@@ -801,7 +803,7 @@ print_basics(struct statisticsparams *p)
 
   /* Find and print the median:  */
   tmp=gal_statistics_median(p->input, 0);
-  str=gal_data_write_to_string(tmp->array, tmp->type, 0);
+  str=gal_type_to_string(tmp->array, tmp->type, 0);
   printf("  %-*s %s\n", namewidth, "Median:", str);
   gal_data_free(tmp);
   free(str);
diff --git a/bin/statistics/ui.c b/bin/statistics/ui.c
index b6b6607..662717a 100644
--- a/bin/statistics/ui.c
+++ b/bin/statistics/ui.c
@@ -750,7 +750,7 @@ ui_read_columns(struct statisticsparams *p)
         case GAL_TYPE_COMPLEX64:
           error(EXIT_FAILURE, 0, " read column number %zu has a %s type, "
                 "which is not currently supported by %s", counter,
-                gal_type_to_string(tmp->type, 1), PROGRAM_NAME);
+                gal_type_name(tmp->type, 1), PROGRAM_NAME);
         }
 
       /* Put the column into the proper pointer. */
diff --git a/doc/gnuastro.texi b/doc/gnuastro.texi
index 1e7a97f..a232cd9 100644
--- a/doc/gnuastro.texi
+++ b/doc/gnuastro.texi
@@ -547,10 +547,10 @@ Gnuastro library
 
 Data container (@file{data.h})
 
-* Generic data container::
-* Dataset size and allocation::
-* Arrays of datasets::
-* Copying datasets::
+* Generic data container::      Definition of Gnuastro's generic container.
+* Dataset size and allocation::  Functions for size and allocation.
+* Arrays of datasets::          Functions to help with array of datasets.
+* Copying datasets::            Functions to copy a dataset to a new one.
 
 Linked lists (@file{linkedlist.h})
 
@@ -16788,20 +16788,24 @@ Return the number of bytes occurpied by @code{type}. 
Internally, this
 function uses C's @code{sizeof} operator to measure the size of each type.
 @end deftypefun
 
address@hidden {char *} gal_type_to_string (uint8_t @code{type}, int 
@code{long_name})
-Return a string that contains the name of the type. This can be used in
address@hidden {char *} gal_type_name (uint8_t @code{type}, int 
@code{long_name})
+Return a string that contains the name of @code{type}. This can be used in
 messages to the users when your function/program accepts many types. It can
-return two types of string identifiers (short like @code{f32} or long like
address@hidden). The output string is statically allocated, so it should
-not be freed. The strings it will return for each type are the identifiers
-of the types in @ref{Numeric data types}.
+return both short and long formats of the type names (for example
address@hidden and @code{float32}). If @code{long_name} is non-zero, the long
+format will be returned, otherwise the short name will be returned. The
+output string is statically allocated, so it should not be freed. This
+function is the inverse of the @code{gal_type_from_name} function. For the
+full list of names/strings that this function will return, see @ref{Numeric
+data types}.
 @end deftypefun
 
address@hidden uint8_t gal_type_from_string (char @code{*str})
address@hidden uint8_t gal_type_from_name (char @code{*str})
 Return the Gnuastro integer constant that corresponds to the string
address@hidden This is effectively the inverse of the
address@hidden function and accepts both the short and long
-formats of each type.
address@hidden This function is the inverse of the @code{gal_type_name}
+function and accepts both the short and long formats of each type. For the
+full list of names/strings that this function will return, see @ref{Numeric
+data types}.
 @end deftypefun
 
 @deftypefun void gal_type_min (uint8_t @code{type}, void @code{*in})
@@ -16836,7 +16840,7 @@ Note: Do not use the maximum value for a blank value of 
a general
 @ref{Library blank values} for the definition and usage of blank values.
 @end deftypefun
 
address@hidden int gal_type_is_linked_list (uint8_t @code{type})
address@hidden int gal_type_is_list (uint8_t @code{type})
 Return 1 if the type is a linked list and zero otherwise.
 @end deftypefun
 
@@ -16859,7 +16863,7 @@ free(bitstr);
 @end example
 
 @noindent
-It will produce:
+which will produce:
 @example
 2017: 11100001000001110000000000000000  (7E1)
 @end example
@@ -16871,6 +16875,66 @@ use @code{printf}'s @code{%x} or @code{%X} to print 
integers in hexadecimal
 format.
 @end deftypefun
 
address@hidden {char *} gal_type_to_string (void @code{*ptr}, uint8_t 
@code{type}, int @code{quote_if_str_has_space});
+Read the contents of the memory that @code{ptr} points to (assuming it has
+type @code{type} and print it into an allocated string which is returned.
+
+If the memory is a string of characters and @code{quote_if_str_has_space}
+is non-zero, the output string will have double-quotes around it if it
+contains space characters. Also, note that in this case, @code{ptr} must be
+a pointer to an array of characters (or @code{char **}), as in the example
+below (which will put @code{"sample string"} into @code{out}):
+
address@hidden
+char *out, *string="sample string"
+out = gal_type_to_string(&string, GAL_TYPE_STRING, 1);
address@hidden example
address@hidden deftypefun
+
address@hidden 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
address@hidden When @code{*out!=NULL}, then it is assumed to be already
+allocated and the value will be simply put the memory. If
address@hidden, 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
+interpretted as @code{char **} (one element in an array of pointers to
+different strings). In other words, @code{out} should be @code{char ***}.
+
+This function can be used to fill in arrays of numbers from strings (in an
+already allocated data structure), or add nodes to a linked list (if the
+type is a list type). For an array, you have to pass the pointer to the
address@hidden element where you want the value to be stored, for example
address@hidden&(array[i]}).
+
+If the string was successfully parsed to the requested type, this function
+will return a @code{0} (zero), otherwise it will return @code{1}
+(one). This output format will help you check the status of the conversion
+in a code like the example below:
+
address@hidden
+if( gal_type_from_string(&out, string, GAL_TYPE_FLOAT32) )
+  @{
+    fprintf(stderr, "%s couldn't be read as float32.\n", string);
+    exit(EXIT_FAILURE);
+  @}
address@hidden example
address@hidden deftypefun
+
+
+
address@hidden {void *} gal_type_string_to_number (char @code{*string}, uint8_t 
@code{*type})
+Read @code{string} into smallest type that can host the number, the
+allocated space for the number will be returned and the type of the number
+will be put into the memory that @code{type} points to. If @code{string}
+couldn't be read as a number, this function will return @code{NULL}.
+
+For the ranges acceptable by each type see @ref{Numeric data types}. For
+integers it is clear, for floating point types, this function will count
+the number of significant digits and determine if the given string is
+single or double precision as described in that section.
address@hidden deftypefun
 
 @node Library blank values, Library data container, Library data types, 
Gnuastro library
 @subsection Library blank values (@file{blank.h})
@@ -17041,10 +17105,10 @@ dataset, the name of the dataset and some comments. 
To deal with any
 generic dataset, Gnuastro defines the @code{gal_data_t} as input or output.
 
 @menu
-* Generic data container::
-* Dataset size and allocation::
-* Arrays of datasets::
-* Copying datasets::
+* Generic data container::      Definition of Gnuastro's generic container.
+* Dataset size and allocation::  Functions for size and allocation.
+* Arrays of datasets::          Functions to help with array of datasets.
+* Copying datasets::            Functions to copy a dataset to a new one.
 @end menu
 
 @node Generic data container, Dataset size and allocation, Library data 
container, Library data container
@@ -17520,10 +17584,60 @@ given datset into another. The new dataset can have a 
different type
 values will be written into it). In all these cases, if the input dataset
 is a tile, only the data within the tile are copied.
 
+In many of the functions here, it is possible to copy the dataset to a new
+numeric data type (see @ref{Numeric data types}. In such cases, Gnuastro's
+library is going to use the native conversion by C. So if you are
+converting to a smaller type, it is up to you to make sure that the values
+fit into the output type.
+
 @deftypefun {gal_data_t *} gal_data_copy (gal_data_t @code{*in})
-Return a new dataset that is a copy of @code{in}.
+Return a new dataset that is a copy of @code{in}, the main meta-data of the
+input is also copied into the output.
address@hidden deftypefun
+
address@hidden {gal_data_t *} gal_data_copy_to_new_type (gal_data_t @code{*in}, 
uint8_t @code{newtype})
+Return a copy of the dataset @code{in}, converted to @code{newtype}, see
address@hidden data types} for Gnuastro library's type identifiers. The
+returned dataset will have all meta-data accept their type equal to the
+input's metadata.
address@hidden deftypefun
+
address@hidden {gal_data_t *} gal_data_copy_to_new_type_free (gal_data_t 
@code{*in}, uint8_t @code{newtype})
+Return a copy of the dataset @code{in} that is converted to @code{newtype}
+and free the input dataset. See @ref{Library data types} for Gnuastro
+library's type identifiers. The returned dataset will have all meta-data,
+except their type, equal to the input's metadata. This function is similar
+to @code{gal_data_copy_to_new_type}, except that it will free the input
+dataset.
 @end deftypefun
 
address@hidden {void} gal_data_copy_to_allocated (gal_data_t @code{*in}, 
gal_data_t @code{*out})
+Copy the contents of the array in @code{in} into the already allocated
+array in @code{out}. The types of the input and output may be different,
+type conversion will be done internally. When @code{in->size != out->size}
+this function will behave as follows:
+
address@hidden @code
address@hidden out->size < in->size
+This function won't re-allocate the necessary space, it will abort with an
+error, so please check before calling this function.
+
address@hidden out->size > in->size
+This function will write the values in @code{out->size} and
address@hidden>dsize} from the same values of @code{in}. So if you want to use
+a pre-allocated space/dataset multiple times with varying input sizes, be
+sure to reset @code{out->size} before every call to this function.
address@hidden table
address@hidden deftypefun
+
address@hidden {gal_data_t *} gal_data_copy_string_to_number (char 
@code{*string})
+Read @code{string} into the smallest type that can store the value (see
address@hidden data types}). This function is just a wrapper for the
address@hidden, but will put the value into a
+single-element dataset.
address@hidden deftypefun
+
+
 @node Linked lists, Table input output, Library data container, Gnuastro 
library
 @subsection Linked lists (@file{linkedlist.h})
 
diff --git a/lib/arithmetic-onlyint.c b/lib/arithmetic-onlyint.c
index b776496..53db601 100644
--- a/lib/arithmetic-onlyint.c
+++ b/lib/arithmetic-onlyint.c
@@ -315,7 +315,7 @@ arithmetic_onlyint_binary(int operator, unsigned char flags,
           "and `q' to return to the command-line):\n\n"
           "    $ info gnuastro \"Gnuastro configure options\"\n",
           gal_arithmetic_operator_string(operator),
-          gal_type_to_string(lo->type, 1), gal_type_to_string(ro->type, 1));
+          gal_type_name(lo->type, 1), gal_type_name(ro->type, 1));
 
   /* Set the output type. */
   otype=gal_type_out(l->type, r->type);
diff --git a/lib/arithmetic.c b/lib/arithmetic.c
index 7055de8..969a9b0 100644
--- a/lib/arithmetic.c
+++ b/lib/arithmetic.c
@@ -238,7 +238,7 @@ arithmetic_check_float_input(gal_data_t *in, int operator, 
char *numstr)
             "after it so it is directly read into the proper precision "
             "floating point number (based on the number of non-zero "
             "decimals it has)", gal_arithmetic_operator_string(operator),
-            numstr, gal_type_to_string(in->type, 1));
+            numstr, gal_type_name(in->type, 1));
     }
 }
 
@@ -615,7 +615,7 @@ arithmetic_where(unsigned char flags, gal_data_t *out, 
gal_data_t *cond,
   if(cond->type!=GAL_TYPE_UINT8)
     error(EXIT_FAILURE, 0, "%s: the condition operand must be an "
           "`uint8' type, but the given condition operand has a "
-          "`%s' type", __func__, gal_type_to_string(cond->type, 1));
+          "`%s' type", __func__, gal_type_name(cond->type, 1));
 
   /* The dimension and sizes of the out and condition data sets must be the
      same. */
@@ -1325,7 +1325,7 @@ gal_arithmetic_convert_to_compiled_type(gal_data_t *in, 
unsigned char flags)
         }
       else
         {
-          typestring=gal_type_to_string(in->type, 1);
+          typestring=gal_type_name(in->type, 1);
           error(EXIT_FAILURE, 0, "The given %s type data given to "
                 "binary operators is not compiled for native operation "
                 "and no larger types are compiled either.\n\nThe "
diff --git a/lib/binary.c b/lib/binary.c
index 67fd22c..8ac04af 100644
--- a/lib/binary.c
+++ b/lib/binary.c
@@ -383,7 +383,7 @@ gal_binary_connected_components(gal_data_t *binary, 
gal_data_t **out,
       if( lab->type!=GAL_TYPE_INT32 )
         error(EXIT_FAILURE, 0, "%s: the `out' dataset must have `int32' type"
               "but the array you have given is `%s' type", __func__,
-              gal_type_to_string(lab->type, 1));
+              gal_type_name(lab->type, 1));
 
       /* Reset all its values to zero. */
       memset(lab->array, 0, lab->size * gal_type_sizeof(lab->type));
@@ -487,7 +487,7 @@ gal_binary_connected_adjacency_matrix(gal_data_t *adjacency,
   if(adjacency->type != GAL_TYPE_UINT8)
     error(EXIT_FAILURE, 0, "%s: input must have type `uint8'. However, the "
           "input dataset has type of `%s'", __func__,
-          gal_type_to_string(adjacency->type, 1));
+          gal_type_name(adjacency->type, 1));
 
   if(adjacency->ndim != 2)
     error(EXIT_FAILURE, 0, "%s: input must be 2-dimensional (a matrix)."
@@ -673,7 +673,7 @@ gal_binary_fill_holes(gal_data_t *input)
   if( input->type != GAL_TYPE_UINT8 )
     error(EXIT_FAILURE, 0, "%s: input must have `uint8' type, but its "
           "input dataset has `%s' type", __func__,
-          gal_type_to_string(input->type, 1));
+          gal_type_name(input->type, 1));
 
 
   /* Make the inverse image. */
diff --git a/lib/blank.c b/lib/blank.c
index 8cc48e4..80ed2e2 100644
--- a/lib/blank.c
+++ b/lib/blank.c
@@ -288,7 +288,7 @@ gal_blank_flag(gal_data_t *input)
         case GAL_TYPE_COMPLEX32:
         case GAL_TYPE_COMPLEX64:
           error(EXIT_FAILURE, 0, "%s: %s type not yet supported",
-                __func__, gal_type_to_string(input->type, 1));
+                __func__, gal_type_name(input->type, 1));
 
           /* Bad input. */
         default:
diff --git a/lib/convolve.c b/lib/convolve.c
index 93ba823..608c005 100644
--- a/lib/convolve.c
+++ b/lib/convolve.c
@@ -618,8 +618,7 @@ gal_convolve_spatial_correct_ch_edge(gal_data_t *tiles, 
gal_data_t *kernel,
     error(EXIT_FAILURE, 0, "%s: the `tocorrect' dataset has to have the same "
           "type as the block of the `tiles' input. The given types are `%s' "
           "and `%s' respectively", __func__,
-          gal_type_to_string(tocorrect->type, 1),
-          gal_type_to_string(block->type, 1));
+          gal_type_name(tocorrect->type, 1), gal_type_name(block->type, 1));
 
   /* Call the general function, which will do the correction. */
   gal_convolve_spatial_general(tiles, kernel, numthreads,
diff --git a/lib/data.c b/lib/data.c
index de3163b..e06c243 100644
--- a/lib/data.c
+++ b/lib/data.c
@@ -548,7 +548,7 @@ data_copy_to_string_not_parsed(char *string, void *to, 
uint8_t type)
     gal_blank_write(to, type);
   else
     error(EXIT_FAILURE, 0, "%s: `%s' couldn't be parsed as `%s' type",
-          __func__, string, gal_type_to_string(type, 1));
+          __func__, string, gal_type_name(type, 1));
 }
 
 
@@ -594,7 +594,7 @@ data_copy_from_string(gal_data_t *from, gal_data_t *to)
         case GAL_TYPE_COMPLEX32:
         case GAL_TYPE_COMPLEX64:
           error(EXIT_FAILURE, 0, "%s: copying to %s type not currently "
-                "supported", __func__, gal_type_to_string(to->type, 1));
+                "supported", __func__, gal_type_name(to->type, 1));
           break;
 
         default:
@@ -607,7 +607,7 @@ data_copy_from_string(gal_data_t *from, gal_data_t *to)
         gal_checkset_allocate_copy(strarr[i], &outstrarr[i]);
       else
         {
-          if( gal_data_string_to_type(&ptr, strarr[i], to->type) )
+          if( gal_type_from_string(&ptr, strarr[i], to->type) )
             data_copy_to_string_not_parsed(strarr[i], ptr, to->type);
         }
     }
@@ -699,7 +699,7 @@ data_copy_to_string(gal_data_t *from, gal_data_t *to)
     case GAL_TYPE_COMPLEX32:
     case GAL_TYPE_COMPLEX64:
       error(EXIT_FAILURE, 0, "%s: copying to %s type not currently supported",
-            __func__, gal_type_to_string(from->type, 1));
+            __func__, gal_type_name(from->type, 1));
       break;
 
     default:
@@ -791,7 +791,7 @@ data_copy_to_string(gal_data_t *from, gal_data_t *to)
     case GAL_TYPE_COMPLEX64:                                            \
       error(EXIT_FAILURE, 0, "%s: copying from %s type to a numeric "   \
             "(real) type not supported", "COPY_OT_SET",                 \
-            gal_type_to_string(in->type, 1));                           \
+            gal_type_name(in->type, 1));                                \
       break;                                                            \
                                                                         \
     default:                                                            \
@@ -816,16 +816,6 @@ gal_data_copy(gal_data_t *in)
 
 
 
-/* Copy the input dataset into the already allocated space of out. */
-void
-gal_data_copy_to_allocated(gal_data_t *in, gal_data_t *out)
-{
-  gal_data_copy_to_new_type_to_allocated(in, out, out->type);
-}
-
-
-
-
 
 /* Copy a given data structure to a new one with any type (for the
    output). The input can be a tile, in which case the output will be a
@@ -841,7 +831,7 @@ gal_data_copy_to_new_type(gal_data_t *in, uint8_t newtype)
                      0, in->minmapsize, in->name, in->unit, in->comment);
 
   /* Fill in the output array: */
-  gal_data_copy_to_new_type_to_allocated(in, out, newtype);
+  gal_data_copy_to_allocated(in, out);
 
   /* Return the created array */
   return out;
@@ -851,6 +841,40 @@ gal_data_copy_to_new_type(gal_data_t *in, uint8_t newtype)
 
 
 
+/* Copy the input data structure into a new type and free the allocated
+   space. */
+gal_data_t *
+gal_data_copy_to_new_type_free(gal_data_t *in, uint8_t newtype)
+{
+  gal_data_t *out, *iblock=gal_tile_block(in);
+
+  /* In a general application, it might happen that the type is equal with
+     the type of the input and the input isn't a tile. Since the job of
+     this function is to free the input dataset, and the user just wants
+     one dataset after this function finishes, we can safely just return
+     the input. */
+  if(newtype==iblock->type && in==iblock)
+    return in;
+  else
+    {
+      out=gal_data_copy_to_new_type(in, newtype);
+      if(iblock==in)
+        gal_data_free(in);
+      else
+        fprintf(stderr, "#####\nWarning from "
+                "`gal_data_copy_to_new_type_free'\n#####\n The input "
+                "dataset is a tile, not a contiguous (fully allocated) "
+                "patch of memory. So it has not been freed. Please use "
+                "`gal_data_copy_to_new_type' to avoid this warning.\n"
+                "#####");
+      return out;
+    }
+}
+
+
+
+
+
 /* Copy a given dataset (`in') into an already allocated dataset `out' (the
    actual dataset and its `array' element). The meta-data of `in' will be
    fully copied into `out' also. `out->size' will be used to find the
@@ -867,8 +891,7 @@ gal_data_copy_to_new_type(gal_data_t *in, uint8_t newtype)
           pre-allocated space with varying input sizes, be sure to reset
           `out->size' before every call to this function. */
 void
-gal_data_copy_to_new_type_to_allocated(gal_data_t *in, gal_data_t *out,
-                                       uint8_t newtype)
+gal_data_copy_to_allocated(gal_data_t *in, gal_data_t *out)
 {
   gal_data_t *iblock=gal_tile_block(in);
 
@@ -911,7 +934,7 @@ gal_data_copy_to_new_type_to_allocated(gal_data_t *in, 
gal_data_t *out,
     case GAL_TYPE_COMPLEX32:
     case GAL_TYPE_COMPLEX64:
       error(EXIT_FAILURE, 0, "%s: copying to %s type not yet supported",
-            __func__, gal_type_to_string(out->type, 1));
+            __func__, gal_type_name(out->type, 1));
       break;
 
     default:
@@ -931,344 +954,17 @@ gal_data_copy_to_new_type_to_allocated(gal_data_t *in, 
gal_data_t *out,
 
 
 
-/* Copy the input data structure into a new type and free the allocated
-   space. */
+/* Just a wrapper around `gal_type_from_string_auto', to return a
+   `gal_data_t' dataset hosting the allocated number. */
 gal_data_t *
-gal_data_copy_to_new_type_free(gal_data_t *in, uint8_t type)
-{
-  gal_data_t *out, *iblock=gal_tile_block(in);
-
-  /* In a general application, it might happen that the type is equal with
-     the type of the input and the input isn't a tile. Since the job of
-     this function is to free the input dataset, and the user just wants
-     one dataset after this function finishes, we can safely just return
-     the input. */
-  if(type==iblock->type && in==iblock)
-    return in;
-  else
-    {
-      out=gal_data_copy_to_new_type(in, type);
-      if(iblock==in)
-        gal_data_free(in);
-      else
-        fprintf(stderr, "#####\nWarning from "
-                "`gal_data_copy_to_new_type_free'\n#####\n The input "
-                "dataset is a tile, not a contiguous (fully allocated) "
-                "patch of memory. So it has not been freed. Please use "
-                "`gal_data_copy_to_new_type' to avoid this warning.\n"
-                "#####");
-      return out;
-    }
-}
-
-
-
-
-
-/* Copy/read the element at `index' of the array in `data' into the space
-   pointed to by `ptr'. */
-#define COPY_ELEM(IT) {                                                 \
-    IT *restrict o=ptr, *restrict a=input->array; *o = a[index];        \
-}
-void
-gal_data_copy_element_same_type(gal_data_t *input, size_t index, void *ptr)
-{
-  /* Set the value. */
-  switch(input->type)
-    {
-    case GAL_TYPE_UINT8:     COPY_ELEM( uint8_t  );    break;
-    case GAL_TYPE_INT8:      COPY_ELEM( int8_t   );    break;
-    case GAL_TYPE_UINT16:    COPY_ELEM( uint16_t );    break;
-    case GAL_TYPE_INT16:     COPY_ELEM( int16_t  );    break;
-    case GAL_TYPE_UINT32:    COPY_ELEM( uint32_t );    break;
-    case GAL_TYPE_INT32:     COPY_ELEM( int32_t  );    break;
-    case GAL_TYPE_UINT64:    COPY_ELEM( uint64_t );    break;
-    case GAL_TYPE_INT64:     COPY_ELEM( int64_t  );    break;
-    case GAL_TYPE_FLOAT32:   COPY_ELEM( float    );    break;
-    case GAL_TYPE_FLOAT64:   COPY_ELEM( double   );    break;
-    default:
-      error(EXIT_FAILURE, 0, "%s: type code %d not recognized", __func__,
-            input->type);
-    }
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-/*************************************************************
- **************              Write             ***************
- *************************************************************/
-#define WRITE_TO_STRING(CTYPE, FMT) asprintf(&str, FMT, *(CTYPE *)ptr);
-
-char *
-gal_data_write_to_string(void *ptr, uint8_t type, int quote_if_str_has_space)
-{
-  char *c, *str=NULL;
-  switch(type)
-    {
-    /* For a string we might need to make sure it has no white space
-       characters, if it does, it can be printed it within quotation
-       signs. */
-    case GAL_TYPE_STRING:
-      if(quote_if_str_has_space)
-        {
-          c=*(char **)ptr; while(*c!='\0') if(isspace(*c++)) break;
-          if(*c=='\0') asprintf(&str, "%s",      *(char **)ptr);
-          else         asprintf(&str, "\"%s\" ", *(char **)ptr);
-        }
-      else
-        asprintf(&str, "%s", *(char **)ptr);
-      break;
-
-    case GAL_TYPE_UINT8:   WRITE_TO_STRING( uint8_t,  "%"PRIu8  );  break;
-    case GAL_TYPE_INT8:    WRITE_TO_STRING( int8_t,   "%"PRId8  );  break;
-    case GAL_TYPE_UINT16:  WRITE_TO_STRING( uint16_t, "%"PRIu16 );  break;
-    case GAL_TYPE_INT16:   WRITE_TO_STRING( int16_t,  "%"PRId16 );  break;
-    case GAL_TYPE_UINT32:  WRITE_TO_STRING( uint32_t, "%"PRIu32 );  break;
-    case GAL_TYPE_INT32:   WRITE_TO_STRING( int32_t,  "%"PRId32 );  break;
-    case GAL_TYPE_UINT64:  WRITE_TO_STRING( uint64_t, "%"PRIu64 );  break;
-    case GAL_TYPE_INT64:   WRITE_TO_STRING( int64_t,  "%"PRId64 );  break;
-    case GAL_TYPE_FLOAT32: WRITE_TO_STRING( float,    "%.6g"    );  break;
-    case GAL_TYPE_FLOAT64: WRITE_TO_STRING( double,   "%.10g"   );  break;
-
-    default:
-      error(EXIT_FAILURE, 0, "%s: type code %d not recognized", __func__, 
type);
-    }
-  return str;
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-/*************************************************************
- **************              Read              ***************
- *************************************************************/
-/* If the data structure was correctly created (the string was a number),
-   then return its pointer. Otherwise, return NULL. */
-gal_data_t *
-gal_data_string_to_number(char *string)
+gal_data_copy_string_to_number(char *string)
 {
   void *ptr;
-  gal_data_t *out;
-  int fnz=-1, lnz=0;     /* `F'irst (or `L'ast) `N'on-`Z'ero. */
-  char *tailptr, *cp;
-  size_t dsize[1]={1};
-  uint8_t type, forcedfloat=0;
-
-  /* Define initial spaces to keep the value. */
-  uint8_t   u8;   int8_t   i8;      uint16_t u16;   int16_t i16;
-  uint32_t u32;   int32_t i32;      uint64_t u64;   int64_t i64;
-  float      f;   double    d;
-
-  /* First see if the number is a double (the most generic). */
-  d=strtod(string, &tailptr);
-  if(*tailptr=='f') { if(tailptr[1]=='\0') forcedfloat=1; else return NULL; }
-  else if (*tailptr!='\0')  return NULL;
-
-  /* See if the number is actually an integer: */
-  if( forcedfloat==0 && ceil(d) == d )
-    {
-      /* If the number is negative, put it in the signed types (based on
-         its value). If its zero or positive, then put it in the unsigned
-         types. */
-      if( d < 0 )
-        {
-          if     (d>INT8_MIN)    {i8=d;  ptr=&i8;  type=GAL_TYPE_INT8;}
-          else if(d>INT16_MIN)   {i16=d; ptr=&i16; type=GAL_TYPE_INT16;}
-          else if(d>INT32_MIN)   {i32=d; ptr=&i32; type=GAL_TYPE_INT32;}
-          else                   {i64=d; ptr=&i64; type=GAL_TYPE_INT64;}
-        }
-      else
-        {
-          if     (d<=UINT8_MAX)  {u8=d;  ptr=&u8;  type=GAL_TYPE_UINT8;}
-          else if(d<=UINT16_MAX) {u16=d; ptr=&u16; type=GAL_TYPE_UINT16;}
-          else if(d<=UINT32_MAX) {u32=d; ptr=&u32; type=GAL_TYPE_UINT32;}
-          else                   {u64=d; ptr=&u64; type=GAL_TYPE_UINT64;}
-        }
-    }
-  else
-    {
-      /* The maximum number of decimal digits to store in float or double
-         precision floating point are:
-
-         float:  23 mantissa bits + 1 hidden bit: log(224)÷log(10) = 7.22
-         double: 52 mantissa bits + 1 hidden bit: log(253)÷log(10) = 15.95
-
-         FLT_DIG (at least 6 in ISO C) keeps the number of digits (not zero
-         before or after) that can be represented by a single precision
-         floating point number. If there are more digits, then we should
-         store the value as a double precision.
-
-         Note that the number can have non-digit characters that we don't
-         want, like: `.', `e', `E', `,'. */
-      for(cp=string;*cp!='\0';++cp)
-        if(isdigit(*cp) && *cp!='0' && fnz==-1)
-          fnz=cp-string;
-
-      /* In the previous loop, we went to the end of the string, so `cp'
-         now points to its `\0'. We just have to iterate backwards! */
-      for(;cp!=string;--cp)
-        if(isdigit(*cp) && *cp!='0')
-          {
-            lnz=cp-string;
-            break;
-          }
-
-      /* Calculate the number of decimal digits and decide if it the number
-         should be a float or a double. */
-      if( lnz-fnz < FLT_DIG || ( d<FLT_MAX && d>FLT_MIN ) )
-        { f=d; ptr=&f; type=GAL_TYPE_FLOAT32; }
-      else
-        {      ptr=&d; type=GAL_TYPE_FLOAT64; }
-    }
-
-  /* Allocate a one-element dataset, then copy the number into it. */
-  out=gal_data_alloc(NULL, type, 1, dsize, NULL, 0, -1, NULL, NULL, NULL);
-  memcpy(out->array, ptr, gal_type_sizeof(type));
-  return out;
-}
-
-
-
-
-
-/* Read a string as a given data type and put a the pointer to it in
-   *out. When the input `*out!=NULL', then it is assumed to be allocated
-   and the value will be simply put there. If `*out==NULL', then space will
-   be allocated for the given type and the string's value (in the given
-   type) will be stored there.
-
-   Note that when we are dealing with a string type, `*out' should be
-   interpretted as `char **' (one element in an array of pointers to
-   different strings). In other words, `out' should be `char ***'.
-
-   This function can be used to fill in arrays of numbers from strings (in
-   an already allocated data structure), or add nodes to a linked list. For
-   an array, you have to pass the pointer to the `i'th element where you
-   want the value to be stored, for example &(array[i]).
-
-   If parsing was successful, it will return a 0. If there was a problem,
-   it will return 1.  */
-int
-gal_data_string_to_type(void **out, char *string, uint8_t type)
-{
-  long l;
-  double d;
-  void *value;
-  char *tailptr;
-  int status=0, allocated=0;
-
-  /* If the output is NULL, then allocate the necessary space if we are not
-     dealing with a linked list. In a linked list, a NULL value is
-     meaningful (it is the end of the list). */
-  if( *out==NULL && !gal_type_is_linked_list(type) )
-    {
-      allocated=1;
-      *out=gal_data_malloc_array(type, 1);
-    }
-  value=*out;
-
-  /* Read the string depending on the type. */
-  switch(type)
-    {
-
-    /* Linked lists, currently only string linked lists. */
-    case GAL_TYPE_STRLL:
-      gal_list_str_add( (struct gal_list_str_t **)out, string, 1);
-      break;
-
-    /* String, just allocate and copy the string and keep its pointer in
-       the place `*out' points to (for strings, `*out' is `char **'). */
-    case GAL_TYPE_STRING:
-      gal_checkset_allocate_copy(string, value);
-      break;
-
-    /* Floating point: Read it as a double or long, then put it in the
-       array. When the conversion can't be done (the string isn't a number
-       for example), then just assume no blank value was given. */
-    case GAL_TYPE_FLOAT32:
-    case GAL_TYPE_FLOAT64:
-      d=strtod(string, &tailptr);
-      if(*tailptr!='\0')
-        status=1;
-      else
-        {
-          if(type==GAL_TYPE_FLOAT32) *(float *) value=d;
-          else                            *(double *) value=d;
-        }
-      break;
-
-    /* Integers. */
-    default:
-      l=strtol(string, &tailptr, 0);
-      if(*tailptr!='\0')
-        status=1;
-      else
-        switch(type)
-          {
-          /* The signed values can easily be put in. */
-          case GAL_TYPE_INT8:         *(int8_t *)    value = l; break;
-          case GAL_TYPE_INT16:        *(int16_t *)   value = l; break;
-          case GAL_TYPE_INT32:        *(int32_t *)   value = l; break;
-          case GAL_TYPE_INT64:        *(int64_t *)   value = l; break;
-
-          /* For the unsigned types, the value has to be positive, so if
-             the input was negative, then just return a status of one and
-             don't store the value. */
-          default:
-            if(l<0)
-              status=1;
-            else
-              switch(type)
-                {
-                case GAL_TYPE_UINT8:  *(uint8_t *)   value=l;   break;
-                case GAL_TYPE_UINT16: *(uint16_t *)  value=l;   break;
-                case GAL_TYPE_UINT32: *(uint32_t *)  value=l;   break;
-                case GAL_TYPE_UINT64: *(uint64_t *)  value=l;   break;
-                default:
-                  error(EXIT_FAILURE, 0, "%s: type code %d not recognized",
-                        __func__, type);
-                }
-          }
-    }
-
-  /* If reading was unsuccessful, then free the space if it was allocated,
-     then return the status, don't touch the pointer. */
-  if(status && allocated)
-    {
-      free(*out);
-      *out=NULL;
-    }
-  return status;
+  uint8_t type;
+  size_t dsize=1;
+  ptr=gal_type_string_to_number(string, &type);
+  return ( ptr
+           ? gal_data_alloc(ptr, type, 1, &dsize, NULL, 0, -1,
+                            NULL, NULL, NULL)
+           : NULL );
 }
diff --git a/lib/fits.c b/lib/fits.c
index 31069d0..bdaac68 100644
--- a/lib/fits.c
+++ b/lib/fits.c
@@ -218,7 +218,7 @@ gal_fits_type_to_bitpix(uint8_t type)
     case GAL_TYPE_COMPLEX32:
     case GAL_TYPE_COMPLEX64:
       error(EXIT_FAILURE, 0, "%s: type %s not recognized for FITS image "
-            "BITPIX", __func__, gal_type_to_string(type, 1));
+            "BITPIX", __func__, gal_type_name(type, 1));
 
     default:
       error(EXIT_FAILURE, 0, "%s: type value of %d not recognized",
@@ -258,7 +258,7 @@ gal_fits_type_to_bin_tform(uint8_t type)
     /* Not recognized by CFITSIO. */
     case GAL_TYPE_UINT64:
       error(EXIT_FAILURE, 0, "%s: type %s not recognized for FITS binary "
-            "table TFORM", __func__, gal_type_to_string(type, 1));
+            "table TFORM", __func__, gal_type_name(type, 1));
       break;
 
     /* Wrong type code. */
@@ -342,12 +342,12 @@ gal_fits_type_to_datatype(uint8_t type)
   if(w)
     error(EXIT_FAILURE, 0, "%s: this system doesn't have a %d byte integer "
           "type, so type `%s' cannot be written to FITS", __func__, w,
-          gal_type_to_string(type, 1));
+          gal_type_name(type, 1));
   else
     error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at %s so we can "
           "fix the problem. Control must not have reached the end for the "
           "given type `%s'", __func__, PACKAGE_BUGREPORT,
-          gal_type_to_string(type, 1));
+          gal_type_name(type, 1));
   return -1;
 }
 
diff --git a/lib/gnuastro/data.h b/lib/gnuastro/data.h
index dfe6c14..15761c9 100644
--- a/lib/gnuastro/data.h
+++ b/lib/gnuastro/data.h
@@ -287,45 +287,17 @@ gal_data_array_free(gal_data_t *dataarr, size_t num, int 
free_array);
 gal_data_t *
 gal_data_copy(gal_data_t *in);
 
-void
-gal_data_copy_to_allocated(gal_data_t *in, gal_data_t *out);
-
 gal_data_t *
 gal_data_copy_to_new_type(gal_data_t *in, uint8_t newtype);
 
-void
-gal_data_copy_to_new_type_to_allocated(gal_data_t *in, gal_data_t *out,
-                                       uint8_t newtype);
-
 gal_data_t *
-gal_data_copy_to_new_type_free(gal_data_t *in, uint8_t type);
+gal_data_copy_to_new_type_free(gal_data_t *in, uint8_t newtype);
 
 void
-gal_data_copy_element_same_type(gal_data_t *input, size_t index, void *ptr);
-
-
-
-
-
-/*************************************************************
- **************              Write             ***************
- *************************************************************/
-char *
-gal_data_write_to_string(void *ptr, uint8_t type, int quote_if_str_has_space);
-
-
-
-
+gal_data_copy_to_allocated(gal_data_t *in, gal_data_t *out);
 
-/*************************************************************
- **************              Read              ***************
- *************************************************************/
 gal_data_t *
-gal_data_string_to_number(char *string);
-
-int
-gal_data_string_to_type(void **out, char *string, uint8_t type);
-
+gal_data_copy_string_to_number(char *string);
 
 
 __END_C_DECLS    /* From C++ preparations */
diff --git a/lib/gnuastro/type.h b/lib/gnuastro/type.h
index 3a1c605..e40aca5 100644
--- a/lib/gnuastro/type.h
+++ b/lib/gnuastro/type.h
@@ -103,16 +103,16 @@ enum gal_types
 
 
 /*************************************************************
- **************           Functions            ***************
+ **************         General info           ***************
  *************************************************************/
 size_t
 gal_type_sizeof(uint8_t type);
 
 char *
-gal_type_to_string(uint8_t type, int long_name);
+gal_type_name(uint8_t type, int long_name);
 
 uint8_t
-gal_type_from_string(char *str);
+gal_type_from_name(char *str);
 
 void
 gal_type_min(uint8_t type, void *in);
@@ -121,14 +121,34 @@ void
 gal_type_max(uint8_t type, void *in);
 
 int
-gal_type_is_linked_list(uint8_t type);
+gal_type_is_list(uint8_t type);
 
 int
 gal_type_out(int first_type, int second_type);
 
+
+
+
+
+/*************************************************************
+ **************         To/from string         ***************
+ *************************************************************/
+
 char *
 gal_type_bit_string(void *in, size_t size);
 
+char *
+gal_type_to_string(void *ptr, uint8_t type, int quote_if_str_has_space);
+
+int
+gal_type_from_string(void **out, char *string, uint8_t type);
+
+void *
+gal_type_string_to_number(char *string, uint8_t *type);
+
+
+
+
 
 __END_C_DECLS    /* From C++ preparations */
 
diff --git a/lib/options.c b/lib/options.c
index 7172e83..611fd71 100644
--- a/lib/options.c
+++ b/lib/options.c
@@ -403,7 +403,7 @@ gal_options_read_type(struct argp_option *option, char *arg,
       /* Note that `gal_data_type_as_string' returns a static string. But
          the output must be an allocated string so we can free it. */
       gal_checkset_allocate_copy(
-           gal_type_to_string( *(uint8_t *)(option->value), 1), &str);
+           gal_type_name( *(uint8_t *)(option->value), 1), &str);
       return str;
     }
   else
@@ -412,7 +412,7 @@ gal_options_read_type(struct argp_option *option, char *arg,
       if(option->set) return NULL;
 
       /* Read the value. */
-      if ( (*(uint8_t *)(option->value) = gal_type_from_string(arg) )
+      if ( (*(uint8_t *)(option->value) = gal_type_from_name(arg) )
            == GAL_TYPE_INVALID )
         error_at_line(EXIT_FAILURE, 0, filename, lineno, "`%s' (value to "
                       "`%s' option) couldn't be recognized as a known "
@@ -916,7 +916,7 @@ gal_options_read_check(struct argp_option *option, char 
*arg, char *filename,
           if(option->set==GAL_OPTIONS_SET) return;
 
           /* Read the string argument into the value. */
-          if( gal_data_string_to_type(&option->value, arg, option->type) )
+          if( gal_type_from_string(&option->value, arg, option->type) )
             /* Fortunately `error_at_line' will behave like `error' when the
                filename is NULL (the option was read from a command-line). */
             error_at_line(EXIT_FAILURE, 0, filename, lineno,
@@ -952,8 +952,8 @@ gal_options_read_check(struct argp_option *option, char 
*arg, char *filename,
               "correct it. Options with no arguments, must have "
               "type `%s'. However, the `%s' option has type %s",
               __func__, PACKAGE_BUGREPORT,
-              gal_type_to_string(GAL_OPTIONS_NO_ARG_TYPE, 1),
-              option->name, gal_type_to_string(option->type, 1));
+              gal_type_name(GAL_OPTIONS_NO_ARG_TYPE, 1),
+              option->name, gal_type_name(option->type, 1));
     }
 
 
@@ -1010,7 +1010,7 @@ gal_options_set_from_key(int key, char *arg, struct 
argp_option *options,
              As a result, only when searching for options on the
              command-line, a second value to the same option will replace
              the first one. This will not happen in configuration files. */
-          if(options[i].set && gal_type_is_linked_list(options[i].type)==0)
+          if(options[i].set && gal_type_is_list(options[i].type)==0)
             options[i].set=GAL_OPTIONS_NOT_SET;
 
           /* Parse the value. */
@@ -1188,7 +1188,7 @@ options_set_from_name(char *name, char *arg,  struct 
argp_option *options,
                  list. */
           if( options[i].flags==OPTION_HIDDEN
               || ( options[i].set
-                   && !gal_type_is_linked_list(options[i].type ) ) )
+                   && !gal_type_is_list(options[i].type ) ) )
             return 0;
 
           /* Read the value into the option and do a sanity check. */
@@ -1504,7 +1504,7 @@ options_print_any_type(struct argp_option *option, void 
*ptr, int type,
   /* Write the value into a string. */
   str = ( option->func
           ? option->func(option, NULL, NULL, (size_t)(-1), cp->program_struct)
-          : gal_data_write_to_string(ptr, type, 1) );
+          : gal_type_to_string(ptr, type, 1) );
 
   /* If only the width was desired, don't actually print the string, just
      return its length. Otherwise, print it. */
@@ -1538,7 +1538,7 @@ options_correct_max_lengths(struct argp_option *option, 
int *max_nlen,
 
   /* Get the length of the value and save its length length if its
      larger than the widest value. */
-  if(gal_type_is_linked_list(option->type))
+  if(gal_type_is_list(option->type))
     {
       /* A small sanity check. */
       if(option->type!=GAL_TYPE_STRLL)
@@ -1668,7 +1668,7 @@ options_print_all_in_group(struct argp_option *options, 
int groupint,
         && option_is_printable(&options[i]) )  /* Is relevant for printing.*/
       {
         /* Linked lists */
-        if(gal_type_is_linked_list(options[i].type))
+        if(gal_type_is_list(options[i].type))
           for(tmp=*(gal_list_str_t **)(options[i].value);
               tmp!=NULL; tmp=tmp->next)
             {
diff --git a/lib/statistics.c b/lib/statistics.c
index 0daa22e..419b9af 100644
--- a/lib/statistics.c
+++ b/lib/statistics.c
@@ -27,6 +27,7 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 #include <errno.h>
 #include <error.h>
 #include <float.h>
+#include <string.h>
 #include <stdint.h>
 #include <stdlib.h>
 
@@ -320,8 +321,9 @@ gal_statistics_quantile(gal_data_t *input, double quantile, 
int inplace)
   /* Find the index of the quantile. */
   index=gal_statistics_quantile_index(nbs->size, quantile);
 
-  /* Read the value at this index into the output. */
-  gal_data_copy_element_same_type(nbs, index, out->array);
+  /* Write the value at this index into the output. */
+  memcpy(out->array, gal_data_ptr_increment(nbs->array, index, nbs->type),
+         gal_type_sizeof(nbs->type));
 
   /* Clean up and return. */
   if(nbs!=input) gal_data_free(nbs);
@@ -828,8 +830,8 @@ gal_statistics_mode(gal_data_t *input, float mirrordist, 
int inplace)
   size_t dsize=4, mdsize=1;
   struct statistics_mode_params p;
   int type=gal_tile_block(input)->type;
-  gal_data_t *mode=gal_data_alloc(NULL, type, 1, &mdsize, NULL, 1, -1,
-                                  NULL, NULL, NULL);
+  gal_data_t *tmptype=gal_data_alloc(NULL, type, 1, &mdsize, NULL, 1, -1,
+                                     NULL, NULL, NULL);
   gal_data_t *b_val=gal_data_alloc(NULL, type, 1, &mdsize, NULL, 1, -1,
                                    NULL, NULL, NULL);
   gal_data_t *out=gal_data_alloc(NULL, GAL_TYPE_FLOAT64, 1, &dsize,
@@ -838,8 +840,9 @@ gal_statistics_mode(gal_data_t *input, float mirrordist, 
int inplace)
 
   /* A small sanity check. */
   if(mirrordist<=0)
-    error(EXIT_FAILURE, 0, "%s: %f not acceptable as a value to `mirrordist'. "
-          "Only positive values can be given to it", __func__, mirrordist);
+    error(EXIT_FAILURE, 0, "%s: %f not acceptable as a value to "
+          "`mirrordist'. Only positive values can be given to it",
+          __func__, mirrordist);
 
 
   /* Make sure the input doesn't have blank values and is sorted.  */
@@ -879,15 +882,21 @@ gal_statistics_mode(gal_data_t *input, float mirrordist, 
int inplace)
 
 
   /* Do the golden-section search iteration, read the mode value from the
-     input array and save it as the first element of the output dataset's
-     array, then free the `mode' structure. */
+     input array and save it in the `tmptype' data structure that has the
+     same type as the input. */
   modeindex = mode_golden_section(&p);
-  gal_data_copy_element_same_type(p.data, modeindex, mode->array);
-  mode=gal_data_copy_to_new_type_free(mode, GAL_TYPE_FLOAT64);
-  gal_data_copy_element_same_type(mode, 0, &oa[0]);
+  memcpy( tmptype->array,
+          gal_data_ptr_increment(p.data->array, modeindex, p.data->type),
+          gal_type_sizeof(p.data->type) );
 
 
-  /* Put in the rest of the values of the output structure. */
+  /* Convert the mode (which is in the same type as the input at this
+     stage) to float64. */
+  tmptype=gal_data_copy_to_new_type_free(tmptype, GAL_TYPE_FLOAT64);
+
+
+  /* Put the first three values into the output structure. */
+  oa[0] = *((double *)(tmptype->array));
   oa[1] = ((double)modeindex) / ((double)(p.data->size-1));
   oa[2] = mode_symmetricity(&p, modeindex, b_val->array);
 
@@ -897,7 +906,7 @@ gal_statistics_mode(gal_data_t *input, float mirrordist, 
int inplace)
   if(oa[2]>GAL_STATISTICS_MODE_GOOD_SYM)
     {
       b_val=gal_data_copy_to_new_type_free(b_val, GAL_TYPE_FLOAT64);
-      gal_data_copy_element_same_type(b_val, 0, &oa[3]);
+      oa[3] = *((double *)(b_val->array));
     }
   else oa[0]=oa[1]=oa[2]=oa[3]=NAN;
 
@@ -909,8 +918,8 @@ gal_statistics_mode(gal_data_t *input, float mirrordist, 
int inplace)
 
   /* Clean up (if necessary), then return the output */
   if(p.data!=input) gal_data_free(p.data);
+  gal_data_free(tmptype);
   gal_data_free(b_val);
-  gal_data_free(mode);
   return out;
 }
 
diff --git a/lib/table.c b/lib/table.c
index 1814dc3..17f1f23 100644
--- a/lib/table.c
+++ b/lib/table.c
@@ -237,8 +237,8 @@ gal_table_print_info(gal_data_t *allcols, size_t numcols, 
size_t numrows)
       if(allcols[i].unit && strlen(allcols[i].unit)>uw)
         uw=strlen(allcols[i].unit);
       if(allcols[i].type
-         && strlen(gal_type_to_string(allcols[i].type, 1))>tw)
-        tw=strlen(gal_type_to_string(allcols[i].type, 1));
+         && strlen(gal_type_name(allcols[i].type, 1))>tw)
+        tw=strlen(gal_type_name(allcols[i].type, 1));
     }
 
   /* We want one column space between the columns for readability, not the
@@ -262,7 +262,7 @@ gal_table_print_info(gal_data_t *allcols, size_t numcols, 
size_t numrows)
       printf("%-*zu%-*s%-*s%-*s%s\n", Nw, i+1,
              nw, name ? name : GAL_BLANK_STRING ,
              uw, unit ? unit : GAL_BLANK_STRING ,
-             tw, gal_type_to_string(allcols[i].type, 1),
+             tw, gal_type_name(allcols[i].type, 1),
              comment ? comment : GAL_BLANK_STRING);
     }
 
@@ -460,7 +460,7 @@ gal_table_read_blank(gal_data_t *col, char *blank)
      `gal_data_string_to_type' will return 0. In that case, we need to
      initialize the necessary paramters to read this data structure
      correctly. */
-  if( !gal_data_string_to_type(&colarr, blank, col->type) )
+  if( !gal_type_from_string(&colarr, blank, col->type) )
     {
       errno=0;
       col->dsize=malloc(sizeof *col->dsize);
diff --git a/lib/txt.c b/lib/txt.c
index f67e6dd..bfe4e0c 100644
--- a/lib/txt.c
+++ b/lib/txt.c
@@ -245,7 +245,7 @@ txt_info_from_comment(char *line, gal_data_t **datall, char 
*comm_start)
             }
           else
             {
-              type=gal_type_from_string(typestr);
+              type=gal_type_from_name(typestr);
               if(type==GAL_TYPE_INVALID) return;
             }
         }
@@ -746,7 +746,7 @@ txt_read_token(gal_data_t *data, gal_data_t *info, char 
*token,
   if(data->type!=GAL_TYPE_STRING && *tailptr!='\0')
     error_at_line(EXIT_FAILURE, 0, filename, lineno, "column %zu "
                   "(`%s') couldn't be read as a `%s' number",
-                  colnum, token, gal_type_to_string(data->type, 1) );
+                  colnum, token, gal_type_name(data->type, 1) );
 }
 
 
@@ -1081,10 +1081,10 @@ make_fmts_for_printf(gal_data_t *datall, int 
leftadjust, size_t *len)
       /* Set the string for the Gnuastro type. For strings, we also need to
          write the maximum number of characters.*/
       if(data->type==GAL_TYPE_STRING)
-        sprintf(fmts[i*FMTS_COLS+1], "%s%d",
-                gal_type_to_string(data->type, 0), data->disp_width);
+        sprintf(fmts[i*FMTS_COLS+1], "%s%d", gal_type_name(data->type, 0),
+                data->disp_width);
       else
-        strcpy(fmts[i*FMTS_COLS+1], gal_type_to_string(data->type, 0));
+        strcpy(fmts[i*FMTS_COLS+1], gal_type_name(data->type, 0));
 
 
       /* Increment the column counter. */
diff --git a/lib/type.c b/lib/type.c
index 12a644b..3dca101 100644
--- a/lib/type.c
+++ b/lib/type.c
@@ -26,14 +26,24 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 #include <errno.h>
 #include <error.h>
 #include <float.h>
+#include <ctype.h>
 #include <stdlib.h>
 #include <string.h>
+#include <inttypes.h>
 
 #include <gnuastro/type.h>
 #include <gnuastro/data.h>
+#include <gnuastro/list.h>
+#include <gnuastro-internal/checkset.h>
 
 
 
+
+
+
+/*************************************************************
+ **************         General info           ***************
+ *************************************************************/
 size_t
 gal_type_sizeof(uint8_t type)
 {
@@ -100,7 +110,7 @@ gal_type_sizeof(uint8_t type)
 
 
 char *
-gal_type_to_string(uint8_t type, int long_name)
+gal_type_name(uint8_t type, int long_name)
 {
   switch(type)
     {
@@ -167,7 +177,7 @@ gal_type_to_string(uint8_t type, int long_name)
 
 
 uint8_t
-gal_type_from_string(char *str)
+gal_type_from_name(char *str)
 {
   if(      !strcmp(str, "b")     || !strcmp(str, "bit") )
     return GAL_TYPE_BIT;
@@ -281,7 +291,7 @@ gal_type_max(uint8_t type, void *in)
    that work on both, it is convenient to simiplify the check with this
    function. */
 int
-gal_type_is_linked_list(uint8_t type)
+gal_type_is_list(uint8_t type)
 {
   return type==GAL_TYPE_STRLL;
 }
@@ -300,6 +310,24 @@ gal_type_out(int first_type, int second_type)
 
 
 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/*************************************************************
+ **************         To/from string         ***************
+ *************************************************************/
 /* Write the bit (0 or 1) contents of `in' into a string ready for
    printing. `size' is used to determine the number of bytes to print. The
    output string will be dynamically allocated within this function. This
@@ -327,3 +355,249 @@ gal_type_bit_string(void *in, size_t size)
   /* Return the allocated and filled string. */
   return str;
 }
+
+
+
+
+
+/* Write the contents of memory that `ptr' points to as a string of type
+   `type'.*/
+#define TO_STRING(CTYPE, FMT) asprintf(&str, FMT, *(CTYPE *)ptr);
+char *
+gal_type_to_string(void *ptr, uint8_t type, int quote_if_str_has_space)
+{
+  char *c, *str=NULL;
+  switch(type)
+    {
+    /* For a string we might need to make sure it has no white space
+       characters, if it does, it can be printed it within quotation
+       signs. */
+    case GAL_TYPE_STRING:
+      if(quote_if_str_has_space)
+        {
+          c=*(char **)ptr; while(*c!='\0') if(isspace(*c++)) break;
+          if(*c=='\0') asprintf(&str, "%s",      *(char **)ptr);
+          else         asprintf(&str, "\"%s\" ", *(char **)ptr);
+        }
+      else
+        asprintf(&str, "%s", *(char **)ptr);
+      break;
+
+    case GAL_TYPE_UINT8:   TO_STRING( uint8_t,  "%"PRIu8  );  break;
+    case GAL_TYPE_INT8:    TO_STRING( int8_t,   "%"PRId8  );  break;
+    case GAL_TYPE_UINT16:  TO_STRING( uint16_t, "%"PRIu16 );  break;
+    case GAL_TYPE_INT16:   TO_STRING( int16_t,  "%"PRId16 );  break;
+    case GAL_TYPE_UINT32:  TO_STRING( uint32_t, "%"PRIu32 );  break;
+    case GAL_TYPE_INT32:   TO_STRING( int32_t,  "%"PRId32 );  break;
+    case GAL_TYPE_UINT64:  TO_STRING( uint64_t, "%"PRIu64 );  break;
+    case GAL_TYPE_INT64:   TO_STRING( int64_t,  "%"PRId64 );  break;
+    case GAL_TYPE_FLOAT32: TO_STRING( float,    "%.6g"    );  break;
+    case GAL_TYPE_FLOAT64: TO_STRING( double,   "%.10g"   );  break;
+
+    default:
+      error(EXIT_FAILURE, 0, "%s: type code %d not recognized",
+            __func__, type);
+    }
+  return str;
+}
+
+
+
+
+
+/* Read a string as a given data type and put a the pointer to it in
+   *out. When the input `*out!=NULL', then it is assumed to be allocated
+   and the value will be simply put there. If `*out==NULL', then space will
+   be allocated for the given type and the string's value (in the given
+   type) will be stored there.
+
+   Note that when we are dealing with a string type, `*out' should be
+   interpretted as `char **' (one element in an array of pointers to
+   different strings). In other words, `out' should be `char ***'.
+
+   This function can be used to fill in arrays of numbers from strings (in
+   an already allocated data structure), or add nodes to a linked list. For
+   an array, you have to pass the pointer to the `i'th element where you
+   want the value to be stored, for example &(array[i]).
+
+   If parsing was successful, it will return a 0. If there was a problem,
+   it will return 1.  */
+int
+gal_type_from_string(void **out, char *string, uint8_t type)
+{
+  long l;
+  double d;
+  void *value;
+  char *tailptr;
+  int status=0, allocated=0;
+
+  /* If the output is NULL, then allocate the necessary space if we are not
+     dealing with a linked list. In a linked list, a NULL value is
+     meaningful (it is the end of the list). */
+  if( *out==NULL && !gal_type_is_list(type) )
+    {
+      allocated=1;
+      *out=gal_data_malloc_array(type, 1);
+    }
+  value=*out;
+
+  /* Read the string depending on the type. */
+  switch(type)
+    {
+
+    /* Linked lists, currently only string linked lists. */
+    case GAL_TYPE_STRLL:
+      gal_list_str_add( (struct gal_list_str_t **)out, string, 1);
+      break;
+
+    /* String, just allocate and copy the string and keep its pointer in
+       the place `*out' points to (for strings, `*out' is `char **'). */
+    case GAL_TYPE_STRING:
+      gal_checkset_allocate_copy(string, value);
+      break;
+
+    /* Floating point: Read it as a double or long, then put it in the
+       array. When the conversion can't be done (the string isn't a number
+       for example), then just assume no blank value was given. */
+    case GAL_TYPE_FLOAT32:
+    case GAL_TYPE_FLOAT64:
+      d=strtod(string, &tailptr);
+      if(*tailptr!='\0')
+        status=1;
+      else
+        {
+          if(type==GAL_TYPE_FLOAT32) *(float *) value=d;
+          else                            *(double *) value=d;
+        }
+      break;
+
+    /* Integers. */
+    default:
+      l=strtol(string, &tailptr, 0);
+      if(*tailptr!='\0')
+        status=1;
+      else
+        switch(type)
+          {
+          /* The signed values can easily be put in. */
+          case GAL_TYPE_INT8:         *(int8_t *)    value = l; break;
+          case GAL_TYPE_INT16:        *(int16_t *)   value = l; break;
+          case GAL_TYPE_INT32:        *(int32_t *)   value = l; break;
+          case GAL_TYPE_INT64:        *(int64_t *)   value = l; break;
+
+          /* For the unsigned types, the value has to be positive, so if
+             the input was negative, then just return a status of one and
+             don't store the value. */
+          default:
+            if(l<0)
+              status=1;
+            else
+              switch(type)
+                {
+                case GAL_TYPE_UINT8:  *(uint8_t *)   value=l;   break;
+                case GAL_TYPE_UINT16: *(uint16_t *)  value=l;   break;
+                case GAL_TYPE_UINT32: *(uint32_t *)  value=l;   break;
+                case GAL_TYPE_UINT64: *(uint64_t *)  value=l;   break;
+                default:
+                  error(EXIT_FAILURE, 0, "%s: type code %d not recognized",
+                        __func__, type);
+                }
+          }
+    }
+
+  /* If reading was unsuccessful, then free the space if it was allocated,
+     then return the status, don't touch the pointer. */
+  if(status && allocated)
+    {
+      free(*out);
+      *out=NULL;
+    }
+  return status;
+}
+
+
+
+
+
+/* If the data structure was correctly created (the string was a number),
+   then return its pointer. Otherwise, return NULL. */
+void *
+gal_type_string_to_number(char *string, uint8_t *type)
+{
+  void *ptr, *out;
+  int fnz=-1, lnz=0;     /* `F'irst (or `L'ast) `N'on-`Z'ero. */
+  char *tailptr, *cp;
+  uint8_t forcedfloat=0;
+
+  /* Define initial spaces to keep the value. */
+  uint8_t   u8;   int8_t   i8;      uint16_t u16;   int16_t i16;
+  uint32_t u32;   int32_t i32;      uint64_t u64;   int64_t i64;
+  float      f;   double    d;
+
+  /* First see if the number is a double (the most generic). */
+  d=strtod(string, &tailptr);
+  if(*tailptr=='f') { if(tailptr[1]=='\0') forcedfloat=1; else return NULL; }
+  else if (*tailptr!='\0')  return NULL;
+
+  /* See if the number is actually an integer: */
+  if( forcedfloat==0 && ceil(d) == d )
+    {
+      /* If the number is negative, put it in the signed types (based on
+         its value). If its zero or positive, then put it in the unsigned
+         types. */
+      if( d < 0 )
+        {
+          if     (d>INT8_MIN)    { i8=d;  ptr=&i8;  *type=GAL_TYPE_INT8;   }
+          else if(d>INT16_MIN)   { i16=d; ptr=&i16; *type=GAL_TYPE_INT16;  }
+          else if(d>INT32_MIN)   { i32=d; ptr=&i32; *type=GAL_TYPE_INT32;  }
+          else                   { i64=d; ptr=&i64; *type=GAL_TYPE_INT64;  }
+        }
+      else
+        {
+          if     (d<=UINT8_MAX)  { u8=d;  ptr=&u8;  *type=GAL_TYPE_UINT8;  }
+          else if(d<=UINT16_MAX) { u16=d; ptr=&u16; *type=GAL_TYPE_UINT16; }
+          else if(d<=UINT32_MAX) { u32=d; ptr=&u32; *type=GAL_TYPE_UINT32; }
+          else                   { u64=d; ptr=&u64; *type=GAL_TYPE_UINT64; }
+        }
+    }
+  else
+    {
+      /* The maximum number of decimal digits to store in float or double
+         precision floating point are:
+
+         float:  23 mantissa bits + 1 hidden bit: log(224)÷log(10) = 7.22
+         double: 52 mantissa bits + 1 hidden bit: log(253)÷log(10) = 15.95
+
+         FLT_DIG (at least 6 in ISO C) keeps the number of digits (not zero
+         before or after) that can be represented by a single precision
+         floating point number. If there are more digits, then we should
+         store the value as a double precision.
+
+         Note that the number can have non-digit characters that we don't
+         want, like: `.', `e', `E', `,'. */
+      for(cp=string;*cp!='\0';++cp)
+        if(isdigit(*cp) && *cp!='0' && fnz==-1)
+          fnz=cp-string;
+
+      /* In the previous loop, we went to the end of the string, so `cp'
+         now points to its `\0'. We just have to iterate backwards! */
+      for(;cp!=string;--cp)
+        if(isdigit(*cp) && *cp!='0')
+          {
+            lnz=cp-string;
+            break;
+          }
+
+      /* Calculate the number of decimal digits and decide if it the number
+         should be a float or a double. */
+      if( lnz-fnz < FLT_DIG || ( d<FLT_MAX && d>FLT_MIN ) )
+        { f=d; ptr=&f; *type=GAL_TYPE_FLOAT32; }
+      else
+        {      ptr=&d; *type=GAL_TYPE_FLOAT64; }
+    }
+
+  /* Allocate a one-element dataset, then copy the number into it. */
+  out=gal_data_malloc_array(*type, 1);
+  memcpy(out, ptr, gal_type_sizeof(*type));
+  return out;
+}



reply via email to

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