gnuastro-commits
[Top][All Lists]
Advanced

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

[gnuastro-commits] master efdbb758 1/2: Library (fits, copykeys): List o


From: Mohammad Akhlaghi
Subject: [gnuastro-commits] master efdbb758 1/2: Library (fits, copykeys): List of Keywords
Date: Tue, 19 Apr 2022 15:03:08 -0400 (EDT)

branch: master
commit efdbb7586a9847329241faf3ec1bd574101b1aec
Author: Jash Shah <jash28582@gmail.com>
Commit: Mohammad Akhlaghi <mohammad@akhlaghi.org>

    Library (fits, copykeys): List of Keywords
    
    Until now, copykeys option for astfits used to only accept a range of
    keywords for eg: 5:10.
    
    With this commit it now also accepts a range of keywords as a comma
    separated list for eg: BITPIX,LTV1.
    
    This is done by parsing the input of copykeys, and if an alphabet is
    detected, then it considers them as a list of keywords.
    
    This is a solution to the task#16073.
---
 bin/fits/args.h     |   4 +-
 bin/fits/keywords.c | 181 +++++++++++++++++++++++++++++++++++++++-------------
 bin/fits/main.h     |   1 +
 bin/fits/ui.c       | 163 ++++++++++++++++++++++++++--------------------
 doc/gnuastro.texi   |  13 +++-
 5 files changed, 242 insertions(+), 120 deletions(-)

