774 lines
20 KiB
C
774 lines
20 KiB
C
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@file simple.c
|
|
@author N. Devillard
|
|
@date Jan 1999
|
|
@version $Revision: 1.18 $
|
|
@brief Simple FITS access routines.
|
|
|
|
This module offers a number of very basic low-level FITS access
|
|
routines.
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
/*
|
|
$Id: simple.c,v 1.18 2005/07/20 14:31:22 yjung Exp $
|
|
$Author: yjung $
|
|
$Date: 2005/07/20 14:31:22 $
|
|
$Revision: 1.18 $
|
|
*/
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
Includes
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <sys/types.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <regex.h>
|
|
|
|
#include "simple.h"
|
|
#include "fits_p.h"
|
|
#include "expkey.h"
|
|
#include "cache.h"
|
|
#include "fits_std.h"
|
|
#include "qerror.h"
|
|
#include "xmemory.h"
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
Global variables
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
/*
|
|
* The following global variables are only used for regular expression
|
|
* matching of integers and floats. These definitions are private to
|
|
* this module.
|
|
*/
|
|
/** A regular expression matching a floating-point number */
|
|
static char regex_float[] =
|
|
"^[+-]?([0-9]+[.]?[0-9]*|[.][0-9]+)([eEdD][+-]?[0-9]+)?$";
|
|
|
|
/** A regular expression matching an integer */
|
|
static char regex_int[] = "^[+-]?[0-9]+$";
|
|
|
|
/** A regular expression matching a complex number (int or float) */
|
|
static char regex_cmp[] =
|
|
"^[+-]?([0-9]+[.]?[0-9]*|[.][0-9]+)([eEdD][+-]?[0-9]+)?[ ]+[+-]?([0-9]+[.]?[0-9]*|[.][0-9]+)([eEdD][+-]?[0-9]+)?$";
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
Function codes
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief Retrieve the value of a key in a FITS header
|
|
@param filename Name of the FITS file to browse
|
|
@param keyword Name of the keyword to find
|
|
@return pointer to statically allocated character string
|
|
|
|
Provide the name of a FITS file and a keyword to look for. The input
|
|
file is memory-mapped and the first keyword matching the requested one is
|
|
located. The value corresponding to this keyword is copied to a
|
|
statically allocated area, so do not modify it or free it.
|
|
|
|
The input keyword is first converted to upper case and expanded to
|
|
the HIERARCH scheme if given in the shortFITS notation.
|
|
|
|
This function is pretty fast due to the mmapping. Due to buffering
|
|
on most Unixes, it is possible to call many times this function in a
|
|
row on the same file and do not suffer too much from performance
|
|
problems. If the file contents are already in the cache, the file
|
|
will not be re-opened every time.
|
|
|
|
It is possible, though, to modify this function to perform several
|
|
searches in a row. See the source code.
|
|
|
|
Returns NULL in case the requested keyword cannot be found.
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
char *
|
|
qfits_query_hdr (char *filename, const char *keyword)
|
|
{
|
|
return qfits_query_ext (filename, keyword, 0);
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief Retrieve the value of a keyin a FITS extension header.
|
|
@param filename name of the FITS file to browse.
|
|
@param keyword name of the FITS key to look for.
|
|
@param xtnum xtension number
|
|
@return pointer to statically allocated character string
|
|
|
|
Same as qfits_query_hdr but for extensions. xtnum starts from 1 to
|
|
the number of extensions. If xtnum is zero, this function is
|
|
strictly identical to qfits_query_hdr().
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
char *
|
|
qfits_query_ext (char *filename, const char *keyword, int xtnum)
|
|
{
|
|
char *exp_key;
|
|
char *where;
|
|
char *start;
|
|
char *value;
|
|
char test1, test2;
|
|
int i;
|
|
int len;
|
|
int different;
|
|
int seg_start;
|
|
int seg_size;
|
|
long bufcount;
|
|
size_t size;
|
|
|
|
/* Bulletproof entries */
|
|
if (filename == NULL || keyword == NULL || xtnum < 0)
|
|
return NULL;
|
|
|
|
/* Expand keyword */
|
|
exp_key = qfits_expand_keyword (keyword);
|
|
|
|
/*
|
|
* Find out offsets to the required extension
|
|
* Record the xtension start and stop offsets
|
|
*/
|
|
if (qfits_get_hdrinfo (filename, xtnum, &seg_start, &seg_size) == -1)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Get a hand on requested buffer
|
|
*/
|
|
|
|
start = falloc (filename, seg_start, &size);
|
|
if (start == NULL)
|
|
return NULL;
|
|
|
|
/*
|
|
* Look for keyword in header
|
|
*/
|
|
|
|
bufcount = 0;
|
|
where = start;
|
|
len = (int) strlen (exp_key);
|
|
while (1)
|
|
{
|
|
different = 0;
|
|
for (i = 0; i < len; i++)
|
|
{
|
|
if (where[i] != exp_key[i])
|
|
{
|
|
different++;
|
|
break;
|
|
}
|
|
}
|
|
if (!different)
|
|
{
|
|
/* Get 2 chars after keyword */
|
|
test1 = where[len];
|
|
test2 = where[len + 1];
|
|
/* If first subsequent character is the equal sign, bingo. */
|
|
if (test1 == '=')
|
|
break;
|
|
/* If subsequent char is equal sign, bingo */
|
|
if (test1 == ' ' && (test2 == '=' || test2 == ' '))
|
|
break;
|
|
}
|
|
/* Watch out for header end */
|
|
if ((where[0] == 'E') &&
|
|
(where[1] == 'N') && (where[2] == 'D') && (where[3] == ' '))
|
|
{
|
|
/* Detected header end */
|
|
fdealloc (start, seg_start, size);
|
|
return NULL;
|
|
}
|
|
/* Forward one line */
|
|
where += 80;
|
|
bufcount += 80;
|
|
if (bufcount > seg_size)
|
|
{
|
|
/* File is damaged or not FITS: bailout */
|
|
fdealloc (start, seg_start, size);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/* Found the keyword, now get its value */
|
|
value = qfits_getvalue (where);
|
|
fdealloc (start, seg_start, size);
|
|
return value;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief Counts the number of extensions in a FITS file
|
|
@param filename Name of the FITS file to browse.
|
|
@return int
|
|
Counts how many extensions are in the file. Returns 0 if no
|
|
extension is found, and -1 if an error occurred.
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
int
|
|
qfits_query_n_ext (char *filename)
|
|
{
|
|
return qfits_query (filename, QFITS_QUERY_N_EXT);
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief Counts the number of planes in a FITS extension.
|
|
@param filename Name of the FITS file to browse.
|
|
@param exnum Extensin number
|
|
@return int
|
|
Counts how many planes are in the extension. Returns 0 if no plane is found,
|
|
and -1 if an error occurred.
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
int
|
|
qfits_query_nplanes (char *filename, int extnum)
|
|
{
|
|
char *sval;
|
|
int next;
|
|
int naxes;
|
|
int nplanes;
|
|
|
|
/* Check file existence */
|
|
if (filename == NULL)
|
|
return -1;
|
|
/* Check validity of extnum */
|
|
next = qfits_query_n_ext (filename);
|
|
if (extnum > next)
|
|
{
|
|
qfits_error ("invalid extension specified");
|
|
return -1;
|
|
}
|
|
|
|
/* Find the number of axes */
|
|
naxes = 0;
|
|
if ((sval = qfits_query_ext (filename, "NAXIS", extnum)) == NULL)
|
|
{
|
|
qfits_error ("missing key in header: NAXIS");
|
|
return -1;
|
|
}
|
|
naxes = atoi (sval);
|
|
|
|
/* Check validity of naxes */
|
|
if ((naxes < 2) || (naxes > 3))
|
|
return -1;
|
|
|
|
/* Two dimensions cube */
|
|
if (naxes == 2)
|
|
nplanes = 1;
|
|
else
|
|
{
|
|
/* For 3D cubes, get the third dimension size */
|
|
if ((sval = qfits_query_ext (filename, "NAXIS3", extnum)) == NULL)
|
|
{
|
|
qfits_error ("missing key in header: NAXIS3");
|
|
return -1;
|
|
}
|
|
nplanes = atoi (sval);
|
|
if (nplanes < 1)
|
|
nplanes = 0;
|
|
}
|
|
return nplanes;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief Clean out a FITS string value.
|
|
@param s pointer to allocated FITS value string.
|
|
@return pointer to statically allocated character string
|
|
|
|
From a string FITS value like 'marvin o''hara', remove head and tail
|
|
quotes, replace double '' with simple ', trim blanks on each side,
|
|
and return the result in a statically allocated area.
|
|
|
|
Examples:
|
|
|
|
- ['o''hara'] becomes [o'hara]
|
|
- [' H '] becomes [H]
|
|
- ['1.0 '] becomes [1.0]
|
|
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
#define PRETTY_STRING_STATICBUFS 8
|
|
char *
|
|
qfits_pretty_string (char *s)
|
|
{
|
|
static char pretty_buf[PRETTY_STRING_STATICBUFS][81];
|
|
static int flip = 0;
|
|
char *pretty;
|
|
int i, j;
|
|
|
|
/* bulletproof */
|
|
if (s == NULL)
|
|
return NULL;
|
|
|
|
/* Switch between static buffers */
|
|
pretty = pretty_buf[flip];
|
|
flip++;
|
|
if (flip == PRETTY_STRING_STATICBUFS)
|
|
flip = 0;
|
|
|
|
pretty[0] = (char) 0;
|
|
if (s[0] != '\'')
|
|
return s;
|
|
|
|
/* skip first quote */
|
|
i = 1;
|
|
j = 0;
|
|
/* trim left-side blanks */
|
|
while (s[i] == ' ')
|
|
{
|
|
if (i == (int) strlen (s))
|
|
break;
|
|
i++;
|
|
}
|
|
if (i >= (int) (strlen (s) - 1))
|
|
return pretty;
|
|
/* copy string, changing double quotes to single ones */
|
|
while (i < (int) strlen (s))
|
|
{
|
|
if (s[i] == '\'')
|
|
{
|
|
i++;
|
|
}
|
|
pretty[j] = s[i];
|
|
i++;
|
|
j++;
|
|
}
|
|
/* NULL-terminate the pretty string */
|
|
pretty[j + 1] = (char) 0;
|
|
/* trim right-side blanks */
|
|
j = (int) strlen (pretty) - 1;
|
|
while (pretty[j] == ' ')
|
|
j--;
|
|
pretty[j + 1] = (char) 0;
|
|
return pretty;
|
|
}
|
|
|
|
#undef PRETTY_STRING_STATICBUFS
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief Identify if a FITS value is boolean
|
|
@param s FITS value as a string
|
|
@return int 0 or 1
|
|
|
|
Identifies if a FITS value is boolean.
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
int
|
|
qfits_is_boolean (char *s)
|
|
{
|
|
if (s == NULL)
|
|
return 0;
|
|
if (s[0] == 0)
|
|
return 0;
|
|
if ((int) strlen (s) > 1)
|
|
return 0;
|
|
if (s[0] == 'T' || s[0] == 'F')
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief Identify if a FITS value is an int.
|
|
@param s FITS value as a string
|
|
@return int 0 or 1
|
|
|
|
Identifies if a FITS value is an integer.
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
int
|
|
qfits_is_int (char *s)
|
|
{
|
|
regex_t re_int;
|
|
int status;
|
|
|
|
if (s == NULL)
|
|
return 0;
|
|
if (s[0] == 0)
|
|
return 0;
|
|
if (regcomp (&re_int, ®ex_int[0], REG_EXTENDED | REG_NOSUB) != 0)
|
|
{
|
|
qfits_error ("internal error: compiling int rule");
|
|
exit (-1);
|
|
}
|
|
status = regexec (&re_int, s, 0, NULL, 0);
|
|
regfree (&re_int);
|
|
return (status) ? 0 : 1;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief Identify if a FITS value is float.
|
|
@param s FITS value as a string
|
|
@return int 0 or 1
|
|
|
|
Identifies if a FITS value is float.
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
int
|
|
qfits_is_float (char *s)
|
|
{
|
|
regex_t re_float;
|
|
int status;
|
|
|
|
if (s == NULL)
|
|
return 0;
|
|
if (s[0] == 0)
|
|
return 0;
|
|
if (regcomp (&re_float, ®ex_float[0], REG_EXTENDED | REG_NOSUB) != 0)
|
|
{
|
|
qfits_error ("internal error: compiling float rule");
|
|
exit (-1);
|
|
}
|
|
status = regexec (&re_float, s, 0, NULL, 0);
|
|
regfree (&re_float);
|
|
return (status) ? 0 : 1;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief Identify if a FITS value is complex.
|
|
@param s FITS value as a string
|
|
@return int 0 or 1
|
|
|
|
Identifies if a FITS value is complex.
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
int
|
|
qfits_is_complex (char *s)
|
|
{
|
|
regex_t re_cmp;
|
|
int status;
|
|
|
|
if (s == NULL)
|
|
return 0;
|
|
if (s[0] == 0)
|
|
return 0;
|
|
if (regcomp (&re_cmp, ®ex_cmp[0], REG_EXTENDED | REG_NOSUB) != 0)
|
|
{
|
|
qfits_error ("internal error: compiling complex rule");
|
|
exit (-1);
|
|
}
|
|
status = regexec (&re_cmp, s, 0, NULL, 0);
|
|
regfree (&re_cmp);
|
|
return (status) ? 0 : 1;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief Identify if a FITS value is string.
|
|
@param s FITS value as a string
|
|
@return int 0 or 1
|
|
|
|
Identifies if a FITS value is a string.
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
int
|
|
qfits_is_string (char *s)
|
|
{
|
|
if (s == NULL)
|
|
return 0;
|
|
if (s[0] == '\'')
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief Identify the type of a FITS value given as a string.
|
|
@param s FITS value as a string
|
|
@return integer naming the FITS type
|
|
|
|
Returns the following value:
|
|
|
|
- QFITS_UNKNOWN (0) for an unknown type.
|
|
- QFITS_BOOLEAN (1) for a boolean type.
|
|
- QFITS_INT (2) for an integer type.
|
|
- QFITS_FLOAT (3) for a floating-point type.
|
|
- QFITS_COMPLEX (4) for a complex number.
|
|
- QFITS_STRING (5) for a FITS string.
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
int
|
|
qfits_get_type (char *s)
|
|
{
|
|
if (s == NULL)
|
|
return QFITS_UNKNOWN;
|
|
if (qfits_is_boolean (s))
|
|
return QFITS_BOOLEAN;
|
|
if (qfits_is_int (s))
|
|
return QFITS_INT;
|
|
if (qfits_is_float (s))
|
|
return QFITS_FLOAT;
|
|
if (qfits_is_complex (s))
|
|
return QFITS_COMPLEX;
|
|
return QFITS_STRING;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief Retrieve offset to start and size of a header in a FITS file.
|
|
@param filename Name of the file to examine
|
|
@param xtnum Extension number (0 for main)
|
|
@param seg_start Segment start in bytes (output)
|
|
@param seg_size Segment size in bytes (output)
|
|
@return int 0 if Ok, -1 otherwise.
|
|
|
|
This function retrieves the two most important informations about
|
|
a header in a FITS file: the offset to its beginning, and the size
|
|
of the header in bytes. Both values are returned in the passed
|
|
pointers to ints. It is Ok to pass NULL for any pointer if you do
|
|
not want to retrieve the associated value.
|
|
|
|
You must provide an extension number for the header, 0 meaning the
|
|
main header in the file.
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
int
|
|
qfits_get_hdrinfo (char *filename, int xtnum, int *seg_start, int *seg_size)
|
|
{
|
|
if (filename == NULL || xtnum < 0
|
|
|| (seg_start == NULL && seg_size == NULL))
|
|
{
|
|
return -1;
|
|
}
|
|
if (seg_start != NULL)
|
|
{
|
|
*seg_start = qfits_query (filename, QFITS_QUERY_HDR_START | xtnum);
|
|
if (*seg_start < 0)
|
|
return -1;
|
|
}
|
|
if (seg_size != NULL)
|
|
{
|
|
*seg_size = qfits_query (filename, QFITS_QUERY_HDR_SIZE | xtnum);
|
|
if (*seg_size < 0)
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief Retrieve offset to start and size of a data section in a file.
|
|
@param filename Name of the file to examine.
|
|
@param xtnum Extension number (0 for main).
|
|
@param seg_start Segment start in bytes (output).
|
|
@param seg_size Segment size in bytes (output).
|
|
@return int 0 if Ok, -1 otherwise.
|
|
|
|
This function retrieves the two most important informations about
|
|
a data section in a FITS file: the offset to its beginning, and the size
|
|
of the section in bytes. Both values are returned in the passed
|
|
pointers to ints. It is Ok to pass NULL for any pointer if you do
|
|
not want to retrieve the associated value.
|
|
|
|
You must provide an extension number for the header, 0 meaning the
|
|
main header in the file.
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
int
|
|
qfits_get_datinfo (char *filename, int xtnum, int *seg_start, int *seg_size)
|
|
{
|
|
if (filename == NULL || xtnum < 0
|
|
|| (seg_start == NULL && seg_size == NULL))
|
|
{
|
|
return -1;
|
|
}
|
|
if (seg_start != NULL)
|
|
{
|
|
*seg_start = qfits_query (filename, QFITS_QUERY_DAT_START | xtnum);
|
|
if (*seg_start < 0)
|
|
return -1;
|
|
}
|
|
if (seg_size != NULL)
|
|
{
|
|
*seg_size = qfits_query (filename, QFITS_QUERY_DAT_SIZE | xtnum);
|
|
if (*seg_size < 0)
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief Query a card in a FITS (main) header by a given key
|
|
@param filename Name of the FITS file to check.
|
|
@param keyword Where to read a card in the header.
|
|
@return Allocated string containing the card or NULL
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
char *
|
|
qfits_query_card (char *filename, char *keyword)
|
|
{
|
|
char *exp_key;
|
|
int fd;
|
|
char *buf;
|
|
char *buf2;
|
|
char *where;
|
|
int hs;
|
|
char *card;
|
|
|
|
/* Bulletproof entries */
|
|
if (filename == NULL || keyword == NULL)
|
|
return NULL;
|
|
|
|
/* Expand keyword */
|
|
exp_key = qfits_expand_keyword (keyword);
|
|
|
|
/* Memory-map the FITS header of the input file */
|
|
qfits_get_hdrinfo (filename, 0, NULL, &hs);
|
|
if (hs < 1)
|
|
{
|
|
qfits_error ("error getting FITS header size for %s", filename);
|
|
return NULL;
|
|
}
|
|
fd = open (filename, O_RDWR);
|
|
if (fd == -1)
|
|
return NULL;
|
|
buf = (char *) mmap (0, hs, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
|
if (buf == (char *) -1)
|
|
{
|
|
perror ("mmap");
|
|
close (fd);
|
|
return NULL;
|
|
}
|
|
|
|
/* Apply search for the input keyword */
|
|
buf2 = malloc (hs + 1);
|
|
memcpy (buf2, buf, hs);
|
|
buf2[hs] = (char) 0;
|
|
where = buf2;
|
|
do
|
|
{
|
|
where = strstr (where, exp_key);
|
|
if (where == NULL)
|
|
{
|
|
close (fd);
|
|
munmap (buf, hs);
|
|
free (buf2);
|
|
return NULL;
|
|
}
|
|
if ((where - buf2) % 80)
|
|
where++;
|
|
}
|
|
while ((where - buf2) % 80);
|
|
|
|
where = buf + (int) (where - buf2);
|
|
|
|
/* Create the card */
|
|
card = malloc (81 * sizeof (char));
|
|
strncpy (card, where, 80);
|
|
card[80] = (char) 0;
|
|
|
|
/* Free and return */
|
|
close (fd);
|
|
munmap (buf, hs);
|
|
free (buf2);
|
|
return card;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief Replace a card in a FITS (main) header by a given card
|
|
@param filename Name of the FITS file to modify.
|
|
@param keyword Where to substitute a card in the header.
|
|
@param substitute What to replace the line with.
|
|
@return int 0 if Ok, -1 otherwise
|
|
|
|
Replaces a whole card (80 chars) in a FITS header by a given FITS
|
|
line (80 chars). The replacing line is assumed correctly formatted
|
|
and containing at least 80 characters. The file is modified: it must
|
|
be accessible in read/write mode.
|
|
|
|
The input keyword is first converted to upper case and expanded to
|
|
the HIERARCH scheme if given in the shortFITS notation.
|
|
|
|
Returns 0 if everything worked Ok, -1 otherwise.
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
int
|
|
qfits_replace_card (char *filename, const char *keyword, char *substitute)
|
|
{
|
|
char *exp_key;
|
|
int fd;
|
|
char *buf;
|
|
char *buf2;
|
|
char *where;
|
|
int hs;
|
|
|
|
|
|
/* Bulletproof entries */
|
|
if (filename == NULL || keyword == NULL || substitute == NULL)
|
|
return -1;
|
|
|
|
/* Expand keyword */
|
|
exp_key = qfits_expand_keyword (keyword);
|
|
/*
|
|
* Memory-map the FITS header of the input file
|
|
*/
|
|
|
|
qfits_get_hdrinfo (filename, 0, NULL, &hs);
|
|
if (hs < 1)
|
|
{
|
|
qfits_error ("error getting FITS header size for %s", filename);
|
|
return -1;
|
|
}
|
|
fd = open (filename, O_RDWR);
|
|
if (fd == -1)
|
|
{
|
|
return -1;
|
|
}
|
|
buf = (char *) mmap (0, hs, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
|
if (buf == (char *) -1)
|
|
{
|
|
perror ("mmap");
|
|
close (fd);
|
|
return -1;
|
|
}
|
|
|
|
/* Apply search and replace for the input keyword lists */
|
|
buf2 = malloc (hs + 1);
|
|
memcpy (buf2, buf, hs);
|
|
buf2[hs] = (char) 0;
|
|
where = buf2;
|
|
do
|
|
{
|
|
where = strstr (where, exp_key);
|
|
if (where == NULL)
|
|
{
|
|
close (fd);
|
|
munmap (buf, hs);
|
|
free (buf2);
|
|
return -1;
|
|
}
|
|
if ((where - buf2) % 80)
|
|
where++;
|
|
}
|
|
while ((where - buf2) % 80);
|
|
|
|
where = buf + (int) (where - buf2);
|
|
|
|
/* Replace current placeholder by blanks */
|
|
memset (where, ' ', 80);
|
|
/* Copy substitute into placeholder */
|
|
memcpy (where, substitute, strlen (substitute));
|
|
|
|
close (fd);
|
|
munmap (buf, hs);
|
|
free (buf2);
|
|
return 0;
|
|
}
|
|
|
|
/* vim: set ts=4 et sw=4 tw=75 */
|