[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[gnuastro-commits] master b78b0c7 16/16: New Table utility merged
From: |
Mohammad Akhlaghi |
Subject: |
[gnuastro-commits] master b78b0c7 16/16: New Table utility merged |
Date: |
Wed, 24 Aug 2016 22:27:45 +0000 (UTC) |
branch: master
commit b78b0c7e19d537f12f582a1f183a7548a946b182
Merge: 56bd4e5 b16c7a4
Author: Mohammad Akhlaghi <address@hidden>
Commit: Mohammad Akhlaghi <address@hidden>
New Table utility merged
The commits of the Table utility are now merged into the main history-line
of Gnuastro.
---
Makefile.am | 5 +-
bootstrap.conf | 1 +
configure.ac | 12 +-
doc/gnuastro.texi | 263 ++++++++++-
genauthors | 2 +
lib/checkset.c | 54 ++-
lib/fits.c | 568 ++++++++++++++++++----
lib/gnuastro/checkset.h | 3 +
lib/gnuastro/fits.h | 55 ++-
lib/gnuastro/linkedlist.h | 4 +-
lib/gnuastro/txtarray.h | 4 +
lib/linkedlist.c | 13 +-
lib/txtarray.c | 7 +-
src/imgcrop/crop.c | 36 +-
src/imgcrop/imgcrop.c | 4 +-
src/imgcrop/ui.c | 4 +-
src/mkcatalog/ui.c | 2 +-
src/table/Makefile.am | 41 ++
src/table/args.h | 371 +++++++++++++++
src/table/asttable.conf | 32 ++
src/table/cite.h | 38 ++
src/table/main.c | 56 +++
src/table/main.h | 126 +++++
src/table/table.c | 437 +++++++++++++++++
src/table/table.h | 31 ++
src/table/ui.c | 1041 +++++++++++++++++++++++++++++++++++++++++
src/table/ui.h | 39 ++
tests/Makefile.am | 6 +-
tests/during-dev.sh | 22 +-
tests/prepconf.sh | 2 +-
tests/table/asciitobinary.sh | 51 ++
tests/table/asciitobinary.txt | 2 +
tests/table/binarytoascii.sh | 51 ++
33 files changed, 3211 insertions(+), 172 deletions(-)
diff --git a/Makefile.am b/Makefile.am
index 1559349..1c819fa 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -88,6 +88,9 @@ endif
if COND_SUBTRACTSKY
MAYBE_SUBTRACTSKY = src/subtractsky
endif
+if COND_TABLE
+ MAYBE_TABLE = src/table
+endif
#if COND_TEMPLATE
# MAYBE_TEMPLATE = src/TEMPLATE
#endif
@@ -105,7 +108,7 @@ SUBDIRS = bootstrapped/lib $(MAYBE_GNULIBCHECK) lib
$(MAYBE_ARITHMETIC) \
$(MAYBE_CONVERTT) $(MAYBE_CONVOLVE) $(MAYBE_COSMICCAL) $(MAYBE_HEADER) \
$(MAYBE_IMGCROP) $(MAYBE_IMGSTAT) $(MAYBE_IMGWARP) $(MAYBE_MKCATALOG) \
$(MAYBE_MKNOISE) $(MAYBE_MKPROF) $(MAYBE_NOISECHISEL) $(MAYBE_SUBTRACTSKY) \
-$(MAYBE_TEMPLATE) doc tests
+$(MAYBE_TABLE) $(MAYBE_TEMPLATE) doc tests
diff --git a/bootstrap.conf b/bootstrap.conf
index 88ca654..1783522 100644
--- a/bootstrap.conf
+++ b/bootstrap.conf
@@ -161,6 +161,7 @@ gnulib_modules="
fdl
math
argp
+ regex
error
nproc
strcase
diff --git a/configure.ac b/configure.ac
index 33b40cd..c3d54f5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -299,10 +299,16 @@ AC_ARG_ENABLE([noisechisel],
[enable_noisechisel=notset])
AC_ARG_ENABLE([subtractsky],
[AS_HELP_STRING([--enable-subtractsky],
- [Install SubtractSky and other enabled packages only.])],
+ [Install SubtractSky and other enabled packages only.])],
[AS_IF([test "x$enable_subtractsky" != xno],
[enable_subtractsky=yes; ayes=true])],
[enable_subtractsky=notset])
+AC_ARG_ENABLE([table],
+ [AS_HELP_STRING([--enable-table],
+ [Install Table and other enabled packages only.])],
+ [AS_IF([test "x$enable_table" != xno],
+ [enable_table=yes; ayes=true])],
+ [enable_table=notset])
#AC_ARG_ENABLE([TEMPLATE],
# [AS_HELP_STRING([--enable-TEMPLATE],
# [Install TEMPLATE and other enabled packages only.])],
@@ -337,6 +343,7 @@ AS_IF([test $ayes = true ],
AS_IF([test $enable_mkprof = notset], [enable_mkprof=no])
AS_IF([test $enable_noisechisel = notset], [enable_noisechisel=no])
AS_IF([test $enable_subtractsky = notset], [enable_subtractsky=no])
+ AS_IF([test $enable_table = notset], [enable_table=no])
# AS_IF([test $enable_TEMPLATE = notset], [enable_TEMPLATE=no])
],
@@ -353,6 +360,7 @@ AS_IF([test $ayes = true ],
AS_IF([test $enable_mkprof = notset], [enable_mkprof=yes])
AS_IF([test $enable_noisechisel = notset], [enable_noisechisel=yes])
AS_IF([test $enable_subtractsky = notset], [enable_subtractsky=yes])
+ AS_IF([test $enable_table = notset], [enable_table=yes])
# AS_IF([test $enable_TEMPLATE = notset], [enable_TEMPLATE=yes])
]
)
@@ -375,6 +383,7 @@ AM_CONDITIONAL([COND_MKNOISE], [test $enable_mknoise = yes])
AM_CONDITIONAL([COND_MKPROF], [test $enable_mkprof = yes])
AM_CONDITIONAL([COND_NOISECHISEL], [test $enable_noisechisel = yes])
AM_CONDITIONAL([COND_SUBTRACTSKY], [test $enable_subtractsky = yes])
+AM_CONDITIONAL([COND_TABLE], [test $enable_table = yes])
#AM_CONDITIONAL([COND_TEMPLATE], [test $enable_TEMPLATE = yes])
@@ -388,6 +397,7 @@ AC_CONFIG_FILES([Makefile
doc/Makefile
lib/Makefile
tests/Makefile
+ src/table/Makefile
src/mkprof/Makefile
src/header/Makefile
src/mknoise/Makefile
diff --git a/doc/gnuastro.texi b/doc/gnuastro.texi
index 87743aa..703d795 100644
--- a/doc/gnuastro.texi
+++ b/doc/gnuastro.texi
@@ -51,6 +51,9 @@ Texts. A copy of the license is included in the section
entitled
* ConvertType: (gnuastro)ConvertType. Convert different file types.
* astconvertt: (gnuastro)Invoking astconvertt. Options to ConvertType.
+* Table: (gnuastro)Table. Read and write FITS binary or ASCII tables.
+* asttable: (gnuastro)Invoking asttable. Options to Table.
+
* Convolve: (gnuastro)Convolve. Convolve an input file with kernel.
* astconvolve: (gnuastro)Invoking astconvolve. Options to Convolve.
@@ -186,7 +189,7 @@ sub-component to a title is present.
* Tutorials:: Tutorials or Cookbooks.
* Installation:: Requirements and installation.
* Common behavior:: Common behavior in all programs.
-* Files:: File information and type conversion.
+* Extensions and Tables:: Tools to operate on extensions and tables.
* Image manipulation:: Tools for basic image manipulation.
* Image analysis:: Analyze images.
* Modeling and fittings:: Make and fit models.
@@ -311,10 +314,11 @@ Getting help
* Info:: View complete book in terminal.
* help-gnuastro mailing list:: Contacting experienced users.
-Files
+Extensions and Tables
* Header:: Print and manipulate data file header.
* ConvertType:: Convert data to various formats.
+* Table:: Read and Write FITS tables to plain text.
Header
@@ -326,6 +330,10 @@ ConvertType
* Color:: Some explanations on color.
* Invoking astconvertt:: Options and arguments to ConvertType.
+Table
+
+* Invoking asttable:: Options and arguments to Table.
+
Image manipulation
* ImageCrop:: Crop region(s) from FITS image(s).
@@ -3766,7 +3774,7 @@ If your problem was not listed above, please file a bug
report
address@hidden Common behavior, Files, Installation, Top
address@hidden Common behavior, Extensions and Tables, Installation, Top
@chapter Common behavior
There are some facts that are common to all the programs in Gnuastro
@@ -5175,30 +5183,42 @@ END
address@hidden Files, Image manipulation, Common behavior, Top
address@hidden Files
address@hidden Extensions and Tables, Image manipulation, Common behavior, Top
address@hidden Extensions and Tables
@cindex File operations
@cindex Operations on files
@cindex General file operations
-This chapter documents the programs in Gnuastro that are provided for
-getting information on the contents of a data file or converting a
-file format. Before working on a FITS file, it is commonly the case
-that you are not sure how many extensions it has within it and also
-what each extension is (image, table or blank). In other cases you
-want to use the data in a FITS file in other programs (for example in
-reports) that don't recognize the FITS format.
+This chapter documents those Gnuastro utilities that don't directly operate
+on the contents of the data file, they just print information, or convert
+from different data types. Before working on a FITS file, it is commonly
+the case that you are not sure how many extensions it has within it and
+also what each extension is (image, table or blank). In such cases, Header
+(see @ref{Header}) can be handy by printing the full header of a FITS file
+to the terminal for easy inspection.
+
+In other cases you want to use the data in a FITS file in other programs
+(for example in reports) that don't recognize the FITS format, for example
+converting a FITS image into a Jpeg, or PDF format image. ConvertType (see
address@hidden) was built for such situations. Finally, the FITS format
+is not just for images, it can also store tables. Binary tables in
+particular can be very useful in storing very large catalogs or tables
+compared to a plain text file. Table (see @ref{Table}) can be used to
+choose certain table columns in a FITS table and see them as a human
+readable output on the terminal, or to save them in another plain text or
+FITS table.
@menu
* Header:: Print and manipulate data file header.
* ConvertType:: Convert data to various formats.
+* Table:: Read and Write FITS tables to plain text.
@end menu
address@hidden Header, ConvertType, Files, Files
address@hidden Header, ConvertType, Extensions and Tables, Extensions and Tables
@section Header
The FITS standard requires each extension of a FITS file to have a
@@ -5432,7 +5452,7 @@ continue with the rest of actions.
address@hidden ConvertType, , Header, Files
address@hidden ConvertType, Table, Header, Extensions and Tables
@section ConvertType
@cindex Data format conversion
@@ -5922,9 +5942,212 @@ is best to call this option so the image is not
inverted.
@end table
address@hidden Table, , ConvertType, Extensions and Tables
address@hidden Table
+
+The FITS standard is not just for storing astronomical images, from its
+early days, it also included tables. Tables are the products of processing
+astronomical images and spectra. For example in Gnuastro, MakeCatalog will
+process the defined pixels over an object and produce a catalog (see
address@hidden). For each identified object, MakeCatalog can print its
+position on the image or sky, its total brightness and many other
+information that is deducible from the given image. Each one of these
+properties is a column in its output catalog (or table) and for each input
+object, we have a row.
+
+When there are only a small number of objects (rows) and not too many
+properties (columns), then a simple plain text file is mainly enough to
+store, transfer, or even use the produced data. However, to be more
+efficient in all these aspects, astronomers have defined the FITS binary
+table standard to store data in a binary (0 and 1) format, not plain
+text. This can offer major advantages in all those aspects: the file size
+will be greatly reduced and the reading and writing will be faster (because
+the RAM and CPU also work in binary).
+
+The FITS standard also defines a standard for ASCII tables, where the data
+are stored in the human readable ASCII format, but within the FITS file
+structure. These are mainly useful for keeping ASCII data along with images
+and possibly binary data as multiple (conceptually related) extensions
+within a FITS file.
+
address@hidden AWK
address@hidden GNU AWK
+However, this comes at a cost: binary tables are not easily readable by
+human eyes. There is no standard on how the zero and ones should be
+interpretted. The Unix-like operating systems have flurished because of a
+simple fact: communication between the various tools is based on human
+readible address@hidden ``The art of Unix programming'', Eric
+Raymond makes this suggestion to programmers: ``When you feel the urge to
+design a complex binary file format, or a complex binary application
+protocol, it is generally wise to lie down until the feeling
+passes.''. This is a great book and strongly recommended, give it a look if
+you want to truely enjoy your work/life in this environment.}. So while the
+FITS table standards are very beneficial for the tools that recognize them,
+they are hard to use in the vast majority of available software. This cases
+some major limitations for their generic use.
+
+`Table' is Gnuastro's solution to this problem. With Table, FITS tables
+(ASCII or binary) are directly accessible to the Unix-like operating
+systems power-users (those working the command-line or shell, see
address@hidden interface}). With Table, a FITS table (in binary or ASCII
+formats) is only one command away from AWK (or any other tool you want to
+use). Just like a plain text file that you read with the @command{cat}
+command. You can pipe the output of Table into any other tool for
+higher-level processing, see the examples in @ref{Invoking asttable} for
+some very simple examples.
+
address@hidden
+* Invoking asttable:: Options and arguments to Table.
address@hidden menu
+
address@hidden Invoking asttable, , Table, Table
address@hidden Invoking Table
+
+Table will convert FITS binary and ASCII tables into other such tables, or
+print them on the command-line, or save them in a plain text file. Output
+columns can also be determined by number or regular expression matching of
+column names. The executable name is @file{asttable} with the following
+general template
+
address@hidden
+$ asttable [OPTION...] InputFile
address@hidden example
+
address@hidden
+One line examples:
+
address@hidden
+## Get the table column information (name, data type, or units)
+$ asttable bintab.fits --information
+
+## Only print those columns which have a name starting with "MAG_"
+$ asttable bintab.fits --columns=^MAG_
+
+## Only print the 2nd column, and the third column multiplied by 5
+$ asttable bintab.fits | awk '@{print $2, address@hidden'
+
+## Only print those rows with a value in the 10th column above 100000
+$ asttable bintab.fits | awk '$10>10e5 @address@hidden'
+
+## Sort the output columns by the third column, save output
+$ asttable bintab.fits | sort -k3 > output.txt
+
+## Convert a plain text table to a binary FITS table
+$ asttable plaintext.txt --output=inbinary.fits
address@hidden example
+
+Table can accept plain text files, or binary and ASCII FITS table
+extensions in a FITS file. For the full list of options common to all
+Gnuastro utilities please see @ref{Common options}. Options can also be
+stored in directory, user or system-wide configuration files to avoid
+repeating on the command-line, see @ref{Configuration files}. Currently all
+plain text files are processed (and thus printed, or saved to a binary FITS
+table) as double floating point types. We are still working on this many
+many more features.
+Table does not follow Automatic output that is common in most Gnuastro, see
address@hidden output}. If no value is given to the @option{--output}
+option, the desired columns will be printed to the standard output (on the
+command-line). This feature makes it very useful to directly pipe the
+output as input to other programs as the examples above demonstrate. Note
+that the options below which relate to print formatting are only relevant
+when the output is in human readable format (on the command-line and plain
+text files), they are ignored when the output is a binary FITS table.
address@hidden @option
address@hidden -i
address@hidden --information
+Print the information for each column and abort. The information for each
+column will be printed as a row on the command-line. The column name (if
+present), units (if present) and datatype will printed. Note that the FITS
+standard does not require a name or units for columns, only the datatype is
+mandatory.
+
address@hidden -c
address@hidden --column
+(@option{=STR} or @option{=INT}) Specify the columns to output for this
+table. If an integer number is given, the column number will be used
+(counting from 1). Otherwise the value (a string) will be passed to an
+internal regular expression processor which will try to match all the
+columns in the table with the given regular expression. Currently only FITS
+tables might have column names (it is an optional feature in the FITS
+standard). There is currently no particular standard to name plain text
+columns.
+
+This option can be called any number of times with one run of Table. The
+order of the output columns will be determined by the input order. This
+option is also not mandatory. If not given, all the input table columns are
+output.
+
+Regular expressions are a very powerful tool in matching text and since
+FITS binary tables usually have a large number of columns, this feature can
+greatly simply the selection of the output columns.
+
address@hidden -I
address@hidden --ignorescase
+Ignore case while matching the column names with the value(s) of the
address@hidden option. The FITS standard suggests to treat the column
+names as case insensitive, however it is not a requirement.
+
address@hidden --feg
+(@option{=STR}) Format of printing floating point numbers in non-binary
+outputs. It can only accept one of the three following values (same as C's
address@hidden):
address@hidden
address@hidden
address@hidden: Print complete floating point value, this is good when the
numbers
+aren't too small, for example @mymath{3.286}. But it will print all the
+zeros in @mymath{3.2\times10^{-15}}.
+
address@hidden
address@hidden: Only print in exponential format. This is good for very large or
+very small numbers, but can make reading the values of more ordinary
+numbers a little hard.
+
address@hidden
address@hidden: Let the system choose which representation is better for the
+number.
address@hidden itemize
+
address@hidden --sintwidth
+(@option{=INT}) The minimum width (number of characters) for printing
+columns of shorter integer datatypes. The shorter datatypes are considered
+to be signed and unsigned characters, short integers, integers.
+
address@hidden --lintwidth
+(@option{=INT}) The minimum width (number of characters) for printing
+columns of longer datatypes. The longer datatypes are considered to be long
+and longlong types.
+
address@hidden --floatwidth
+(@option{=INT}) The minimum width (number of characters) for printing
+columns of single precision floating point datatypes.
+
address@hidden --doublewidth
+(@option{=INT}) The minimum width (number of characters) for printing
+columns of double precision floating point datatypes.
+
address@hidden --strwidth
+(@option{=INT}) The minimum width (number of characters) for printing
+columns of strings (given as one column, the FITS standard allows ASCII
+strings as table elements).
+
address@hidden --floatprecision
+(@option{=INT}) The number of digits to print after the floating point for
+single precision floating point numbers.
+
address@hidden --doubleprecision
+(@option{=INT}) The number of digits to print after the floating point for
+double precision floating point numbers.
+
address@hidden --fitstabletype
+(@option{=STR}) The type of FITS table when a FITS file is specified as the
+output. This option can only have two values: @option{binary}, or
address@hidden However, currently ASCII FITS table outputs are not yet
+implemented due to lack of need. If you need it, please get in touch with
+so we implement it.
address@hidden table
@@ -5942,14 +6165,14 @@ is best to call this option so the image is not
inverted.
address@hidden Image manipulation, Image analysis, Files, Top
address@hidden Image manipulation, Image analysis, Extensions and Tables, Top
@chapter Image manipulation
-Images are one of the major formats of data that is used in
-astronomy. The functions in this chapter explain the GNU Astronomy
-Utilities which are provided for their manipulation. For example
-cropping out a part of a larger image or convolving the image with a
-given kernel or applying a transformation to it.
+Images are one of the major formats of data that is used in astronomy. The
+functions in this chapter explain the GNU Astronomy Utilities which are
+provided for their manipulation. For example cropping out a part of a
+larger image or convolving the image with a given kernel or applying a
+transformation to it.
@menu
* ImageCrop:: Crop region(s) from FITS image(s).
diff --git a/genauthors b/genauthors
index 5371b6d..8bb3889 100755
--- a/genauthors
+++ b/genauthors
@@ -153,6 +153,8 @@ for util in src/* "lib/" "doc/"; do
elif [ $util = src/mkprof ]; then name=MakeProfile
elif [ $util = src/noisechisel ]; then name=NoiseChisel
elif [ $util = src/subtractsky ]; then name=SubtractSky
+ elif [ $util = src/table ]; then name=Table
+ elif [ $util = src/TEMPLATE ]; then name=TEMPLATE
elif [ $util = lib/ ]; then name=Libraries
elif [ $util = doc/ ]; then name=Documentation
else echo; echo; echo "genauthors.sh: $util not recognized!"; exit 1;
diff --git a/lib/checkset.c b/lib/checkset.c
index 58de7cd..1ad53e3 100644
--- a/lib/checkset.c
+++ b/lib/checkset.c
@@ -125,8 +125,8 @@ gal_checkset_int_zero_or_one(char *optarg, int *var, char
*lo, char so,
void
-gal_checkset_int_4_or_8(char *optarg, int *var, char *lo, char so, char *spack,
- char *filename, size_t lineno)
+gal_checkset_int_4_or_8(char *optarg, int *var, char *lo, char so,
+ char *spack, char *filename, size_t lineno)
{
long tmp;
char *tailptr;
@@ -150,8 +150,8 @@ gal_checkset_int_4_or_8(char *optarg, int *var, char *lo,
char so, char *spack,
void
-gal_checkset_int_el_zero(char *optarg, int *var, char *lo, char so, char
*spack,
- char *filename, size_t lineno)
+gal_checkset_int_el_zero(char *optarg, int *var, char *lo, char so,
+ char *spack, char *filename, size_t lineno)
{
long tmp;
char *tailptr;
@@ -174,8 +174,8 @@ gal_checkset_int_el_zero(char *optarg, int *var, char *lo,
char so, char *spack,
void
-gal_checkset_int_l_zero(char *optarg, int *var, char *lo, char so, char *spack,
- char *filename, size_t lineno)
+gal_checkset_int_l_zero(char *optarg, int *var, char *lo, char so,
+ char *spack, char *filename, size_t lineno)
{
long tmp;
char *tailptr;
@@ -247,8 +247,8 @@ gal_checkset_long_el_zero(char *optarg, long *var, char
*lo, char so,
void
-gal_checkset_any_long(char *optarg, long *var, char *lo, char so, char *spack,
- char *filename, size_t lineno)
+gal_checkset_any_long(char *optarg, long *var, char *lo, char so,
+ char *spack, char *filename, size_t lineno)
{
char *tailptr;
*var=strtol(optarg, &tailptr, 0);
@@ -339,8 +339,8 @@ gal_checkset_sizet_p_odd(char *optarg, size_t *var, char
*lo, char so,
void
-gal_checkset_float_l_0(char *optarg, float *var, char *lo, char so, char*
spack,
- char *filename, size_t lineno)
+gal_checkset_float_l_0(char *optarg, float *var, char *lo, char so,
+ char* spack, char *filename, size_t lineno)
{
float tmp;
char *tailptr;
@@ -386,8 +386,8 @@ gal_checkset_float_l_0_s_1(char *optarg, float *var, char
*lo, char so,
void
-gal_checkset_any_float(char *optarg, float *var, char *lo, char so, char
*spack,
- char *filename, size_t lineno)
+gal_checkset_any_float(char *optarg, float *var, char *lo, char so,
+ char *spack, char *filename, size_t lineno)
{
char *tailptr;
*var=strtof(optarg, &tailptr);
@@ -622,6 +622,28 @@ gal_checkset_check_file(char *filename)
+/* Similar to `gal_checkset_check_file', but will report the result instead
+ of doing it quietly. */
+int
+gal_checkset_check_file_report(char *filename)
+{
+ FILE *tmpfile;
+ errno=0;
+ tmpfile = fopen(filename, "r");
+ if(tmpfile) /* The file opened. */
+ {
+ if(fclose(tmpfile)==EOF)
+ error(EXIT_FAILURE, errno, "%s", filename);
+ return 1;
+ }
+ else
+ return 0;
+}
+
+
+
+
+
/* Check if a file exists. If so, remove it. */
void
gal_checkset_check_remove_file(char *filename, int dontdelete)
@@ -672,10 +694,10 @@ gal_checkset_dir_0_file_1(char *name, int dontdelete)
struct stat nameinfo;
if(name==NULL)
- error(EXIT_FAILURE, 0, "a bug! The input to the gal_checkset_dir_0_file_1 "
- "function in checkset.c should not be NULL. Please contact us at "
- PACKAGE_BUGREPORT" so we can see what went wrong and fix it in "
- "future updates");
+ error(EXIT_FAILURE, 0, "a bug! The input to the "
+ "gal_checkset_dir_0_file_1 function in checkset.c should not "
+ "be NULL. Please contact us at "PACKAGE_BUGREPORT" so we can "
+ "see what went wrong and fix it in future updates");
errno=0;
if(stat(name, &nameinfo)!=0)
diff --git a/lib/fits.c b/lib/fits.c
index 1168bd3..38ecb07 100644
--- a/lib/fits.c
+++ b/lib/fits.c
@@ -29,7 +29,6 @@ along with Gnuastro. If not, see
<http://www.gnu.org/licenses/>.
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#include <assert.h>
#include <gnuastro/fits.h>
#include <gnuastro/checkset.h>
@@ -167,6 +166,12 @@ gal_fits_bitpix_to_dtype(int bitpix)
return TFLOAT;
case DOUBLE_IMG:
return TDOUBLE;
+ case SBYTE_IMG:
+ return TSBYTE;
+ case USHORT_IMG:
+ return TUSHORT;
+ case ULONG_IMG:
+ return TULONG;
default:
error(EXIT_FAILURE, 0, "bitpix value of %d not recognized",
bitpix);
@@ -178,64 +183,204 @@ gal_fits_bitpix_to_dtype(int bitpix)
+/* The values to the TFORM header keyword are single letter capital
+ letters, but that is useless in identifying the data type of the
+ column. So this function will do the conversion based on the CFITSIO
+ manual.*/
+int
+gal_fits_tform_to_dtype(char tform)
+{
+ switch(tform)
+ {
+ case 'X':
+ return TBIT;
+ case 'B':
+ return TBYTE;
+ case 'L':
+ return TLOGICAL;
+ case 'A':
+ return TSTRING;
+ case 'I':
+ return TSHORT;
+ case 'J':
+ return TLONG;
+ case 'K':
+ return TLONGLONG;
+ case 'E':
+ return TFLOAT;
+ case 'D':
+ return TDOUBLE;
+ case 'C':
+ return TCOMPLEX;
+ case 'M':
+ return TDBLCOMPLEX;
+ case 'S':
+ return TSBYTE;
+ case 'V':
+ return TUINT;
+ case 'U':
+ return TUSHORT;
+ default:
+ error(EXIT_FAILURE, 0, "'%c' is not a recognized CFITSIO value for "
+ "the TFORMn header keyword(s).", tform);
+ }
+
+ error(EXIT_FAILURE, 0, "A bug! Please contact us so we can fix this. "
+ "For some reason, control has reached to the end of the "
+ "gal_fits_tform_to_dtype function in fits.c.");
+ return -1;
+}
+
+
+
+
+
void *
-gal_fits_bitpix_blank(int bitpix)
+gal_fits_datatype_blank(int datatype)
{
+ /* Define the pointers, note that we are ordering them based on the
+ CFITSIO manual to be more easily comparable. */
unsigned char *b;
+ char *c;
+ char **str;
short *s;
long *l;
LONGLONG *L;
float *f;
double *d;
+ gsl_complex_float *cx;
+ gsl_complex *dcx;
+ int *i;
+ unsigned int *ui;
+ unsigned short *us;
+ unsigned long *ul;
errno=0;
- switch(bitpix)
+ switch(datatype)
{
- case BYTE_IMG:
- b=malloc(sizeof(unsigned char));
+ case TBIT:
+ error(EXIT_FAILURE, 0, "Currently Gnuastro doesn't support TBIT "
+ "datatype, please get in touch with us to implement it.");
+
+ case TBYTE:
+ b=malloc(sizeof *b);
if(b==NULL)
- error(EXIT_FAILURE, errno, "%lu bytes", sizeof(unsigned char));
+ error(EXIT_FAILURE, errno, "%lu bytes for blank TBYTE",
+ sizeof *b);
*b=GAL_FITS_BYTE_BLANK;
return b;
- case SHORT_IMG:
- s=malloc(sizeof(short));
+ /* CFITSIO says "int for keywords, char for table columns". Here we
+ are only assuming table columns. So in practice this also applies
+ to TSBYTE.*/
+ case TLOGICAL: case TSBYTE:
+ c=malloc(sizeof *c);
+ if(c==NULL)
+ error(EXIT_FAILURE, errno, "%lu bytes for blank TLOGICAL, or TSBYTE",
+ sizeof *c);
+ *c=GAL_FITS_LOGICAL_BLANK;
+ return c;
+
+ case TSTRING:
+ str=malloc(sizeof *str);
+ if(str==NULL)
+ error(EXIT_FAILURE, errno, "%lu bytes for blank TSTRING",
+ sizeof *s);
+ *str=GAL_FITS_STRING_BLANK;
+ return str;
+
+ case TSHORT:
+ s=malloc(sizeof *s);
if(s==NULL)
- error(EXIT_FAILURE, errno, "%lu bytes", sizeof(short));
+ error(EXIT_FAILURE, errno, "%lu bytes for blank TSHORT",
+ sizeof *s);
*s=GAL_FITS_SHORT_BLANK;
return s;
- case LONG_IMG:
- l=malloc(sizeof(long));
+ case TLONG:
+ l=malloc(sizeof *l);
if(l==NULL)
- error(EXIT_FAILURE, errno, "%lu bytes", sizeof(long));
+ error(EXIT_FAILURE, errno, "%lu bytes for blank TLONG",
+ sizeof *l);
*l=GAL_FITS_LONG_BLANK;
return l;
- case LONGLONG_IMG:
- L=malloc(sizeof(LONGLONG));
+ case TLONGLONG:
+ L=malloc(sizeof *L);
if(L==NULL)
- error(EXIT_FAILURE, errno, "%lu bytes", sizeof(LONGLONG));
+ error(EXIT_FAILURE, errno, "%lu bytes for blank TLONGLONG",
+ sizeof *L);
*L=GAL_FITS_LLONG_BLANK;
return L;
- case FLOAT_IMG:
- f=malloc(sizeof(float));
+ case TFLOAT:
+ f=malloc(sizeof *f);
if(f==NULL)
- error(EXIT_FAILURE, errno, "%lu bytes", sizeof(float));
+ error(EXIT_FAILURE, errno, "%lu bytes for blank TFLOAT",
+ sizeof *f);
*f=GAL_FITS_FLOAT_BLANK;
return f;
- case DOUBLE_IMG:
- d=malloc(sizeof(double));
+ case TDOUBLE:
+ d=malloc(sizeof *d);
if(d==NULL)
- error(EXIT_FAILURE, errno, "%lu bytes", sizeof(double));
- *d=GAL_FITS_FLOAT_BLANK;
+ error(EXIT_FAILURE, errno, "%lu bytes for blank TDOUBLE",
+ sizeof *d);
+ *d=GAL_FITS_DOUBLE_BLANK;
return d;
+ case TCOMPLEX:
+ cx=malloc(sizeof *cx);
+ if(cx==NULL)
+ error(EXIT_FAILURE, errno, "%lu bytes for blank TCOMPLEX",
+ sizeof *cx);
+ GSL_SET_COMPLEX(cx,GAL_FITS_FLOAT_BLANK,GAL_FITS_FLOAT_BLANK);
+ return cx;
+
+ case TDBLCOMPLEX:
+ dcx=malloc(sizeof *dcx);
+ if(dcx==NULL)
+ error(EXIT_FAILURE, errno, "%lu bytes for blank TDBLCOMPLEX",
+ sizeof *dcx);
+ GSL_SET_COMPLEX(dcx,GAL_FITS_DOUBLE_BLANK,GAL_FITS_DOUBLE_BLANK);
+ return dcx;
+
+ case TINT:
+ i=malloc(sizeof *i);
+ if(i==NULL)
+ error(EXIT_FAILURE, errno, "%lu bytes for blank TINT",
+ sizeof *i);
+ *i=GAL_FITS_INT_BLANK;
+ return i;
+
+ case TUINT:
+ ui=malloc(sizeof *ui);
+ if(ui==NULL)
+ error(EXIT_FAILURE, errno, "%lu bytes for blank TUINT",
+ sizeof *ui);
+ *ui=GAL_FITS_UINT_BLANK;
+ return ui;
+
+ case TUSHORT:
+ us=malloc(sizeof *us);
+ if(us==NULL)
+ error(EXIT_FAILURE, errno, "%lu bytes for blank TUSHORT",
+ sizeof *us);
+ *ui=GAL_FITS_USHORT_BLANK;
+ return us;
+
+ case TULONG:
+ ul=malloc(sizeof *ul);
+ if(ul==NULL)
+ error(EXIT_FAILURE, errno, "%lu bytes for blank TULONG",
+ sizeof *ul);
+ *ul=GAL_FITS_ULONG_BLANK;
+ return ul;
+
+
default:
- error(EXIT_FAILURE, 0, "bitpix value of %d not recognized",
- bitpix);
+ error(EXIT_FAILURE, 0, "datatype value of %d not recognized",
+ datatype);
}
return NULL;
@@ -245,55 +390,108 @@ gal_fits_bitpix_blank(int bitpix)
-/* Allocate an array based on the value of bitpix. */
+/* Allocate an array based on the value of bitpix. Note that the argument
+ `size' is the number of elements, necessary in the array, the number of
+ bytes each element needs will be determined internaly by this function
+ using the datatype argument, so you don't have to worry about it. */
void *
-gal_fits_bitpix_alloc(size_t size, int bitpix)
+gal_fits_datatype_alloc(size_t size, int datatype)
{
void *array;
/* Allocate space for the array to keep the image. */
- switch(bitpix)
+ switch(datatype)
{
- case BYTE_IMG:
- size*=sizeof(unsigned char);
+ case TBIT:
+ error(EXIT_FAILURE, 0, "Currently Gnuastro doesn't support TBIT "
+ "datatype, please get in touch with us to implement it.");
+
+ /* The parenthesis after sizeof is not a function, it is actually a
+ type cast, so we have put a space between size of and the
+ parenthesis to highlight this. In C, `sizeof' is an operator, not
+ a function.*/
+ case TBYTE:
+ size *= sizeof (unsigned char);
break;
- case SHORT_IMG:
- size*=sizeof(short);
+ case TLOGICAL: case TSBYTE:
+ size *= sizeof (char);
break;
- case LONG_IMG:
- size*=sizeof(long);
+ case TSTRING:
+ size *= sizeof (char *);
break;
- case LONGLONG_IMG:
- size*=sizeof(LONGLONG);
+ case TSHORT:
+ size *= sizeof (short);
break;
- case FLOAT_IMG:
- if(sizeof(float)!=4)
+ case TLONG:
+ size *= sizeof (long);
+ break;
+
+ case TLONGLONG:
+ size *= sizeof (LONGLONG);
+ break;
+
+ case TFLOAT:
+ if( sizeof (float) != 4 )
error(EXIT_FAILURE, 0,
"`float` is not 32bits on this machine. The FITS standard "
"Requires this size");
- size*=sizeof(float);
+ size *= sizeof (float);
break;
- case DOUBLE_IMG:
- if(sizeof(double)!=8)
+ case TDOUBLE:
+ if( sizeof (double) != 8 )
+ error(EXIT_FAILURE, 0,
+ "`double` is not 64bits on this machine. The FITS standard "
+ "requires this size");
+ size *= sizeof (double);
+ break;
+
+ case TCOMPLEX:
+ if( sizeof (float) != 4 )
+ error(EXIT_FAILURE, 0,
+ "`float` is not 32bits on this machine. The FITS standard "
+ "Requires this size");
+ size *= sizeof (gsl_complex_float);
+ break;
+
+ case TDBLCOMPLEX:
+ if( sizeof (double) != 8 )
error(EXIT_FAILURE, 0,
"`double` is not 64bits on this machine. The FITS standard "
"requires this size");
- size*=sizeof(double);
+ size *= sizeof (gsl_complex);
+ break;
+
+ case TINT:
+ size *= sizeof (int);
+ break;
+
+ case TUINT:
+ size *= sizeof (unsigned int);
+ break;
+
+ case TUSHORT:
+ size *= sizeof (unsigned short);
+ break;
+
+ case TULONG:
+ size *= sizeof (unsigned long);
break;
default:
- error(EXIT_FAILURE, 0, "bitpix value of %d not recognized", bitpix);
+ error(EXIT_FAILURE, 0, "datatype value of %d not recognized in "
+ "gal_fits_datatype_alloc", datatype);
}
errno=0;
array=malloc(size);
if(array==NULL)
- error(EXIT_FAILURE, errno, "array of %lu bytes", size);
+ error(EXIT_FAILURE, errno,
+ "array of %lu bytes in gal_fits_datatype_alloc", size);
return array;
}
@@ -303,54 +501,155 @@ gal_fits_bitpix_alloc(size_t size, int bitpix)
void
-blanktovalue(void *array, int bitpix, size_t size, void *value)
+gal_fits_blank_to_value(void *array, int datatype, size_t size, void *value)
{
- /* 'value' will only be read from one of these based on bitpix. Which the
- caller assigned. If there is any problem, it is their responsability,
- not this functions :-).*/
- unsigned char *b, *bf, bv=*(uint8_t *) value;
- short *s, *sf, sv=*(int16_t *) value;
- long *l, *lf, lv=*(int32_t *) value;
- LONGLONG *L, *Lf, Lv=*(int64_t *) value;
- float *f, *ff, fv=*(float *) value;
- double *d, *df, dv=*(double *) value;
-
- switch(bitpix)
+ /* 'value' will only be read from one of these based on the
+ datatype. Which the caller assigned. If there is any problem, it is
+ their responsability, not this function's.*/
+ unsigned char *b, *bf, bv = *(uint8_t *) value;
+ char *c, *cf, cv = *(char *) value;
+ char **str, **strf, *strv = *(char **) value;
+ short *s, *sf, sv = *(int16_t *) value;
+ long *l, *lf, lv = *(int32_t *) value;
+ LONGLONG *L, *Lf, Lv = *(int64_t *) value;
+ float *f, *ff, fv = *(float *) value;
+ double *d, *df, dv = *(double *) value;
+ gsl_complex_float *cx, *cxf, cxv = *(gsl_complex_float *) value;
+ gsl_complex *dcx, *dcxf, dcxv = *(gsl_complex *) value;
+ int *in, *inf, inv = *(int *) value;
+ unsigned int *ui, *uif, uiv = *(unsigned int *) value;
+ unsigned short *us, *usf, usv = *(unsigned short *) value;
+ unsigned long *ul, *ulf, ulv = *(unsigned long *) value;
+
+ switch(datatype)
{
- case BYTE_IMG:
+ case TBIT:
+ error(EXIT_FAILURE, 0, "Currently Gnuastro doesn't support TBIT "
+ "datatype, please get in touch with us to implement it.");
+
+ case TBYTE:
bf=(b=array)+size;
- do if(*b==GAL_FITS_BYTE_BLANK) *b=bv; while(++b<bf);
+ do if(*b==GAL_FITS_BYTE_BLANK) *b++=bv; while(b<bf);
break;
- case SHORT_IMG:
+
+ case TLOGICAL: case TSBYTE:
+ cf=(c=array)+size;
+ do if(*c==GAL_FITS_LOGICAL_BLANK) *c++=cv; while(c<cf);
+ break;
+
+
+ case TSTRING:
+ strf=(str=array)+size;
+ do if(*str==GAL_FITS_STRING_BLANK) *str++=strv; while(str<strf);
+ break;
+
+
+ case TSHORT:
sf=(s=array)+size;
- do if(*s==GAL_FITS_SHORT_BLANK) *s=sv; while(++s<sf);
+ do if(*s==GAL_FITS_SHORT_BLANK) *s++=sv; while(s<sf);
break;
- case LONG_IMG:
+
+ case TLONG:
lf=(l=array)+size;
- do if(*l==GAL_FITS_LONG_BLANK) *l=lv; while(++l<lf);
+ do if(*l==GAL_FITS_LONG_BLANK) *l++=lv; while(l<lf);
break;
- case LONGLONG_IMG:
+
+ case TLONGLONG:
Lf=(L=array)+size;
- do if(*L==GAL_FITS_LLONG_BLANK) *L=Lv; while(++L<Lf);
+ do if(*L==GAL_FITS_LLONG_BLANK) *L++=Lv; while(L<Lf);
break;
- case FLOAT_IMG:
+
+ /* Note that a NaN value is not equal to another NaN value, so we
+ can't use the easy check for cases were the blank value is
+ NaN. Also note that `isnan' is actually a macro, so it works for
+ both float and double types.*/
+ case TFLOAT:
ff=(f=array)+size;
- do if(*f==GAL_FITS_FLOAT_BLANK) *f=fv; while(++f<ff);
+ if(isnan(GAL_FITS_FLOAT_BLANK))
+ do if(isnan(*f)) *f++=fv; while(f<ff);
+ else
+ do if(*f==GAL_FITS_FLOAT_BLANK) *f++=fv; while(f<ff);
break;
- case DOUBLE_IMG:
+
+ case TDOUBLE:
df=(d=array)+size;
- do if(*d==GAL_FITS_FLOAT_BLANK) *d=dv; while(++d<df);
+ if(isnan(GAL_FITS_DOUBLE_BLANK))
+ do if(isnan(*d)) *d++=dv; while(d<df);
+ else
+ do if(*d==GAL_FITS_FLOAT_BLANK) *d++=dv; while(d<df);
+ break;
+
+
+ case TCOMPLEX:
+ cxf=(cx=array)+size;
+ if(isnan(GAL_FITS_FLOAT_BLANK))
+ do
+ if(isnan(GSL_COMPLEX_P_REAL(cx))
+ && isnan(GSL_COMPLEX_P_IMAG(cx)) )
+ GSL_SET_COMPLEX(cx, GSL_COMPLEX_P_REAL(&cxv),
+ GSL_COMPLEX_P_IMAG(&cxv));
+ while(++cx<cxf);
+ else
+ do
+ if( GSL_COMPLEX_P_REAL(cx) == GAL_FITS_FLOAT_BLANK
+ && GSL_COMPLEX_P_IMAG(cx) == GAL_FITS_FLOAT_BLANK)
+ GSL_SET_COMPLEX(cx, GSL_COMPLEX_P_REAL(&cxv),
+ GSL_COMPLEX_P_IMAG(&cxv));
+ while(++cx<cxf);
+ break;
+
+
+ case TDBLCOMPLEX:
+ dcxf=(dcx=array)+size;
+ if(isnan(GAL_FITS_DOUBLE_BLANK))
+ do
+ if(isnan(GSL_COMPLEX_P_REAL(dcx))
+ && isnan(GSL_COMPLEX_P_IMAG(dcx)) )
+ GSL_SET_COMPLEX(dcx, GSL_COMPLEX_P_REAL(&dcxv),
+ GSL_COMPLEX_P_IMAG(&dcxv));
+ while(++dcx<dcxf);
+ else
+ do
+ if( GSL_COMPLEX_P_REAL(dcx) == GAL_FITS_FLOAT_BLANK
+ && GSL_COMPLEX_P_IMAG(dcx) == GAL_FITS_FLOAT_BLANK)
+ GSL_SET_COMPLEX(dcx, GSL_COMPLEX_P_REAL(&dcxv),
+ GSL_COMPLEX_P_IMAG(&dcxv));
+ while(++dcx<dcxf);
+ break;
+
+
+ case TINT:
+ inf=(in=array)+size;
+ do if(*in==GAL_FITS_INT_BLANK) *in++=inv; while(in<inf);
+ break;
+
+
+ case TUINT:
+ uif=(ui=array)+size;
+ do if(*ui==GAL_FITS_UINT_BLANK) *ui++=uiv; while(ui<uif);
+ break;
+
+
+ case TUSHORT:
+ usf=(us=array)+size;
+ do if(*us==GAL_FITS_USHORT_BLANK) *us++=usv; while(us<usf);
+ break;
+
+
+ case TULONG:
+ ulf=(ul=array)+size;
+ do if(*ul==GAL_FITS_ULONG_BLANK) *ul++=ulv; while(ul<ulf);
break;
default:
- error(EXIT_FAILURE, 0, "a bug! Bitpix value of %d not recognized. "
+ error(EXIT_FAILURE, 0, "a bug! datatype value of %d not recognized. "
"This should not happen here (blanktovalue in fitsarrayvv.c). "
- "Please contact us at %s to see how this happened", bitpix,
+ "Please contact us at %s to see how this happened", datatype,
PACKAGE_BUGREPORT);
}
}
@@ -364,15 +663,15 @@ gal_fits_change_type(void *in, int inbitpix, size_t size,
int anyblank,
void **out, int outbitpix)
{
size_t i=0;
- unsigned char *b, *bf, *ib=in, *iib=in;
- short *s, *sf, *is=in, *iis=in;
- long *l, *lf, *il=in, *iil=in;
- LONGLONG *L, *Lf, *iL=in, *iiL=in;
- float *f, *ff, *iif=in, *iiif=in;
- double *d, *df, *id=in, *iid=in;
+ unsigned char *b, *bf, *ib=in, *iib=in;
+ short *s, *sf, *is=in, *iis=in;
+ long *l, *lf, *il=in, *iil=in;
+ LONGLONG *L, *Lf, *iL=in, *iiL=in;
+ float *f, *ff, *iif=in, *iiif=in;
+ double *d, *df, *id=in, *iid=in;
/* Allocate space for the output and start filling it. */
- *out=gal_fits_bitpix_alloc(size, outbitpix);
+ *out=gal_fits_datatype_alloc(size, gal_fits_bitpix_to_dtype(outbitpix) );
switch(outbitpix)
{
case BYTE_IMG:
@@ -733,7 +1032,7 @@ hdutypestring(int hdutype)
/* Check the desired HDU in a FITS image and also if it has the
desired type. */
void
-gal_fits_read_hdu(char *filename, char *hdu, int desiredtype,
+gal_fits_read_hdu(char *filename, char *hdu, unsigned char img0_tab1,
fitsfile **outfptr)
{
size_t len;
@@ -758,11 +1057,24 @@ gal_fits_read_hdu(char *filename, char *hdu, int
desiredtype,
if (fits_get_hdu_type(fptr, &hdutype, &status) )
gal_fits_io_error(status, NULL);
- if(hdutype!=desiredtype)
- error(EXIT_FAILURE, 0, "%s: HDU %s is %s, not %s",
- filename, hdu, hdutypestring(hdutype),
- hdutypestring(desiredtype));
+ /* Check if the type of the HDU is the expected type. We could have
+ written these as && conditions, but this is easier to read, it makes
+ no meaningful difference to the compiler. */
+ if(img0_tab1)
+ {
+ if(hdutype==IMAGE_HDU)
+ error(EXIT_FAILURE, 0, "%s: HDU %s is an image, not a table",
+ filename, hdu);
+ }
+ else
+ {
+ if(hdutype!=IMAGE_HDU)
+ error(EXIT_FAILURE, 0, "%s: HDU %s is %s, not an image",
+ filename, hdu, hdutypestring(hdutype));
+ }
+
+ /* Clean up. */
free(ffname);
}
@@ -1309,7 +1621,7 @@ gal_fits_read_wcs(char *filename, char *hdu, size_t
hstartwcs,
fitsfile *fptr;
/* Check HDU for realistic conditions: */
- gal_fits_read_hdu(filename, hdu, IMAGE_HDU, &fptr);
+ gal_fits_read_hdu(filename, hdu, 0, &fptr);
/* Read the WCS information: */
gal_fits_read_wcs_from_pointer(fptr, nwcs, wcs, hstartwcs, hendwcs);
@@ -1332,15 +1644,15 @@ gal_fits_read_wcs(char *filename, char *hdu, size_t
hstartwcs,
the macros in fitsarrayvv.h and depends on the type of the data.*/
int
gal_fits_hdu_to_array(char *filename, char *hdu, int *bitpix,
- void **array, size_t *s0, size_t *s1)
+ void **array, size_t *s0, size_t *s1)
{
void *bitblank;
fitsfile *fptr;
- int status=0, anyblank=0;
long naxes[2], fpixel[]={1,1};
+ int status=0, anyblank=0, datatype;
/* Check HDU for realistic conditions: */
- gal_fits_read_hdu(filename, hdu, IMAGE_HDU, &fptr);
+ gal_fits_read_hdu(filename, hdu, 0, &fptr);
/* Get the bitpix and size of the image: */
gal_fits_img_bitpix_size(fptr, bitpix, naxes);
@@ -1348,8 +1660,9 @@ gal_fits_hdu_to_array(char *filename, char *hdu, int
*bitpix,
*s1=naxes[0];
/* Allocate space for the array. */
- bitblank=gal_fits_bitpix_blank(*bitpix);
- *array=gal_fits_bitpix_alloc(*s0 * *s1, *bitpix);
+ datatype=gal_fits_bitpix_to_dtype(*bitpix);
+ bitblank=gal_fits_datatype_blank(datatype);
+ *array=gal_fits_datatype_alloc(*s0 * *s1, datatype);
/* Read the image into the allocated array: */
fits_read_pix(fptr, gal_fits_bitpix_to_dtype(*bitpix), fpixel,
@@ -1416,7 +1729,7 @@ gal_fits_array_to_file(char *filename, char *hdu, int
bitpix,
if(bitpix==BYTE_IMG || bitpix==SHORT_IMG
|| bitpix==LONG_IMG || bitpix==LONGLONG_IMG)
{
- blank=gal_fits_bitpix_blank(bitpix);
+ blank=gal_fits_datatype_blank( gal_fits_bitpix_to_dtype(bitpix) );
if(fits_write_key(fptr, datatype, "BLANK", blank,
"Pixels with no data.", &status) )
gal_fits_io_error(status, "adding the BLANK keyword");
@@ -1516,6 +1829,85 @@ gal_fits_atof_correct_wcs(char *filename, char *hdu, int
bitpix,
/**************************************************************/
+/********** Table ************/
+/**************************************************************/
+/* Get the size of a table HDU. CFITSIO doesn't use size_t, also we want to
+ check status here.*/
+void
+gal_fits_table_size(fitsfile *fitsptr, size_t *nrows, size_t *ncols)
+{
+ long lnrows;
+ int incols, status=0;
+
+ /* Read the sizes and put them in. */
+ fits_get_num_rows(fitsptr, &lnrows, &status);
+ fits_get_num_cols(fitsptr, &incols, &status);
+ *ncols=incols;
+ *nrows=lnrows;
+
+ /* Report an error if any was issued. */
+ gal_fits_io_error(status, NULL);
+}
+
+
+
+
+
+int
+gal_fits_table_type(fitsfile *fptr)
+{
+ int status=0;
+ char value[FLEN_VALUE];
+
+ fits_read_key(fptr, TSTRING, "XTENSION", value, NULL, &status);
+
+ if(status==0)
+ {
+ if(!strcmp(value, "TABLE "))
+ return ASCII_TBL;
+ else if(!strcmp(value, "BINTABLE"))
+ return BINARY_TBL;
+ else
+ error(EXIT_FAILURE, 0, "The `XTENSION' keyword of this FITS file "
+ "doesn't have a standard value (`%s')", value);
+ }
+ else
+ {
+ if(status==KEY_NO_EXIST)
+ error(EXIT_FAILURE, 0, "the `gal_fits_table_type' function was "
+ "called on a FITS extension which is not a table. As part "
+ "of a utility, this is bug, so please contact us at %s so "
+ "we can fix it.", PACKAGE_BUGREPORT);
+ else
+ gal_fits_io_error(status, NULL);
+ }
+
+ error(EXIT_FAILURE, 0, "A bug! Please contact us at %s so we can fix it. "
+ "for some reason, the control of `gal_fits_table_type' has reached "
+ "the end of the function! This must not happen", PACKAGE_BUGREPORT);
+ return -1;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/**************************************************************/
/********** Check prepare file ************/
/**************************************************************/
/* We have the name of the input file. But in most cases, the files
diff --git a/lib/gnuastro/checkset.h b/lib/gnuastro/checkset.h
index 532a64d..1de6428 100644
--- a/lib/gnuastro/checkset.h
+++ b/lib/gnuastro/checkset.h
@@ -205,6 +205,9 @@ gal_checkset_allocate_copy_set(char *arg, char **copy, int
*set);
void
gal_checkset_check_file(char *filename);
+int
+gal_checkset_check_file_report(char *filename);
+
void
gal_checkset_check_remove_file(char *filename, int dontdelete);
diff --git a/lib/gnuastro/fits.h b/lib/gnuastro/fits.h
index a0456a4..4a81360 100644
--- a/lib/gnuastro/fits.h
+++ b/lib/gnuastro/fits.h
@@ -26,18 +26,36 @@ along with Gnuastro. If not, see
<http://www.gnu.org/licenses/>.
#include <math.h>
#include <float.h>
#include <stdint.h>
+#include <limits.h>
#include <fitsio.h>
#include <wcslib/wcs.h>
#include <wcslib/wcshdr.h>
#include <wcslib/wcsfix.h>
+#include <gsl/gsl_complex.h>
+
+
+
+
+
+/* Order is based on the CFITSIO manual. Note that for the unsigned types
+ or small types (like char), the maximum value is considered as a blank
+ value, since the minimum value of an unsigned type is zero and zero is
+ often meaningful in contexts were unsigned values are used. */
+#define GAL_FITS_STRING_BLANK NULL
+#define GAL_FITS_BYTE_BLANK UCHAR_MAX
+#define GAL_FITS_LOGICAL_BLANK SCHAR_MAX
+#define GAL_FITS_SHORT_BLANK INT16_MIN
+#define GAL_FITS_LONG_BLANK INT32_MIN
+#define GAL_FITS_LLONG_BLANK INT64_MIN
+#define GAL_FITS_FLOAT_BLANK NAN
+#define GAL_FITS_DOUBLE_BLANK NAN
+#define GAL_FITS_INT_BLANK INT_MIN
+#define GAL_FITS_SBYTE_BLANK SCHAR_MAX
+#define GAL_FITS_UINT_BLANK UINT_MAX
+#define GAL_FITS_USHORT_BLANK USHRT_MAX
+#define GAL_FITS_ULONG_BLANK ULONG_MAX
-#define GAL_FITS_STRING_BLANK NULL
-#define GAL_FITS_BYTE_BLANK UCHAR_MAX /* 0 is often meaningful here! */
-#define GAL_FITS_SHORT_BLANK INT16_MIN
-#define GAL_FITS_LONG_BLANK INT32_MIN
-#define GAL_FITS_LLONG_BLANK INT64_MIN
-#define GAL_FITS_FLOAT_BLANK NAN
@@ -160,11 +178,14 @@ gal_fits_copyright_end(fitsfile *fptr,
****************** Read/Write *****************
*************************************************************/
void *
-gal_fits_bitpix_blank(int bitpix);
+gal_fits_datatype_blank(int datatype);
void
gal_fits_convert_blank(void *array, int bitpix, size_t size, void *value);
+void
+gal_fits_blank_to_value(void *array, int datatype, size_t size, void *value);
+
int
gal_fits_bitpix_to_dtype(int bitpix);
@@ -172,11 +193,11 @@ void
gal_fits_img_bitpix_size(fitsfile *fptr, int *bitpix, long *naxis);
void
-gal_fits_read_hdu(char *filename, char *hdu, int desiredtype,
+gal_fits_read_hdu(char *filename, char *hdu, unsigned char img0_tab1,
fitsfile **outfptr);
void *
-gal_fits_bitpix_alloc(size_t size, int bitpix);
+gal_fits_datatype_alloc(size_t size, int datatype);
void
gal_fits_change_type(void *in, int inbitpix, size_t size, int anyblank,
@@ -213,6 +234,22 @@ gal_fits_atof_correct_wcs(char *filename, char *hdu, int
bitpix,
/**************************************************************/
+/********** Table ************/
+/**************************************************************/
+int
+gal_fits_tform_to_dtype(char tform);
+
+void
+gal_fits_table_size(fitsfile *fitsptr, size_t *nrows, size_t *ncols);
+
+int
+gal_fits_table_type(fitsfile *fptr);
+
+
+
+
+
+/**************************************************************/
/********** Check prepare file ************/
/**************************************************************/
void
diff --git a/lib/gnuastro/linkedlist.h b/lib/gnuastro/linkedlist.h
index 045a950..daac34c 100644
--- a/lib/gnuastro/linkedlist.h
+++ b/lib/gnuastro/linkedlist.h
@@ -170,14 +170,14 @@ void
gal_linkedlist_pop_from_sll(struct gal_linkedlist_sll **list, size_t *value);
size_t
-gal_linkedlist_num_in_xsll(struct gal_linkedlist_sll *list);
+gal_linkedlist_num_in_sll(struct gal_linkedlist_sll *list);
void
gal_linkedlist_print_sll(struct gal_linkedlist_sll *list);
void
gal_linkedlist_sll_to_array(struct gal_linkedlist_sll *list,
- size_t **f, size_t *num);
+ size_t **f, size_t *num, int inverse);
void
gal_linkedlist_free_sll(struct gal_linkedlist_sll *list);
diff --git a/lib/gnuastro/txtarray.h b/lib/gnuastro/txtarray.h
index 277adb3..6c65281 100644
--- a/lib/gnuastro/txtarray.h
+++ b/lib/gnuastro/txtarray.h
@@ -50,6 +50,10 @@ gal_txtarray_txt_to_array(char *filename, double **array,
size_t *s0, size_t *s1);
void
+gal_txtarray_printf_format(int numcols, char **fmt, int *int_cols,
+ int *accu_cols, int *space, int *prec, char forg);
+
+void
gal_txtarray_array_to_txt(double *array, size_t s0, size_t s1, char *comments,
int *int_cols, int *accu_cols, int *space, int *prec,
char forg, const char *filename);
diff --git a/lib/linkedlist.c b/lib/linkedlist.c
index 5d79777..f3eb1f1 100644
--- a/lib/linkedlist.c
+++ b/lib/linkedlist.c
@@ -447,9 +447,9 @@ gal_linkedlist_num_in_sll(struct gal_linkedlist_sll *list)
void
gal_linkedlist_sll_to_array(struct gal_linkedlist_sll *list,
- size_t **f, size_t *num)
+ size_t **f, size_t *num, int inverse)
{
- size_t i=0, *tf;
+ size_t i, *tf;
struct gal_linkedlist_sll *tmp;
*num=gal_linkedlist_num_in_sll(list);
@@ -461,8 +461,13 @@ gal_linkedlist_sll_to_array(struct gal_linkedlist_sll
*list,
"with %lu elements", *num);
tf=*f;
- for(tmp=list;tmp!=NULL;tmp=tmp->next)
- tf[i++]=tmp->v;
+ i = inverse ? *num-1: 0;
+ if(inverse)
+ for(tmp=list;tmp!=NULL;tmp=tmp->next)
+ tf[i--]=tmp->v;
+ else
+ for(tmp=list;tmp!=NULL;tmp=tmp->next)
+ tf[i++]=tmp->v;
}
diff --git a/lib/txtarray.c b/lib/txtarray.c
index 638bd79..d5f11de 100644
--- a/lib/txtarray.c
+++ b/lib/txtarray.c
@@ -292,8 +292,8 @@ gal_txtarray_txt_to_array(char *filename, double **array,
by writeasciitable and makes an array of formatting conditions that
is suitable for printing. */
void
-doformatting(int numcols, char **fmt, int *int_cols, int *accu_cols,
- int *space, int *prec, char forg)
+gal_txtarray_printf_format(int numcols, char **fmt, int *int_cols,
+ int *accu_cols, int *space, int *prec, char forg)
{
int i,j, found=0;
@@ -403,7 +403,8 @@ gal_txtarray_array_to_txt(double *array, size_t s0, size_t
s1,
"column with %lu elements", s1);
/* Prepare the formatting for each column */
- doformatting(s1, fmt, int_cols, accu_cols, space, prec, forg);
+ gal_txtarray_printf_format(s1, fmt, int_cols, accu_cols,
+ space, prec, forg);
/* Open the output file: */
errno=0;
diff --git a/src/imgcrop/crop.c b/src/imgcrop/crop.c
index 2d234fd..244f3cd 100644
--- a/src/imgcrop/crop.c
+++ b/src/imgcrop/crop.c
@@ -295,8 +295,8 @@ polygonmask(struct cropparams *crp, void *array, long
*fpixel_i,
LONGLONG *Lb, *La=array;
unsigned char *bb, *ba=array;
double *db, *ipolygon, point[2], *da=array;
- int outpolygon=crp->p->outpolygon, bitpix=crp->p->bitpix;
size_t i, *ordinds, size=s0*s1, nvertices=crp->p->nvertices;
+ int outpolygon=crp->p->outpolygon, datatype=crp->p->datatype;
/* First of all, allocate enough space to put a copy of the input
@@ -325,10 +325,10 @@ polygonmask(struct cropparams *crp, void *array, long
*fpixel_i,
/* Go over all the pixels in the image and if they are within the
polygon keep them if the user has asked for it.*/
- switch(bitpix)
+ switch(datatype)
{
- case BYTE_IMG:
- bb=gal_fits_bitpix_blank(bitpix);
+ case TBYTE:
+ bb=gal_fits_datatype_blank(datatype);
for(i=0;i<size;++i)
{
point[0]=i%s1+1; point[1]=i/s1+1;
@@ -337,8 +337,8 @@ polygonmask(struct cropparams *crp, void *array, long
*fpixel_i,
}
free(bb);
break;
- case SHORT_IMG:
- sb=gal_fits_bitpix_blank(bitpix);
+ case TSHORT:
+ sb=gal_fits_datatype_blank(datatype);
for(i=0;i<size;++i)
{
point[0]=i%s1+1; point[1]=i/s1+1;
@@ -347,8 +347,8 @@ polygonmask(struct cropparams *crp, void *array, long
*fpixel_i,
}
free(sb);
break;
- case LONG_IMG:
- lb=gal_fits_bitpix_blank(bitpix);
+ case TLONG:
+ lb=gal_fits_datatype_blank(datatype);
for(i=0;i<size;++i)
{
point[0]=i%s1+1; point[1]=i/s1+1;
@@ -357,8 +357,8 @@ polygonmask(struct cropparams *crp, void *array, long
*fpixel_i,
}
free(lb);
break;
- case LONGLONG_IMG:
- Lb=gal_fits_bitpix_blank(bitpix);
+ case TLONGLONG:
+ Lb=gal_fits_datatype_blank(datatype);
for(i=0;i<size;++i)
{
point[0]=i%s1+1; point[1]=i/s1+1;
@@ -367,8 +367,8 @@ polygonmask(struct cropparams *crp, void *array, long
*fpixel_i,
}
free(Lb);
break;
- case FLOAT_IMG:
- fb=gal_fits_bitpix_blank(bitpix);
+ case TFLOAT:
+ fb=gal_fits_datatype_blank(datatype);
for(i=0;i<size;++i)
{
point[0]=i%s1+1; point[1]=i/s1+1;
@@ -377,8 +377,8 @@ polygonmask(struct cropparams *crp, void *array, long
*fpixel_i,
}
free(fb);
break;
- case DOUBLE_IMG:
- db=gal_fits_bitpix_blank(bitpix);
+ case TDOUBLE:
+ db=gal_fits_datatype_blank(datatype);
for(i=0;i<size;++i)
{
point[0]=i%s1+1; point[1]=i/s1+1;
@@ -390,8 +390,8 @@ polygonmask(struct cropparams *crp, void *array, long
*fpixel_i,
default:
error(EXIT_FAILURE, 0, "a bug! Please contact us at %s, so we "
"can fix the problem. For some reason, an unrecognized "
- "bitpix value (%d) has been seen in polygonmask (crop.c)",
- PACKAGE_BUGREPORT, bitpix);
+ "datatype value (%d) has been seen in polygonmask (crop.c)",
+ PACKAGE_BUGREPORT, datatype);
}
/* Clean up: */
@@ -713,7 +713,7 @@ onecrop(struct cropparams *crp)
/* Read the desired part of the image, then write it into this
array. */
cropsize=(lpixel_i[0]-fpixel_i[0]+1)*(lpixel_i[1]-fpixel_i[1]+1);
- array=gal_fits_bitpix_alloc(cropsize, bitpix);
+ array=gal_fits_datatype_alloc(cropsize, p->datatype);
status=0;
if(fits_read_subset(ifp, p->datatype, fpixel_i, lpixel_i, inc,
p->bitnul, array, &anynul, &status))
@@ -828,7 +828,7 @@ iscenterfilled(struct cropparams *crp)
/* Allocate the array and read in the pixels. */
size=checkcenter*checkcenter;
- array=gal_fits_bitpix_alloc(size, bitpix);
+ array=gal_fits_datatype_alloc(size, gal_fits_bitpix_to_dtype(bitpix) );
if( fits_read_subset(ofp, p->datatype, fpixel, lpixel, inc,
p->bitnul, array, &anynul, &status) )
gal_fits_io_error(status, NULL);
diff --git a/src/imgcrop/imgcrop.c b/src/imgcrop/imgcrop.c
index 849ed75..2f17b09 100644
--- a/src/imgcrop/imgcrop.c
+++ b/src/imgcrop/imgcrop.c
@@ -90,7 +90,7 @@ imgmodecrop(void *inparam)
/* The whole catalog is from one image, so you can get the
information here:*/
img=&p->imgs[crp->imgindex];
- gal_fits_read_hdu(img->name, cp->hdu, IMAGE_HDU, &crp->infits);
+ gal_fits_read_hdu(img->name, cp->hdu, 0, &crp->infits);
/* Go over all the outputs that are assigned to this thread: */
for(i=0;crp->indexs[i]!=GAL_THREADS_NON_THRD_INDEX;++i)
@@ -181,7 +181,7 @@ wcsmodecrop(void *inparam)
if(radecoverlap(crp))
{
gal_fits_read_hdu(p->imgs[crp->imgindex].name, p->cp.hdu,
- IMAGE_HDU, &crp->infits);
+ 0, &crp->infits);
if(log->name==NULL) cropname(crp);
diff --git a/src/imgcrop/ui.c b/src/imgcrop/ui.c
index 61cc70f..61813c0 100644
--- a/src/imgcrop/ui.c
+++ b/src/imgcrop/ui.c
@@ -608,7 +608,7 @@ preparearrays(struct imgcropparams *p)
status=0;
img=&p->imgs[i];
gal_linkedlist_pop_from_stll(&p->up.gal_linkedlist_stll, &img->name);
- gal_fits_read_hdu(img->name, p->cp.hdu, IMAGE_HDU, &tmpfits);
+ gal_fits_read_hdu(img->name, p->cp.hdu, 0, &tmpfits);
gal_fits_img_bitpix_size(tmpfits, &p->bitpix, img->naxes);
gal_fits_read_wcs_from_pointer(tmpfits, &img->nwcs, &img->wcs,
p->hstartwcs, p->hendwcs);
@@ -635,7 +635,7 @@ preparearrays(struct imgcropparams *p)
{
firstbitpix=p->bitpix;
p->datatype=gal_fits_bitpix_to_dtype(p->bitpix);
- p->bitnul=gal_fits_bitpix_blank(p->bitpix);
+ p->bitnul=gal_fits_datatype_blank(p->datatype);
}
else if(firstbitpix!=p->bitpix)
error(EXIT_FAILURE, 0, "%s: BITPIX=%d. Previous images had a "
diff --git a/src/mkcatalog/ui.c b/src/mkcatalog/ui.c
index 38fef36..0d898f4 100644
--- a/src/mkcatalog/ui.c
+++ b/src/mkcatalog/ui.c
@@ -1095,7 +1095,7 @@ preparearrays(struct mkcatalogparams *p)
/* Prepare the columns and allocate the p->objcols and p->clumpcols
arrays to keep the macros of what output they should keep. */
- gal_linkedlist_sll_to_array(p->allcolsll, &p->allcols, &p->allncols);
+ gal_linkedlist_sll_to_array(p->allcolsll, &p->allcols, &p->allncols, 0);
if(p->allncols==0)
error(EXIT_FAILURE, 0, "no columns specified for output");
errno=0; p->objcols=malloc(p->allncols*sizeof *p->objcols);
diff --git a/src/table/Makefile.am b/src/table/Makefile.am
new file mode 100644
index 0000000..4c66f48
--- /dev/null
+++ b/src/table/Makefile.am
@@ -0,0 +1,41 @@
+## Process this file with automake to produce Makefile.inx
+##
+## Original author:
+## Mohammad Akhlaghi <address@hidden>
+## Contributing author(s):
+## Copyright (C) 2016, Free Software Foundation, Inc.
+##
+## Gnuastro is free software: you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## Gnuastro is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+## General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Gnuastro. If not, see <http://www.gnu.org/licenses/>.
+
+
+
+
+
+## Utility and its sources
+bin_PROGRAMS = asttable
+
+asttable_SOURCES = main.c main.h cite.h ui.c ui.h args.h \
+table.c table.h
+
+asttable_LDADD = $(top_builddir)/bootstrapped/lib/libgnu.la \
+-lgalconfigfiles -lgalfits -lgalcheckset -lgaltiming -lgallinkedlist \
+-lgaltxtarray
+
+
+
+
+
+# To destribute the defaults file.
+# NOTE: the man page is created in doc/Makefile.am
+dist_sysconf_DATA = asttable.conf
diff --git a/src/table/args.h b/src/table/args.h
new file mode 100644
index 0000000..ac82696
--- /dev/null
+++ b/src/table/args.h
@@ -0,0 +1,371 @@
+/*********************************************************************
+Table - View and manipulate a FITS table structures.
+Table is part of GNU Astronomy Utilities (Gnuastro) package.
+
+Original author:
+ Mohammad Akhlaghi <address@hidden>
+Contributing author(s):
+Copyright (C) 2016, Free Software Foundation, Inc.
+
+Gnuastro is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation, either version 3 of the License, or (at your
+option) any later version.
+
+Gnuastro is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Gnuastro. If not, see <http://www.gnu.org/licenses/>.
+**********************************************************************/
+#ifndef ARGS_H
+#define ARGS_H
+
+#include <argp.h>
+
+#include <gnuastro/commonargs.h>
+#include <gnuastro/linkedlist.h>
+#include <gnuastro/fixedstringmacros.h>
+
+
+
+
+
+
+
+
+
+
+/**************************************************************/
+/************** argp.h definitions ***************/
+/**************************************************************/
+
+
+
+
+/* Definition parameters for the argp: */
+const char *argp_program_version=SPACK_STRING"\n"GAL_STRINGS_COPYRIGHT
+ "\n\nWritten by Mohammad Akhlaghi";
+const char *argp_program_bug_address=PACKAGE_BUGREPORT;
+static char args_doc[] = "ASTRdata";
+
+
+
+
+
+const char doc[] =
+ /* Before the list of options: */
+ GAL_STRINGS_TOP_HELP_INFO
+ SPACK_NAME" prints (in a human readable format) a FITS table or its "
+ "information. The output columns can either be selected by number, name "
+ "or using regular expressions. The format of their printing can also "
+ "be set (based on the type of data in the column).\n"
+ GAL_STRINGS_MORE_HELP_INFO
+ /* After the list of options: */
+ "\v"
+ PACKAGE_NAME" home page: "PACKAGE_URL;
+
+
+
+
+
+/* Available letters for short options:
+
+ a b d e f g j k l m n p r s u v w x y z
+ A B C E F G H J L M O Q R T U W X Y Z
+
+ Number keys used: 1008
+
+ Options with keys (second structure element) larger than 500 do not
+ have a short version.
+ */
+static struct argp_option options[] =
+ {
+ {
+ 0, 0, 0, 0,
+ "Input:",
+ 1
+ },
+ {
+ "column",
+ 'c',
+ "STR",
+ 0,
+ "Input column name, number or regular expression.",
+ 1
+ },
+ {
+ "ignorecase",
+ 'I',
+ 0,
+ 0,
+ "Ignore case when matching column names.",
+ 1
+ },
+
+
+
+
+ {
+ 0, 0, 0, 0,
+ "Output:",
+ 2
+ },
+ {
+ "feg",
+ 1001,
+ "STR",
+ 0,
+ "`f': only decimals, `e': scientific, `g': either.",
+ 2
+ },
+ {
+ "sintwidth",
+ 1002,
+ "INT",
+ 0,
+ "Shorter integer column(s) width (num charachers).",
+ 2
+ },
+ {
+ "lintwidth",
+ 1003,
+ "INT",
+ 0,
+ "Longer integer column(s) width (num charachers).",
+ 2
+ },
+ {
+ "floatwidth",
+ 1004,
+ "INT",
+ 0,
+ "`float' column(s) width (num charachers).",
+ 2
+ },
+ {
+ "doublewidth",
+ 1005,
+ "INT",
+ 0,
+ "`double' column(s) width (num charachers).",
+ 2
+ },
+ {
+ "strwidth",
+ 1006,
+ "INT",
+ 0,
+ "String column(s) width (num charachers).",
+ 2
+ },
+ {
+ "floatprecision",
+ 1007,
+ "INT",
+ 0,
+ "`float' column(s) precision.",
+ 2
+ },
+ {
+ "doubleprecision",
+ 1008,
+ "INT",
+ 0,
+ "`double' column(s) precision.",
+ 2
+ },
+ {
+ "fitstabletype",
+ 't',
+ "STR",
+ 0,
+ "Only `ascii', or `binary' are acceptable.",
+ 2
+ },
+
+
+
+
+ {
+ 0, 0, 0, 0,
+ "Operating modes:",
+ -1
+ },
+ {
+ "information",
+ 'i',
+ 0,
+ 0,
+ "Only print table and columns information.",
+ -1
+ },
+
+
+ {0}
+ };
+
+
+
+
+
+/* Parse a single option: */
+static error_t
+parse_opt(int key, char *arg, struct argp_state *state)
+{
+ /* Save the arguments structure: */
+ char *tstring;
+ struct tableparams *p = state->input;
+
+ /* Set the pointer to the common parameters for all programs
+ here: */
+ state->child_inputs[0]=&p->cp;
+
+ /* In case the user incorrectly uses the equal sign (for example
+ with a short format or with space in the long format, then `arg`
+ start with (if the short version was called) or be (if the long
+ version was called with a space) the equal sign. So, here we
+ check if the first character of arg is the equal sign, then the
+ user is warned and the program is stopped: */
+ if(arg && arg[0]=='=')
+ argp_error(state, "incorrect use of the equal sign (`=`). For short "
+ "options, `=` should not be used and for long options, "
+ "there should be no space between the option, equal sign "
+ "and value");
+
+ switch(key)
+ {
+
+
+ /* Input: */
+ case 'c':
+ gal_checkset_allocate_copy(arg, &tstring);
+ gal_linkedlist_add_to_stll(&p->up.columns, tstring);
+ break;
+
+ case 'I':
+ p->up.ignorecase=1;
+ p->up.ignorecaseset=1;
+ break;
+
+
+ /* Output: */
+ case 1001:
+ checksetfge(arg, &p->up.feg, NULL, 0);
+ p->up.fegset=1;
+ break;
+
+ case 1002:
+ gal_checkset_sizet_el_zero(arg, &p->up.sintwidth, "sintwidth", key,
+ SPACK, NULL, 0);
+ p->up.sintwidthset=1;
+ break;
+
+ case 1003:
+ gal_checkset_sizet_el_zero(arg, &p->up.lintwidth, "lintwidth", key,
+ SPACK, NULL, 0);
+ p->up.lintwidthset=1;
+ break;
+
+ case 1004:
+ gal_checkset_sizet_el_zero(arg, &p->up.floatwidth, "floatwidth", key,
+ SPACK, NULL, 0);
+ p->up.floatwidthset=1;
+ break;
+
+ case 1005:
+ gal_checkset_sizet_el_zero(arg, &p->up.doublewidth, "doublewidth", key,
+ SPACK, NULL, 0);
+ p->up.doublewidthset=1;
+ break;
+
+ case 1006:
+ gal_checkset_sizet_el_zero(arg, &p->up.strwidth, "strwidth", key,
+ SPACK, NULL, 0);
+ p->up.strwidthset=1;
+ break;
+
+ case 1007:
+ gal_checkset_sizet_el_zero(arg, &p->up.floatprecision,
+ "floatprecision", key, SPACK, NULL, 0);
+ p->up.floatprecisionset=1;
+ break;
+
+ case 1008:
+ gal_checkset_sizet_el_zero(arg, &p->up.doubleprecision,
+ "doubleprecision", key, SPACK, NULL, 0);
+ p->up.doubleprecisionset=1;
+ break;
+
+ case 't':
+ checksetfitstabletype(arg, &p->up.feg, NULL, 0);
+ p->up.fitstabletypeset=1;
+ break;
+
+
+ /* Operating modes: */
+ case 'i':
+ p->up.information=1;
+ p->up.informationset=1;
+ break;
+
+
+ /* Read the non-option arguments: */
+ case ARGP_KEY_ARG:
+
+ /* Table gets only one input argument. */
+ if(p->up.inputset)
+ argp_error(state, "only one input file should be given");
+
+ /* This is the first (and must be only) argument. */
+ p->up.inputset=1;
+
+ /* See what type of input this is, and save the value. */
+ if( gal_fits_name_is_fits(arg) )
+ p->up.fitsname=arg;
+ else
+ p->up.txtname=arg;
+
+ 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;
+
+
+
+
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
+
+
+
+
+/* Specify the children parsers: */
+struct argp_child children[]=
+ {
+ {&commonargp, 0, NULL, 0},
+ {0, 0, 0, 0}
+ };
+
+
+
+
+
+/* Basic structure defining the whole argument reading process. */
+static struct argp thisargp = {options, parse_opt, args_doc,
+ doc, children, NULL, NULL};
+
+#endif
diff --git a/src/table/asttable.conf b/src/table/asttable.conf
new file mode 100644
index 0000000..7bb2a00
--- /dev/null
+++ b/src/table/asttable.conf
@@ -0,0 +1,32 @@
+# Default parameters (System) for Table.
+# Table is part of GNU Astronomy Utitlies.
+#
+# Use the long option name of each paramter followed by
+# a value. The name and value should be separated by
+# atleast one of the following charaacters:
+# space, `,`, `=` or `:`
+#
+# Run with `--help` option or read the manual for a full
+# explanation of what each option means.
+#
+# NOTE I: All counting is from zero, not one.
+# NOTE II: Lines starting with `#` are ignored.
+#
+# Copying and distribution of this file, with or without modification,
+# are permitted in any medium without royalty provided the copyright
+# notice and this notice are preserved. This file is offered as-is,
+# without any warranty.
+
+# Input:
+ hdu 0
+
+# Output:
+ feg f
+ sintwidth 5
+ lintwidth 15
+ floatwidth 10
+ doublewidth 15
+ strwidth 20
+ floatprecision 3
+ doubleprecision 8
+ fitstabletype binary
diff --git a/src/table/cite.h b/src/table/cite.h
new file mode 100644
index 0000000..de9ab4f
--- /dev/null
+++ b/src/table/cite.h
@@ -0,0 +1,38 @@
+/*********************************************************************
+Table - View and manipulate a FITS table structures.
+Table is part of GNU Astronomy Utilities (Gnuastro) package.
+
+Original author:
+ Mohammad Akhlaghi <address@hidden>
+Contributing author(s):
+Copyright (C) 2016, Free Software Foundation, Inc.
+
+Gnuastro is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation, either version 3 of the License, or (at your
+option) any later version.
+
+Gnuastro is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Gnuastro. If not, see <http://www.gnu.org/licenses/>.
+**********************************************************************/
+#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); \
+ }
+
+#endif
diff --git a/src/table/main.c b/src/table/main.c
new file mode 100644
index 0000000..b2eb42a
--- /dev/null
+++ b/src/table/main.c
@@ -0,0 +1,56 @@
+/*********************************************************************
+Table - View and manipulate a FITS table structures.
+Table is part of GNU Astronomy Utilities (Gnuastro) package.
+
+Original author:
+ Mohammad Akhlaghi <address@hidden>
+Contributing author(s):
+Copyright (C) 2016, Free Software Foundation, Inc.
+
+Gnuastro is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation, either version 3 of the License, or (at your
+option) any later version.
+
+Gnuastro is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Gnuastro. If not, see <http://www.gnu.org/licenses/>.
+**********************************************************************/
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <progname.h>
+
+#include <gnuastro/timing.h> /* Includes time.h and sys/time.h */
+
+#include "main.h"
+
+#include "ui.h" /* needs main.h. */
+#include "table.h" /* needs main.h. */
+
+int
+main (int argc, char *argv[])
+{
+ struct tableparams p={{0}, {0}, 0};
+
+ /* Set the program name (needed by non-gnu operating systems): */
+ time(&p.rawtime);
+ set_program_name(argv[0]);
+
+ /* Read the input parameters. */
+ setparams(argc, argv, &p);
+
+ /* Run MakeProfiles */
+ table(&p);
+
+ /* Free all non-freed allocations. */
+ freeandreport(&p);
+
+ /* Return successfully.*/
+ return EXIT_SUCCESS;
+}
diff --git a/src/table/main.h b/src/table/main.h
new file mode 100644
index 0000000..50f5c80
--- /dev/null
+++ b/src/table/main.h
@@ -0,0 +1,126 @@
+/*********************************************************************
+Table - View and manipulate a FITS table structures.
+Table is part of GNU Astronomy Utilities (Gnuastro) package.
+
+Original author:
+ Mohammad Akhlaghi <address@hidden>
+Contributing author(s):
+Copyright (C) 2016, Free Software Foundation, Inc.
+
+Gnuastro is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation, either version 3 of the License, or (at your
+option) any later version.
+
+Gnuastro is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Gnuastro. If not, see <http://www.gnu.org/licenses/>.
+**********************************************************************/
+#ifndef MAIN_H
+#define MAIN_H
+
+#include <gnuastro/fits.h>
+#include <gnuastro/commonparams.h>
+
+/* Progarm name macros: */
+#define SPACK "asttable" /* Subpackage executable name. */
+#define SPACK_NAME "Table" /* Subpackage full name. */
+#define SPACK_STRING SPACK_NAME" ("PACKAGE_NAME") "PACKAGE_VERSION
+
+#define MAX_COL_FORMAT_LENGTH 20
+
+
+
+/* Structure to keep the information for each output column */
+struct outcolumn
+{
+ size_t inindex; /* Row index (from 0) in input array. */
+ int datatype; /* Type of data (from CFITSIO macros). */
+ int anynul; /* If there is any blank characters. */
+ void *nulval; /* The blank value for this column. */
+ void *data; /* Array keeping the column data. */
+ char fmt[MAX_COL_FORMAT_LENGTH]; /* format to use in printf. */
+};
+
+
+
+
+
+/* User interface structure. */
+struct uiparams
+{
+ int information; /* ==1, only print FITS information. */
+ char *fitsname; /* Name of input FITS file. */
+ char *txtname; /* Name of input text file. */
+ int ignorecase; /* Ignore case matching column names. */
+
+ /* Input table parameters. */
+ size_t ncols; /* Number of columns in table. */
+ int *datatype; /* Type of data in column. */
+ char **ttstr; /* TFORM (another format for type). */
+ char **tname; /* Column name (one word). */
+ char **tunit; /* Unit of values in column. */
+ double *txtarray; /* Array keeping text file values. */
+ int infitstabletype; /* Input table is ASCII or binary. */
+
+ /* Print parameters: */
+ int feg; /* format of floating points. */
+ size_t sintwidth; /* Full width for short integers. */
+ size_t lintwidth; /* Full width for short integers. */
+ size_t floatwidth; /* Full width for all floats. */
+ size_t doublewidth; /* Full width for all doubles. */
+ size_t strwidth; /* Full width for all floats. */
+ size_t floatprecision; /* Number of decimals for floats. */
+ size_t doubleprecision; /* Number of decimals for doubles. */
+
+ /* If values are set: */
+ int inputset;
+ int informationset;
+ int ignorecaseset;
+ int fegset;
+ int sintwidthset;
+ int lintwidthset;
+ int floatwidthset;
+ int doublewidthset;
+ int strwidthset;
+ int floatprecisionset;
+ int doubleprecisionset;
+ int fitstabletypeset;
+
+
+ struct gal_linkedlist_stll *columns;
+};
+
+
+
+
+
+/* Main program parameters structure */
+struct tableparams
+{
+ /* Other structures: */
+ struct uiparams up; /* User interface parameters. */
+ struct gal_commonparams cp; /* Common parameters. */
+
+ /* Input: */
+ fitsfile *fitsptr; /* FITS pointer (input or output). */
+
+ /* Output: */
+ size_t nrows; /* Number of rows in table. */
+ size_t nocols; /* Number of output columns. */
+ struct outcolumn *ocols; /* Array of output column informatio. */
+ int outputtofits; /* ==1: output is a FITS file. */
+ int outputtotxt; /* ==1: output is a text file. */
+ int outputtostdout; /* ==1: output is the standard output. */
+ int fitstabletype; /* ASCII, or binary table CFITSIO macro.*/
+
+ /* Internal: */
+ int onlyview;
+ time_t rawtime; /* Starting time of the program. */
+};
+
+#endif
diff --git a/src/table/table.c b/src/table/table.c
new file mode 100644
index 0000000..6b682b0
--- /dev/null
+++ b/src/table/table.c
@@ -0,0 +1,437 @@
+/*********************************************************************
+Table - View and manipulate a FITS table structures.
+Table is part of GNU Astronomy Utilities (Gnuastro) package.
+
+Original author:
+ Mohammad Akhlaghi <address@hidden>
+Contributing author(s):
+Copyright (C) 2016, Free Software Foundation, Inc.
+
+Gnuastro is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation, either version 3 of the License, or (at your
+option) any later version.
+
+Gnuastro is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Gnuastro. If not, see <http://www.gnu.org/licenses/>.
+**********************************************************************/
+#include <config.h>
+
+#include <errno.h>
+#include <error.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <gnuastro/fits.h>
+
+#include "main.h"
+
+
+
+/**************************************************************/
+/*************** Input table *******************/
+/**************************************************************/
+/* Set the format string for each column: */
+void
+setformatstring(struct tableparams *p, size_t outcolid)
+{
+ struct uiparams *up=&p->up;
+ char width[10], accu[10], *type=NULL;
+ struct outcolumn *ocol=&p->ocols[outcolid];
+
+
+ switch(ocol->datatype)
+ {
+ case TBIT:
+ error(EXIT_FAILURE, 0, "Table doesn't print TBIT data type "
+ "currently, please contact us at %s so we can implement "
+ "it.", PACKAGE_BUGREPORT);
+
+ case TBYTE:
+ type="u";
+ sprintf(width, "%lu", up->sintwidth);
+ accu[0]='\0';
+ break;
+
+ case TLOGICAL: case TSBYTE:
+ type="d";
+ sprintf(width, "%lu", up->sintwidth);
+ accu[0]='\0';
+ break;
+
+ case TSTRING:
+ type="s";
+ if(up->sintwidth) sprintf(width, "%lu", up->sintwidth);
+ else width[0]='\0';
+ accu[0]='\0';
+ break;
+
+ case TSHORT:
+ type="d";
+ sprintf(width, "%lu", up->sintwidth);
+ accu[0]='\0';
+ break;
+
+ case TLONG:
+ type="ld";
+ sprintf(width, "%lu", up->lintwidth);
+ accu[0]='\0';
+ break;
+
+ case TLONGLONG:
+ type="ld";
+ sprintf(width, "%lu", up->lintwidth);
+ accu[0]='\0';
+ break;
+
+ case TFLOAT:
+ type = up->feg=='f' ? "f" : ( up->feg=='e' ? "e" : "g");
+ sprintf(width, "%lu", up->floatwidth);
+ sprintf(accu, ".%lu", up->floatprecision);
+ break;
+
+ case TDOUBLE:
+ type = up->feg=='f' ? "f" : ( up->feg=='e' ? "e" : "g");
+ sprintf(width, "%lu", up->doublewidth);
+ sprintf(accu, ".%lu", up->doubleprecision);
+ break;
+
+ case TCOMPLEX:
+ error(EXIT_FAILURE, 0, "Table doesn't print TCOMPLEX data type "
+ "currently, please contact us at %s so we can implement "
+ "it.", PACKAGE_BUGREPORT);
+ break;
+
+ case TDBLCOMPLEX:
+ error(EXIT_FAILURE, 0, "Table doesn't print TDBLCOMPLEX data type "
+ "currently, please contact us at %s so we can implement "
+ "it.", PACKAGE_BUGREPORT);
+ break;
+
+ case TINT:
+ type="d";
+ sprintf(width, "%lu", up->sintwidth);
+ accu[0]='\0';
+ break;
+
+ case TUINT:
+ type="u";
+ sprintf(width, "%lu", up->sintwidth);
+ accu[0]='\0';
+ break;
+
+ case TUSHORT:
+ type="u";
+ sprintf(width, "%lu", up->sintwidth);
+ accu[0]='\0';
+ break;
+
+ case TULONG:
+ type="lu";
+ sprintf(width, "%lu", up->lintwidth);
+ accu[0]='\0';
+ break;
+
+ default:
+ error(EXIT_FAILURE, 0, "datatype value of %d not recognized in "
+ "gal_fits_datatype_alloc", ocol->datatype);
+ }
+
+ /* Put the type, width and accu into the format string for this
+ column: */
+ sprintf(ocol->fmt, "%%-%s%s%s", width, accu, type);
+}
+
+
+
+
+
+/* Read all the input columns */
+void
+readinputcols(struct tableparams *p)
+{
+ double *colfromtxt;
+ struct outcolumn *col;
+ int datatype, status=0;
+ size_t i, j, nrows=p->nrows, incols=p->up.ncols;
+
+ /* Get the contents of each table column: */
+ for(i=0;i<p->nocols;++i)
+ {
+ /* Variables for simple reading */
+ col=&p->ocols[i];
+
+ datatype=col->datatype;
+
+ /* Allocate the blank value for this column. Note that we will also
+ need the blankvalue for a text file when outputing to a FITS. */
+ col->nulval=gal_fits_datatype_blank(datatype);
+
+ /* Read the input column. */
+ if(p->fitsptr)
+ {
+ /* Allocate space for the data in this column */
+ col->data=gal_fits_datatype_alloc(nrows, datatype);
+
+ /* Call CFITSIO to read the column information. */
+ fits_read_col(p->fitsptr, datatype, col->inindex+1, 1, 1,
+ nrows, col->nulval, col->data, &col->anynul,
+ &status);
+ }
+ else
+ {
+ /* This is a text file, read by Gnuastro's current txtarray
+ library. This library currently only reads a 2D table into a
+ 2D array of type double. The important thing here is that the
+ array is row-contiguous. But here we want column contiguous
+ data. So we allocate an array to only put this column's values
+ in.*/
+ errno=0;
+ colfromtxt=col->data=malloc(nrows * sizeof *col->data);
+
+ if(col->data==NULL)
+ error(EXIT_FAILURE, errno, "%lu bytes for col->data",
+ nrows * sizeof *col->data);
+ for(j=0;j<nrows;++j)
+ colfromtxt[j]=p->up.txtarray[ j * incols + col->inindex ];
+ }
+
+ /* Set the format string to print the column values if the output is
+ to be printed as text (either in a text file or to the standard
+ output. */
+ if(p->outputtotxt || p->outputtostdout)
+ setformatstring(p, i);
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/**************************************************************/
+/*************** Output table *******************/
+/**************************************************************/
+void
+saveouttofits(struct tableparams *p)
+{
+ size_t i;
+ int status=0;
+ fitsfile *fptr;
+ struct uiparams *up=&p->up;
+ char **ttype, **tform, **tunit;
+ struct outcolumn *ocols=p->ocols;
+
+ /* Allocate the information arrays for CFITSIO. */
+ errno=0;
+ ttype=malloc(p->nocols*sizeof *ttype);
+ if(ttype==NULL)
+ error(EXIT_FAILURE, errno, "%lu bytes for ttype",
+ p->nocols*sizeof *ttype);
+ errno=0;
+ tform=malloc(p->nocols*sizeof *tform);
+ if(tform==NULL)
+ error(EXIT_FAILURE, errno, "%lu bytes for tform",
+ p->nocols*sizeof *tform);
+ errno=0;
+ tunit=malloc(p->nocols*sizeof *tunit);
+ if(tunit==NULL)
+ error(EXIT_FAILURE, errno, "%lu bytes for tunit",
+ p->nocols*sizeof *tunit);
+
+ /* Fill in the information arrays: */
+ for(i=0;i<p->nocols;++i)
+ {
+ tform[i]=up->ttstr[ ocols[i].inindex ];
+ ttype[i]=up->tname[ ocols[i].inindex ];
+ tunit[i]=up->tunit[ ocols[i].inindex ];
+ }
+
+ /* Open the output FITS file. */
+ if(access(p->cp.output,F_OK) != -1 )
+ fits_open_file(&fptr, p->cp.output, READWRITE, &status);
+ else
+ fits_create_file(&fptr, p->cp.output, &status);
+
+ /* Create a new table extension */
+ fits_create_tbl(fptr, p->fitstabletype, p->nrows, p->nocols, ttype,
+ tform, tunit, "Table", &status);
+
+ /* Write this column's data into the FITS file. */
+ for(i=0;i<p->nocols;++i)
+ fits_write_colnull(fptr, ocols[i].datatype, i+1, 1, 1, p->nrows,
+ ocols[i].data, ocols[i].nulval, &status);
+
+ /* Include the ending comments and close the file. */
+ gal_fits_copyright_end(fptr, NULL, SPACK_STRING);
+ fits_close_file(fptr, &status);
+ gal_fits_io_error(status, NULL);
+
+ /* Clean up */
+ free(ttype);
+ free(tform);
+ free(tunit);
+}
+
+
+
+
+
+void
+printoutput(struct tableparams *p)
+{
+ FILE *fp;
+ size_t i, row;
+ struct outcolumn *ocols=p->ocols;
+
+ /* Determine the output stream and open the file for writing if its a
+ file. */
+ if(p->outputtotxt)
+ {
+ errno=0;
+ fp=fopen(p->cp.output, "w");
+ if(fp==NULL)
+ error(EXIT_FAILURE, errno, "%s", p->cp.output);
+ }
+ else
+ fp=stdout;
+
+ /* Print each column and each row: */
+ for(row=0;row<p->nrows;++row)
+ {
+ for(i=0;i<p->nocols;++i)
+ switch(ocols[i].datatype)
+ {
+ case TBIT:
+ error(EXIT_FAILURE, 0, "Table doesn't print TBIT data type "
+ "currently, please contact us at %s so we can implement "
+ "it.", PACKAGE_BUGREPORT);
+
+ case TBYTE:
+ fprintf(fp, ocols[i].fmt, ((unsigned char *)ocols[i].data)[row]);
+ break;
+
+ case TLOGICAL: case TSBYTE:
+ fprintf(fp, ocols[i].fmt, ((char *)ocols[i].data)[row]);
+ break;
+
+ case TSTRING:
+ fprintf(fp, ocols[i].fmt, ((char **)ocols[i].data)[row]);
+ break;
+
+ case TSHORT:
+ fprintf(fp, ocols[i].fmt, ((short *)ocols[i].data)[row]);
+ break;
+
+ case TLONG:
+ fprintf(fp, ocols[i].fmt, ((long *)ocols[i].data)[row]);
+ break;
+
+ case TLONGLONG:
+ fprintf(fp, ocols[i].fmt, ((LONGLONG *)ocols[i].data)[row]);
+ break;
+
+ case TFLOAT:
+ fprintf(fp, ocols[i].fmt, ((float *)ocols[i].data)[row]);
+ break;
+
+ case TDOUBLE:
+ fprintf(fp, ocols[i].fmt, ((double *)ocols[i].data)[row]);
+ break;
+
+ case TCOMPLEX:
+ error(EXIT_FAILURE, 0, "Table doesn't print TCOMPLEX data type "
+ "currently, please contact us at %s so we can implement "
+ "it.", PACKAGE_BUGREPORT);
+ break;
+
+ case TDBLCOMPLEX:
+ error(EXIT_FAILURE, 0, "Table doesn't print TDBLCOMPLEX data "
+ "type currently, please contact us at %s so we can "
+ "implement it.", PACKAGE_BUGREPORT);
+ break;
+
+ case TINT:
+ fprintf(fp, ocols[i].fmt, ((char *)ocols[i].data)[row]);
+ break;
+
+ case TUINT:
+ fprintf(fp, ocols[i].fmt, ((unsigned int *)ocols[i].data)[row]);
+ break;
+
+ case TUSHORT:
+ fprintf(fp, ocols[i].fmt, ((unsigned short *)ocols[i].data)[row]);
+ break;
+
+ case TULONG:
+ fprintf(fp, ocols[i].fmt, ((unsigned long *)ocols[i].data)[row]);
+ break;
+
+ default:
+ error(EXIT_FAILURE, 0, "datatype value of %d not recognized in "
+ "printoutput", ocols[i].datatype);
+ }
+ fprintf(fp, "\n");
+ }
+
+ /* If we printed to a file, then close it. */
+ if(p->outputtotxt)
+ {
+ errno=0;
+ if( fclose(fp) == EOF )
+ error(EXIT_FAILURE, errno, "%s", p->cp.output);
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/**************************************************************/
+/*************** Top function *******************/
+/**************************************************************/
+void
+table(struct tableparams *p)
+{
+ readinputcols(p);
+
+ if(p->outputtofits)
+ saveouttofits(p);
+ else
+ printoutput(p);
+}
diff --git a/src/table/table.h b/src/table/table.h
new file mode 100644
index 0000000..8c164ec
--- /dev/null
+++ b/src/table/table.h
@@ -0,0 +1,31 @@
+/*********************************************************************
+Table - View and manipulate a FITS table structures.
+Table is part of GNU Astronomy Utilities (Gnuastro) package.
+
+Original author:
+ Mohammad Akhlaghi <address@hidden>
+Contributing author(s):
+Copyright (C) 2016, Free Software Foundation, Inc.
+
+Gnuastro is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation, either version 3 of the License, or (at your
+option) any later version.
+
+Gnuastro is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Gnuastro. If not, see <http://www.gnu.org/licenses/>.
+**********************************************************************/
+#ifndef TABLE_H
+#define TABLE_H
+
+
+
+void
+table(struct tableparams *p);
+
+#endif
diff --git a/src/table/ui.c b/src/table/ui.c
new file mode 100644
index 0000000..d4825d1
--- /dev/null
+++ b/src/table/ui.c
@@ -0,0 +1,1041 @@
+/*********************************************************************
+Table - View and manipulate a FITS table structures.
+Table is part of GNU Astronomy Utilities (Gnuastro) package.
+
+Original author:
+ Mohammad Akhlaghi <address@hidden>
+Contributing author(s):
+Copyright (C) 2016, Free Software Foundation, Inc.
+
+Gnuastro is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation, either version 3 of the License, or (at your
+option) any later version.
+
+Gnuastro is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Gnuastro. If not, see <http://www.gnu.org/licenses/>.
+**********************************************************************/
+#include <config.h>
+
+#include <math.h>
+#include <stdio.h>
+#include <errno.h>
+#include <error.h>
+#include <regex.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fitsio.h>
+
+#include <nproc.h> /* From Gnulib. */
+
+#include <gnuastro/fits.h>
+#include <gnuastro/timing.h> /* Includes time.h and sys/time.h */
+#include <gnuastro/checkset.h>
+#include <gnuastro/txtarray.h>
+#include <gnuastro/commonargs.h>
+#include <gnuastro/configfiles.h>
+
+#include "main.h"
+
+#include "ui.h" /* Needs main.h */
+#include "args.h" /* Needs main.h, includes argp.h. */
+
+
+/* Set the file names of the places where the default parameters are
+ put. */
+#define CONFIG_FILE SPACK CONF_POSTFIX
+#define SYSCONFIG_FILE SYSCONFIG_DIR "/" CONFIG_FILE
+#define USERCONFIG_FILEEND USERCONFIG_DIR CONFIG_FILE
+#define CURDIRCONFIG_FILE CURDIRCONFIG_DIR CONFIG_FILE
+
+
+
+
+
+
+
+
+
+
+/**************************************************************/
+/************** Options and parameters ***************/
+/**************************************************************/
+/* Check the value given for the fge option. */
+void
+checksetfge(char *optarg, int *fge, char *filename, size_t lineno)
+{
+ *fge=optarg[0];
+ if( *fge!='f' && *fge!='g' && *fge!='g' )
+ {
+ if(filename)
+ error_at_line(EXIT_FAILURE, 0, filename, lineno,
+ "the value of `fge' must only be one of the three "
+ "`f', `g', or `e' characters. You have given `%s'",
+ optarg);
+ else
+ error(EXIT_FAILURE, 0, "the value of `--fge' (`-f') must only be "
+ "one of the three `f', `g', or `e' characters. You have "
+ "given `%s'", optarg);
+ }
+}
+
+
+
+
+
+void
+checksetfitstabletype(char *optarg, int *fitstabletype, char *filename,
+ size_t lineno)
+{
+ if( !strcmp(optarg, "ascii") )
+ *fitstabletype=ASCII_TBL;
+ else if( !strcmp(optarg, "binary") )
+ *fitstabletype=BINARY_TBL;
+ else
+ {
+ if(filename)
+ error_at_line(EXIT_FAILURE, 0, filename, lineno,
+ "The value to the `fitstabletype' must be either "
+ "`ascii', or `binary'. You have given `%s'", optarg);
+ else
+ error(EXIT_FAILURE, 0, "The value to the `--fitstabletype' (`-t') "
+ "option must be either one of `ascii', or `binary'. You have, "
+ "given `%s'", optarg);
+ }
+}
+
+
+
+
+
+void
+readconfig(char *filename, struct tableparams *p)
+{
+ FILE *fp;
+ size_t lineno=0, len=200;
+ /*struct uiparams *up=&p->up;*/
+ struct gal_commonparams *cp=&p->cp;
+ char *line, *name, *value, *tstring;
+ char key='a'; /* Not used, just a place holder. */
+
+ /* When the file doesn't exist or can't be opened, it is ignored. It
+ might be intentional, so there is no error. If a parameter is
+ missing, it will be reported after all defaults are read. */
+ fp=fopen(filename, "r");
+ if (fp==NULL) return;
+
+
+ /* Allocate some space for `line` with `len` elements so it can
+ easily be freed later on. The value of `len` is arbitarary at
+ this point, during the run, getline will change it along with the
+ pointer to line. */
+ errno=0;
+ line=malloc(len*sizeof *line);
+ if(line==NULL)
+ error(EXIT_FAILURE, errno, "ui.c: %lu bytes in readdefaults",
+ len * sizeof *line);
+
+ /* Read the tokens in the file: */
+ while(getline(&line, &len, fp) != -1)
+ {
+ /* Prepare the "name" and "value" strings, also set lineno. */
+ GAL_CONFIGFILES_START_READING_LINE;
+
+
+
+
+ /* Inputs: */
+ if(strcmp(name, "hdu")==0)
+ gal_checkset_allocate_copy_set(value, &cp->hdu, &cp->hduset);
+
+ else if(strcmp(name, "column")==0)
+ {
+ gal_checkset_allocate_copy(value, &tstring);
+ gal_linkedlist_add_to_stll(&p->up.columns, tstring);
+ }
+
+ else if(strcmp(name, "ignorecase")==0)
+ {
+ if(p->up.ignorecaseset) continue;
+ gal_checkset_int_zero_or_one(value, &p->up.ignorecase, "ignorecase",
+ key, SPACK, filename, lineno);
+ p->up.ignorecaseset=1;
+ }
+
+
+
+ /* Outputs */
+ else if(strcmp(name, "output")==0)
+ gal_checkset_allocate_copy_set(value, &cp->output, &cp->outputset);
+
+ else if (strcmp(name, "feg")==0)
+ {
+ if(p->up.fegset) continue;
+ checksetfge(value, &p->up.feg, filename, lineno);
+ p->up.fegset=1;
+ }
+
+ else if (strcmp(name, "sintwidth")==0)
+ {
+ if(p->up.sintwidthset) continue;
+ gal_checkset_sizet_el_zero(value, &p->up.sintwidth, name,
+ key, SPACK, filename, lineno);
+ p->up.sintwidthset=1;
+ }
+
+ else if (strcmp(name, "lintwidth")==0)
+ {
+ if(p->up.lintwidthset) continue;
+ gal_checkset_sizet_el_zero(value, &p->up.lintwidth, name,
+ key, SPACK, filename, lineno);
+ p->up.lintwidthset=1;
+ }
+
+ else if (strcmp(name, "floatwidth")==0)
+ {
+ if(p->up.floatwidthset) continue;
+ gal_checkset_sizet_el_zero(value, &p->up.floatwidth, name,
+ key, SPACK, filename, lineno);
+ p->up.floatwidthset=1;
+ }
+
+ else if (strcmp(name, "doublewidth")==0)
+ {
+ if(p->up.doublewidthset) continue;
+ gal_checkset_sizet_el_zero(value, &p->up.doublewidth, name,
+ key, SPACK, filename, lineno);
+ p->up.doublewidthset=1;
+ }
+
+ else if (strcmp(name, "strwidth")==0)
+ {
+ if(p->up.strwidthset) continue;
+ gal_checkset_sizet_el_zero(value, &p->up.strwidth, name,
+ key, SPACK, filename, lineno);
+ p->up.strwidthset=1;
+ }
+
+ else if (strcmp(name, "floatprecision")==0)
+ {
+ if(p->up.floatprecisionset) continue;
+ gal_checkset_sizet_el_zero(value, &p->up.floatprecision,
+ name, key, SPACK, filename, lineno);
+ p->up.floatprecisionset=1;
+ }
+
+ else if (strcmp(name, "doubleprecision")==0)
+ {
+ if(p->up.doubleprecisionset) continue;
+ gal_checkset_sizet_el_zero(value, &p->up.doubleprecision,
+ name, key, SPACK, filename, lineno);
+ p->up.doubleprecisionset=1;
+ }
+ else if (strcmp(name, "fitstabletype")==0)
+ {
+ if(p->up.fitstabletypeset) continue;
+ checksetfitstabletype(value, &p->fitstabletype, filename, lineno);
+ p->up.fitstabletypeset=1;
+ }
+
+
+
+ /* Operating modes: */
+ else if (strcmp(name, "information")==0)
+ {
+ if(p->up.informationset) continue;
+ gal_checkset_int_zero_or_one(value, &p->up.information, name,
+ key, SPACK, filename, lineno);
+ p->up.informationset=1;
+ }
+
+
+ /* Read options common to all programs */
+ GAL_CONFIGFILES_READ_COMMONOPTIONS_FROM_CONF
+
+
+ else
+ error_at_line(EXIT_FAILURE, 0, filename, lineno,
+ "`%s` not recognized.\n", name);
+ }
+
+ free(line);
+ fclose(fp);
+}
+
+
+
+
+
+void
+printvalues(FILE *fp, struct tableparams *p)
+{
+ struct uiparams *up=&p->up;
+ struct gal_linkedlist_stll *tmp;
+ struct gal_commonparams *cp=&p->cp;
+
+
+ /* Print all the options that are set. Separate each group with a
+ commented line explaining the options in that group. */
+ fprintf(fp, "\n# Input:\n");
+ if(cp->hduset)
+ GAL_CHECKSET_PRINT_STRING_MAYBE_WITH_SPACE("hdu", cp->hdu);
+ if(up->columns)
+ for(tmp=up->columns;tmp!=NULL;tmp=tmp->next)
+ GAL_CHECKSET_PRINT_STRING_MAYBE_WITH_SPACE("column", tmp->v);
+ if(up->ignorecaseset)
+ fprintf(fp, CONF_SHOWFMT"%d\n", "ignorecase", up->ignorecase);
+
+
+ fprintf(fp, "\n# Output:\n");
+ if(up->fegset)
+ fprintf(fp, CONF_SHOWFMT"%c\n", "feg", up->feg);
+ if(up->sintwidthset)
+ fprintf(fp, CONF_SHOWFMT"%lu\n", "sintwidth", up->sintwidth);
+ if(up->lintwidthset)
+ fprintf(fp, CONF_SHOWFMT"%lu\n", "lintwidth", up->lintwidth);
+ if(up->floatwidthset)
+ fprintf(fp, CONF_SHOWFMT"%lu\n", "floatwidth", up->floatwidth);
+ if(up->doublewidthset)
+ fprintf(fp, CONF_SHOWFMT"%lu\n", "doublewidth", up->doublewidth);
+ if(up->strwidthset)
+ fprintf(fp, CONF_SHOWFMT"%lu\n", "strwidth", up->strwidth);
+ if(up->floatprecisionset)
+ fprintf(fp, CONF_SHOWFMT"%lu\n", "floatprecision", up->floatprecision);
+ if(up->doubleprecisionset)
+ fprintf(fp, CONF_SHOWFMT"%lu\n", "doubleprecision", up->doubleprecision);
+ if(up->fitstabletypeset)
+ fprintf(fp, CONF_SHOWFMT"%s\n", "fitstabletype",
+ p->fitstabletype==ASCII_TBL ? "ascii" : "binary");
+
+
+ /* For the operating mode, first put the macro to print the common
+ options, then the (possible options particular to this
+ program). */
+ fprintf(fp, "\n# Operating mode:\n");
+ if(up->informationset)
+ fprintf(fp, CONF_SHOWFMT"%d\n", "information", up->information);
+
+ GAL_CONFIGFILES_PRINT_COMMONOPTIONS;
+}
+
+
+
+
+
+
+/* Note that numthreads will be used automatically based on the
+ configure time. */
+void
+checkifset(struct tableparams *p)
+{
+ /*struct uiparams *up=&p->up;*/
+ struct uiparams *up=&p->up;
+ struct gal_commonparams *cp=&p->cp;
+
+ int intro=0;
+ if(cp->hduset==0)
+ GAL_CONFIGFILES_REPORT_NOTSET("hdu");
+
+ if(up->fegset==0)
+ GAL_CONFIGFILES_REPORT_NOTSET("feg");
+ if(up->sintwidthset==0)
+ GAL_CONFIGFILES_REPORT_NOTSET("sintwidth");
+ if(up->lintwidthset==0)
+ GAL_CONFIGFILES_REPORT_NOTSET("lintwidth");
+ if(up->floatwidthset==0)
+ GAL_CONFIGFILES_REPORT_NOTSET("floatwidth");
+ if(up->doublewidthset==0)
+ GAL_CONFIGFILES_REPORT_NOTSET("doublewidth");
+ if(up->strwidthset==0)
+ GAL_CONFIGFILES_REPORT_NOTSET("strwidth");
+ if(up->floatprecisionset==0)
+ GAL_CONFIGFILES_REPORT_NOTSET("floatprecision");
+ if(up->doubleprecisionset==0)
+ GAL_CONFIGFILES_REPORT_NOTSET("doubleprecision");
+ if(up->fitstabletypeset==0)
+ GAL_CONFIGFILES_REPORT_NOTSET("fitstabletype");
+
+ GAL_CONFIGFILES_END_OF_NOTSET_REPORT;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/**************************************************************/
+/************ Read and Write column info ***************/
+/**************************************************************/
+
+/* */
+ /* Allocate the arrays to keep the column information. Initialize the
+ arrays with a NULL pointer to make sure that they are all found in the
+ end if they are necessary. The values that are directly read from the
+ input file are initialized to NULL, so they can be treated
+ appropriately if they do not exist in the input (for example if they
+ are mandatory, or if they need to be printed).*/
+void
+allocinputcolinfo(struct tableparams *p)
+{
+ char **c, **fc;
+ size_t ncols=p->up.ncols;
+ struct uiparams *up=&p->up;
+
+ /* up->datatype keeps the type of data in each column as CFITSIO type
+ macros. */
+ errno=0;
+ up->datatype=malloc(ncols * sizeof *up->datatype);
+ if(up->datatype==NULL)
+ error(EXIT_FAILURE, errno, "%lu bytes for up->datatype",
+ ncols * sizeof *up->datatype);
+
+ /* up->ttstr keeps the actual string used to specify the datatype. */
+ errno=0;
+ up->ttstr=malloc(ncols * sizeof *up->ttstr);
+ if(up->ttstr==NULL)
+ error(EXIT_FAILURE, errno, "%lu bytes for ttstr",
+ ncols * sizeof *up->ttstr);
+ fc=(c=up->ttstr)+ncols; do *c++=NULL; while(c<fc);
+
+ /* up->tname keeps the name of the column. */
+ errno=0;
+ up->tname=malloc(ncols * sizeof *up->tname);
+ if(up->tname==NULL)
+ error(EXIT_FAILURE, errno, "%lu bytes for tname",
+ ncols * sizeof *up->tname);
+ fc=(c=up->tname)+ncols; do *c++=NULL; while(c<fc);
+
+ /* up->tunit keeps the input units of the column. */
+ errno=0;
+ up->tunit=malloc(ncols * sizeof *up->tunit);
+ if(up->tunit==NULL)
+ error(EXIT_FAILURE, errno, "%lu bytes for tunit",
+ ncols * sizeof *up->tunit);
+ fc=(c=up->tunit)+ncols; do *c++=NULL; while(c<fc);
+}
+
+
+
+
+
+/* This function will read all the table information from a FITS table HDU
+ and store them in arrays for use later. It is mainly good for getting
+ all the information in a FITS table HDU. This function will only go
+ through the header keywords once and does not depend on the ordering of
+ the keywords, so it is much more efficient than having to ask for each
+ column's information separately.*/
+void
+allfitscolinfo(struct tableparams *p)
+{
+ char *tailptr;
+ int i, status=0;
+ struct uiparams *up=&p->up;
+ size_t index, ncols=p->up.ncols;
+ char keyname[FLEN_KEYWORD]="XXXXXXXXXXXXX", value[FLEN_VALUE];
+
+
+ /* First allocate the arrays to keep the input column information. */
+ allocinputcolinfo(p);
+
+
+ /* Read all the keywords one by one and if they match, then put them in
+ the correct value. Note that we are starting from keyword 9 because
+ according to the FITS standard, the first 8 keys in a FITS table are
+ reserved. */
+ for(i=9; strcmp(keyname, "END"); ++i)
+ {
+ /* Read the next keyword. */
+ fits_read_keyn(p->fitsptr, i, keyname, value, NULL, &status);
+
+ /* Check the type of the keyword. */
+ if(strncmp(keyname, "TFORM", 5)==0)
+ {
+ /* Currently we can only read repeat==1 cases. When no number
+ exists before the defined capital letter, it defaults to 1,
+ but if a number exists (for example `5D'), then the repeat is
+ 5 (there are actually five values here. Note that value[0] is
+ a single quote.*/
+ if(isdigit(value[1] && value[1]!='1'))
+ error(EXIT_FAILURE, 0, "The repeat value of column %d is "
+ "%c, currently Table can only use columns with a repeat "
+ "of 1.", i+1, value[1]);
+
+
+ /* The values to TFORM are only a single character, so start the
+ pointer to copy at 1 and put the string terminator at 3. */
+ value[2]='\0';
+ index=strtoul(&keyname[5], &tailptr, 10)-1;
+ if(index<ncols)
+ {
+ gal_checkset_allocate_copy(&value[1], &up->ttstr[index] );
+ up->datatype[index]=gal_fits_tform_to_dtype(value[1]);
+ }
+ }
+ else if(strncmp(keyname, "TTYPE", 5)==0)
+ {
+ /* All strings in CFITSIO start and finish with single quotation
+ marks, CFITSIO puts them in itsself, so if we don't remove
+ them here, we might have duplicates later, its easier to just
+ remove them to have a simple string that might be used else
+ where too (without the single quotes). */
+ value[strlen(value)-1]='\0';
+ index=strtoul(&keyname[5], &tailptr, 10)-1;
+ if(index<ncols)
+ gal_checkset_allocate_copy(&value[1], &up->tname[index] );
+ }
+ else if(strncmp(keyname, "TUNIT", 5)==0)
+ {
+ /* similar to tname, see above.*/
+ value[strlen(value)-1]='\0';
+ index=strtoul(&keyname[5], &tailptr, 10)-1;
+ if(index<ncols)
+ gal_checkset_allocate_copy(&value[1], &up->tunit[index] );
+ }
+ }
+
+
+ /* Check if the mandatory TFORMn values are set: */
+ for(i=0;i<ncols;++i)
+ if(!up->ttstr[i])
+ error(EXIT_FAILURE, 0, "TFORM%d could not be found in header", i+1);
+}
+
+
+
+
+
+/* Prepare column information from a text input file. Note that we are
+ currently using Gnuastro's very simple txtarray library, which was only
+ designed for a 2D array of floating point numbers. Later, we must update
+ it to be more aware of the types of input columns and also accept
+ non-number columns.*/
+void
+alltxtcolinfo(struct tableparams *p)
+{
+ size_t i;
+ size_t ncols=p->up.ncols;
+
+ /* Check if there were any strings in the array. If there were strings,
+ then warn the user that we currently can't deal with them. */
+ if(gal_checkset_check_file_report(GAL_TXTARRAY_LOG))
+ error(EXIT_FAILURE, 0, "The input text file `%s' contained "
+ "non-numerical values (probably strings). Please see `%s' for "
+ "a listing of all such terms. Currently Table cannot operate on "
+ "such files. We are working on correcting this issue.",
+ p->up.txtname, GAL_TXTARRAY_LOG);
+
+ /* Allocate the arrays to keep the input column information. */
+ allocinputcolinfo(p);
+
+ /* Set all the column types to double and leave the other fields
+ blank.*/
+ for(i=0;i<ncols;++i)
+ {
+ p->up.datatype[i]=TDOUBLE;
+ gal_checkset_allocate_copy("D", &p->up.ttstr[i] );
+ gal_checkset_allocate_copy("", &p->up.tname[i] );
+ gal_checkset_allocate_copy("", &p->up.tunit[i] );
+ }
+}
+
+
+
+
+/* Print the column information. */
+void
+printinfo(struct tableparams *p)
+{
+ size_t i;
+ char *typestring=NULL;
+ struct uiparams *up=&p->up;
+
+ printf("---------------------------------------------------------\n");
+ if(up->fitsname)
+ printf("%s (hdu: %s)\n", p->up.fitsname, p->cp.hdu);
+ else
+ printf("%s\n", p->up.txtname);
+ printf("%-5s%-25s%-15s%s\n", "No.", "Column name", "Units",
+ "Data type");
+ printf("---------------------------------------------------------\n");
+ for(i=0;i<up->ncols;++i)
+ {
+ switch(up->datatype[i])
+ {
+ case TBIT:
+ typestring="bit";
+ break;
+ case TBYTE:
+ typestring="byte";
+ break;
+ case TLOGICAL:
+ typestring="logicals";
+ break;
+ case TSTRING:
+ typestring="string";
+ break;
+ case TSHORT:
+ typestring="short";
+ break;
+ case TLONG:
+ typestring="long";
+ break;
+ case TLONGLONG:
+ typestring="longlong";
+ break;
+ case TFLOAT:
+ typestring="float";
+ break;
+ case TDOUBLE:
+ typestring="double";
+ break;
+ case TCOMPLEX:
+ typestring="complex";
+ break;
+ case TDBLCOMPLEX:
+ typestring="dblcomplex";
+ break;
+ case TSBYTE:
+ typestring="signed byte";
+ break;
+ case TUINT:
+ typestring="unsigned int";
+ break;
+ case TUSHORT:
+ typestring="unsigned short";
+ break;
+ default:
+ error(EXIT_FAILURE, 0, "%d (from TFORM%lu='%c') is not a "
+ "recognized CFITSIO datatype.", up->datatype[i],
+ i, up->ttstr[i][0]);
+ }
+ printf("%-5lu%-25s%-15s%s\n", i+1, up->tname[i] ? up->tname[i] : "---",
+ up->tunit[i] ? up->tunit[i] : "---", typestring);
+ }
+
+
+ /* Print the number of rows: */
+ printf("---------------------------------------------------------\n");
+ printf("Number of rows: %lu\n", p->nrows);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/**************************************************************/
+/*************** Sanity Check *******************/
+/**************************************************************/
+void
+sanitycheck(struct tableparams *p)
+{
+ struct uiparams *up=&p->up;
+
+ /* If the desired FITS output type is ASCII, then inform the user that
+ this type is not yet supported. */
+ if(up->fitsname && p->fitstabletype==ASCII_TBL)
+ error(EXIT_FAILURE, 0, "output to ASCII type FITS tables is currently "
+ "not supported (due to lack of need!). If you need this feature, "
+ "please get in touch with us at %s so we can increase the "
+ "priority of this feature.", PACKAGE_BUGREPORT);
+
+ if(up->fitsname)
+ {
+ /* Set the FITS pointer and check the type of the fits file. */
+ gal_fits_read_hdu(p->up.fitsname, p->cp.hdu, 1, &p->fitsptr);
+ gal_fits_table_size(p->fitsptr, &p->nrows, &up->ncols);
+ up->infitstabletype=gal_fits_table_type(p->fitsptr);
+ allfitscolinfo(p);
+ }
+ else
+ {
+ /* Read the text file into an input array and make the basic column
+ information. */
+ gal_txtarray_txt_to_array(up->txtname, &up->txtarray, &p->nrows,
+ &up->ncols);
+ alltxtcolinfo(p);
+ }
+
+ /* Print the column information and exit successfully if the
+ `--information' option is given. */
+ if(p->up.information)
+ {
+ printinfo(p);
+ freeandreport(p);
+ exit(EXIT_SUCCESS);
+ }
+
+ /* Check the status of the output file. If no output file is set, then
+ the output will be printed to standard output on the terminal.*/
+ p->outputtofits=p->outputtotxt=p->outputtostdout=0;
+ if(p->cp.outputset)
+ {
+ /* First check if the file exists and remove it if it does. */
+ gal_checkset_check_remove_file(p->cp.output, p->cp.dontdelete);
+
+ /* Now set the type of output. */
+ if(gal_fits_name_is_fits(p->cp.output))
+ p->outputtofits=1;
+ else
+ p->outputtotxt=1;
+ }
+ else
+ p->outputtostdout=1;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/**************************************************************/
+/*************** Preparations *******************/
+/**************************************************************/
+
+/* FUnction to print regular expression error. This is taken from the GNU C
+ library manual, with small modifications to fit out style, */
+void
+regexerrorexit(int errcode, regex_t *compiled, char *input)
+{
+ char *regexerrbuf;
+ size_t length = regerror (errcode, compiled, NULL, 0);
+
+ errno=0;
+ regexerrbuf=malloc(length);
+ if(regexerrbuf==NULL)
+ error(EXIT_FAILURE, errno, "%lu bytes for regexerrbuf", length);
+ (void) regerror(errcode, compiled, regexerrbuf, length);
+
+ error(EXIT_FAILURE, 0, "Regular expression error: %s in value to "
+ "`--column' (`-c'): `%s'", regexerrbuf, input);
+}
+
+
+
+
+
+/* If values were given to the columns option, use them to make a list of
+ columns that must be output. Note that because regular expressions are
+ also allowed as values to the column option, we have no idea how many
+ columns must be printed at first, so we define a linked list to keep the
+ column numbers for later.*/
+void
+outputcolumns(struct tableparams *p)
+{
+ long tlong;
+ regex_t *regex;
+ int regreturn=0;
+ size_t i, inindex;
+ char *tailptr, *colstring;
+ struct uiparams *up=&p->up;
+ struct gal_linkedlist_sll *colsll=NULL;
+
+ /* Go through each given column string and take the appropriate step. */
+ while(p->up.columns)
+ {
+ /* Pop out the top node in the string linked list. */
+ gal_linkedlist_pop_from_stll(&p->up.columns, &colstring);
+
+
+ /* First, see if this given column is an integer or a name/regex. If
+ the string is an integer, then tailptr shoult point to the null
+ character. If it points to anything else, it shows that we are not
+ dealing with an integer (usable as a column number). So floating
+ point values are also not acceptable. */
+ tlong=strtol(colstring, &tailptr,0);
+ if(*tailptr=='\0')
+ {
+ /* Make sure we are not dealing with a negative number! */
+ if(tlong<0)
+ error(EXIT_FAILURE, 0, "the column numbers given to the "
+ "`--column' (`-c') option must not be negative, you "
+ "have given a value of `%ld'", tlong);
+
+ /* Check if the given value is not larger than the number of
+ columns in the input catalog. */
+ if(tlong>up->ncols)
+ error(EXIT_FAILURE, 0, "%s (hdu: %s) has %lu columns, but "
+ "you have asked for column number %lu", p->up.fitsname,
+ p->cp.hdu, up->ncols, tlong);
+
+ /* Everything seems to be fine, put this column number in the
+ output column numbers linked list. Note that internally, the
+ column numbers start from 0, not 1.*/
+ gal_linkedlist_add_to_sll(&colsll, tlong-1);
+ }
+ else
+ {
+ /* Allocate the regex_t structure: */
+ errno=0; regex=malloc(sizeof *regex);
+ if(regex==NULL)
+ error(EXIT_FAILURE, errno, "%lu bytes for regex", sizeof *regex);
+
+ /* Go through all the columns names and see if this matches
+ them. But first we have to "compile" the string into the
+ regular expression, see the "POSIX Regular Expression
+ Compilation" section of the GNU C Library.
+
+ About the case of the string: the FITS standard says: "It is
+ _strongly recommended_ that every field of the table be
+ assigned a unique, case insensitive name with this keyword..."
+ So the column names can be case-sensitive.
+
+ Here, we don't care about the details of a match, the only
+ important thing is a match, so we are using the REG_NOSUB
+ flag.*/
+ regreturn=0;
+ regreturn=regcomp(regex, colstring, ( p->up.ignorecase
+ ? REG_NOSUB + REG_ICASE
+ : REG_NOSUB ) );
+ if(regreturn)
+ regexerrorexit(regreturn, regex, colstring);
+
+
+ /* With the regex structure "compile"d you can go through all the
+ column names. Just note that column names are not mandatory in
+ the FITS standard, so some (or all) columns might not have
+ names, if so `p->tname[i]' will be NULL. */
+ for(i=0;i<up->ncols;++i)
+ if(up->tname[i] && regexec(regex, up->tname[i], 0, 0, 0)==0)
+ gal_linkedlist_add_to_sll(&colsll, i);
+
+ /* Free the regex_t structure: */
+ regfree(regex);
+ }
+
+ /* We don't need this user provided column string any more. */
+ free(colstring);
+ }
+
+ /* Based on the number of columns found above, allocate an array of
+ `outcolumn' structures to keep the information for each column. */
+ p->nocols=gal_linkedlist_num_in_sll(colsll);
+ errno=0;
+ p->ocols=malloc(p->nocols*sizeof *p->ocols);
+ if(p->ocols==NULL)
+ error(EXIT_FAILURE, errno, "%lu bytes for p->ocols",
+ p->nocols*sizeof *p->ocols);
+
+ /* Fill in the output column with the needed input table
+ information. Note that a simple linked list is first-in-last-out, so
+ we have to fill in the output columns in reverse order. Also, note
+ that we are popping from the linked list keeping the indexs of the
+ output columns and thus also freeing their allocated space. */
+ i=p->nocols-1;
+ while(colsll)
+ {
+ gal_linkedlist_pop_from_sll(&colsll, &inindex);
+ p->ocols[i].datatype=up->datatype[inindex];
+ p->ocols[i].inindex=inindex;
+ --i;
+ }
+}
+
+
+
+
+
+void
+preparearrays(struct tableparams *p)
+{
+ size_t i;
+ struct uiparams *up=&p->up;
+
+ /* Reverse the columns linked list here (before possibly printing).*/
+ gal_linkedlist_reverse_stll(&up->columns);
+
+ /* Set the columns that should be included in the output. If up->columns
+ is set, then use it, otherwise, set all the columns for printing. */
+ if(p->up.columns)
+ outputcolumns(p);
+ else
+ {
+ p->nocols=up->ncols;
+ errno=0;
+ p->ocols=malloc(p->nocols * sizeof *p->ocols);
+ if(p->ocols==NULL)
+ error(EXIT_FAILURE, errno, "%lu bytes for p->ocols",
+ p->nocols * sizeof *p->ocols);
+ for(i=0;i<p->nocols;++i)
+ {
+ p->ocols[i].datatype=up->datatype[i];
+ p->ocols[i].inindex=i;
+ }
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/**************************************************************/
+/************ Set the parameters *************/
+/**************************************************************/
+void
+setparams(int argc, char *argv[], struct tableparams *p)
+{
+ struct uiparams *up=&p->up;
+ struct gal_commonparams *cp=&p->cp;
+
+ /* Set the non-zero initial values, the structure was initialized to
+ have a zero value for all elements. */
+ cp->spack = SPACK;
+ cp->verb = 1;
+ cp->numthreads = num_processors(NPROC_CURRENT);
+ cp->removedirinfo = 1;
+
+ /* Initialize this utility's pointers to NULL. */
+ p->ocols=NULL;
+ up->columns=NULL;
+ up->txtname=up->fitsname=NULL;
+ up->ttstr=up->tname=up->tunit=NULL;
+
+ /* Read the arguments. */
+ errno=0;
+ if(argp_parse(&thisargp, argc, argv, 0, 0, p))
+ error(EXIT_FAILURE, errno, "parsing arguments");
+
+ /* Add the user default values and save them if asked. */
+ GAL_CONFIGFILES_CHECK_SET_CONFIG;
+
+ /* Check if all the required parameters are set. */
+ checkifset(p);
+
+ /* Print the values for each parameter. */
+ if(cp->printparams)
+ GAL_CONFIGFILES_REPORT_PARAMETERS_SET;
+
+ /* Do a sanity check. */
+ sanitycheck(p);
+
+ /* Make the array of input images. */
+ preparearrays(p);
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/**************************************************************/
+/************ Free allocated, report *************/
+/**************************************************************/
+void
+freeandreport(struct tableparams *p)
+{
+ size_t i, j;
+ int status=0;
+ char **rowofstrings;
+ struct uiparams *up=&p->up;
+
+ /* Free the allocated arrays: */
+ free(p->cp.hdu);
+ free(up->datatype);
+ free(p->cp.output);
+
+ /* Free the input column information: */
+ for(i=0;i<up->ncols;++i)
+ {
+ if(up->ttstr) free(up->ttstr[i]);
+ if(up->tname) free(up->tname[i]);
+ if(up->tunit) free(up->tunit[i]);
+ }
+ free(up->ttstr);
+ free(up->tname);
+ free(up->tunit);
+
+ /* Free the output column information: */
+ for(i=0;i<p->nocols;++i)
+ {
+ free(p->ocols[i].nulval);
+ if(p->ocols[i].datatype==TSTRING)
+ {
+ rowofstrings=(char **)(p->ocols[i].data);
+ for(j=0;j<p->nrows;++j)
+ free(rowofstrings[j]);
+ }
+ else
+ free(p->ocols[i].data);
+ }
+ free(p->ocols);
+
+ /* Close the FITS file: */
+ if(p->up.fitsname && fits_close_file(p->fitsptr, &status))
+ gal_fits_io_error(status, NULL);
+}
diff --git a/src/table/ui.h b/src/table/ui.h
new file mode 100644
index 0000000..1b949be
--- /dev/null
+++ b/src/table/ui.h
@@ -0,0 +1,39 @@
+/*********************************************************************
+Table - View and manipulate a FITS table structures.
+Table is part of GNU Astronomy Utilities (Gnuastro) package.
+
+Original author:
+ Mohammad Akhlaghi <address@hidden>
+Contributing author(s):
+Copyright (C) 2016, Free Software Foundation, Inc.
+
+Gnuastro is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation, either version 3 of the License, or (at your
+option) any later version.
+
+Gnuastro is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Gnuastro. If not, see <http://www.gnu.org/licenses/>.
+**********************************************************************/
+#ifndef UI_H
+#define UI_H
+
+void
+checksetfge(char *optarg, int *fge, char *filename, size_t lineno);
+
+void
+checksetfitstabletype(char *optarg, int *fitstabletype, char *filename,
+ size_t lineno);
+
+void
+setparams(int argc, char *argv[], struct tableparams *p);
+
+void
+freeandreport(struct tableparams *p);
+
+#endif
diff --git a/tests/Makefile.am b/tests/Makefile.am
index f9810ab..7008c4b 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -42,12 +42,12 @@ mkprof/ellipticalmasks.sh mkprof/inputascanvas.sh
header/write.sh \
header/print.sh header/update.sh header/delete.sh imgstat/basicstats.sh \
subtractsky/subtractsky.sh noisechisel/noisechisel.sh mkcatalog/simple.sh \
mkcatalog/aperturephot.sh arithmetic/snimage.sh arithmetic/onlynumbers.sh \
-cosmiccal/simpletest.sh
+cosmiccal/simpletest.sh table/asciitobinary.sh table/binarytoascii.sh
EXTRA_DIST = $(TESTS) during-dev.sh mkprof/mkprofcat1.txt \
mkprof/ellipticalmasks.txt mkprof/inputascanvas.txt mkprof/mkprofcat2.txt \
mkprof/mkprofcat3.txt mkprof/mkprofcat4.txt mkprof/radeccat.txt \
-imgcrop/cat.txt
+imgcrop/cat.txt table/asciitobinary.txt
CLEANFILES = *.log *.txt *.jpg *.fits *.pdf *.eps
@@ -78,6 +78,8 @@ mkprof/mosaic2.sh: prepconf.sh.log
mkprof/mosaic3.sh: prepconf.sh.log
mkprof/mosaic4.sh: prepconf.sh.log
mkprof/radeccat.sh: prepconf.sh.log
+table/asciitobinary.sh: prepconf.sh.log
+table/binarytoascii.sh: table/asciitobinary.sh.log
imgcrop/imgcat.sh: mkprof/mosaic1.sh.log
imgcrop/wcscat.sh: mkprof/mosaic1.sh.log mkprof/mosaic2.sh.log \
mkprof/mosaic3.sh.log mkprof/mosaic4.sh.log
diff --git a/tests/during-dev.sh b/tests/during-dev.sh
index 84ba39e..61065b1 100755
--- a/tests/during-dev.sh
+++ b/tests/during-dev.sh
@@ -102,8 +102,9 @@ if [ x"$builddir" = x ]; then echo "builddir is not set.";
exit 1; fi
# absolute. This is done because we will be going into the output directory
# for executing the utility and we need to know the absolute address of the
# top build directory.
+srcdir=$(pwd)
if [ ! "${builddir:0:1}" = "/" ]; then
- builddir=$(pwd)"/$builddir"
+ builddir="$srcdir/$builddir"
fi
@@ -120,12 +121,29 @@ if [ -f "$utility" ]; then rm "$utility"; fi
# edit/rebuild the libraries too). If Make is successful, then change to
# the output directory and run the utility with the given arguments and
# options.
-curdir=$(pwd)
+#
+# Before actually running put a copy of the configuration file in the
+# output directory and also add the onlydirconf option so user or system
+# wide configuration files don't interfere.
if make -C "$builddir"; then
# Change to the output directory.
cd "$outdir"
+ # Make the .gnuastro directory if it doesn't exist.
+ if [ ! -d .gnuastro ]; then
+ mkdir .gnuastro
+ fi
+
+ # Put a copy of this utility's configuration file there and add the
+ # onlydirconf option. We are first printing an empty line just in case
+ # the last line in the configuration file doesn't actualy end with a
+ # new line (in which case the appended string will be added to the end
+ # of the last line).
+ cp "$srcdir/src/$utilname/ast$utilname.conf" .gnuastro/
+ echo "" >> .gnuastro/ast$utilname.conf
+ echo " onlydirconf 1" >> .gnuastro/ast$utilname.conf
+
# Run the built utility with the given arguments and options.
"$utility" $arguments $options
fi
diff --git a/tests/prepconf.sh b/tests/prepconf.sh
index 437ec72..068c06b 100755
--- a/tests/prepconf.sh
+++ b/tests/prepconf.sh
@@ -76,7 +76,7 @@ EOF
# by `make check'.
for prog in arithmetic convertt convolve cosmiccal header imgcrop \
imgstat imgwarp mkcatalog mknoise mkprof noisechisel \
- subtractsky
+ subtractsky table
do
# Copy the configuration file from the utility source and add the
diff --git a/tests/table/asciitobinary.sh b/tests/table/asciitobinary.sh
new file mode 100755
index 0000000..42ae47b
--- /dev/null
+++ b/tests/table/asciitobinary.sh
@@ -0,0 +1,51 @@
+# Convert an ASCII table to a binary table
+#
+# See the Tests subsection of the manual for a complete explanation
+# (in the Installing gnuastro section).
+#
+# Original author:
+# Mohammad Akhlaghi <address@hidden>
+# Contributing author(s):
+#
+# Copying and distribution of this file, with or without modification,
+# are permitted in any medium without royalty provided the copyright
+# notice and this notice are preserved. This file is offered as-is,
+# without any warranty.
+
+
+
+
+
+# Preliminaries
+# =============
+#
+# Set the variabels (The executable is in the build tree). Do the
+# basic checks to see if the executable is made or if the defaults
+# file exists (basicchecks.sh is in the source tree).
+prog=table
+execname=../src/$prog/ast$prog
+table=$topsrc/tests/$prog/asciitobinary.txt
+
+
+
+
+
+# Skip?
+# =====
+#
+# If the dependencies of the test don't exist, then skip it. There are two
+# types of dependencies:
+#
+# - The executable was not made (for example due to a configure option),
+#
+# - The input data was not made (for example the test that created the
+# data file failed).
+if [ ! -f $execname ] || [ ! -f $img ]; then exit 77; fi
+
+
+
+
+
+# Actual test script
+# ==================
+$execname $table --output=asciitobinary.fits
diff --git a/tests/table/asciitobinary.txt b/tests/table/asciitobinary.txt
new file mode 100644
index 0000000..c4533a0
--- /dev/null
+++ b/tests/table/asciitobinary.txt
@@ -0,0 +1,2 @@
+1 2.323 43.34
+2 3213 1232
diff --git a/tests/table/binarytoascii.sh b/tests/table/binarytoascii.sh
new file mode 100755
index 0000000..5eb8cc0
--- /dev/null
+++ b/tests/table/binarytoascii.sh
@@ -0,0 +1,51 @@
+# Convert an ASCII table to a binary table
+#
+# See the Tests subsection of the manual for a complete explanation
+# (in the Installing gnuastro section).
+#
+# Original author:
+# Mohammad Akhlaghi <address@hidden>
+# Contributing author(s):
+#
+# Copying and distribution of this file, with or without modification,
+# are permitted in any medium without royalty provided the copyright
+# notice and this notice are preserved. This file is offered as-is,
+# without any warranty.
+
+
+
+
+
+# Preliminaries
+# =============
+#
+# Set the variabels (The executable is in the build tree). Do the
+# basic checks to see if the executable is made or if the defaults
+# file exists (basicchecks.sh is in the source tree).
+prog=table
+execname=../src/$prog/ast$prog
+table=asciitobinary.fits
+
+
+
+
+
+# Skip?
+# =====
+#
+# If the dependencies of the test don't exist, then skip it. There are two
+# types of dependencies:
+#
+# - The executable was not made (for example due to a configure option),
+#
+# - The input data was not made (for example the test that created the
+# data file failed).
+if [ ! -f $execname ] || [ ! -f $img ]; then exit 77; fi
+
+
+
+
+
+# Actual test script
+# ==================
+$execname $table --output=binarytoascii.txt -h1
- [gnuastro-commits] master 01dfb1b 05/16: Some code management in Table, (continued)
- [gnuastro-commits] master 01dfb1b 05/16: Some code management in Table, Mohammad Akhlaghi, 2016/08/24
- [gnuastro-commits] master d09e850 04/16: FITS table column information printed by Table, Mohammad Akhlaghi, 2016/08/24
- [gnuastro-commits] master 5606978 11/16: Configuration file in tests/during-dev.sh, Mohammad Akhlaghi, 2016/08/24
- [gnuastro-commits] master c719806 06/16: Table accepts specified column number, name and regex, Mohammad Akhlaghi, 2016/08/24
- [gnuastro-commits] master 647406f 02/16: Table utility bare minimum structure in place, Mohammad Akhlaghi, 2016/08/24
- [gnuastro-commits] master ad16c2a 12/16: Cosmetic changes in fits and txtarray libraries, Mohammad Akhlaghi, 2016/08/24
- [gnuastro-commits] master b16c7a4 15/16: New Section added to the book for Table, Mohammad Akhlaghi, 2016/08/24
- [gnuastro-commits] master cd5b5cf 13/16: Table prints contents of a FITS table, Mohammad Akhlaghi, 2016/08/24
- [gnuastro-commits] master b553085 01/16: Template for creating a new utility added, Mohammad Akhlaghi, 2016/08/24
- [gnuastro-commits] master ce08c34 14/16: FITS (binary) tables <--> plain text in Table, Mohammad Akhlaghi, 2016/08/24
- [gnuastro-commits] master b78b0c7 16/16: New Table utility merged,
Mohammad Akhlaghi <=