[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[gnuastro-commits] master 685bf31: Arithmetic: new tofile- operator to w
From: |
Mohammad Akhlaghi |
Subject: |
[gnuastro-commits] master 685bf31: Arithmetic: new tofile- operator to write the top operand to a file |
Date: |
Wed, 16 Jan 2019 14:03:09 -0500 (EST) |
branch: master
commit 685bf3159e73995fc1871c265b80af9b6223e8b3
Author: Mohammad Akhlaghi <address@hidden>
Commit: Mohammad Akhlaghi <address@hidden>
Arithmetic: new tofile- operator to write the top operand to a file
Until now, as the Arithmetic command got more and more complicated, there
it was relatively hard to check the progress and debug/understand
undexpected outputs.
With this commit, a new `tofile-AAA' operator is added to Arithmetic. It
can be placed anywhere in between the operands and operators to check the
top operand.
---
NEWS | 6 ++++
bin/arithmetic/arithmetic.c | 47 ++++++++++++++++++++++++-----
bin/arithmetic/main.h | 6 ++--
bin/arithmetic/operands.c | 4 +--
bin/arithmetic/ui.c | 65 ++++++++++++++++++++++++++--------------
doc/gnuastro.texi | 19 ++++++++++++
lib/checkset.c | 55 +++++++++++++++++++++++++++++++++-
lib/fits.c | 4 +++
lib/gnuastro-internal/checkset.h | 3 ++
lib/jpeg.c | 10 ++++++-
10 files changed, 182 insertions(+), 37 deletions(-)
diff --git a/NEWS b/NEWS
index 5389881..d2f3afe 100644
--- a/NEWS
+++ b/NEWS
@@ -12,6 +12,12 @@ GNU Astronomy Utilities NEWS -*-
outline -*-
debugging (finding which configuration file is responsible for a given
option's value).
+ Arithmetic:
+ - The new `tofile-' operator will save the top operand into a file
+ without changing the state of the operand stack (popping the top
+ element). This can greatly help in debugging/understanding an
+ Arithmetic command, especially as it gets longer, or more complicated.
+
Fits:
- Add "title" to group FITS keywords with `--write=/,"title name". This
"title" is composed of two keyword records: a blank one, followed by
diff --git a/bin/arithmetic/arithmetic.c b/bin/arithmetic/arithmetic.c
index 595c28e..d3b5dc9 100644
--- a/bin/arithmetic/arithmetic.c
+++ b/bin/arithmetic/arithmetic.c
@@ -804,6 +804,32 @@ arithmetic_collapse(struct arithmeticparams *p, char
*token, int operator)
+void
+arithmetic_tofile(struct arithmeticparams *p, char *token)
+{
+ /* Pop the top dataset. */
+ gal_data_t *popped = operands_pop(p, token);
+ char *filename=&token[ OPERATOR_PREFIX_LENGTH_TOFILE ];
+
+ /* Save it to a file. */
+ popped->wcs=p->refdata.wcs;
+ if(popped->ndim==1 && p->onedasimage==0)
+ gal_table_write(popped, NULL, p->cp.tableformat, filename,
+ "ARITHMETIC", 0);
+ else
+ gal_fits_img_write(popped, filename, NULL, PROGRAM_NAME);
+ if(!p->cp.quiet)
+ printf(" - Write: %s\n", filename);
+
+ /* Reset the WCS to NULL and put it back on the stack. */
+ popped->wcs=NULL;
+ operands_add(p, NULL, popped);
+}
+
+
+
+
+
@@ -848,17 +874,22 @@ reversepolish(struct arithmeticparams *p)
/* Go over each input token and do the work. */
for(token=p->tokens;token!=NULL;token=token->next)
{
- /* If we have a name or number, then add it to the operands linked
- list. Otherwise, pull out two members and do the specified
- operation on them. */
- if( gal_array_name_recognized(token->v)
+ /* The `tofile-' operator's string can end in a `.fits', similar to a
+ FITS file input file. So, it needs to be checked before checking
+ for a filename. If we have a name or number, then add it to the
+ operands linked list. Otherwise, pull out two members and do the
+ specified operation on them. */
+ if( !strncmp(OPERATOR_PREFIX_TOFILE, token->v,
+ OPERATOR_PREFIX_LENGTH_TOFILE) )
+ arithmetic_tofile(p, token->v);
+ else if( !strncmp(token->v, OPERATOR_PREFIX_SET,
+ OPERATOR_PREFIX_LENGTH_SET) )
+ operands_set_name(p, token->v);
+ else if( gal_array_name_recognized(token->v)
|| operands_is_name(p, token->v) )
operands_add(p, token->v, NULL);
else if( (d1=gal_data_copy_string_to_number(token->v)) )
operands_add(p, NULL, d1);
- else if( !strncmp(token->v, SET_OPERATOR_PREFIX,
- SET_OPERATOR_PREFIX_LENGTH) )
- operands_set_name(p, token->v);
else
{
@@ -1186,7 +1217,7 @@ reversepolish(struct arithmeticparams *p)
else
gal_fits_img_write(d1, p->cp.output, NULL, PROGRAM_NAME);
if(!p->cp.quiet)
- printf(" - Output written to %s\n", p->cp.output);
+ printf(" - Write (final): %s\n", p->cp.output);
}
diff --git a/bin/arithmetic/main.h b/bin/arithmetic/main.h
index 2d30c32..73110d8 100644
--- a/bin/arithmetic/main.h
+++ b/bin/arithmetic/main.h
@@ -40,8 +40,10 @@ along with Gnuastro. If not, see
<http://www.gnu.org/licenses/>.
/* Constants: */
#define NEG_DASH_REPLACE 11 /* Vertical tab (ASCII=11) for negative dash */
-#define SET_OPERATOR_PREFIX "set-"
-#define SET_OPERATOR_PREFIX_LENGTH strlen(SET_OPERATOR_PREFIX)
+#define OPERATOR_PREFIX_SET "set-"
+#define OPERATOR_PREFIX_TOFILE "tofile-"
+#define OPERATOR_PREFIX_LENGTH_SET strlen(OPERATOR_PREFIX_SET)
+#define OPERATOR_PREFIX_LENGTH_TOFILE strlen(OPERATOR_PREFIX_TOFILE)
diff --git a/bin/arithmetic/operands.c b/bin/arithmetic/operands.c
index 580b8b7..dc4f31c 100644
--- a/bin/arithmetic/operands.c
+++ b/bin/arithmetic/operands.c
@@ -141,7 +141,7 @@ void
operands_set_name(struct arithmeticparams *p, char *token)
{
gal_data_t *tmp, *tofree;
- char *varname=&token[ SET_OPERATOR_PREFIX_LENGTH ];
+ char *varname=&token[ OPERATOR_PREFIX_LENGTH_SET ];
/* If a dataset with this name already exists, it will be removed/deleted
so we can use the name for the newly designated dataset. */
@@ -387,7 +387,7 @@ operands_pop(struct arithmeticparams *p, char *operator)
}
/* Report the read image if desired: */
- if(!p->cp.quiet) printf(" - %s (hdu %s) is read.\n", filename, hdu);
+ if(!p->cp.quiet) printf(" - Read: %s (hdu %s).\n", filename, hdu);
/* Free the HDU string: */
if(hdu) free(hdu);
diff --git a/bin/arithmetic/ui.c b/bin/arithmetic/ui.c
index bf41d96..8b84588 100644
--- a/bin/arithmetic/ui.c
+++ b/bin/arithmetic/ui.c
@@ -230,9 +230,10 @@ parse_opt(int key, char *arg, struct argp_state *state)
static void
ui_check_options_and_arguments(struct arithmeticparams *p)
{
+ char *filename;
int output_checked=0;
- size_t nummultiext=0, numhdus=0;
gal_list_str_t *token, *hdu;
+ size_t nummultiext=0, numhdus=0;
/* First, make sure that any tokens are actually given. */
if(p->tokens==NULL)
@@ -256,33 +257,51 @@ ui_check_options_and_arguments(struct arithmeticparams *p)
list. */
for(token=p->tokens; token!=NULL; token=token->next)
{
- /* This token is a file, count how many mult-extension files we haev
- and use the first to set the output filename (if it has not been
- set). */
- if( gal_array_name_recognized(token->v) )
- {
- /* Increment the counter for FITS files. */
- if( gal_array_name_recognized_multiext(token->v) )
- ++nummultiext;
+ /* Strings given to the `tofile' operator are also considered as
+ outputs and we should delete them before starting the parse. */
+ if( strncmp(OPERATOR_PREFIX_TOFILE, token->v,
+ OPERATOR_PREFIX_LENGTH_TOFILE) )
- /* If the output filename isn't set yet, then set it. */
- if(output_checked==0)
+ {
+ /* This token is a file, count how many mult-extension files we
+ haev and use the first to set the output filename (if it has
+ not been set). */
+ if( gal_array_name_recognized(token->v) )
{
- if(p->cp.output)
- gal_checkset_writable_remove(p->cp.output, 0,
- p->cp.dontdelete);
- else
- p->cp.output=gal_checkset_automatic_output(&p->cp, token->v,
- "_arith.fits");
- output_checked=1;
+ /* Increment the counter for FITS files (if they are
+ input). Recall that the `tofile' operator can also have
+ `.fits' suffixes (they are the names of the output
+ files). */
+ if( gal_array_name_recognized_multiext(token->v) )
+ ++nummultiext;
+
+ /* If the output filename isn't set yet, then set it. */
+ if(output_checked==0)
+ {
+ if(p->cp.output)
+ gal_checkset_writable_remove(p->cp.output, 0,
+ p->cp.dontdelete);
+ else
+ p->cp.output=gal_checkset_automatic_output(&p->cp,
+ token->v,
+ "_arith.fits");
+ output_checked=1;
+ }
}
+
+ /* This token is a number. Check if a negative dash was present that
+ has been temporarily replaced with `NEG_DASH_REPLACE' before
+ option parsing. */
+ else if(token->v[0]==NEG_DASH_REPLACE && isdigit(token->v[1]) )
+ token->v[0]='-';
}
- /* This token is a number. Check if a negative dash was present that
- has been temporarily replaced with `NEG_DASH_REPLACE' before
- option parsing. */
- else if(token->v[0]==NEG_DASH_REPLACE && isdigit(token->v[1]) )
- token->v[0]='-';
+ /* We are on the `tofile' operator. */
+ else
+ {
+ filename=&token->v[ OPERATOR_PREFIX_LENGTH_TOFILE ];
+ gal_checkset_writable_remove(filename, 0, p->cp.dontdelete);
+ }
}
/* Count the number of HDU values (if globalhdu isn't given) and check if
diff --git a/doc/gnuastro.texi b/doc/gnuastro.texi
index 5af6ba7..371ef36 100644
--- a/doc/gnuastro.texi
+++ b/doc/gnuastro.texi
@@ -12732,6 +12732,25 @@ But with this operator you can simply give
@file{image.fits} the name
$ astarithmetic image.fits set-i i i 5 gt nan where
@end example
address@hidden tofile-AAA
+Write the top oprand on the operands stack into a file called @code{AAA}
+(can be any FITS file name) without changing the operands stack (no operand
+will be operand).
+
+Any file that is given to this operator is deleted before Arithmetic
+actually starts working on the input datasets. The deletion can be
+deactivated with the @option{--dontdelete} option (as in all Gnuastro
+programs, see @ref{Input output options}). If the same FITS file is given
+to this operator multiple times, it will contain multiple extensions (in
+the same order that it was called.
+
+For example the operator @command{tofile-check.fits} will write the top
+operand to @file{check.fits}. Since it doesn't modify the operands stack,
+this operator is very convenient when you want to debug, or understanding,
+a string of operators and operands given to Arithmetic: simply put
address@hidden anywhere in the process to see what is happening
+behind the scenes without modifying the overall process.
+
@end table
@cartouche
diff --git a/lib/checkset.c b/lib/checkset.c
index 324e4c5..0cc2098 100644
--- a/lib/checkset.c
+++ b/lib/checkset.c
@@ -292,7 +292,7 @@ gal_checkset_not_dir_part(char *filename)
-/* Check if a file exists and report if it doesn't: */
+/* Check if a file exists and report if it doesn't. */
void
gal_checkset_check_file(char *filename)
{
@@ -334,6 +334,59 @@ gal_checkset_check_file_return(char *filename)
+/* If a file doesn't exist and its directory is writable, return
+ 1. Otherwise, return 0. */
+int
+gal_checkset_writable_notexist(char *filename)
+{
+ int out=1;
+ char *dir;
+ FILE *tmpfile;
+
+ /* If the filename is `NULL' everything is ok (it doesn't exist)! In some
+ cases, a NULL filename is interpretted to mean standard output. */
+ if(filename==NULL) return 1;
+
+ /* We want to make sure that we can open and write to this file. But
+ the user might have asked to not delete the file, so the
+ contents should not be changed. Therefore we have to open it with
+ `r+`. */
+ errno=0;
+ tmpfile=fopen(filename, "r+");
+ if (tmpfile) /* The file opened. */
+ {
+ /* Close the file. */
+ errno=0;
+ if(fclose(tmpfile))
+ error(EXIT_FAILURE, errno, "%s", filename);
+
+ /* The file exists, return 0. */
+ out=0;
+ }
+
+ /* If the file doesn't exist, we just need to make sure if we have write
+ permissions to its host directory. */
+ else
+ {
+ /* Separate the directory part of the filename. */
+ dir=gal_checkset_dir_part(filename);
+
+ /* See if this directory is writable by this user. */
+ errno=0;
+ if( access(dir, W_OK) ) out=0;
+
+ /* Clean up. */
+ free(dir);
+ }
+
+ /* Return the final value. */
+ return out;
+}
+
+
+
+
+
/* Check if a file exists and can be opened. If the `keep' value is
non-zero, then the file will remain untouched, otherwise, it will be
deleted (since most programs need to make a clean output). When the file
diff --git a/lib/fits.c b/lib/fits.c
index 671b828..994a619 100644
--- a/lib/fits.c
+++ b/lib/fits.c
@@ -1833,6 +1833,10 @@ gal_fits_img_write_to_ptr(gal_data_t *input, char
*filename)
int nkeyrec, hasblank, status=0, datatype=0;
gal_data_t *i64data, *towrite, *block=gal_tile_block(input);
+ /* Small sanity check. */
+ if( gal_fits_name_is_fits(filename)==0 )
+ error(EXIT_FAILURE, 0, "%s: not a FITS suffix", filename);
+
/* If the input is a tile (isn't a contiguous region of memory), then
copy it into a contiguous region. */
towrite = input==block ? input : gal_data_copy(input);
diff --git a/lib/gnuastro-internal/checkset.h b/lib/gnuastro-internal/checkset.h
index 3d5a16e..35e1085 100644
--- a/lib/gnuastro-internal/checkset.h
+++ b/lib/gnuastro-internal/checkset.h
@@ -104,6 +104,9 @@ gal_checkset_check_file(char *filename);
int
gal_checkset_check_file_return(char *filename);
+int
+gal_checkset_writable_notexist(char *filename);
+
void /* keep==0 && dontdelete==0: file will be deleted if exists.*/
gal_checkset_writable_remove(char *filename, int keep, int dontdelete);
diff --git a/lib/jpeg.c b/lib/jpeg.c
index c7c5151..34dc71b 100644
--- a/lib/jpeg.c
+++ b/lib/jpeg.c
@@ -35,7 +35,7 @@ along with Gnuastro. If not, see
<http://www.gnu.org/licenses/>.
#include <gnuastro/list.h>
#include <gnuastro/jpeg.h>
-
+#include <gnuastro-internal/checkset.h>
@@ -404,6 +404,14 @@ gal_jpeg_write(gal_data_t *in, char *filename, uint8_t
quality,
error(EXIT_FAILURE, 0, "%s: input has a `%s' type, but JPEG images can "
"only have a `uint8' type", __func__, gal_type_name(in->type, 1));
+ /* Make sure the file doesn't exist and that we have write
+ permission. Note that the JPEG standard doesn't have multple
+ extensions.*/
+ if( gal_checkset_writable_notexist(filename)==0 )
+ error(EXIT_FAILURE, 0, "%s: already exists or its directory doesn't "
+ "write permssion. Note that the JPEG standard only allows one "
+ "image per file", filename);
+
/* Make sure the JSAMPLE is 8bits, then allocate the necessary space
based on the number of channels. */
if(sizeof *jsr!=1)
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [gnuastro-commits] master 685bf31: Arithmetic: new tofile- operator to write the top operand to a file,
Mohammad Akhlaghi <=