diff --git a/bin/fits/args.h b/bin/fits/args.h
index 51520844..24cb3594 100644
--- a/bin/fits/args.h
+++ b/bin/fits/args.h
@@ -384,9 +384,9 @@ struct argp_option program_options[] =
     {
       "copykeys",
       UI_KEY_COPYKEYS,
-      "INT:INT",
+      "INT:INT/STR,STR",
       0,
-      "Range of keywords to copy to output HDU.",
+      "Range/List of keywords to copy to output HDU.",
       UI_GROUP_KEYWORD,
       &p->copykeys,
       GAL_TYPE_STRING,
diff --git a/bin/fits/keywords.c b/bin/fits/keywords.c
index 5f1d80e4..3a12ded0 100644
--- a/bin/fits/keywords.c
+++ b/bin/fits/keywords.c
@@ -372,72 +372,65 @@ keywords_verify(struct fitsparams *p, fitsfile **fptr)
 
 
 
-
+/* To copy keys to output file when --copykeys are given in STR,STR,STR
+    format. */
 static void
-keywords_copykeys(struct fitsparams *p, char *inkeys, size_t numinkeys)
+keywords_copykeys_str(struct fitsparams *p)
 {
-  size_t i;
-  long initial;
-  fitsfile *fptr;
+  fitsfile *infptr, *outfptr;
+  gal_list_str_t *input, *tmp;
   int status=0, updatechecksum=0, checksumexists=0;
 
-  /* Initial sanity check. Since 'numinkeys' includes 'END' (counting from
-     1, as we do here), the first keyword must not be larger OR EQUAL to
-     'numinkeys'. */
-  if(p->copykeysrange[0]>=numinkeys)
-    error(EXIT_FAILURE, 0, "%s (hdu %s): first keyword number give "
-          "to '--copykeys' (%ld) is larger than the number of "
-          "keywords in this header (%zu, including the 'END' "
-          "keyword)", p->input->v, p->cp.hdu, p->copykeysrange[0],
-          numinkeys);
-
-  /* If the user wanted to count from the end (by giving a negative value),
-     then do that. */
-  if(p->copykeysrange[1]<0)
+  /* Print Keys to Copy. */
+  if (!p->cp.quiet)
     {
-      /* Set the last keyword requested. */
-      initial=p->copykeysrange[1];
-      p->copykeysrange[1] += numinkeys;
-
-      /* Sanity check. */
-      if(p->copykeysrange[0]>=p->copykeysrange[1])
-        error(EXIT_FAILURE, 0, "%s (hdu %s): the last keyword given to "
-              "'--copykeys' (%ld, or %ld after counting from the bottom) "
-              "is earlier than the first (%ld)", p->input->v, p->cp.hdu,
-              initial, p->copykeysrange[1], p->copykeysrange[0]);
+        printf("Keys to Copy :\n");
+        gal_list_str_print(p->keystocopy);
     }
 
-  /* Final sanity check (on range limit). */
-  if(p->copykeysrange[1]>=numinkeys)
-    error(EXIT_FAILURE, 0, "%s (hdu %s): second keyword number give to "
-          "'--copykeys' (%ld) is larger than the number of keywords in "
-          "this header (%zu, including the 'END' keyword)", p->input->v,
-          p->cp.hdu, p->copykeysrange[1], numinkeys);
+  /* Parse  input file, read the keywords and put them in the output
+      (keysll) list. */
+  input=p->input;
+
+  /* Open the input FITS file. */
+  infptr=gal_fits_hdu_open(input->v, p->cp.hdu, READONLY);
 
   /* Open the output HDU. */
-  fptr=gal_fits_hdu_open(p->cp.output, p->outhdu, READWRITE);
+  outfptr=gal_fits_hdu_open(p->cp.output, p->outhdu, READWRITE);
 
-  /* See if a 'CHECKSUM' key exists in the HDU or not (to update in case we
-     wrote anything). */
-  checksumexists=gal_fits_key_exists_fptr(fptr, "CHECKSUM");
+  /* See if a 'CHECKSUM' key exists in the HDU or not (to update in case
+     we wrote anything). */
+  checksumexists=gal_fits_key_exists_fptr(outfptr, "CHECKSUM");
 
-  /* Copy the requested headers into the output. */
-  for(i=p->copykeysrange[0]-1; i<=p->copykeysrange[1]-1; ++i)
+  /* Copy the requested headers into the output files header. */
+  for(tmp=p->keystocopy; tmp!=NULL; tmp=tmp->next)
     {
-      if( fits_write_record(fptr, &inkeys[i*80], &status ) )
+      char inkey[80];
+      char *keyname = tmp->v;
+
+      if(fits_read_card(infptr,keyname, inkey, &status))
+        gal_fits_io_error(status,NULL);
+
+      if( fits_write_record(outfptr, inkey, &status ) )
         gal_fits_io_error(status, NULL);
       else updatechecksum=1;
+
     }
 
+  /* Close the input FITS file. */
+  status=0;
+  if(fits_close_file(infptr, &status))
+    gal_fits_io_error(status, NULL);
+
   /* If a checksum existed, and we made changes in the file, we should
-     upate the checksum. */
+     update the checksum. */
   if(checksumexists && updatechecksum)
-    if( fits_write_chksum(fptr, &status) )
+    if( fits_write_chksum(outfptr, &status) )
       gal_fits_io_error(status, NULL);
 
   /* Close the output FITS file. */
   status=0;
-  if(fits_close_file(fptr, &status))
+  if(fits_close_file(outfptr, &status))
     gal_fits_io_error(status, NULL);
 }
 
@@ -445,6 +438,102 @@ keywords_copykeys(struct fitsparams *p, char *inkeys, 
size_t numinkeys)
 
 
 
+/* To copy keys to output file when --copykeys are given in INT:INT
+    format. */
+static void
+keywords_copykeys_range(struct fitsparams *p,char *inkeys,
+                                            size_t numinkeys)
+{
+  fitsfile *fptr;
+  size_t i;
+  long initial;
+  int status=0, updatechecksum=0, checksumexists=0;
+  /* Initial sanity check. Since 'numinkeys' includes 'END' (counting from
+          1, as we do here), the first keyword must not be larger OR EQUAL to
+          'numinkeys'. */
+      if(p->copykeysrange[0]>=numinkeys)
+        error(EXIT_FAILURE, 0, "%s (hdu %s): first keyword number give "
+              "to '--copykeys' (%ld) is larger than the number of "
+              "keywords in this header (%zu, including the 'END' "
+              "keyword)", p->input->v, p->cp.hdu, p->copykeysrange[0],
+              numinkeys);
+
+      /* If the user wanted to count from the end (by giving a negative value),
+        then do that. */
+      if(p->copykeysrange[1]<0)
+        {
+          /* Set the last keyword requested. */
+          initial=p->copykeysrange[1];
+          p->copykeysrange[1] += numinkeys;
+
+          /* Sanity check. */
+          if(p->copykeysrange[0]>=p->copykeysrange[1])
+            error(EXIT_FAILURE, 0, "%s (hdu %s): the last keyword given to "
+                  "'--copykeys' (%ld, or %ld after counting from the bottom) "
+                  "is earlier than the first (%ld)", p->input->v, p->cp.hdu,
+                  initial, p->copykeysrange[1], p->copykeysrange[0]);
+        }
+
+      /* Final sanity check (on range limit). */
+      if(p->copykeysrange[1]>=numinkeys)
+        error(EXIT_FAILURE, 0, "%s (hdu %s): second keyword number give to "
+              "'--copykeys' (%ld) is larger than the number of keywords in "
+              "this header (%zu, including the 'END' keyword)", p->input->v,
+              p->cp.hdu, p->copykeysrange[1], numinkeys);
+
+      /* Open the output HDU. */
+      fptr=gal_fits_hdu_open(p->cp.output, p->outhdu, READWRITE);
+
+      /* See if a 'CHECKSUM' key exists in the HDU or not (to update in case we
+        wrote anything). */
+      checksumexists=gal_fits_key_exists_fptr(fptr, "CHECKSUM");
+
+      /* Copy the requested headers into the output. */
+      for(i=p->copykeysrange[0]-1; i<=p->copykeysrange[1]-1; ++i)
+        {
+          if( fits_write_record(fptr, &inkeys[i*80], &status ) )
+            gal_fits_io_error(status, NULL);
+          else updatechecksum=1;
+        }
+
+      /* If a checksum existed, and we made changes in the file, we should
+        update the checksum. */
+      if(checksumexists && updatechecksum)
+        if( fits_write_chksum(fptr, &status) )
+          gal_fits_io_error(status, NULL);
+
+      /* Close the output FITS file. */
+      status=0;
+      if(fits_close_file(fptr, &status))
+        gal_fits_io_error(status, NULL);
+}
+
+
+
+
+
+static void
+keywords_copykeys(struct fitsparams *p, char *inkeys, size_t numinkeys)
+{
+  /* File pointer used for accessing input and output files*/
+  fitsfile *fptr;
+
+  /* Call different functions depending on whether a list or range of
+      keywords is given. */
+  if (p->keystocopy)
+    {
+      keywords_copykeys_str(p);
+    }
+  else
+    {
+        keywords_copykeys_range(p,inkeys,numinkeys);
+    }
+}
+
+
+
+
+
 static void
 keywords_date_to_seconds(struct fitsparams *p, fitsfile *fptr)
 {
@@ -1081,8 +1170,8 @@ keywords(struct fitsparams *p)
     }
 
 
-  /* If a range of keywords must be copied, get all the keywords as a
-     single string. */
+  /* If a list/range of keywords must be copied, get all the keywords as a
+      single string. */
   if(p->copykeys)
     {
       keywords_open(p, &fptr, READONLY);
diff --git a/bin/fits/main.h b/bin/fits/main.h
index 2d343e2c..da65cf73 100644
--- a/bin/fits/main.h
+++ b/bin/fits/main.h
@@ -95,6 +95,7 @@ struct fitsparams
   int                 distortionid;  /* ID of desired distortion.       */
   int               updatechecksum;  /* If CHECKSUM should be update.   */
   long            copykeysrange[2];  /* Start and end of copy.          */
+  gal_list_str_t       *keystocopy;  /* Keyword strings list, to copy.  */
   gal_fits_list_key_t  *write_keys;  /* Keys to write in the header.    */
   gal_fits_list_key_t *update_keys;  /* Keys to update in the header.   */
   time_t                   rawtime;  /* Starting time of the program.   */
diff --git a/bin/fits/ui.c b/bin/fits/ui.c
index 57d9ab6f..daca2e2c 100644
--- a/bin/fits/ui.c
+++ b/bin/fits/ui.c
@@ -234,81 +234,106 @@ ui_check_copykeys(struct fitsparams *p)
   /* Initialize the values. */
   p->copykeysrange[0]=p->copykeysrange[1]=GAL_BLANK_LONG;
 
-  /* Parse the string: 'forl': "first-or-last". */
-  while(*pt!='\0')
-    {
-      switch(*pt)
-        {
-        case ':':
-          forl='l';
-          ++pt;
-          break;
-        case '.':
-          error(EXIT_FAILURE, 0, "the numbers in the argument to "
-                "'--section' ('-s') have to be integers. You input "
-                "includes a float number: %s", p->copykeys);
-          break;
-        case ' ': case '\t':
-          ++pt;
-          break;
-
+    /* Parse the string: 'forl': "first-or-last". */
+    while(*pt!='\0')
+      {
+        /* If any alphabet is found then, a list of string keywords
+            are considered. */
+        if (isalpha(*pt))
+          {
+            /* Parse the copykeys string and store name of each keyword
+                in keystocopy list. */
+            char *first = strtok(p->copykeys, ",");
+
+            while(first != NULL)
+              {
+                gal_list_str_add(&p->keystocopy, first, 0);
+                first = strtok(NULL,",");
+              }
+            break;
+          }
+        else if (*pt == ':')
+          {
+            forl='l';
+            ++pt;
+          }
+        else if (*pt == '.')
+          {
+              error(EXIT_FAILURE, 0, "the numbers in the argument to "
+                      "'--section' ('-s') have to be integers. You input "
+                      "includes a float number: %s", p->copykeys);
+          }
+        else if (*pt == ' ' || *pt == '\t')
+          {
+              ++pt;
+          }
         /* Numerical characters signify the start of a number, so we don't
-           need to increment the pointer and can just break out. */
-        case '0': case '1': case '2': case '3': case '4': case '5':
-        case '6': case '7': case '8': case '9': case '-':
-          break;
-
-        /* Identifier for next group of ranges. However, For the time
-           being, we just support one group. So we are commenting the break
-           here for it to follow onto default.
-        case ',':
-          ++group;
-          forl='f';
-          ++pt;
-          break;
-          */
-        default:
-          error(EXIT_FAILURE, 0, "value to '--copykeys' must only contain "
-                "integer numbers and these special characters between them: "
-                "':' when necessary. But it is '%s' (the first "
-                "non-acceptable character is '%c').\n", p->copykeys, *pt);
-          break;
-        }
-
-      /* Read the number: */
-      read=strtol(pt, &tailptr, 0);
-
-      /* Check the progress.
-      printf("\n\n------\n%c: %ld (%s)\n", *pt, read, tailptr);
-      */
-
-      /* Make sure if a number was read at all? */
-      if(tailptr==pt) continue;   /* No number was read!                 */
-
-      /* Put it in the correct place. */
-      p->copykeysrange[ forl=='f' ? 0 : 1 ]=read;
-      pt=tailptr;
+              need to increment the pointer and can just break out. */
+        else if (isdigit(*pt))
+          {
+              /* Read the number: */
+              read=strtol(pt, &tailptr, 0);
+
+              /* Check the progress.
+              printf("\n\n------\n%c: %ld (%s)\n", *pt, read, tailptr);
+              */
+
+              /* Make sure if a number was read at all? */
+              if(tailptr==pt) continue;   /* No number was read!        */
+
+              /* Put it in the correct place. */
+              p->copykeysrange[ forl=='f' ? 0 : 1 ]=read;
+              pt=tailptr;
+          }
+        /* else if (*pt == ',')
+        {
+              ++group;
+              forl='f';
+              ++pt;
+         } */
+        else
+          {
+            error(EXIT_FAILURE, 0, "value to '--copykeys' must only "
+                      "contain integer numbers and these special "
+                      "characters between them: ':' when necessary. "
+                      "But it is '%s' (the first non-acceptable character"
+                       " is '%c').\n", p->copykeys, *pt);
+          }
     }
 
-  /* Basic sanity checks. */
-  if( p->copykeysrange[1]==GAL_BLANK_LONG )
-    error(EXIT_FAILURE, 0, "no ending keyword number given to '--copykeys'. "
-          "If you want to copy all the keywords after a certain one "
-          "(without worrying about how many there are), you can use '-1'.\n\n"
-          "For example if you want to copy all the keywords after the 20th, "
-          "you can use '--copykeys=20,-1'. Generally, you can use negative "
-          "numbers for the last keyword number to count from the end.");
-  if( p->copykeysrange[0]<=0 )
-    error(EXIT_FAILURE, 0, "the first number given to '--copykeys' must be "
-          "positive");
-  if( p->copykeysrange[1]>=0 && p->copykeysrange[0]>=p->copykeysrange[1] )
-    error(EXIT_FAILURE, 0, "the first number (%ld) given to '--copykeys' "
-          "must be smaller than the second (%ld)", p->copykeysrange[0],
-          p->copykeysrange[1]);
+
+    /* Basic sanity checks. */
+    if (!p->keystocopy)
+      {
+        if( p->copykeysrange[1]==GAL_BLANK_LONG )
+          error(EXIT_FAILURE, 0, "no ending keyword number given to "
+                "'--copykeys'. If you want to copy all the keywords after "
+                " a certain one (without worrying about how many there are)"
+                ", you can use '-1'.\n\nFor example if you want to copy "
+                "all the keywords after the 20th, you can use "
+                "'--copykeys=20,-1'. Generally, you can use negative"
+                "numbers for the last keyword number to "
+                "count from the end.");
+        if( p->copykeysrange[0]<=0 )
+          error(EXIT_FAILURE, 0, "the first number given to "
+                "'--copykeys' must be positive");
+        if( p->copykeysrange[1]>=0 &&
+            p->copykeysrange[0]>=p->copykeysrange[1] )
+          error(EXIT_FAILURE, 0, "the first number (%ld) given to "
+                "'--copykeys' must be smaller than the second (%ld)",
+                p->copykeysrange[0], p->copykeysrange[1]);
+      }
+    else
+      {
+          gal_list_str_reverse(&p->keystocopy);
+      }
 
   /* For a check:
-  printf("copykeys: %ld, %ld\n", p->copykeysrange[0], p->copykeysrange[1]);
+  printf("copykeys: %ld, %ld\n", p->copykeysrange[0],
+              p->copykeysrange[1]);
   exit(0);
+  printf("Keys To Copy:\n");
+  gal_list_str_print(p->keystocopy);
   */
 }
 
diff --git a/doc/gnuastro.texi b/doc/gnuastro.texi
index cceeb49c..33143c31 100644
--- a/doc/gnuastro.texi
+++ b/doc/gnuastro.texi
@@ -11189,11 +11189,11 @@ In the latter case (when the keyword values exist but 
can't be verified), the Fi
 By default this function will also print a short description of the 
@code{DATASUM} AND @code{CHECKSUM} keywords.
 You can suppress this extra information with @code{--quiet} option.
 
-@item --copykeys=INT:INT
-Copy the input's keyword records in the given range (inclusive) to the
-output HDU (specified with the @option{--output} and @option{--outhdu}
+@item --copykeys=INT:INT/STR,STR
+Copy the input's keyword records, which can be given as a range (inclusive) or 
a list of Keyword names as comma-separated strings to the output HDU (specified 
with the @option{--output} and @option{--outhdu}
 options, for the filename and HDU/extension respectively).
 
+If a range of Keywords is to be given :
 The given string to this option must be two integers separated by a colon 
(@key{:}).
 The first integer must be positive (counting of the keyword records starts 
from 1).
 The second integer may be negative (zero is not acceptable) or an integer 
larger than the first.
@@ -11207,6 +11207,13 @@ To see the header keywords of the input with a number 
before them, you can pipe
 $ astfits input.fits -h1 | cat -n
 @end example
 
+If a list of keywords is to be given:
+The given string to this option must be a comma separated list of Keywords.
+
+@example
+$ astfits input.fits --copykeys=BITPIX,NAXIS -h0 --output=output.fits 
--outhdu=0
+@end example
+
 @item --outhdu
 The HDU/extension to write the output keywords of @option{--copykeys}.
 



reply via email to

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