gnuastro-commits
[Top][All Lists]
Advanced

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

[gnuastro-commits] master 4f6a8c4 095/125: Fits prints HDU info of FITS


From: Mohammad Akhlaghi
Subject: [gnuastro-commits] master 4f6a8c4 095/125: Fits prints HDU info of FITS file with no options
Date: Sun, 23 Apr 2017 22:36:46 -0400 (EDT)

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

    Fits prints HDU info of FITS file with no options
    
    Until now, the Fits program would print all the keywords in the given
    extension when it was called with no option. But now that it is being
    modified to also work on extensions, it now prints the extension
    information with no option. To print all the keywords in a header, there is
    the new `--printall' option.
    
    The basic idea behind this change is simple: when the user doesn't give any
    options (including specifying a HDU), then it is most probable that they
    don't know the HDUs in the FITS file: how many there are, are they an image
    or a table and so on. To get the full list of keywords, users can now call
    the `--printall' option.
    
    In the process, the source code for Fits was also re-organized to allow
    this more general change of also manipulating extensions also. In the book
    the old `Header' name has also been changed to `Fits' and the `--printall'
    option has been added. The full behavior with the added feature to work on
    extensions is not yet included in the manual. As soon as options to add and
    remove HDUs are added, the book will also be updated.
---
 bin/crop/crop.c     |   6 +-
 bin/crop/ui.c       |   2 +-
 bin/fits/args.h     |  39 ++++--
 bin/fits/fits.c     | 180 ++++++++++++++++++++++++++-
 bin/fits/header.c   | 348 ++++++++++++++++++++++++++++++++++++++--------------
 bin/fits/main.h     |  41 ++++---
 bin/fits/ui.c       | 142 ++++++++-------------
 bin/fits/ui.h       |  21 ++--
 doc/gnuastro.texi   | 103 ++++++++--------
 lib/fits.c          | 172 ++++++++++++++------------
 lib/gnuastro/fits.h |  12 +-
 lib/wcs.c           |   2 +-
 12 files changed, 710 insertions(+), 358 deletions(-)

diff --git a/bin/crop/crop.c b/bin/crop/crop.c
index 0c04a83..12a708e 100644
--- a/bin/crop/crop.c
+++ b/bin/crop/crop.c
@@ -201,7 +201,7 @@ imgmodecrop(void *inparam)
   /* The whole catalog is from one image, so you can get the
      information here:*/
   img=&p->imgs[crp->in_ind];
-  crp->infits=gal_fits_hdu_open(img->name, p->cp.hdu, 0);
+  crp->infits=gal_fits_hdu_open_type(img->name, p->cp.hdu, 0);
 
   /* Go over all the outputs that are assigned to this thread: */
   for(i=0;crp->indexs[i]!=GAL_THREADS_NON_THRD_INDEX;++i)
