Index: /trunk/Ohana/src/libfits/header/F_H_field.c
===================================================================
--- /trunk/Ohana/src/libfits/header/F_H_field.c	(revision 21058)
+++ /trunk/Ohana/src/libfits/header/F_H_field.c	(revision 21059)
@@ -60,4 +60,65 @@
 }
 
+// find the given field among the HIERARCH keywords
+// these have the form: HIERARCH KEYWORD = value
+// returns a pointer to the start of the field
+char *gfits_header_hierarch_field (Header *header, char *field, int N) {
+
+  char *buf, *ptr;
+  int i, Nwant, Nfound, Nfield;
+
+  Nfield = strlen (field);
+  if (Nfield >= 71) return NULL;
+
+  buf = header[0].buffer;
+
+  /* find the Nth entry */
+  if (N > 0) {
+    Nfound = 0;
+    for (i = 0; i < header[0].size; i+= FT_LINE_LENGTH, buf += FT_LINE_LENGTH) {
+      // have we found a HIERARCH entry?
+      if (strncmp ("HIERARCH", buf, 8)) continue;
+      ptr = buf + 9; // start of following keyword
+      if (strncmp (field, ptr, Nfield)) continue;
+      Nfound ++;
+      if (Nfound == N) return (ptr);
+    }
+  }
+
+  /* find the Ntotal - Nth entry */
+  if (N < 0) {
+    /* count the entries */
+    Nfound = 0;
+    for (i = 0; i < header[0].size; i+= FT_LINE_LENGTH, buf += FT_LINE_LENGTH) {
+      if (strncmp ("HIERARCH", buf, 8)) continue;
+      ptr = buf + 9; // start of following keyword
+      if (strncmp (field, ptr, Nfield)) continue;
+      Nfound ++;
+    }
+
+    Nwant = Nfound + N + 1;
+    buf = header[0].buffer;
+
+    /* find the Nwant entry */
+    Nfound = 0;
+    for (i = 0; i < header[0].size; i+= FT_LINE_LENGTH, buf += FT_LINE_LENGTH) {
+      if (strncmp ("HIERARCH", buf, 8)) continue;
+      ptr = buf + 9; // start of following keyword
+      if (strncmp (field, ptr, Nfield)) continue;
+      Nfound ++;
+      if (Nwant == Nfound) return (ptr);
+    }
+  }
+
+  return ((char *) NULL);
+
+/* 
+
+   find the Nth entry of this keyword.
+   if N < 0, find the last - N - 1 word (ie, -1 = last)
+
+*/
+}
+
 /*********************** fits header field ****************************/
 char *gfits_header_lineno (Header *header, int N) {
Index: /trunk/Ohana/src/libfits/header/F_modify.c
===================================================================
--- /trunk/Ohana/src/libfits/header/F_modify.c	(revision 21058)
+++ /trunk/Ohana/src/libfits/header/F_modify.c	(revision 21059)
@@ -1,8 +1,4 @@
 # include <ohana.h>
 # include <gfitsio.h>
-
-char *gfits_keyword_start (char *line);
-char *gfits_keyword_end (char *line);
-void pad_ending (char *line, char value, int Nbyte);
 
 int gfits_modify (Header *header, char *field, char *mode, int N,...) {
@@ -51,5 +47,5 @@
     strncpy (comment, qe, p + 80 - qe);
   }
-  pad_ending (comment, ' ', 82);  /* comment must contain spaces to the end */
+  gfits_pad_ending (comment, ' ', 82);  /* comment must contain spaces to the end */
 
   /* write the numeric modes */
@@ -96,5 +92,5 @@
     strncpy (data, qs, MAX (MIN (qe - qs, 71), 0));
     strncpy (comment, va_arg (argp, char *), 80);
-    pad_ending (comment, ' ', 82);  /* comment must contain spaces to the end */
+    gfits_pad_ending (comment, ' ', 82);  /* comment must contain spaces to the end */
     snprintf (string, 81, "%-8s= %s / %-s", field, data, comment);
     /* this will keep the original line, but truncate the comment */
@@ -156,4 +152,57 @@
   } else {
     while ((*c1 != ' ') && (c1 < line + 80)) c1++;
+  }
+  return (c1);
+}
+
+/* given a pointer to the FITS HIERARCH card field name, return pointer to the start of the data area */
+char *gfits_hierarch_keyword_start (char *line, char *field) {
+
+  char *c;
+
+  /* find the end of the existing data region */
+  c = line + strlen(field) + 1;
+  if (*c != '=') return (c);  /* non-data fields are not allowed */
+  
+  c += 2;
+  /* advance pointer over WHITESPACE */
+  while ((*c == ' ') && (c < line + 71)) { c++; }
+  
+  /* skip one quote mark */
+  if ((*c == 0x27) && (c < line + 71)) { c++; }
+
+  return (c);
+}
+
+/* given a pointer to the FITS HIERARCH card field name, return pointer to the end of the data area */
+char *gfits_hierarch_keyword_end (char *line, char *field) {
+
+  int done;
+  char *c1, *c2;
+
+  /* find the end of the existing data region */
+  c1 = line + strlen(field) + 1;
+  if (*c1 != '=') return (NULL);  /* non-data fields are not allowed */
+  c1 += 2;
+
+  /* advance pointer over WHITESPACE */
+  while ((*c1 == ' ') && (c1 < line + 71)) { c1++; }
+  
+  if (c1[0] == 0x27) { /* entry a string, skip over 'fred' */
+    for (done = FALSE, c2 = c1 + 1; !done && (c2 < line + 71); c2++) {
+      if ((c2[0] == 0x27) && (c2[1] == 0x27)) {
+	c2 += 2;
+	continue;
+      }
+      if (c2[0] == 0x27) {
+	c1 = c2;
+	done = TRUE;
+      }
+    }
+    if (!done) { /* error in line: mismatched ' chars, return fixed position */
+      c1 = line + 30;
+    }
+  } else {
+    while ((*c1 != ' ') && (c1 < line + 71)) c1++;
   }
   return (c1);
@@ -171,5 +220,5 @@
 
 /* fill 'line' with Nbyte space from first NULL to last byte with value */
-void pad_ending (char *line, char value, int Nbyte) {
+void gfits_pad_ending (char *line, char value, int Nbyte) {
   
   char *p;
Index: /trunk/Ohana/src/libfits/header/F_scan.c
===================================================================
--- /trunk/Ohana/src/libfits/header/F_scan.c	(revision 21058)
+++ /trunk/Ohana/src/libfits/header/F_scan.c	(revision 21059)
@@ -1,7 +1,4 @@
 # include <ohana.h>
 # include <gfitsio.h>
-
-char *gfits_keyword_start (char *line);
-char *gfits_keyword_end (char *line);
 
 int gfits_scan (Header *header, char *field, char *mode, int N,...) {
@@ -19,10 +16,13 @@
 
   char *p, *q, *s, tmp[81];
-  int Nchar;
+  int Nchar, status;
   double value;
   
   /* find the correct line with field */
   p = gfits_header_field (header, field, N);
-  if (p == NULL) return (FALSE);
+  if (p == NULL) {
+    status = gfits_vscan_hierarch (header, field, mode, N, argp);
+    return (status);
+  }
 
   /* non-data entry (COMMENT, HISTORY) */
@@ -92,4 +92,83 @@
 }
 
+# define HIERARCH_LENGTH 71
+int gfits_vscan_hierarch (Header *header, char *field, char *mode, int N, va_list argp) {
+
+  char *p, *q, *s, tmp[81];
+  int Nchar, Nfield;
+  double value;
+  
+  /* find the correct line with field */
+  p = gfits_header_hierarch_field (header, field, N);
+  if (p == NULL) return (FALSE);
+
+  /* non-data entries (COMMENT, HISTORY) are not allowed */
+  if (!strcmp (mode, "%S")) {
+    return (FALSE);
+  }
+
+  /* all others require '=' in column p + 1 + strlen(field) */
+  Nfield = strlen (field);
+  if (p[Nfield + 1] != '=') return (FALSE);
+
+  /* comment from data line */
+  if (!strcmp (mode, "%C")) {
+    q = gfits_hierarch_keyword_end (p, field);
+    if (!q) return (FALSE);
+    q += 3;
+    q = MIN (p + HIERARCH_LENGTH, q);
+    bzero (tmp, 81);
+    Nchar = MIN (HIERARCH_LENGTH, p + HIERARCH_LENGTH - q);
+    memcpy (tmp, q, Nchar);
+    stripwhite (tmp);
+    strcpy (va_arg (argp, char *), tmp);
+    return (TRUE);
+  }
+
+  /* extract data into char array (exclude containing ' chars) */
+  if (!strcmp (mode, "%s")) {
+    s = gfits_hierarch_keyword_start (p, field); /* points at first char (not ') */
+    q = gfits_hierarch_keyword_end (p, field); /* points at following space or ' */
+
+    Nchar = MIN (HIERARCH_LENGTH, MAX (0, (q - s)));
+    bzero (tmp, 81);
+    memcpy (tmp, s, Nchar);
+    stripwhite (tmp);
+    strcpy (va_arg (argp, char *), tmp);
+    return (TRUE);
+  }
+  
+  /* boolean data, requires int target */
+  if (!strcmp (mode, "%t")) {
+    s = gfits_hierarch_keyword_start (p, field);
+    if (*s == 'T') {
+      *va_arg (argp, int *) = TRUE;
+      return (TRUE);
+    }
+    if (*s == 'F') {
+      *va_arg (argp, int *) = FALSE;   
+      return (TRUE);
+    }
+  }
+
+  /* remaining options are numerical data */
+  /* need to interpret 1.0d5 as 1.0e5 */
+  s = gfits_hierarch_keyword_start (p, field); /* points at first char (not ') */
+  q = gfits_hierarch_keyword_end (p, field); /* points at following space or ' */
+  value = strtod (s, &q);
+  if ((*q == 'd') || (*q == 'D')) 
+    value *= pow (10.0, atof (q + 1));
+
+  if (!strcmp (mode, "%d"))  { *va_arg (argp, int *)       = value; return (TRUE); }
+  if (!strcmp (mode, "%u"))  { *va_arg (argp, unsigned *)  = value; return (TRUE); }
+  if (!strcmp (mode, "%ld")) { *va_arg (argp, long *)      = value; return (TRUE); }
+  if (!strcmp (mode, "%hd")) { *va_arg (argp, short *)     = value; return (TRUE); }
+  if (!strcmp (mode, "%f"))  { *va_arg (argp, float *)     = value; return (TRUE); }
+  if (!strcmp (mode, "%lf")) { *va_arg (argp, double *)    = value; return (TRUE); }
+
+  /* no valid mode found */
+  return (FALSE);
+}
+
 /* if the variable argument stuff breaks on another system, look 
 at F_modify.c as it has the old code */
Index: /trunk/Ohana/src/libfits/include/gfitsio.h
===================================================================
--- /trunk/Ohana/src/libfits/include/gfitsio.h	(revision 21058)
+++ /trunk/Ohana/src/libfits/include/gfitsio.h	(revision 21059)
@@ -133,5 +133,11 @@
 int 	gfits_primary_to_extended      PROTO((Header *header, char *exttype, char *comment));
 int 	gfits_modify_extended          PROTO((Header *header, char *exttype, char *comment));
-
+char   *gfits_keyword_start 	       PROTO((char *line));
+char   *gfits_keyword_end   	       PROTO((char *line));
+char   *gfits_hierarch_keyword_start   PROTO((char *line, char *field));
+char   *gfits_hierarch_keyword_end     PROTO((char *line, char *field));
+void    gfits_pad_ending               PROTO((char *line, char value, int Nbyte));
+int     gfits_vscan_hierarch           PROTO((Header *header, char *field, char *mode, int N, va_list argp));
+char   *gfits_header_hierarch_field    PROTO((Header *header, char *field, int N));
 
 /******************************* Matrix functions *************/