@@ -292,8 +292,8 @@ wcsmodecrop(void *inparam)
         if(radecoverlap(crp))
           {
             /* Open the input FITS file. */
-            crp->infits=gal_fits_hdu_open(p->imgs[crp->in_ind].name,
-                                          p->cp.hdu, 0);
+            crp->infits=gal_fits_hdu_open_type(p->imgs[crp->in_ind].name,
+                                               p->cp.hdu, 0);
 
             /* If a name isn't set yet, set it. */
             if(crp->name==NULL) cropname(crp);
diff --git a/bin/crop/ui.c b/bin/crop/ui.c
index 021445c..02214f2 100644
--- a/bin/crop/ui.c
+++ b/bin/crop/ui.c
@@ -670,7 +670,7 @@ ui_preparations(struct cropparams *p)
       status=0;
       img=&p->imgs[--input_counter];
       gal_linkedlist_pop_from_stll(&p->inputs, &img->name);
-      tmpfits=gal_fits_hdu_open(img->name, p->cp.hdu, 0);
+      tmpfits=gal_fits_hdu_open_type(img->name, p->cp.hdu, 0);
       gal_fits_img_info(tmpfits, &p->type, &img->ndim, &img->dsize);
       gal_wcs_read_from_fitsptr(tmpfits, &img->nwcs, &img->wcs,
                                 p->hstartwcs, p->hendwcs);
diff --git a/bin/fits/args.h b/bin/fits/args.h
index cdf1774..9e8ae45 100644
--- a/bin/fits/args.h
+++ b/bin/fits/args.h
@@ -31,13 +31,19 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 /* Array of acceptable options. */
 struct argp_option program_options[] =
   {
+
+    {
+      0, 0, 0, 0,
+      "Header keywords:",
+      ARGS_GROUP_KEYWORD
+    },
     {
       "asis",
       ARGS_OPTION_KEY_ASIS,
       "STR",
       0,
       "Write the argument string as is into the header.",
-      GAL_OPTIONS_GROUP_OUTPUT,
+      ARGS_GROUP_KEYWORD,
       &p->asis,
       GAL_DATA_TYPE_STRLL,
       GAL_OPTIONS_RANGE_ANY,
@@ -50,7 +56,7 @@ struct argp_option program_options[] =
       "STR",
       0,
       "Delete a keyword from the header.",
-      GAL_OPTIONS_GROUP_OUTPUT,
+      ARGS_GROUP_KEYWORD,
       &p->delete,
       GAL_DATA_TYPE_STRLL,
       GAL_OPTIONS_RANGE_ANY,
@@ -63,7 +69,7 @@ struct argp_option program_options[] =
       "STR",
       0,
       "Rename keyword, keeping value and comments.",
-      GAL_OPTIONS_GROUP_OUTPUT,
+      ARGS_GROUP_KEYWORD,
       &p->rename,
       GAL_DATA_TYPE_STRLL,
       GAL_OPTIONS_RANGE_ANY,
@@ -76,8 +82,8 @@ struct argp_option program_options[] =
       "STR",
       0,
       "Update a keyword value or comments.",
-      GAL_OPTIONS_GROUP_OUTPUT,
-      &p->updatestr,
+      ARGS_GROUP_KEYWORD,
+      &p->update,
       GAL_DATA_TYPE_STRLL,
       GAL_OPTIONS_RANGE_ANY,
       GAL_OPTIONS_NOT_MANDATORY,
@@ -89,8 +95,8 @@ struct argp_option program_options[] =
       "STR",
       0,
       "Write a keyword (with value, comments and units).",
-      GAL_OPTIONS_GROUP_OUTPUT,
-      &p->writestr,
+      ARGS_GROUP_KEYWORD,
+      &p->write,
       GAL_DATA_TYPE_STRLL,
       GAL_OPTIONS_RANGE_ANY,
       GAL_OPTIONS_NOT_MANDATORY,
@@ -102,7 +108,7 @@ struct argp_option program_options[] =
       "STR",
       0,
       "Add HISTORY keyword, any length is ok.",
-      GAL_OPTIONS_GROUP_OUTPUT,
+      ARGS_GROUP_KEYWORD,
       &p->history,
       GAL_DATA_TYPE_STRING,
       GAL_OPTIONS_RANGE_ANY,
@@ -115,7 +121,7 @@ struct argp_option program_options[] =
       "STR",
       0,
       "Add COMMENT keyword, any length is ok.",
-      GAL_OPTIONS_GROUP_OUTPUT,
+      ARGS_GROUP_KEYWORD,
       &p->comment,
       GAL_DATA_TYPE_STRING,
       GAL_OPTIONS_RANGE_ANY,
@@ -128,13 +134,26 @@ struct argp_option program_options[] =
       0,
       0,
       "Set the DATE keyword to the current time.",
-      GAL_OPTIONS_GROUP_OUTPUT,
+      ARGS_GROUP_KEYWORD,
       &p->date,
       GAL_OPTIONS_NO_ARG_TYPE,
       GAL_OPTIONS_RANGE_0_OR_1,
       GAL_OPTIONS_NOT_MANDATORY,
       GAL_OPTIONS_NOT_SET
     },
+    {
+      "printall",
+      ARGS_OPTION_KEY_PRINTALL,
+      0,
+      0,
+      "Print all keywords in the desired HDU.",
+      GAL_OPTIONS_GROUP_OPERATING_MODE,
+      &p->printall,
+      GAL_OPTIONS_NO_ARG_TYPE,
+      GAL_OPTIONS_RANGE_0_OR_1,
+      GAL_OPTIONS_NOT_MANDATORY,
+      GAL_OPTIONS_NOT_SET
+    },
 
 
 
diff --git a/bin/fits/fits.c b/bin/fits/fits.c
index 483bd3e..63d6a9b 100644
--- a/bin/fits/fits.c
+++ b/bin/fits/fits.c
@@ -22,15 +22,191 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 **********************************************************************/
 #include <config.h>
 
+#include <errno.h>
+#include <error.h>
+
+#include <gnuastro/fits.h>
+#include <gnuastro/blank.h>
+
+#include "timing.h"
+#include "checkset.h"
 
 #include "main.h"
 
 #include "header.h"
 
+
+
+/* Print all the extension informations. */
+void
+fits_print_extension_info(struct fitsparams *p)
+{
+  uint16_t *ui16;
+  fitsfile *fptr;
+  gal_data_t *cols=NULL, *tmp;
+  char **tstra, **estra, **sstra;
+  size_t i, numext, *dsize, ndim;
+  int j, nc, numhdu, hdutype, status=0, type;
+  char *msg, *tstr, *estr, sstr[1000], extname[FLEN_VALUE];
+
+
+  /* Open the FITS file and read the first extension type, upon moving to
+     the next extension, we will read its type, so for the first we will
+     need to do it explicitly. */
+  fptr=gal_fits_hdu_open(p->filename, "0", READONLY);
+  if (fits_get_hdu_type(fptr, &hdutype, &status) )
+    gal_fits_io_error(status, "reading first extension");
+
+
+  /* Get the number of HDUs. */
+  if( fits_get_num_hdus(fptr, &numhdu, &status) )
+    gal_fits_io_error(status, "finding number of HDUs");
+  numext=numhdu;
+
+
+  /* Allocate all the columns (in reverse order, since this is a simple
+     linked list). */
+  gal_data_add_to_ll(&cols, NULL, GAL_DATA_TYPE_STRING, 1, &numext, NULL, 1,
+                     p->cp.minmapsize, "HDU_SIZE", "name",
+                     "Size of image or table number of rows and columns.");
+  gal_data_add_to_ll(&cols, NULL, GAL_DATA_TYPE_STRING, 1, &numext, NULL, 1,
+                     p->cp.minmapsize, "HDU_TYPE", "name",
+                     "Image data type or `table' format (ASCII or binary).");
+  gal_data_add_to_ll(&cols, NULL, GAL_DATA_TYPE_STRING, 1, &numext, NULL, 1,
+                     p->cp.minmapsize, "EXTNAME", "name",
+                     "Extension name of this HDU (EXTNAME in FITS).");
+  gal_data_add_to_ll(&cols, NULL, GAL_DATA_TYPE_UINT16, 1, &numext, NULL, 1,
+                     p->cp.minmapsize, "HDU_INDEX", "count",
+                     "Index (starting from zero) of each HDU (extension).");
+
+
+  /* Keep pointers to the array of each column for easy writing. */
+  ui16  = cols->array;
+  estra = cols->next->array;
+  tstra = cols->next->next->array;
+  sstra = cols->next->next->next->array;
+
+  cols->next->disp_width=15;
+  cols->next->next->disp_width=15;
+
+
+  /* Fill in each column. */
+  for(i=0;i<numext;++i)
+    {
+      /* Work based on the type of the extension. */
+      switch(hdutype)
+        {
+        case IMAGE_HDU:
+          gal_fits_img_info(fptr, &type, &ndim, &dsize);
+          tstr=gal_data_type_as_string(type , 1);
+          break;
+
+        case ASCII_TBL:
+        case BINARY_TBL:
+          ndim=2;
+          tstr = hdutype==ASCII_TBL ? "table_ascii" : "table_binary";
+          dsize=gal_data_malloc_array(GAL_DATA_TYPE_SIZE_T, 2);
+          gal_fits_tab_size(fptr, dsize+1, dsize);
+          break;
+
+        default:
+          error(EXIT_FAILURE, 0, "a bug! the `hdutype' code %d not "
+                "recognized", hdutype);
+        }
+
+
+      /* Read the extension name*/
+      fits_read_keyword(fptr, "EXTNAME", extname, NULL, &status);
+      switch(status)
+        {
+        case 0:
+          estr=gal_fits_key_clean_str_value(extname);
+          break;
+
+        case KEY_NO_EXIST:
+          sprintf(extname, "%s", GAL_BLANK_STRING);
+          estr=extname;
+          status=0;
+          break;
+
+        default:
+          gal_fits_io_error(status, "reading EXTNAME keyword");
+        }
+      status=0;
+
+
+      /* Write the size into a string. `sprintf' returns the number of
+         written characters (excluding the `\0'). So for each dimension's
+         size that is written, we add to `nc' (the number of
+         characters). Note that FITS allows blank extensions, in those
+         cases, return "0". */
+      if(ndim>0)
+        {
+          nc=0;
+          for(j=ndim-1;j>=0;--j)
+            nc += sprintf(sstr+nc, "%zux", dsize[j]);
+          sstr[nc-1]='\0';
+          free(dsize);
+        }
+      else
+        {
+          sstr[0]='0';
+          sstr[1]='\0';
+        }
+
+
+      /* Write the strings into the columns. */
+      j=0;
+      for(tmp=cols; tmp!=NULL; tmp=tmp->next)
+        {
+          switch(j)
+            {
+            case 0: ui16[i]=i;                                   break;
+            case 1: gal_checkset_allocate_copy(estr, estra+i);   break;
+            case 2: gal_checkset_allocate_copy(tstr, tstra+i);   break;
+            case 3: gal_checkset_allocate_copy(sstr, sstra+i);   break;
+            }
+          ++j;
+        }
+
+
+      /* Move to the next extension if we aren't on the last extension. */
+      if( i!=numext-1 && fits_movrel_hdu(fptr, 1, &hdutype, &status) )
+        {
+          asprintf(&msg, "moving to hdu %zu", i+1);
+          gal_fits_io_error(status, msg);
+        }
+    }
+
+
+  /* Print the resutls. */
+  if(!p->cp.quiet)
+    {
+      printf("%s\nRun on %s-----\n", PACKAGE_STRING, ctime(&p->rawtime));
+      printf("HDU (extension) information: `%s'.\n", p->filename);
+      printf(" Column 1: Index (counting from 0).\n");
+      printf(" Column 2: Name (`EXTNAME' in FITS standard).\n");
+      printf(" Column 3: Image data type or `table' format (ASCII or "
+             "binary).\n");
+      printf(" Column 4: Size of data in HDU.\n");
+      printf("-----\n");
+    }
+  gal_table_write(cols, NULL, GAL_TABLE_FORMAT_TXT, NULL, 0);
+  if(!p->cp.quiet) printf("-----\n");
+  gal_data_free_ll(cols);
+}
+
+
+
+
+
 int
 fits(struct fitsparams *p)
 {
-  int r;
-  r=header(p);
+  int r=EXIT_SUCCESS;
+  if(p->mode==FITS_MODE_KEY)
+    r=header(p);
+  else
+    fits_print_extension_info(p);
   return r;
 }
diff --git a/bin/fits/header.c b/bin/fits/header.c
index 04fa158..93baf36 100644
--- a/bin/fits/header.c
+++ b/bin/fits/header.c
@@ -31,10 +31,33 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 #include <gnuastro/fits.h>
 #include <gnuastro/linkedlist.h>
 
+#include "checkset.h"
+
 #include "main.h"
 
 
 
+
+
+
+
+
+
+
+/***********************************************************************/
+/******************           Preparations          ********************/
+/***********************************************************************/
+static void
+header_open(struct fitsparams *p, fitsfile **fptr, int iomode)
+{
+  if(*fptr==NULL)
+    *fptr=gal_fits_hdu_open(p->filename, p->cp.hdu, iomode);
+}
+
+
+
+
+
 int
 haserror(struct fitsparams *p, int actionid, char *string, int status)
 {
@@ -78,50 +101,121 @@ haserror(struct fitsparams *p, int actionid, char 
*string, int status)
 
 
 
-void
-writeupdatekeys(fitsfile *fptr, struct gal_fits_key_ll **keylist,
-                int u1w2)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/***********************************************************************/
+/******************        File manipulation        ********************/
+/***********************************************************************/
+static void
+header_rename_keys(struct fitsparams *p, fitsfile **fptr, int *r)
+{
+  int status=0;
+  char *copy, *str, *from, *to;
+
+  /* Set the FITS file pointer. */
+  header_open(p, fptr, READWRITE);
+
+  /* Tokenize the */
+  while(p->rename!=NULL)
+    {
+      /* Pop out the top element. */
+      gal_linkedlist_pop_from_stll(&p->rename, &str);
+
+      /* Take a copy of the input string for error reporting, because
+         `strtok' will write into the array. */
+      gal_checkset_allocate_copy(str, &copy);
+
+      /* Tokenize the input. */
+      from = strtok(str,  ", ");
+      to   = strtok(NULL, ", ");
+
+      /* Make sure both elements were read. */
+      if(from==NULL || to==NULL)
+        error(EXIT_FAILURE, 0, "`%s' could not be tokenized in order to "
+              "complete rename. There should be a space character "
+              "or a comma (,) between the two keyword names. If you have "
+              "used the space character, be sure to enclose the value to "
+              "the `--rename' option in double quotation marks", copy);
+
+      /* Rename the keyword */
+      fits_modify_name(*fptr, from, to, &status);
+      if(status) *r=haserror(p, 2, from, status);
+
+      /* Clean up the user's input string. Note that `strtok' just changes
+         characters within the allocated string, no extra allocation is
+         done. */
+      free(str);
+      free(copy);
+    }
+}
+
+
+
+
+
+static void
+header_write_update(struct fitsparams *p, fitsfile **fptr,
+                    struct gal_fits_key_ll *keyll, int u1w2)
 {
   int status=0;
-  struct gal_fits_key_ll *tmp, *ttmp;
+  struct gal_fits_key_ll *tmp;
 
-  tmp=*keylist;
-  while(tmp!=NULL)
+  /* Open the FITS file if it hasn't been opened yet. */
+  header_open(p, fptr, READWRITE);
+
+  /* Go through each key and write it in the FITS file. */
+  while(keyll!=NULL)
     {
       /* Write the information: */
       if(u1w2==1)
         {
-          if(tmp->value)
+          if(keyll->value)
             {
-              if( fits_update_key(fptr, gal_fits_type_to_datatype(tmp->type),
-                                  tmp->keyname, tmp->value, tmp->comment,
-                                  &status) )
+              if( fits_update_key(*fptr,
+                                  gal_fits_type_to_datatype(keyll->type),
+                                  keyll->keyname, keyll->value,
+                                  keyll->comment, &status) )
                 gal_fits_io_error(status, NULL);
             }
           else
             {
-              if(fits_write_key_null(fptr, tmp->keyname, tmp->comment,
+              if(fits_write_key_null(*fptr, keyll->keyname, keyll->comment,
                                      &status))
                 gal_fits_io_error(status, NULL);
             }
         }
       else if (u1w2==2)
         {
-          if(tmp->value)
+          if(keyll->value)
             {
-              if( fits_write_key(fptr, gal_fits_type_to_datatype(tmp->type),
-                                 tmp->keyname, tmp->value, tmp->comment,
+              if( fits_write_key(*fptr,
+                                 gal_fits_type_to_datatype(keyll->type),
+                                 keyll->keyname, keyll->value, keyll->comment,
                                  &status) )
                 gal_fits_io_error(status, NULL);
             }
           else
             {
-              if(fits_write_key_null(fptr, tmp->keyname, tmp->comment,
+              if(fits_write_key_null(*fptr, keyll->keyname, keyll->comment,
                                      &status))
                 gal_fits_io_error(status, NULL);
             }
-          if(tmp->unit
-             && fits_write_key_unit(fptr, tmp->keyname, tmp->unit, &status) )
+          if(keyll->unit
+             && fits_write_key_unit(*fptr, keyll->keyname, keyll->unit,
+                                    &status) )
             gal_fits_io_error(status, NULL);
         }
       else
@@ -129,107 +223,171 @@ writeupdatekeys(fitsfile *fptr, struct gal_fits_key_ll 
**keylist,
               "fix this problem. In `header.c'. The value of u1w2 in "
               "writeupdatekeys must not be %d\n", PACKAGE_BUGREPORT, u1w2);
 
-      /* Add the unit: */
-      if(tmp->unit
-         && fits_write_key_unit(fptr, tmp->keyname, tmp->unit, &status) )
+      /* Add the unit (if one was given). */
+      if(keyll->unit
+         && fits_write_key_unit(*fptr, keyll->keyname, keyll->unit, &status) )
         gal_fits_io_error(status, NULL);
 
-      /* Free the value pointer if desired: */
-      if(tmp->vfree) free(tmp->value);
-      if(tmp->kfree) free(tmp->keyname);
-      if(tmp->cfree) free(tmp->comment);
+      /* Free the allocated spaces if necessary: */
+      if(keyll->vfree) free(keyll->value);
+      if(keyll->kfree) free(keyll->keyname);
+      if(keyll->cfree) free(keyll->comment);
 
       /* Keep the pointer to the next keyword and free the allocated
          space for this keyword.*/
-      ttmp=tmp->next;
-      free(tmp);
-      tmp=ttmp;
+      tmp=keyll->next;
+      free(keyll);
+      keyll=tmp;
     }
-  *keylist=NULL;
 }
 
 
 
 
 
-int
-header(struct fitsparams *p)
+static void
+header_print_all_keys(struct fitsparams *p, fitsfile **fptr)
 {
-  size_t i=0;
-  int r=EXIT_SUCCESS;
+  size_t i;
   int nkeys, status=0;
   char *fullheader, *c, *cf;
-  struct gal_linkedlist_stll *tstll, *ttstll;
 
-  if(p->onlyview)
+  /* Open the FITS file. */
+  header_open(p, fptr, READONLY);
+
+  /* Conver the header into a contiguous string. */
+  if( fits_hdr2str(*fptr, 0, NULL, 0, &fullheader, &nkeys, &status) )
+    gal_fits_io_error(status, NULL);
+
+  /* FLEN_CARD supposes that the NULL string character is in the
+     end of each keyword header card. In fits_hdr2str, the NULL
+     characters are removed and so the maximum length is one
+     less. */
+  cf=(c=fullheader)+nkeys*(FLEN_CARD-1);
+  do
     {
-      if( fits_hdr2str(p->fptr, 0, NULL, 0, &fullheader, &nkeys, &status) )
-        gal_fits_io_error(status, NULL);
+      if(i && i%(FLEN_CARD-1)==0)
+        putc('\n', stdout);
+      putc(*c++, stdout);
+      ++i;
+    }
+  while(c<cf);
+  printf("\n");
+
+  if (fits_free_memory(fullheader, &status) )
+    gal_fits_io_error(status, "problem in header.c for freeing "
+                      "the memory used to keep all the headers");
+}
+
+
+
+
+
 
-      /* FLEN_CARD supposes that the NULL string character is in the
-         end of each keyword header card. In fits_hdr2str, the NULL
-         characters are removed and so the maximum length is one
-         less. */
-      cf=(c=fullheader)+nkeys*(FLEN_CARD-1);
-      do
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/***********************************************************************/
+/******************           Main function         ********************/
+/***********************************************************************/
+int
+header(struct fitsparams *p)
+{
+  int status=0;
+  int r=EXIT_SUCCESS;
+  fitsfile *fptr=NULL;
+  struct gal_linkedlist_stll *tstll;
+
+  /* Open the requested extension. */
+  if(!p->cp.hdu)
+    error(EXIT_FAILURE, 0, "to modify keywords in a header data unit (HDU) "
+          "the extension in the FITS file is necessary, but none has been "
+          "specified, please use the `--hdu' (or `-h') option to specify "
+          "one");
+
+
+  /* Delete the requested keywords. */
+  if(p->delete)
+    {
+      header_open(p, &fptr, READWRITE);
+      for(tstll=p->delete; tstll!=NULL; tstll=tstll->next)
         {
-          if(i && i%(FLEN_CARD-1)==0)
-            putc('\n', stdout);
-          putc(*c++, stdout);
-          ++i;
+          fits_delete_key(fptr, tstll->v, &status);
+          if(status) r=haserror(p, 1, tstll->v, status);
         }
-      while(c<cf);
-      printf("\n");
+    }
+
+
+  /* Rename the requested keywords. */
+  if(p->rename)
+    header_rename_keys(p, &fptr, &r);
+
+
+  /* Update the requested keywords. */
+  if(p->update)
+    header_write_update(p, &fptr, p->update_keys, 1);
+
+
+  /* Write the requested keywords. */
+  if(p->write)
+    header_write_update(p, &fptr, p->write_keys, 2);
+
 
-      if (fits_free_memory(fullheader, &status) )
-        gal_fits_io_error(status, "problem in header.c for freeing "
-                               "the memory used to keep all the headers");
+  /* Put in any full line of keywords as-is. */
+  if(p->asis)
+    for(tstll=p->asis; tstll!=NULL; tstll=tstll->next)
+      {
+        fits_write_record(fptr, tstll->v, &status);
+        if(status) r=haserror(p, 1, tstll->v, status);
+      }
+
+
+  /* Add the history keyword(s). */
+  if(p->history)
+    {
+      fits_write_history(fptr, p->history, &status);
+      if(status) r=haserror(p, 4, "HISTORY", status);
     }
-  else
+
+
+  /* Add comment(s). */
+  if(p->comment)
     {
-      if(p->delete)
-        {
-          for(tstll=p->delete; tstll!=NULL; tstll=tstll->next)
-            {
-              fits_delete_key(p->fptr, tstll->v, &status);
-              if(status) r=haserror(p, 1, tstll->v, status);
-            }
-        }
-      if(p->rename)
-        {
-          ttstll=p->renameto;
-          for(tstll=p->renamefrom; tstll!=NULL; tstll=tstll->next)
-            {
-              fits_modify_name(p->fptr, tstll->v, ttstll->v, &status);
-              if(status) r=haserror(p, 2, tstll->v, status);
-              ttstll=ttstll->next;
-            }
-        }
-      if(p->update)
-        writeupdatekeys(p->fptr, &p->update, 1);
-      if(p->write)
-        writeupdatekeys(p->fptr, &p->write, 2);
-      if(p->asis)
-        for(tstll=p->asis; tstll!=NULL; tstll=tstll->next)
-          {
-            fits_write_record(p->fptr, tstll->v, &status);
-            if(status) r=haserror(p, 1, tstll->v, status);
-          }
-      if(p->history)
-        {
-          fits_write_history(p->fptr, p->history, &status);
-          if(status) r=haserror(p, 4, "HISTORY", status);
-        }
-      if(p->comment)
-        {
-          fits_write_comment(p->fptr, p->comment, &status);
-          if(status) r=haserror(p, 4, "COMMENT", status);
-        }
-      if(p->date)
-        {
-          fits_write_date(p->fptr, &status);
-          if(status) r=haserror(p, 4, "DATE", status);
-        }
+      fits_write_comment(fptr, p->comment, &status);
+      if(status) r=haserror(p, 4, "COMMENT", status);
     }
+
+
+  /* Update/add the date. */
+  if(p->date)
+    {
+      fits_write_date(fptr, &status);
+      if(status) r=haserror(p, 4, "DATE", status);
+    }
+
+
+  /* If nothing was requested, then print all the keywords in this
+     extension. */
+  if(p->printall)
+    header_print_all_keys(p, &fptr);
+
+
+  /* Close the FITS file */
+  if(fits_close_file(fptr, &status))
+    gal_fits_io_error(status, NULL);
+
+
+  /* Return. */
   return r;
 }
diff --git a/bin/fits/main.h b/bin/fits/main.h
index 5f656bb..cbb394e 100644
--- a/bin/fits/main.h
+++ b/bin/fits/main.h
@@ -36,39 +36,40 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 
 
 
+enum fits_mode
+  {
+    FITS_MODE_INVALID,          /* ==0, by C standard. */
+
+    FITS_MODE_HDU,
+    FITS_MODE_KEY,
+  };
 
 
-struct fitsparams
-{
-  /* Common parameters */
-  struct gal_options_common_params  cp;  /* Common parameters.        */
 
-  /* Input: */
-  int                            nwcs;  /* Number of WCS structures.       */
-  fitsfile                      *fptr;  /* FITS file pointer.              */
-  struct wcsprm                  *wcs;  /* Pointer to WCS structures.      */
 
-  /* Output: */
+
+/* Main program's structure */
+struct fitsparams
+{
+  /* From the environment. */
+  struct gal_options_common_params cp;  /* Common parameters.              */
+  char                      *filename;  /* Name of input file.             */
+  uint8_t                    printall;  /* Print all the header keywords.  */
   uint8_t                        date;  /* Set DATE to current time.       */
   char                       *comment;  /* COMMENT value.                  */
   char                       *history;  /* HISTORY value.                  */
   struct gal_linkedlist_stll    *asis;  /* Strings to write asis.          */
   struct gal_linkedlist_stll  *delete;  /* Keywords to remove.             */
-  struct gal_linkedlist_stll *renamefrom; /* Initial value of the keyword. */
-  struct gal_linkedlist_stll *renameto; /* The final value of the keyword. */
-  struct gal_fits_key_ll      *update;  /* Keywords to update. */
-  struct gal_fits_key_ll       *write;  /* Keywords to add.                */
-
-  /* Operating mode: */
+  struct gal_linkedlist_stll  *rename;  /* Rename a keyword.               */
+  struct gal_linkedlist_stll  *update;  /* For keywords to update.         */
+  struct gal_linkedlist_stll   *write;  /* Full arg. for keywords to add.  */
   uint8_t                 quitonerror;  /* Quit if an error occurs.        */
 
   /* Internal: */
-  int                        onlyview;
+  int                            mode;
+  struct gal_fits_key_ll  *write_keys;  /* Keys to write in the header.    */
+  struct gal_fits_key_ll *update_keys;  /* Keys to update in the header.   */
   time_t                      rawtime;  /* Starting time of the program.   */
-  char                      *filename;  /* Name of input file.             */
-  struct gal_linkedlist_stll  *rename;  /* Rename a keyword.               */
-  struct gal_linkedlist_stll *updatestr;/* For keywords to update.         */
-  struct gal_linkedlist_stll *writestr; /* Full arg. for keywords to add.  */
 };
 
 #endif
diff --git a/bin/fits/ui.c b/bin/fits/ui.c
index 202ddaf..b2a2672 100644
--- a/bin/fits/ui.c
+++ b/bin/fits/ui.c
@@ -71,6 +71,14 @@ doc[] = GAL_STRINGS_TOP_HELP_INFO PROGRAM_NAME" view and 
manipulate (add, "
 
 
 
+/* Option groups particular to this program. */
+enum program_args_groups
+{
+  ARGS_GROUP_EXTENSION = GAL_OPTIONS_GROUP_AFTER_COMMON,
+  ARGS_GROUP_KEYWORD,
+};
+
+
 
 
 
@@ -94,9 +102,9 @@ ui_initialize_options(struct fitsparams *p,
                       struct argp_option *program_options,
                       struct argp_option *gal_commonopts_options)
 {
+  size_t i;
   struct gal_options_common_params *cp=&p->cp;
 
-
   /* Set the necessary common parameters structure. */
   cp->poptions           = program_options;
   cp->program_name       = PROGRAM_NAME;
@@ -104,6 +112,24 @@ ui_initialize_options(struct fitsparams *p,
   cp->program_bibtex     = PROGRAM_BIBTEX;
   cp->program_authors    = PROGRAM_AUTHORS;
   cp->coptions           = gal_commonopts_options;
+
+  /* For clarity and non-zero initializations. */
+  p->mode=FITS_MODE_INVALID;
+
+  /* Don't show the unused options. */
+  for(i=0; !gal_options_is_last(&cp->coptions[i]); ++i)
+    switch(cp->coptions[i].key)
+      {
+      case GAL_OPTIONS_KEY_SEARCHIN:
+      case GAL_OPTIONS_KEY_IGNORECASE:
+      case GAL_OPTIONS_KEY_OUTPUT:
+      case GAL_OPTIONS_KEY_TYPE:
+      case GAL_OPTIONS_KEY_TABLEFORMAT:
+      case GAL_OPTIONS_KEY_DONTDELETE:
+      case GAL_OPTIONS_KEY_KEEPINPUTDIR:
+        cp->coptions[i].flags=OPTION_HIDDEN;
+      }
+
 }
 
 
@@ -185,13 +211,21 @@ parse_opt(int key, char *arg, struct argp_state *state)
 static void
 ui_read_check_only_options(struct fitsparams *p)
 {
-  /* See if the user just wants to view the header or actually do
-     something. */
-  if(p->delete || p->updatestr || p->writestr || p->asis || p->comment
-     || p->history || p->date || p->rename)
-    p->onlyview=0;
-  else
-    p->onlyview=1;
+  /* If any of the keyword manipulation options are requested, then set the
+     mode flag to keyword-mode. */
+  if( p->date || p->comment || p->history || p->asis || p->delete
+      || p->rename || p->rename || p->update || p->write )
+    p->mode=FITS_MODE_KEY;
+
+  /* If any of the extension keywords are given, then set the mode.
+    error(EXIT_FAILURE, 0, "extension and keyword manipulation options "
+          "cannot be called together");
+  */
+
+  /* If no mode-specifying options are given, then go into extension
+     mode. */
+  if(p->mode==FITS_MODE_INVALID)
+    p->mode=FITS_MODE_HDU;
 }
 
 
@@ -203,16 +237,7 @@ ui_check_options_and_arguments(struct fitsparams *p)
 {
   /* Make sure an input file name was given and if it was a FITS file, that
      a HDU is also given. */
-  if(p->filename)
-    {
-      if( gal_fits_name_is_fits(p->filename) && p->cp.hdu==NULL )
-        error(EXIT_FAILURE, 0, "%s: no HDU specified. A FITS file can "
-              "contain, multiple HDUs. You can use the `--hdu' (`-h') "
-              "option and give it the HDU number (starting from zero), "
-              "extension name, or anything acceptable by CFITSIO",
-              p->filename);
-    }
-  else
+  if(p->filename==NULL)
     error(EXIT_FAILURE, 0, "no input file is specified");
 }
 
@@ -238,51 +263,12 @@ ui_check_options_and_arguments(struct fitsparams *p)
 /**************************************************************/
 /*****************       Preparations      ********************/
 /**************************************************************/
-static void
-ui_setup_rename(struct fitsparams *p)
-{
-  char *c;
-  struct gal_linkedlist_stll *tmp;
-
-  for(tmp=p->rename; tmp!=NULL; tmp=tmp->next)
-    {
-      /* `c' is created in case of an error, so the input value can be
-         reported. */
-      errno=0;
-      c=malloc(strlen(tmp->v) + 1);
-      if(c==NULL) error(EXIT_FAILURE, errno, "space for c in setuprename");
-      strcpy(c, tmp->v);
-
-      /* Tokenize the input. */
-      gal_linkedlist_add_to_stll(&p->renamefrom, strtok(tmp->v, ", "), 1);
-      gal_linkedlist_add_to_stll(&p->renameto, strtok(NULL, ", "), 1);
-      if(p->renamefrom->v==NULL || p->renameto->v==NULL)
-        error(EXIT_FAILURE, 0, "`%s' could not be tokenized in order to "
-              "complete rename. There should be a space character "
-              "or a comma (,) between the two keyword names. If you have "
-              "used the space character, be sure to enclose the value to "
-              "the `--rename' option in double quotation marks", c);
-      free(c);
-    }
-  /*
-  {
-    struct gal_linkedlist_stll *tmp2=p->renameto;
-    for(tmp=p->renamefrom; tmp!=NULL; tmp=tmp->next)
-      {
-        printf("%s to %s\n", tmp->v, tmp2->v);
-        tmp2=tmp2->next;
-      }
-  }
-  */
-}
-
-
-
-
-
+/* The `--update' and `--write' options take multiple values for each
+   keyword, so here, we tokenize them and put them into a `gal_fits_key_ll'
+   list. */
 static void
 ui_fill_fits_headerll(struct gal_linkedlist_stll *input,
-                      struct gal_fits_key_ll **output)
+                          struct gal_fits_key_ll **output)
 {
   long l, *lp;
   void *fvalue;
@@ -403,25 +389,11 @@ ui_fill_fits_headerll(struct gal_linkedlist_stll *input,
 static void
 ui_preparations(struct fitsparams *p)
 {
-  char *ffname;
-  int status=0, iomode;
-
-  /* Add hdu to filename: */
-  asprintf(&ffname, "%s[%s#]", p->filename, p->cp.hdu);
-
-  /* Open the FITS file: */
-  iomode = p->onlyview ? READONLY : READWRITE;
-  if( fits_open_file(&p->fptr, ffname, iomode, &status) )
-    gal_fits_io_error(status, "reading file");
-  free(ffname);
-
-  /* Separate the comma-separated values:  */
-  if(p->rename)
-    ui_setup_rename(p);
-  if(p->updatestr)
-    ui_fill_fits_headerll(p->updatestr, &p->update);
-  if(p->writestr)
-    ui_fill_fits_headerll(p->writestr, &p->write);
+  /* Fill in the key linked lists. We want to do this here so if there is
+     any error in parsing the user's input, the error is reported before
+     any change is made in the input file. */
+  if(p->write)  ui_fill_fits_headerll(p->write, &p->write_keys);
+  if(p->update) ui_fill_fits_headerll(p->update, &p->update_keys);
 }
 
 
@@ -465,6 +437,7 @@ ui_read_check_inputs_setup(int argc, char *argv[], struct 
fitsparams *p)
   /* Initialize the options and necessary information.  */
   ui_initialize_options(p, program_options, gal_commonopts_options);
 
+
   /* Read the command-line options and arguments. */
   errno=0;
   if(argp_parse(&thisargp, argc, argv, 0, 0, p))
@@ -521,16 +494,7 @@ ui_read_check_inputs_setup(int argc, char *argv[], struct 
fitsparams *p)
 void
 ui_free_and_report(struct fitsparams *p)
 {
-  int status=0;
-
   /* Free the allocated arrays: */
   free(p->cp.hdu);
   free(p->cp.output);
-
-  /* Close the FITS file: */
-  if(fits_close_file(p->fptr, &status))
-    gal_fits_io_error(status, NULL);
-
-  if(p->wcs)
-    wcsvfree(&p->nwcs, &p->wcs);
 }
diff --git a/bin/fits/ui.h b/bin/fits/ui.h
index 8f0d0a5..be2fed0 100644
--- a/bin/fits/ui.h
+++ b/bin/fits/ui.h
@@ -29,22 +29,23 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 
 /* Available letters for short options:
 
-   b e f g i j k l m n p s v x y z
+   b e f g j k l m n s v x y z
    A B C E F G J L M O R W X Y Z
 
 */
 enum option_keys_enum
 {
   /* With short-option version. */
-  ARGS_OPTION_KEY_ASIS        = 'a',
-  ARGS_OPTION_KEY_DELETE      = 'd',
-  ARGS_OPTION_KEY_RENAME      = 'r',
-  ARGS_OPTION_KEY_UPDATE      = 'u',
-  ARGS_OPTION_KEY_WRITE       = 'w',
-  ARGS_OPTION_KEY_COMMENT     = 'c',
-  ARGS_OPTION_KEY_HISTORY     = 'H',
-  ARGS_OPTION_KEY_DATE        = 't',
-  ARGS_OPTION_KEY_QUITONERROR = 'Q',
+  ARGS_OPTION_KEY_PRINTALL     = 'p',
+  ARGS_OPTION_KEY_ASIS         = 'a',
+  ARGS_OPTION_KEY_DELETE       = 'd',
+  ARGS_OPTION_KEY_RENAME       = 'r',
+  ARGS_OPTION_KEY_UPDATE       = 'u',
+  ARGS_OPTION_KEY_WRITE        = 'w',
+  ARGS_OPTION_KEY_COMMENT      = 'c',
+  ARGS_OPTION_KEY_HISTORY      = 'H',
+  ARGS_OPTION_KEY_DATE         = 't',
+  ARGS_OPTION_KEY_QUITONERROR  = 'Q',
 
 
   /* Only with long version (start with a value 1000, the rest will be set
diff --git a/doc/gnuastro.texi b/doc/gnuastro.texi
index 0bfccf7..98265bf 100644
--- a/doc/gnuastro.texi
+++ b/doc/gnuastro.texi
@@ -62,8 +62,8 @@ License''.
 * Crop: (gnuastro)Crop. Crop region(s) from image(s).
 * astcrop: (gnuastro)Invoking astcrop. Options to Crop.
 
-* Header: (gnuastro)Header. Print and manipulate data header info.
-* astheader: (gnuastro)Invoking astheader. Options to Header.
+* Fits: (gnuastro)Fits. View and manipulate FITS extensions and keywords.
+* astfits: (gnuastro)Invoking astfits. Options to Fits.
 
 * Arithmetic: (gnuastro)Arithmetic. Arithmetic operations on pixels.
 * astarithmetic: (gnuastro)Invoking astarithmetic. Options to Arithmetic.
@@ -333,13 +333,13 @@ Getting help
 
 Extensions and Tables
 
-* Header::                      Print and manipulate data file header.
+* Fits::                        View and manipulate extensions and keywords.
 * ConvertType::                 Convert data to various formats.
 * Table::                       Read and Write FITS tables to plain text.
 
-Header
+Fits
 
-* Invoking astheader::          Arguments and options to Header.
+* Invoking astfits::            Arguments and options to Header.
 
 ConvertType
 
@@ -4352,7 +4352,7 @@ output names explained in @ref{Automatic output} are 
ignored.
 @item -T STR
 @itemx --type=STR
 The data type of the output depending on the program context. This option
-isn't applicable to some programs like @ref{Header} and will be ignored by
+isn't applicable to some programs like @ref{Fits} and will be ignored by
 them. The different acceptable values to this option are fully described in
 @ref{Numeric data types}.
 
@@ -5353,7 +5353,7 @@ mainly contains ASCII columns (for example file names, or
 descriptions). They can be useful when you need to include columns with
 structured ASCII information along with other extensions in one FITS
 file. In such cases, you can also consider header keywords (see
address@hidden).
address@hidden).
 
 @cindex Binary table, FITS
 @item FITS binary tables
@@ -6080,11 +6080,13 @@ END
 @cindex General file operations
 This chapter documents those Gnuastro programs 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.
+from different data types, there is no further processing. 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, Fits (see @ref{Fits}) can be handy by printing
+the information for all the extensions in a FITS file, or all the keywords
+in an extension of a FITS file to the terminal for easy inspection. You can
+also add/remove extensions/keywords with it.
 
 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
@@ -6098,7 +6100,7 @@ readable output on the terminal, or to save them in 
another plain text or
 FITS table.
 
 @menu
-* Header::                      Print and manipulate data file header.
+* Fits::                        View and manipulate extensions and keywords.
 * ConvertType::                 Convert data to various formats.
 * Table::                       Read and Write FITS tables to plain text.
 @end menu
@@ -6107,8 +6109,8 @@ FITS table.
 
 
 
address@hidden Header, ConvertType, Extensions and Tables, Extensions and Tables
address@hidden Header
address@hidden Fits, ConvertType, Extensions and Tables, Extensions and Tables
address@hidden Fits
 
 The FITS standard requires each extension of a FITS file to have a
 header, giving basic information about what is in that extension. Each
@@ -6120,15 +6122,15 @@ the World Coordinate System that is used to translate 
pixel
 coordinates to sky or spectrum coordinates on the image or table.
 
 @menu
-* Invoking astheader::          Arguments and options to Header.
+* Invoking astfits::            Arguments and options to Header.
 @end menu
 
address@hidden Invoking astheader,  , Header, Header
address@hidden Invoking Header
address@hidden Invoking astfits,  , Fits, Fits
address@hidden Invoking Fits
 
-Header can print or manipulate the header information in an extension
-of an astronomical data file. The executable name is @file{astheader}
-with the following general template
+Fits can print or manipulate the header information in an extension of an
+astronomical data file. The executable name is @file{astheader} with the
+following general template
 
 @example
 $ astheader [OPTION...] ASTRdata
@@ -6146,13 +6148,12 @@ $ astheader --write=MYKEY1,20.00,"An example keyword" 
--write=MYKEY2,fd
 @end example
 
 @cindex HDU
-If no keyword modification options are given, the full header of the
-given HDU will be printed on the command-line. If any of the keywords
-are to be modified, the headers of the input file will be changed. If
-you want to keep the original FITS file, it is easiest to create a
-copy first and then run Header on that. In the FITS standard, keywords
-are always uppercase. So case does not matter in the input or output
-keyword names you specify.
+If no keyword modification options are given, the full header of the given
+HDU will be printed on the command-line. If any of the keywords are to be
+modified, the headers of the input file will be changed. If you want to
+keep the original FITS file, it is easiest to create a copy first and then
+run Fits on that. In the FITS standard, keywords are always uppercase. So
+case does not matter in the input or output keyword names you specify.
 
 Most of the options can accept multiple instances in one command. For
 example you can add multiple keywords to delete by calling delete
@@ -6196,30 +6197,31 @@ operations are going to take effect then the update 
operations.
 @option{--comment}
 @item
 @option{--date}
address@hidden
address@hidden
 @end enumerate
 @noindent
 All possible syntax errors will be reported before the keywords are
-actually written. FITS errors during any of these actions will be
-reported, but Header won't stop until all the operations are
-complete. If @option{quitonerror} is called, then Header will
-immediately stop upon the first error.
+actually written. FITS errors during any of these actions will be reported,
+but Fits won't stop until all the operations are complete. If
address@hidden is called, then Fits will immediately stop upon the
+first error.
 @end cartouche
 
 @cindex GNU Grep
-If only a certain set of header keywords are desired, it is easiest to
-pipe the output of Header to GNU Grep. Grep is a very powerful and
-advanced tool to search strings which is precisely made for such
-situations. For example if you only want to check the size of an image
-FITS HDU, you can run:
+If only a certain set of header keywords are desired, it is easiest to pipe
+the output of Fits to GNU Grep. Grep is a very powerful and advanced tool
+to search strings which is precisely made for such situations. For example
+if you only want to check the size of an image FITS HDU, you can run:
 
 @example
 $ astheader input.fits | grep NAXIS
 @end example
 
 @noindent
-The options particular to Header can be seen below. See @ref{Common
-options} for a list of the options that are common to all Gnuastro
-programs, they are not repeated here.
+The options particular to Fits can be seen below. See @ref{Common options}
+for a list of the options that are common to all Gnuastro programs, they
+are not repeated here.
 @table @option
 
 @item -a STR
@@ -6255,7 +6257,7 @@ Delete one instance of the @option{STR} keyword from the 
FITS
 header. Multiple instances of @option{--delete} can be given (possibly even
 for the same keyword). All keywords given will be removed from the headers
 in the opposite order (last given keyword will be deleted first). If the
-keyword doesn't exist, Header will give a warning and return with a
+keyword doesn't exist, Fits will give a warning and return with a
 non-zero value, but will not stop.
 
 @item -r STR
@@ -6293,7 +6295,7 @@ written. Commit hashes are very important in keeping the 
history of a file
 during your research and such values might arise without you noticing them
 in your reproduction pipeline. One solution is to use @command{git
 describe} instead of the short hash alone. A less recommended solution is
-to add a space after the commit hash and Header will write the value as
+to add a space after the commit hash and Fits will write the value as
 address@hidden }' in the header. If you later compare the strings on the
 shell, the space character will be ignored by the shell in the latter
 solution and there will be no problem.}. Other than the @code{KEYWORD}, all
@@ -6328,10 +6330,15 @@ Add a @code{COMMENT} keyword to the header. Similar to 
the explanation for
 Put the current date and time in the header. If the @code{DATE}
 keyword already exists in the header, it will be updated.
 
address@hidden -p
address@hidden --printall
+Print all the keywords in the specified FITS extension (HDU) on the
+command-line.
+
 @item -Q
 @itemx --quitonerror
 Quit if any of the operations above are not successful. By default if
-an error occurs, Header will warn the user of the faulty keyword and
+an error occurs, Fits will warn the user of the faulty keyword and
 continue with the rest of actions.
 
 @end table
@@ -6349,7 +6356,7 @@ continue with the rest of actions.
 
 
 
address@hidden ConvertType, Table, Header, Extensions and Tables
address@hidden ConvertType, Table, Fits, Extensions and Tables
 @section ConvertType
 
 @cindex Data format conversion
@@ -12782,7 +12789,7 @@ all clump related options will be ignored.
 @cindex Photometry, aperture
 @cindex Aperture photometry
 For example, if you only need an object catalog from NoiseChisel's output,
-you can use Header (see @ref{Header}) to modify or remove the
+you can use Fits (see @ref{Fits}) to modify or remove the
 @code{WCLUMPS} keyword in the objects HDU, then run MakeCatalog on
 it. Another example can be aperture photometry: let's assume you have made
 your labeled image (defining the apertures) with MakeProfiles. Clumps are
@@ -19355,9 +19362,9 @@ comoving volume and many more.
 several images if necessary. Inputs can be in pixel coordinates or world
 coordinates.
 
address@hidden Header
-(@file{astheader}, see @ref{Header}) Print and manipulate the header data
-of a FITS file.
address@hidden Fits
+(@file{astfits}, see @ref{Fits}) View and manipulate FITS file extensions
+and header keywords.
 
 @item Statistics
 (@file{aststatistics}, see @ref{Statistics}) Get pixel statistics and
diff --git a/lib/fits.c b/lib/fits.c
index 373fc81..6c8bd1d 100644
--- a/lib/fits.c
+++ b/lib/fits.c
@@ -499,48 +499,27 @@ gal_fits_hdu_num(char *filename, int *numhdu)
 
 
 
-/* Check the desired HDU in a FITS image and also if it has the
-   desired type. */
+/* Open a given HDU and return the FITS pointer. `iomode' determines how
+   the FITS file will be opened: only to read or to read and write. You
+   should use the macros given by the CFITSIO header:
+
+     READONLY:   read-only.
+     READWRITE:  read and write.         */
 fitsfile *
-gal_fits_hdu_open(char *filename, char *hdu, unsigned char img0_tab1)
+gal_fits_hdu_open(char *filename, char *hdu, int iomode)
 {
+  int status=0;
   char *ffname;
   fitsfile *fptr;
-  int status=0, hdutype;
-
-  /* A small sanity check. */
-  if(hdu==NULL)
-    error(EXIT_FAILURE, 0, "no HDU specified for %s", filename);
 
   /* Add hdu to filename: */
   asprintf(&ffname, "%s[%s#]", filename, hdu);
 
   /* Open the FITS file: */
-  if( fits_open_file(&fptr, ffname, READONLY, &status) )
+  if( fits_open_file(&fptr, ffname, iomode, &status) )
     gal_fits_io_error(status, "reading this FITS file");
 
-  /* Check the type of the given HDU: */
-  if (fits_get_hdu_type(fptr, &hdutype, &status) )
-    gal_fits_io_error(status, NULL);
-
-  /* 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 not a table",
-              filename, hdu);
-    }
-  else
-    {
-      if(hdutype!=IMAGE_HDU)
-        error(EXIT_FAILURE, 0, "%s (hdu: %s): not an image",
-              filename, hdu);
-    }
-
-  /* Clean up and return. */
-  free(ffname);
+  /* Return the pointer. */
   return fptr;
 }
 
@@ -558,23 +537,17 @@ gal_fits_hdu_open(char *filename, char *hdu, unsigned 
char img0_tab1)
 int
 gal_fits_hdu_type(char *filename, char *hdu)
 {
-  char *ffname;
   fitsfile *fptr;
   int hdutype, status=0;
 
-  /* Add hdu to filename: */
-  asprintf(&ffname, "%s[%s#]", filename, hdu);
-
-  /* Open the FITS file: */
-  if( fits_open_file(&fptr, ffname, READONLY, &status) )
-    gal_fits_io_error(status, "reading this FITS file");
+  /* Open the HDU. */
+  fptr=gal_fits_hdu_open(filename, hdu, READONLY);
 
   /* Check the type of the given HDU: */
   if (fits_get_hdu_type(fptr, &hdutype, &status) )
     gal_fits_io_error(status, NULL);
 
   /* Clean up and return.. */
-  free(ffname);
   if( fits_close_file(fptr, &status) )
     gal_fits_io_error(status, NULL);
   return hdutype;
@@ -584,6 +557,50 @@ gal_fits_hdu_type(char *filename, char *hdu)
 
 
 
+/* Check the desired HDU in a FITS image and also if it has the
+   desired type. */
+fitsfile *
+gal_fits_hdu_open_type(char *filename, char *hdu, unsigned char img0_tab1)
+{
+  fitsfile *fptr;
+  int status=0, hdutype;
+
+  /* A small sanity check. */
+  if(hdu==NULL)
+    error(EXIT_FAILURE, 0, "no HDU specified for %s", filename);
+
+  /* Open the HDU. */
+  fptr=gal_fits_hdu_open(filename, hdu, READONLY);
+
+  /* Check the type of the given HDU: */
+  if (fits_get_hdu_type(fptr, &hdutype, &status) )
+    gal_fits_io_error(status, NULL);
+
+  /* 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 not a table",
+              filename, hdu);
+    }
+  else
+    {
+      if(hdutype!=IMAGE_HDU)
+        error(EXIT_FAILURE, 0, "%s (hdu: %s): not an image",
+              filename, hdu);
+    }
+
+  /* Clean up and return. */
+  return fptr;
+}
+
+
+
+
+
+
 
 
 
@@ -723,6 +740,38 @@ gal_fits_key_read_from_ptr(fitsfile *fptr, gal_data_t 
*keysll,
 
 
 
+/* CFITSIO doesn't remove the two single quotes around the string value, so
+   the strings it reads are like: 'value ', or 'some_very_long_value'. To
+   use the value, it is commonly necessary to remove the single quotes (and
+   possible extra spaces). This function fill modify the string in its own
+   allocated space. You can use this to later free the original string (if
+   it was allocated). */
+char *
+gal_fits_key_clean_str_value(char *string)
+{
+  size_t i;
+  char *out=string+1;
+
+  /* Start from the second last character (the last is a single quote) and
+     go down until you hit a non-space character. This will also work when
+     there is no space characters between the last character of the value
+     and ending single-quote: it will be set to '\0' after this loop. */
+  for(i=strlen(out)-2;i>0;--i)
+    if(out[i]!=' ')
+      break;
+
+  /* If the string is empty, it will stop at the first character that is a
+     single quote. So no need to check further. */
+  out[i+1]='\0';
+
+  /* Return the new string. */
+  return out;
+}
+
+
+
+
+
 /* Same as `gal_fits_read_keywords_fptr', but accepts the filename and HDU
    as input instead of an already opened CFITSIO `fitsfile' pointer. */
 void
@@ -1147,7 +1196,7 @@ gal_fits_img_read(char *filename, char *hdu, size_t 
minmapsize)
 
 
   /* Check HDU for realistic conditions: */
-  fptr=gal_fits_hdu_open(filename, hdu, 0);
+  fptr=gal_fits_hdu_open_type(filename, hdu, 0);
 
 
   /* Get the info and allocate the data structure. */
@@ -1177,9 +1226,9 @@ gal_fits_img_read(char *filename, char *hdu, size_t 
minmapsize)
      free the linked list after `gal_data_alloc' has read/copied the
      values.*/
   gal_data_add_to_ll(&keysll, NULL, GAL_DATA_TYPE_STRING, 1, &dsize_key,
-                        NULL, 0, -1, "EXTNAME", NULL, NULL);
+                     NULL, 0, -1, "EXTNAME", NULL, NULL);
   gal_data_add_to_ll(&keysll, NULL, GAL_DATA_TYPE_STRING, 1, &dsize_key,
-                        NULL, 0, -1, "BUNIT", NULL, NULL);
+                     NULL, 0, -1, "BUNIT", NULL, NULL);
   gal_fits_key_read_from_ptr(fptr, keysll, 0, 0);
   if(keysll->status==0)       {str=keysll->array;       unit=*str; }
   if(keysll->next->status==0) {str=keysll->next->array; name=*str; }
@@ -1554,27 +1603,6 @@ gal_fits_tab_type(fitsfile *fptr)
 
 
 
-static void
-remove_trailing_space(char *str)
-{
-  size_t i;
-
-  /* Start from the second last character (the last is a single quote) and
-     go down until you hit a non-space character. This will also work when
-     there is no space characters between the last character of the value
-     and ending single-quote: it will be set to '\0' after this loop. */
-  for(i=strlen(str)-2;i>0;--i)
-    if(str[i]!=' ')
-      break;
-
-  /* If the string is empty, it will stop at the first character that is a
-     single quote. So no need to check further. */
-  str[i+1]='\0';
-}
-
-
-
-
 
 /* The general format of the TDISPn keywords in FITS is like this: `Tw.p',
    where `T' specifies the general format, `w' is the width to be given to
@@ -1728,7 +1756,7 @@ gal_fits_tab_info(char *filename, char *hdu, size_t 
*numcols,
 
 
   /* Open the FITS file and get the basic information. */
-  fptr=gal_fits_hdu_open(filename, hdu, 1);
+  fptr=gal_fits_hdu_open_type(filename, hdu, 1);
   *tabletype=gal_fits_tab_type(fptr);
   gal_fits_tab_size(fptr, numrows, numcols);
 
@@ -1766,12 +1794,7 @@ gal_fits_tab_info(char *filename, char *hdu, size_t 
*numcols,
          single quotes around the value string, one before and one
          after. The latter single-quote will be automatically be removed
          with the `remove_trailign_space' function.*/
-      if(value[0]=='\'')
-        {
-          val=value+1;
-          remove_trailing_space(val);
-        }
-      else val=value;
+      val = value[0]=='\'' ? gal_fits_key_clean_str_value(value) : value;
 
       /* COLUMN DATA TYPE. According the the FITS standard, the value of
          TFORM is most generally in this format: `rTa'. `T' is actually a
@@ -1899,11 +1922,8 @@ gal_fits_tab_info(char *filename, char *hdu, size_t 
*numcols,
         {
           index = strtoul(&keyname[5], &tailptr, 10) - 1;
           if(index<tfields)
-            {
-              remove_trailing_space(value);
-              set_display_format(&value[1], &allcols[index], filename, hdu,
-                                 keyname);
-            }
+            set_display_format(val, &allcols[index], filename, hdu,
+                               keyname);
         }
 
       /* Column zero. */
@@ -1943,7 +1963,7 @@ gal_fits_tab_read(char *filename, char *hdu, size_t 
numrows,
   struct gal_linkedlist_sll *ind;
 
   /* Open the FITS file */
-  fptr=gal_fits_hdu_open(filename, hdu, 1);
+  fptr=gal_fits_hdu_open_type(filename, hdu, 1);
 
   /* Pop each index and read/store the array. */
   for(ind=indexll; ind!=NULL; ind=ind->next)
diff --git a/lib/gnuastro/fits.h b/lib/gnuastro/fits.h
index c9b5437..57d2a99 100644
--- a/lib/gnuastro/fits.h
+++ b/lib/gnuastro/fits.h
@@ -148,12 +148,15 @@ gal_fits_datatype_to_type(int datatype, int 
is_table_column);
 void
 gal_fits_hdu_num(char *filename, int *numhdu);
 
-fitsfile *
-gal_fits_hdu_open(char *filename, char *hdu, unsigned char img0_tab1);
-
 int
 gal_fits_hdu_type(char *filename, char *hdu);
 
+fitsfile *
+gal_fits_hdu_open(char *filename, char *hdu, int iomode);
+
+fitsfile *
+gal_fits_hdu_open_type(char *filename, char *hdu, unsigned char img0_tab1);
+
 
 
 
@@ -192,6 +195,9 @@ void
 gal_fits_key_write_version(fitsfile *fptr, struct gal_fits_key_ll *headers,
                            char *program_string);
 
+char *
+gal_fits_key_clean_str_value(char *string);
+
 
 
 
diff --git a/lib/wcs.c b/lib/wcs.c
index 00252ff..e881110 100644
--- a/lib/wcs.c
+++ b/lib/wcs.c
@@ -152,7 +152,7 @@ gal_wcs_read(char *filename, char *hdu, size_t hstartwcs,
   fitsfile *fptr;
 
   /* Check HDU for realistic conditions: */
-  fptr=gal_fits_hdu_open(filename, hdu, 0);
+  fptr=gal_fits_hdu_open_type(filename, hdu, 0);
 
   /* Read the WCS information: */
   gal_wcs_read_from_fitsptr(fptr, nwcs, wcs, hstartwcs, hendwcs);



reply via email to

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