qfits-4.0.2

main qfits-4.0.2
Jeff Moe 2022-06-01 19:35:16 -06:00
parent f43dae9f53
commit 200bc18074
68 changed files with 27214 additions and 0 deletions

3
qfits/AUTHORS 100644
View File

@ -0,0 +1,3 @@
Nicolas Devillard ndevilla@eso.org
Yves Jung yjung@eso.org

47
qfits/INSTALL 100644
View File

@ -0,0 +1,47 @@
Installing qfits as an ANSI C library
-------------------------------------
% ./configure
% make
That should do it. You should now have a library called
libqfits.a in the lib/ directory, and the include files
you need are in the include/ directory.
To review possible configure options, type:
% configure --help
To install this library system-wide, use:
% make install
This will install the library in /opt/qfits. To change the
destination, use the --prefix option from configure.
Example: to install under /usr/local/qfits you would do:
% configure --prefix=/usr/local/qfits
If you want to perform basic tests, use:
% make tests
Using qfits from C++
--------------------
Compile the C library and link your C++ program against
libqfits.a. This will avoid a number of issues with your
C++ compiler trying to compile a C library.
Installing qfits as a Python module
-----------------------------------
See python/README in this directory.
Using qfits from other languages
--------------------------------
This used to be offered through a SWIG interface file, but
is not supported any more.
Fri Nov 30 11:36:29 CET 2001

22
qfits/LICENSE 100644
View File

@ -0,0 +1,22 @@
Copyright (c) 1995-2001, European Southern Observatory
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

102
qfits/Makefile 100644
View File

@ -0,0 +1,102 @@
#
# qfits Makefile
#
include config.make
AR = ar
ARFLAGS = rc
RM = rm -f
CP = cp -f
# Implicit rules
SUFFIXES = .o .c .h .a .so .sl
COMPILE.c=$(CC) $(CFLAGS) $(FTRACE) -Iinclude $(RELOC) -c
.c.o:
@(echo "compiling $< ...")
@($(COMPILE.c) -o $@ $<)
SRCS = src/byteswap.c \
src/cache.c \
src/expkey.c \
src/fits_h.c \
src/fits_md5.c \
src/fits_p.c \
src/fits_rw.c \
src/md5.c \
src/pixio.c \
src/ptrace.c \
src/qerror.c \
src/simple.c \
src/t_iso8601.c \
src/tfits.c \
src/version.c \
src/xmemory.c
OBJS = $(SRCS:.c=.o)
default: all
all: $(TARGETS) progs
static: lib/libqfits.a
dynamic: lib/libqfits.$(DYNSUF)
lib/libqfits.a: $(OBJS)
@(echo "Building static library...")
@($(AR) $(ARFLAGS) lib/libqfits.a $(OBJS))
lib/libqfits.$(DYNSUF): $(OBJS)
@(echo "Building shared library...")
@(ld $(SHARED) -o lib/libqfits.$(DYNSUF) $(OBJS))
install:
@(echo "Installing library in " $(prefix))
mkdir -p $(prefix)
mkdir -p $(prefix)/lib
mkdir -p $(prefix)/include
mkdir -p $(prefix)/bin
$(CP) include/qfits.h $(prefix)/include
$(CP) src/xmemory.h $(prefix)/include
$(CP) lib/libqfits.a $(prefix)/lib
$(CP) bin/* $(prefix)/bin
clean:
$(RM) $(OBJS)
veryclean:
$(RM) $(OBJS) lib/libqfits.a lib/libqfits.$(DYNSUF)
$(RM) -r build
cd test ; $(MAKE) veryclean ; cd ..
cd main ; $(MAKE) veryclean ; cd ..
cd saft ; $(MAKE) veryclean ; cd ..
#
# Build example and stand-alone programs
#
progs:
cd main ; $(MAKE) ; cd ..
cd saft ; $(MAKE) ; cd ..
#
# Building qfits as a Python module.
#
# type:
# % python setup.py build
# % python setup.py install
#
docs:
@(echo "Building HTML documentation...")
@(cd doc ; $(MAKE))
tests:
cd test ; $(MAKE)

45
qfits/README 100644
View File

@ -0,0 +1,45 @@
qfits: a quick and simple FITS access library
---------------------------------------------
qfits is a stand-alone FITS library aiming at simplicity rather than
trying to cover every possible application field in the FITS domain.
The FITS format is pretty simple, declaring ancillary data in 80-char
lines in ASCII format, and storing values in fixed-size, uncompressed
format. Data are stored on the disk more or less as they will be in
memory (bar some trivial transformations).
This library tries to cover various needs. It has not been developped
from scratch as a library trying to cover the FITS format, but rather
built day after day upon request. There are several levels of
complexity, depending on whether you only want to retrieve ancillary
data from headers, or only read pixels in, or do some true data
manipulation or header re-formatting.
qfits is written in 100% pure ANSI C that should compile on any Unix.
qfits has not been compiled or tested on any non-Unix platform. qfits
has been shown to work reliably on the following platforms:
- Solaris
- HPUX
- AIX
- Dec/OSF1 (True64)
- Linux
- BSD (tested on FreeBSD and Darwin, aka Mac OS X)
qfits should work fine on all POSIX-compliant Unixes.
If you port qfits to any other platform, please let me know.
You can compile this library with a C++ compiler for inclusion in a C++
program, the header files include the usual blurb to allow that without
warning from the compiler.
qfits also exports a limited number of functionalities to
retrieve and parse FITS headers under Python. See the INSTALL
file to learn how to install qfits as a Python module.
N. Devillard
Tue Mar 20 11:22:30 CET 2001

View File

18
qfits/configure vendored 100755
View File

@ -0,0 +1,18 @@
#!/bin/sh
#
# Bootstrap script: it tries to compile a simple C script using cc or
# gcc and launches it to create config.h and config.make files.
#
echo "configuring qfits..."
if (cc -o sysconf sysconf.c) ; then
echo "compiled sysconf successfully"
elif (gcc -o sysconf sysconf.c) ; then
echo "compiled sysconf successfully"
else echo "cannot find cc or gcc: aborting" ; exit
fi
./sysconf $*
mv config.h ./src
rm -f sysconf

View File

@ -0,0 +1,20 @@
H1 { text-align: center; }
A.qindex {}
A.qindexRef {}
A.el { text-decoration: none; font-weight: bold }
A.elRef { font-weight: bold }
A.code { text-decoration: none; font-weight: normal; color: #4444ee }
A.codeRef { font-weight: normal; color: #4444ee }
DL.el { margin-left: -1cm }
DIV.fragment { width: 100%; border: none; background-color: #eeeeee }
DIV.ah { background-color: black; margin-bottom: 3; margin-top: 3 }
TD.md { background-color: #f2f2ff }
DIV.groupHeader { margin-left: 16; margin-top: 12; margin-bottom: 6; font-weight: bold }
DIV.groupText { margin-left: 16; font-style: italic; font-size: smaller }
FONT.keyword { color: #008000 }
FONT.keywordtype { color: #604020 }
FONT.keywordflow { color: #e08000 }
FONT.comment { color: #800000 }
FONT.preprocessor { color: #806020 }
FONT.stringliteral { color: #002080 }
FONT.charliteral { color: #008080 }

View File

@ -0,0 +1,272 @@
<html>
<head>
<meta name="author" content="ndevil@eso.org">
<meta name="editor" content="ndevil@eso.org">
<meta name="maintainer" content="ndevil@eso.org">
<meta name="organisation" content="ESO, DMD">
<meta name="keywords" content="eso, FITS format, C library">
<link href="doxygen.css" rel="stylesheet" type="text/css">
<title>qfits 4.0</title>
</head>
<body text="#000000" bgcolor="#ffffff">
<!-- Generated by Doxygen 1.2.5 on Wed Jan 23 15:41:02 2002 -->
<h1>qfits reference Manual</h1>
<p>
<h3 align="center">4.0</h3>
<p>
<hr>
<p>
<a name="welcome"><h2>Introduction</h2></a>
<p>
<b>qfits</b> is a stand-alone written in C to handle interactions with files complying with the FITS format. It is extremely fast and portable over any kind of POSIX-compliant platform.
<p>
Rather than going through the FITS format specification and trying to implement some support for everything that is described there, this library was built day after day upon request. This guarantees that all the functions you will find in the library have been written for some purpose in the VLT pipeline context, and all of them are used daily in a production environment.
<p>
Functionalities offered by this library are:
<p>
<ul>
<li>Header queries (get keywords, values).<li>Header manipulation (load/modify/save).<li>Pixel loading/saving to memory.<li>Support for files of any dimension (NAXIS).<li>Support for FITS extensions, including ASCII and binary tables.</ul>
This library also comes with a limited set of interfaces to Python to make some of its functionalities usable from this language. See the compilation instructions to build it as a Python module.
<p>
<hr>
<p>
<a name="history"><h2>History</h2></a>
<p>
<b>qfits</b> was born from the need to have a simple but powerful C library to handle FITS file accesses. There are already many libraries on the Net to handle FITS files, but they tend to be bloated with far too many features and would cause lots of problems in including in our own software (mainly for portability).
<p>
<b>qfits</b> was written to take care of all low-level aspects of the FITS format, and only these. You will find there a wealth of optimized functions to access everything inside FITS files, but nothing about what you could do with the data, this is left to other (e.g. image processing) libraries. There is no suggested image or cube type, and the table object only loads the data without trying to interpret them.
<p>
The idea is that people wanting to work with FITS might have different requirements: somebody writing an image viewer might just want to load a pixel buffer, somebody handling headers only might want to have easy access to header information without touching pixel data. <b>qfits</b> allows you to get your hands on what is contained in a FITS file but does not force you to use any specific high-level data type to describe your data.
<p>
<hr>
<p>
<a name="authors"><h2>Authors</h2></a>
<p>
Nicolas Devillard and Yves Jung, ESO.
<p>
<hr>
<p>
<a name="header"><h2>Header handling</h2></a>
<p>
This section gives you an overview of the functionalities offered to work on FITS headers with <b>qfits</b>. For a complete reference, check out the manual generated from the header file: <a class="el" href="qfits_h.html">qfits.h</a>.
<p>
FITS headers are simply formatted as 80-char lines (cards) containing ancillary data represented in ASCII format like:
<p>
keyword = value / comment
<p>
If you want to retrieve data from a FITS file header, you will find various useful query routines to get a keyword value from main or extension headers. Values are returned as strings and not coerced to any particular (e.g. numerical) type. See e.g.
<p>
<ul>
<li><a class="el" href="qfits_h.html#a48">qfits_query_hdr</a>() to query the main header.<li><a class="el" href="qfits_h.html#a49">qfits_query_ext</a>() to query an extension header.<li><a class="el" href="qfits_h.html#a50">qfits_query_n_ext</a>() to get the number of extensions.</ul>
You may also want to handle file inputs by yourself and have FITS lines (called <em>cards</em> in FITS terminology) split into their components key/value/comment. See e.g.
<p>
<ul>
<li><a class="el" href="qfits_h.html#a32">qfits_getkey</a>() extract the key from a FITS line.<li><a class="el" href="qfits_h.html#a33">qfits_getvalue</a>() extract the value.<li><a class="el" href="qfits_h.html#a34">qfits_getcomment</a>() extract the comment.</ul>
Since all FITS values are returned as strings, you may need to identify types. See e.g.
<p>
<ul>
<li><a class="el" href="qfits_h.html#a57">qfits_get_type</a>() identifies a value type<li><a class="el" href="qfits_h.html#a52">qfits_is_boolean</a>()<li><a class="el" href="qfits_h.html#a53">qfits_is_int</a>()<li><a class="el" href="qfits_h.html#a54">qfits_is_float</a>()<li><a class="el" href="qfits_h.html#a55">qfits_is_complex</a>()<li><a class="el" href="qfits_h.html#a56">qfits_is_string</a>()</ul>
Of course, you can use the usual <code>atof()</code>, <code>atoi()</code> and <code>scanf()</code> functions to convert a string to a numerical type.
<p>
You may also want to perform more complex operations on FITS headers, like loading one, modifying it and saving it back to a new file. The qfits_header data structure is offered for that purpose. It comes with utilities like:
<p>
<ul>
<li><a class="el" href="qfits_h.html#a35">qfits_header_read</a>() loads a header.<li><a class="el" href="qfits_h.html#a36">qfits_header_readext</a>() same from an extension.<li><a class="el" href="qfits_h.html#a29">qfits_header_dump</a>() saves a header to a file.<li>...</ul>
And of course all manipulation tools you can think of:
<p>
<ul>
<li><a class="el" href="qfits_h.html#a10">qfits_header_add</a>()<li><a class="el" href="qfits_h.html#a11">qfits_header_add_after</a>()<li><a class="el" href="qfits_h.html#a12">qfits_header_append</a>()<li><a class="el" href="qfits_h.html#a14">qfits_header_mod</a>()<li><a class="el" href="qfits_h.html#a13">qfits_header_del</a>()<li>...</ul>
There are other functions to create new FITS cards, dump a header to screen for debugging purposes, etc. See <a class="el" href="qfits_h.html">qfits.h</a> for an exhaustive description.
<p>
An important feature of the qfits_header object when loaded from a file, is that it conserves the memory of the initial FITS card. The data structure that is carried around for each FITS card contains:
<p>
<ul>
<li>Identified keyword<li>Identified value<li>Possible comment<li>Line as read from initial file when applicable.</ul>
This feature is fairly useful if you want to perform header manipulation without getting too intrusive. You can use this to load a header, modify a couple of cards and dump all back to disk. The dumped header will only be modified for the cards you have touched, all others will be forwarded verbatim as they appeared in the initial file. This least-modification policy ensures that you will not modify the lines you do not need to touch.
<p>
This feature can be turned off by "touching" all lines in a header using <a class="el" href="qfits_h.html#a17">qfits_header_touchall</a>(), which removes all initial line information from a qfits_header object. This is useful to force a reformatting of a FITS header e.g. when the file header is damaged.
<p>
Notice that ESO's <code>HIERARCH</code> keywords and DICB ordering are natively supported by <b>qfits</b>, i.e. when you work with qfits_header objects you can be sure that they will properly recognize and order keywords following ESO conventions.
<p>
<hr>
<p>
<a name="data"><h2>Data handling</h2></a>
<p>
This section gives you an overview of the functionalities offered to work on FITS data segments with <b>qfits</b>. For a complete reference, check out the manual generated from the header file: <a class="el" href="qfits_h.html">qfits.h</a>.
<p>
Data segments are quite simply stored: they always contain data contiguously in uncompressed format, so reading them is mostly a matter of applying an <code>fread()</code> statement at the right place in the file, with the right size. To find out about offsets to data and header parts in a FITS file (possibly containing several extensions), you can make use of:
<p>
<ul>
<li><a class="el" href="qfits_h.html#a58">qfits_get_hdrinfo</a>() returns information about a header position and size (in bytes) in a file.<li><a class="el" href="qfits_h.html#a59">qfits_get_datinfo</a>() returns information about a data segment position and size (in bytes) in a file.</ul>
<b>qfits</b> includes a caching mechanism to accelerate accesses to large files to an optimal access time (only one parsing of the file is needed, even with multiple queries on the same file). This mechanism is internal to this module and used invisibly for the programmer using <b>qfits</b>. This means that you can loop on all sections on a huge file to retrieve file offsets for each extension, and pay the price of file parsing only at the first call.
<p>
If you want to dive further into data loading, you may want to have a look at table and image handling functionalities.
<p>
<a name="table"><h3>Table handling</h3></a>
<p>
The qfits_table and qfits_col objects are offered to help you load table data into memory. I/O operators are e.g.
<p>
<ul>
<li><a class="el" href="qfits_h.html#a64">qfits_table_open</a>() to load table information.<li><a class="el" href="qfits_h.html#a66">qfits_query_column</a>() to load column data into memory.</ul>
The idea is that you first request general information about a table contained in a FITS file, then launch as many column queries as you need to retrieve the data. Data are byte-swapped if needed and returned as a pointer to void which must be cast to the proper data type (known from the column information tag).
<p>
Tables can of course be created from scratch and saved to disk or dumped to screen. See <a class="el" href="qfits_h.html">qfits.h</a> for a complete reference.
<p>
<a name="image"><h3>Image handling</h3></a>
<p>
The qfitsloader and qfitsdumper objects are offered to simplify the action of reading/writing image data. The corresponding operators take care of retrieving all necessary ancillary information (image size, pixel type, buffer position), perform a memory allocation or mapping and read the file into memory. The returned data buffers can be chosen to be float, int, or double pixels. See e.g.
<p>
<ul>
<li><a class="el" href="qfits_h.html#a39">qfitsloader_init</a>() to initialize a loader object.<li><a class="el" href="qfits_h.html#a40">qfits_loadpix</a>() to load pixel data into memory.<li><a class="el" href="qfits_h.html#a44">qfits_pixdump</a>() to save pixel data to disk.</ul>
As for tables, the idea is that you first launch an analysis of the file to get back a number of informations about what is present there. In the case of images, you use <a class="el" href="qfits_h.html#a39">qfitsloader_init</a>() to see if pixel loading could be done, then use <a class="el" href="qfits_h.html#a40">qfits_loadpix</a>() to perform the actual load.
<p>
Pixel I/O are taking place in float, int or double format. See the corresponding functions:
<p>
<ul>
<li><a class="el" href="qfits_h.html#a41">qfits_pixin_float</a>()<li><a class="el" href="qfits_h.html#a42">qfits_pixin_int</a>()<li><a class="el" href="qfits_h.html#a43">qfits_pixin_double</a>()<li><a class="el" href="qfits_h.html#a45">qfits_pixdump_float</a>()<li><a class="el" href="qfits_h.html#a46">qfits_pixdump_int</a>()<li><a class="el" href="qfits_h.html#a47">qfits_pixdump_double</a>()</ul>
Loading pixels as floats means that whichever pixel format (BITPIX) is used in your input FITS file, all pixels will be converted to your local representation of float upon loading. The 3 offered types basically allow you to work with 3 kinds of pixels internally, choose the one that best suits your needs. 'int' is not recommended for loss of precision, and 'double' for memory and performance issues.
<p>
Saving pixels can be done with any BITPIX setting. There are 3 pixel dumpers as there are 3 pixel loaders because your pixel buffer to save might be stored in any of the 3 supported types. All pixels are converted on the fly to the requested BITPIX setting.
<p>
Notice that as soon as you start using pixel loading functions, you must comply with the <b>qfits</b> memory model. This basically means that you should not only include <code><a class="el" href="qfits_h.html">qfits.h</a></code> in your program, but also <code>xmemory.h</code> to get the proper definitions for memory allocation functions.
<p>
<a name="utils"><h2>Other utilities</h2></a>
<p>
Some additional functions are offered in <b>qfits</b>, they are useful in the VLT context. See:
<p>
<ul>
<li><a class="el" href="qfits_h.html#a72">date_now</a>()<li><a class="el" href="qfits_h.html#a73">time_now</a>()<li><a class="el" href="qfits_h.html#a74">get_date_iso8601</a>()<li><a class="el" href="qfits_h.html#a75">get_datetime_iso8601</a>()</ul>
<hr>
<p>
<a name="features"><h2>Features</h2></a>
<p>
Some of the unique features of this library are:
<p>
<a name="portability"><h3>Portability</h3></a>
<p>
This library has been ported and tested on the following platforms:
<p>
<ul>
<li>Linux x86 and alpha<li>Solaris 2.5, 2.6 and 2.8<li>HPUX 8, 9, 10, 11<li>AIX<li>BSD compatible, including Darwin (Mac OS X)<li>OSF/1 or Tru64</ul>
Since <b>qfits</b> makes lots of calls to POSIX system routines, there is little chance it could compile natively on Windows, except with the help from GNU porting tools from Cygnus. This has never been attempted so far.
<p>
<a name="speed"><h3>Speed</h3></a>
<p>
The offered routines are extremely fast, making use of caching mechanisms and memory-mapping system calls to enhance FITS file parsing.
<p>
<a name="interfaces"><h3>Interfaces to C++/Python</h3></a>
<p>
You should be able to compile this library with a C++ compiler, the header files include the usual blurb to allow that without warning from the compiler. You might have problems due to pointer casts and other various incompatibilities due to the variety of C++ dialects and compilers, though. If you really need to hook this library into C++ code, your best bet is probably to compile the library as a standard C library and link your C++ code against it.
<p>
A limited set of interfaces to Python is offered. See the INSTALL file in the main distribution directory for instructions about installing this library as a Python module.
<p>
<a name="precision"><h3>Numerical precision</h3></a>
<p>
Since FITS headers are stored as strings, numerical precision is limited by the number of digits used to write a number in a FITS card, which is in theory larger than what a 32-bit floating-point can store. Using <b>qfits</b>, these values are available to a C programmer as a string, making sure that precision has at least not be lost in the reading process.
<p>
<a name="conservative"><h3>Conservative headers</h3></a>
<p>
As mentioned above, if you only need to load a header, modify a card and save it back, you will find out that <em>only</em> the card you touched has been modified, the rest was verbatim transferred. This is useful to ensure that the library formatting does not disturb your format.
<p>
<a name="hierarch"><h3>Native HIERARCH support</h3></a>
<p>
Native support for ESO's <code>HIERARCH</code> keywords, as well as keywords of any length (up to 80 chars per line).
<p>
<a name="dicb"><h3>ESO/DICB keyword ordering</h3></a>
<p>
Native support for DICB (ESO only) ordering of keywords in the headers. If you use this library to produce FITS files, you can reasonably be sure that all the files you create will be DICB compliant with respect to keyword ordering.
<p>
<a name="xmemory"><h3>Memory model</h3></a>
<p>
<b>qfits</b> does not only offer pixel loading mechanisms, it also comes bundled with a memory module based on a model optimized for the handling of very large data segments. In practice, it means that as soon as you have included <code>xmemory.h</code>, your calls to malloc/calloc/free are re-directed to specific versions which put your program on steroids. Calls to memory allocators will yield valid data pointers past the hardware limits of your machine, up to 2 or 4 Gb on a 32-bit workstation and insanely high values on 64-bit processors.
<p>
This memory module is also distributed as a stand-alone module which can be downloaded and used without <b>qfits</b>. It is mandatory to use this module when using <b>qfits</b> pixel loaders, to get the advantages of large memory handling.
<p>
If you are only interested in header manipulation, you do not need to include <code>xmemory.h</code>.
<p>
<hr>
<p>
<a name="install"><h2>Installation instructions</h2></a>
<p>
In the main <b>qfits</b> directory, type:
<p>
<div class="fragment"><pre>
./configure ; make
</div></pre>
<p>
To use the library in your programs, add the following line on top of your module:
<p>
<div class="fragment"><pre><font class="preprocessor">#include "<a class="code" href="qfits_h.html">qfits.h</a>"</font></div></pre>
<p>
And link your program with the <b>qfits</b> library by adding <code>-lqfits</code> to the compile line.
<p>
If you ever need to make calls to one of the <b>qfits</b> pixel loaders, you need to include the memory model definitions also with:
<p>
<div class="fragment"><pre><font class="preprocessor">#include "xmemory.h"</font></div></pre>
<p>
Including this file is needed so that you can safely <code>free()</code> the pointer returned by a pixel loader. See the documentation about pixel loaders for more information.
<p>
To compile <b>qfits</b> as a Python module, you need to have Python installed on your machine and available in your PATH. Type:
<p>
<div class="fragment"><pre>
% python setup.py install
</div></pre>
<p>
This should build the module and install it in your default library path. This makes use of the distutils package, standardized since Python 2.0. This means that you need Python 2.0 at least to compile and run this module. If you are running Python 1.5 or 1.6, you may want to install the <code>distutils</code> package on your platform, which will handle the <b>qfits</b> module installation.
<p>
<hr>
<p>
<a name="faq"><h2>Frequently Asked Questions</h2></a>
<p>
<a name="faq1"><h3>Where should I start to use qfits?</h3></a>
<p>
Try to build the library on your system first. You should then have a new library file called libqfits.a. To use the library functionalities in your programs, you must add the following include in your list of includes:
<p>
<div class="fragment"><pre>
#include "qfits.h"
</div></pre>
<p>
And then compile your program adding the correct flags to indicate where the <b><a class="el" href="qfits_h.html">qfits.h</a></b> header file is, where the libqfits.a file is, and that you want to link against libqfits. Example: if the header file is in /usr/local/include and the library in /usr/local/lib, you would use:
<p>
<div class="fragment"><pre>
% cc -o myprog myprog.c -I/usr/local/include -L/usr/local/lib -lqfits
</div></pre>
<p>
<a name="faq2"><h3>What should I know about the cache mechanism?</h3></a>
<p>
Parsing FITS files to find extensions is a lengthy process, because the FITS format does not declare in the main header where the following extensions are located in the file. Any access to a FITS file with this library will cache a number of offset pointers in the file to allow fast access to extensions. This means that the file is parsed completely only once, the first time it is accessed through any of the <b>qfits</b> functions.
<p>
This has two side-effects, due to the cache implementation. The cache is a memory buffer located inside the <b>qfits</b> library, which will grow for any new FITS file presented to its query functions. The amount of memory taken for each new file is small (less than 100 bytes), but will nonetheless accumulate if you start reading lots of new FITS files in an application that is meant to live a relatively long amount of time. To prevent the cache from growing indefinitely, a cache purging mechanism called <a class="el" href="qfits_h.html#a6">qfits_cache_purge</a>() is offered.
<p>
Purging will be called every time you reach 4096 FITS files in the cache, which corresponds roughly to 300 kbytes. If you are working with huge number of files simultaneously and need to access them often, you might want to increase this limit in cache.c. On the other hand, if you want to reduce the memory usage due to cache, you may want to reduce the corresponding limits accordingly, or purge more often.
<p>
The second side-effet is that the cache structure makes the cache module thread-unsafe. If you are concerned about writing multi-threaded applications, you should put a mutex on accessing this library. A thread-safe compliant version might become available some day, so if you want to help...
<p>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,502 @@
<html>
<head>
<meta name="author" content="ndevil@eso.org">
<meta name="editor" content="ndevil@eso.org">
<meta name="maintainer" content="ndevil@eso.org">
<meta name="organisation" content="ESO, DMD">
<meta name="keywords" content="eso, FITS format, C library">
<link href="doxygen.css" rel="stylesheet" type="text/css">
<title>qfits 4.0</title>
</head>
<body text="#000000" bgcolor="#ffffff">
<!-- Generated by Doxygen 1.2.5 on Wed Jan 23 15:41:02 2002 -->
<h1>_qfits_col_ Struct Reference</h1>Column object.
<a href="#_details">More...</a>
<p>
<code>#include &lt;qfits.h&gt;</code>
<p>
<table border=0 cellpadding=0 cellspacing=0>
<tr><td colspan=2><br><h2>Data Fields</h2></td></tr>
<tr><td nowrap align=right valign=top>int&nbsp;</td><td valign=bottom><a class="el" href="struct__qfits_col_.html#m0">nelem</a></td></tr>
<tr><td nowrap align=right valign=top>int&nbsp;</td><td valign=bottom><a class="el" href="struct__qfits_col_.html#m1">natoms</a></td></tr>
<tr><td nowrap align=right valign=top>int&nbsp;</td><td valign=bottom><a class="el" href="struct__qfits_col_.html#m2">atom_size</a></td></tr>
<tr><td nowrap align=right valign=top>int&nbsp;</td><td valign=bottom><a class="el" href="struct__qfits_col_.html#m3">ascii_size</a></td></tr>
<tr><td nowrap align=right valign=top>char&nbsp;</td><td valign=bottom><a class="el" href="struct__qfits_col_.html#m4">atom_type</a></td></tr>
<tr><td nowrap align=right valign=top>int&nbsp;</td><td valign=bottom><a class="el" href="struct__qfits_col_.html#m5">atom_nb</a></td></tr>
<tr><td nowrap align=right valign=top>char&nbsp;</td><td valign=bottom><a class="el" href="struct__qfits_col_.html#m6">tlabel</a> [FITSVALSZ]</td></tr>
<tr><td nowrap align=right valign=top>char&nbsp;</td><td valign=bottom><a class="el" href="struct__qfits_col_.html#m7">tunit</a> [FITSVALSZ]</td></tr>
<tr><td nowrap align=right valign=top>char&nbsp;</td><td valign=bottom><a class="el" href="struct__qfits_col_.html#m8">nullval</a> [FITSVALSZ]</td></tr>
<tr><td nowrap align=right valign=top>char&nbsp;</td><td valign=bottom><a class="el" href="struct__qfits_col_.html#m9">disp</a> [FITSVALSZ]</td></tr>
<tr><td nowrap align=right valign=top>int&nbsp;</td><td valign=bottom><a class="el" href="struct__qfits_col_.html#m10">zero_present</a></td></tr>
<tr><td nowrap align=right valign=top>float&nbsp;</td><td valign=bottom><a class="el" href="struct__qfits_col_.html#m11">zero</a></td></tr>
<tr><td nowrap align=right valign=top>int&nbsp;</td><td valign=bottom><a class="el" href="struct__qfits_col_.html#m12">scale_present</a></td></tr>
<tr><td nowrap align=right valign=top>float&nbsp;</td><td valign=bottom><a class="el" href="struct__qfits_col_.html#m13">scale</a></td></tr>
<tr><td nowrap align=right valign=top>int&nbsp;</td><td valign=bottom><a class="el" href="struct__qfits_col_.html#m14">off_beg</a></td></tr>
<tr><td nowrap align=right valign=top>int&nbsp;</td><td valign=bottom><a class="el" href="struct__qfits_col_.html#m15">off_jmp</a></td></tr>
<tr><td nowrap align=right valign=top>int&nbsp;</td><td valign=bottom><a class="el" href="struct__qfits_col_.html#m16">readable</a></td></tr>
</table>
<hr><a name="_details"></a><h2>Detailed Description</h2>
Column object.
<p>
<p>
This structure contains all information needed to read a column in a table. These informations come from the header. The qfits_table object contains a list of qfits_col objects.
<p>
This structure has to be created from scratch and filled if one want to generate a FITS table.
<p>
<hr><h2>Field Documentation</h2>
<a name="m3" doxytag="_qfits_col_::ascii_size"></a><p>
<table width="100%" cellpadding="2" cellspacing="0" border="0">
<tr>
<td class="md">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td nowrap valign="top"><b>
int _qfits_col_::ascii_size
</b></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing=5 cellpadding=0 border=0>
<tr>
<td>
&nbsp;
</td>
<td>
<p>
Only for ASCII fields (0 otherwise). Nb of characters of the field. </td>
</tr>
</table>
<a name="m5" doxytag="_qfits_col_::atom_nb"></a><p>
<table width="100%" cellpadding="2" cellspacing="0" border="0">
<tr>
<td class="md">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td nowrap valign="top"><b>
int _qfits_col_::atom_nb
</b></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing=5 cellpadding=0 border=0>
<tr>
<td>
&nbsp;
</td>
<td>
<p>
Number of atoms per field as specified in TFORM keyword Differ from natoms for ASCII table fields of type different from A: you can have the string "1234" (natoms = 1) specified as I4 (atom_nb = 4) </td>
</tr>
</table>
<a name="m2" doxytag="_qfits_col_::atom_size"></a><p>
<table width="100%" cellpadding="2" cellspacing="0" border="0">
<tr>
<td class="md">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td nowrap valign="top"><b>
int _qfits_col_::atom_size
</b></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing=5 cellpadding=0 border=0>
<tr>
<td>
&nbsp;
</td>
<td>
<p>
Size of one element in bytes. In ASCII tables, atom_size is the size of the element once it has been converted in its 'destination' type. For example, if "123" is contained in an ASCII table in a column defined as I type, natoms=1, ascii_size=3, atom_size=4. In ASCII tables:<ul>
<li>type 'A' : atom_size = ascii_size = number of chars<li>type 'I', 'F' or 'E' : atom_size = 4<li>type 'D' : atom_size = 8 In BIN tables :<li>type 'A' : atom_size = ascii_size = atom_nb = number of chars<li>type 'L', 'X', B' : atom_size = 1<li>type 'I' : atom_size = 2<li>type 'E', 'J', 'C', 'P' : atom_size = 4<li>type 'D', 'M' : atom_size = 8 </ul>
</td>
</tr>
</table>
<a name="m4" doxytag="_qfits_col_::atom_type"></a><p>
<table width="100%" cellpadding="2" cellspacing="0" border="0">
<tr>
<td class="md">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td nowrap valign="top"><b>
char _qfits_col_::atom_type
</b></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing=5 cellpadding=0 border=0>
<tr>
<td>
&nbsp;
</td>
<td>
<p>
Type of data in the column as specified in TFORM keyword In ASCII tables : A, I, F, E or D In BIN tables : L, X, B, I, J, A, E, D, C, M or P </td>
</tr>
</table>
<a name="m9" doxytag="_qfits_col_::disp"></a><p>
<table width="100%" cellpadding="2" cellspacing="0" border="0">
<tr>
<td class="md">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td nowrap valign="top"><b>
char _qfits_col_::disp[FITSVALSZ]
</b></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing=5 cellpadding=0 border=0>
<tr>
<td>
&nbsp;
</td>
<td>
<p>
Display format </td>
</tr>
</table>
<a name="m1" doxytag="_qfits_col_::natoms"></a><p>
<table width="100%" cellpadding="2" cellspacing="0" border="0">
<tr>
<td class="md">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td nowrap valign="top"><b>
int _qfits_col_::natoms
</b></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing=5 cellpadding=0 border=0>
<tr>
<td>
&nbsp;
</td>
<td>
<p>
Number of elements in one field. There are some differences according types <ul>
<li>If the field contains a string, natoms = 1. In this case, the number of characters is given by ascii_size.<li>If the field contains elements of types 'L', 'I', 'J', 'E', 'D' or 'B', natoms is simply the number of elements.<li>For complex types ('C' or 'M') natoms is the number of double or float (number of complex * 2).<li>If the field contains elements of type P (pair of int), natoms is the number of int (nb of 'P' element * 2) </ul>
</td>
</tr>
</table>
<a name="m0" doxytag="_qfits_col_::nelem"></a><p>
<table width="100%" cellpadding="2" cellspacing="0" border="0">
<tr>
<td class="md">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td nowrap valign="top"><b>
int _qfits_col_::nelem
</b></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing=5 cellpadding=0 border=0>
<tr>
<td>
&nbsp;
</td>
<td>
<p>
Number of rows in the column. In a same table, all columns have the same nelem value. </td>
</tr>
</table>
<a name="m8" doxytag="_qfits_col_::nullval"></a><p>
<table width="100%" cellpadding="2" cellspacing="0" border="0">
<tr>
<td class="md">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td nowrap valign="top"><b>
char _qfits_col_::nullval[FITSVALSZ]
</b></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing=5 cellpadding=0 border=0>
<tr>
<td>
&nbsp;
</td>
<td>
<p>
Null value </td>
</tr>
</table>
<a name="m14" doxytag="_qfits_col_::off_beg"></a><p>
<table width="100%" cellpadding="2" cellspacing="0" border="0">
<tr>
<td class="md">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td nowrap valign="top"><b>
int _qfits_col_::off_beg
</b></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing=5 cellpadding=0 border=0>
<tr>
<td>
&nbsp;
</td>
<td>
<p>
Offset between the beg. of the table and the beg. of the column. </td>
</tr>
</table>
<a name="m15" doxytag="_qfits_col_::off_jmp"></a><p>
<table width="100%" cellpadding="2" cellspacing="0" border="0">
<tr>
<td class="md">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td nowrap valign="top"><b>
int _qfits_col_::off_jmp
</b></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing=5 cellpadding=0 border=0>
<tr>
<td>
&nbsp;
</td>
<td>
<p>
Width of the table in bytes </td>
</tr>
</table>
<a name="m16" doxytag="_qfits_col_::readable"></a><p>
<table width="100%" cellpadding="2" cellspacing="0" border="0">
<tr>
<td class="md">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td nowrap valign="top"><b>
int _qfits_col_::readable
</b></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing=5 cellpadding=0 border=0>
<tr>
<td>
&nbsp;
</td>
<td>
<p>
Flag to know if the column is readable. An empty col is not readable </td>
</tr>
</table>
<a name="m13" doxytag="_qfits_col_::scale"></a><p>
<table width="100%" cellpadding="2" cellspacing="0" border="0">
<tr>
<td class="md">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td nowrap valign="top"><b>
float _qfits_col_::scale
</b></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing=5 cellpadding=0 border=0>
<tr>
<td>
&nbsp;
</td>
<td>
<p>
</td>
</tr>
</table>
<a name="m12" doxytag="_qfits_col_::scale_present"></a><p>
<table width="100%" cellpadding="2" cellspacing="0" border="0">
<tr>
<td class="md">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td nowrap valign="top"><b>
int _qfits_col_::scale_present
</b></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing=5 cellpadding=0 border=0>
<tr>
<td>
&nbsp;
</td>
<td>
<p>
</td>
</tr>
</table>
<a name="m6" doxytag="_qfits_col_::tlabel"></a><p>
<table width="100%" cellpadding="2" cellspacing="0" border="0">
<tr>
<td class="md">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td nowrap valign="top"><b>
char _qfits_col_::tlabel[FITSVALSZ]
</b></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing=5 cellpadding=0 border=0>
<tr>
<td>
&nbsp;
</td>
<td>
<p>
Label of the column </td>
</tr>
</table>
<a name="m7" doxytag="_qfits_col_::tunit"></a><p>
<table width="100%" cellpadding="2" cellspacing="0" border="0">
<tr>
<td class="md">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td nowrap valign="top"><b>
char _qfits_col_::tunit[FITSVALSZ]
</b></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing=5 cellpadding=0 border=0>
<tr>
<td>
&nbsp;
</td>
<td>
<p>
Unit of the data </td>
</tr>
</table>
<a name="m11" doxytag="_qfits_col_::zero"></a><p>
<table width="100%" cellpadding="2" cellspacing="0" border="0">
<tr>
<td class="md">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td nowrap valign="top"><b>
float _qfits_col_::zero
</b></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing=5 cellpadding=0 border=0>
<tr>
<td>
&nbsp;
</td>
<td>
<p>
</td>
</tr>
</table>
<a name="m10" doxytag="_qfits_col_::zero_present"></a><p>
<table width="100%" cellpadding="2" cellspacing="0" border="0">
<tr>
<td class="md">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td nowrap valign="top"><b>
int _qfits_col_::zero_present
</b></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing=5 cellpadding=0 border=0>
<tr>
<td>
&nbsp;
</td>
<td>
<p>
zero and scale are used when the quantity in the field does not represent a true physical quantity. Basically, thez should be used when they are present: physical_value = zero + scale * field_value They are read from TZERO and TSCAL in the header </td>
</tr>
</table>
<hr>The documentation for this struct was generated from the following file:<ul>
<li><a class="el" href="qfits_h.html">qfits.h</a></ul>
</body>
</html>

View File

@ -0,0 +1,118 @@
<html>
<head>
<meta name="author" content="ndevil@eso.org">
<meta name="editor" content="ndevil@eso.org">
<meta name="maintainer" content="ndevil@eso.org">
<meta name="organisation" content="ESO, DMD">
<meta name="keywords" content="eso, FITS format, C library">
<link href="doxygen.css" rel="stylesheet" type="text/css">
<title>qfits 4.0</title>
</head>
<body text="#000000" bgcolor="#ffffff">
<!-- Generated by Doxygen 1.2.5 on Wed Jan 23 15:41:02 2002 -->
<h1>_qfits_header_ Struct Reference</h1>FITS header object.
<a href="#_details">More...</a>
<p>
<code>#include &lt;qfits.h&gt;</code>
<p>
<table border=0 cellpadding=0 cellspacing=0>
<tr><td colspan=2><br><h2>Data Fields</h2></td></tr>
<tr><td nowrap align=right valign=top>void*&nbsp;</td><td valign=bottom><a class="el" href="struct__qfits_header_.html#m0">first</a></td></tr>
<tr><td nowrap align=right valign=top>void*&nbsp;</td><td valign=bottom><a class="el" href="struct__qfits_header_.html#m1">last</a></td></tr>
<tr><td nowrap align=right valign=top>int&nbsp;</td><td valign=bottom><a class="el" href="struct__qfits_header_.html#m2">n</a></td></tr>
</table>
<hr><a name="_details"></a><h2>Detailed Description</h2>
FITS header object.
<p>
<p>
This structure represents a FITS header in memory. It is actually no more than a thin layer on top of the keytuple object. No field in this structure should be directly modifiable by the user, only through accessor functions.
<p>
<hr><h2>Field Documentation</h2>
<a name="m0" doxytag="_qfits_header_::first"></a><p>
<table width="100%" cellpadding="2" cellspacing="0" border="0">
<tr>
<td class="md">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td nowrap valign="top"><b>
void * _qfits_header_::first
</b></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing=5 cellpadding=0 border=0>
<tr>
<td>
&nbsp;
</td>
<td>
<p>
</td>
</tr>
</table>
<a name="m1" doxytag="_qfits_header_::last"></a><p>
<table width="100%" cellpadding="2" cellspacing="0" border="0">
<tr>
<td class="md">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td nowrap valign="top"><b>
void * _qfits_header_::last
</b></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing=5 cellpadding=0 border=0>
<tr>
<td>
&nbsp;
</td>
<td>
<p>
</td>
</tr>
</table>
<a name="m2" doxytag="_qfits_header_::n"></a><p>
<table width="100%" cellpadding="2" cellspacing="0" border="0">
<tr>
<td class="md">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td nowrap valign="top"><b>
int _qfits_header_::n
</b></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing=5 cellpadding=0 border=0>
<tr>
<td>
&nbsp;
</td>
<td>
<p>
</td>
</tr>
</table>
<hr>The documentation for this struct was generated from the following file:<ul>
<li><a class="el" href="qfits_h.html">qfits.h</a></ul>
</body>
</html>

View File

@ -0,0 +1,163 @@
<html>
<head>
<meta name="author" content="ndevil@eso.org">
<meta name="editor" content="ndevil@eso.org">
<meta name="maintainer" content="ndevil@eso.org">
<meta name="organisation" content="ESO, DMD">
<meta name="keywords" content="eso, FITS format, C library">
<link href="doxygen.css" rel="stylesheet" type="text/css">
<title>qfits 4.0</title>
</head>
<body text="#000000" bgcolor="#ffffff">
<!-- Generated by Doxygen 1.2.5 on Wed Jan 23 15:41:02 2002 -->
<h1>_qfits_table_ Struct Reference</h1>Table object.
<a href="#_details">More...</a>
<p>
<code>#include &lt;qfits.h&gt;</code>
<p>
<table border=0 cellpadding=0 cellspacing=0>
<tr><td colspan=2><br><h2>Data Fields</h2></td></tr>
<tr><td nowrap align=right valign=top>char&nbsp;</td><td valign=bottom><a class="el" href="struct__qfits_table_.html#m0">filename</a> [FILENAMESZ]</td></tr>
<tr><td nowrap align=right valign=top>int&nbsp;</td><td valign=bottom><a class="el" href="struct__qfits_table_.html#m1">tab_t</a></td></tr>
<tr><td nowrap align=right valign=top>int&nbsp;</td><td valign=bottom><a class="el" href="struct__qfits_table_.html#m2">nc</a></td></tr>
<tr><td nowrap align=right valign=top><a class="el" href="qfits_h.html#a3">qfits_col</a>*&nbsp;</td><td valign=bottom><a class="el" href="struct__qfits_table_.html#m3">col</a></td></tr>
</table>
<hr><a name="_details"></a><h2>Detailed Description</h2>
Table object.
<p>
<p>
This structure contains all information needed to read a FITS table. These information come from the header. The object is created by qfits_open().
<p>
To read a FITS table, here is a code example: <div class="fragment"><pre> <font class="keywordtype">int</font> main(<font class="keywordtype">int</font> argc, <font class="keywordtype">char</font>* argv[])<font class="keyword"></font>
<font class="keyword"> </font>{
<a class="code" href="struct__qfits_table_.html">qfits_table</a> * table ;
<font class="keywordtype">int</font> n_ext ;
<font class="keywordtype">int</font> i ;
n_ext = <a class="code" href="qfits_h.html#a50">qfits_query_n_ext</a>(argv[1]);
<font class="keywordflow">for</font> (i=0 ; i&lt;n_ext ; i++) {
<font class="keywordflow">if</font> ((table = <a class="code" href="qfits_h.html#a64">qfits_table_open</a>(argv[1], i+1)) == NULL) {
printf(<font class="stringliteral">"cannot open table [%s]:[%d]\n"</font>, argv[1], i+1);
} <font class="keywordflow">else</font> {
dump_extension(table, stdout, <font class="charliteral">'|'</font>, 1, 1) ;
<a class="code" href="qfits_h.html#a65">qfits_table_close</a>(table) ;
}
}
<font class="keywordflow">return</font> ;
}</div></pre>
<p>
<hr><h2>Field Documentation</h2>
<a name="m3" doxytag="_qfits_table_::col"></a><p>
<table width="100%" cellpadding="2" cellspacing="0" border="0">
<tr>
<td class="md">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td nowrap valign="top"><b>
<a class="el" href="qfits_h.html#a3">qfits_col</a> * _qfits_table_::col
</b></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing=5 cellpadding=0 border=0>
<tr>
<td>
&nbsp;
</td>
<td>
<p>
Array of qfits_col objects </td>
</tr>
</table>
<a name="m0" doxytag="_qfits_table_::filename"></a><p>
<table width="100%" cellpadding="2" cellspacing="0" border="0">
<tr>
<td class="md">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td nowrap valign="top"><b>
char _qfits_table_::filename[FILENAMESZ]
</b></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing=5 cellpadding=0 border=0>
<tr>
<td>
&nbsp;
</td>
<td>
<p>
Name of the file the table comes from or it is intended to end to </td>
</tr>
</table>
<a name="m2" doxytag="_qfits_table_::nc"></a><p>
<table width="100%" cellpadding="2" cellspacing="0" border="0">
<tr>
<td class="md">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td nowrap valign="top"><b>
int _qfits_table_::nc
</b></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing=5 cellpadding=0 border=0>
<tr>
<td>
&nbsp;
</td>
<td>
<p>
Number of columns </td>
</tr>
</table>
<a name="m1" doxytag="_qfits_table_::tab_t"></a><p>
<table width="100%" cellpadding="2" cellspacing="0" border="0">
<tr>
<td class="md">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td nowrap valign="top"><b>
int _qfits_table_::tab_t
</b></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing=5 cellpadding=0 border=0>
<tr>
<td>
&nbsp;
</td>
<td>
<p>
Table type. Possible values are QFITS_INVALIDTABLE, QFITS_BINTABLE or QFITS_ASCIITABLE </td>
</tr>
</table>
<hr>The documentation for this struct was generated from the following file:<ul>
<li><a class="el" href="qfits_h.html">qfits.h</a></ul>
</body>
</html>

View File

@ -0,0 +1,253 @@
<html>
<head>
<meta name="author" content="ndevil@eso.org">
<meta name="editor" content="ndevil@eso.org">
<meta name="maintainer" content="ndevil@eso.org">
<meta name="organisation" content="ESO, DMD">
<meta name="keywords" content="eso, FITS format, C library">
<link href="doxygen.css" rel="stylesheet" type="text/css">
<title>qfits 4.0</title>
</head>
<body text="#000000" bgcolor="#ffffff">
<!-- Generated by Doxygen 1.2.5 on Wed Jan 23 15:41:02 2002 -->
<h1>_qfitsdumper_ Struct Reference</h1>qfits dumper control object.
<a href="#_details">More...</a>
<p>
<code>#include &lt;qfits.h&gt;</code>
<p>
<table border=0 cellpadding=0 cellspacing=0>
<tr><td colspan=2><br><h2>Data Fields</h2></td></tr>
<tr><td nowrap align=right valign=top>char*&nbsp;</td><td valign=bottom><a class="el" href="struct__qfitsdumper_.html#m0">filename</a></td></tr>
<tr><td nowrap align=right valign=top>int&nbsp;</td><td valign=bottom><a class="el" href="struct__qfitsdumper_.html#m1">npix</a></td></tr>
<tr><td nowrap align=right valign=top>int&nbsp;</td><td valign=bottom><a class="el" href="struct__qfitsdumper_.html#m2">ptype</a></td></tr>
<tr><td nowrap align=right valign=top>int*&nbsp;</td><td valign=bottom><a class="el" href="struct__qfitsdumper_.html#m3">ibuf</a></td></tr>
<tr><td nowrap align=right valign=top>float*&nbsp;</td><td valign=bottom><a class="el" href="struct__qfitsdumper_.html#m4">fbuf</a></td></tr>
<tr><td nowrap align=right valign=top>double*&nbsp;</td><td valign=bottom><a class="el" href="struct__qfitsdumper_.html#m5">dbuf</a></td></tr>
<tr><td nowrap align=right valign=top>int&nbsp;</td><td valign=bottom><a class="el" href="struct__qfitsdumper_.html#m6">out_ptype</a></td></tr>
</table>
<hr><a name="_details"></a><h2>Detailed Description</h2>
qfits dumper control object.
<p>
<p>
This structure offers various control parameters to dump a pixel buffer to a FITS file. The buffer will be dumped as requested to the requested file in append mode. Of course, the requested file must be writeable for the operation to succeed.
<p>
The following example demonstrates how to save a linear ramp sized 100x100 to a FITS file with BITPIX=16. Notice that this code only dumps the pixel buffer, no header information is provided in this case.
<p>
<div class="fragment"><pre> <font class="keywordtype">int</font> i, j ;
<font class="keywordtype">int</font> * ibuf ;
<a class="code" href="struct__qfitsdumper_.html">qfitsdumper</a> qd ;
<font class="comment">// Fill a buffer with 100x100 int pixels</font>
ibuf = malloc(100 * 100 * <font class="keyword">sizeof</font>(<font class="keywordtype">int</font>));
<font class="keywordflow">for</font> (j=0 ; j&lt;100 ; j++) {
<font class="keywordflow">for</font> (i=0 ; i&lt;100 ; i++) {
ibuf[i+j*100] = i+j ;
}
}
qd.filename = <font class="stringliteral">"out.fits"</font> ; <font class="comment">// Output file name</font>
qd.npix = 100 * 100 ; <font class="comment">// Number of pixels</font>
qd.ptype = PTYPE_INT ; <font class="comment">// Input buffer type</font>
qd.ibuf = ibuf ; <font class="comment">// Set buffer pointer</font>
qd.out_ptype = BPP_16_SIGNED ; <font class="comment">// Save with BITPIX=16</font>
<font class="comment">// Dump buffer to file (error checking omitted for clarity)</font>
<a class="code" href="qfits_h.html#a44">qfits_pixdump</a>(&amp;qd);
free(ibuf);</div></pre>
<p>
If the provided output file name is "STDOUT" (all capitals), the function will dump the pixels to the stdout steam (usually the console, could have been re-directed).
<p>
<hr><h2>Field Documentation</h2>
<a name="m5" doxytag="_qfitsdumper_::dbuf"></a><p>
<table width="100%" cellpadding="2" cellspacing="0" border="0">
<tr>
<td class="md">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td nowrap valign="top"><b>
double * _qfitsdumper_::dbuf
</b></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing=5 cellpadding=0 border=0>
<tr>
<td>
&nbsp;
</td>
<td>
<p>
Pointer to input double pixel buffer </td>
</tr>
</table>
<a name="m4" doxytag="_qfitsdumper_::fbuf"></a><p>
<table width="100%" cellpadding="2" cellspacing="0" border="0">
<tr>
<td class="md">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td nowrap valign="top"><b>
float * _qfitsdumper_::fbuf
</b></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing=5 cellpadding=0 border=0>
<tr>
<td>
&nbsp;
</td>
<td>
<p>
Pointer to input float pixel buffer </td>
</tr>
</table>
<a name="m0" doxytag="_qfitsdumper_::filename"></a><p>
<table width="100%" cellpadding="2" cellspacing="0" border="0">
<tr>
<td class="md">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td nowrap valign="top"><b>
char * _qfitsdumper_::filename
</b></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing=5 cellpadding=0 border=0>
<tr>
<td>
&nbsp;
</td>
<td>
<p>
Name of the file to dump to, "STDOUT" to dump to stdout </td>
</tr>
</table>
<a name="m3" doxytag="_qfitsdumper_::ibuf"></a><p>
<table width="100%" cellpadding="2" cellspacing="0" border="0">
<tr>
<td class="md">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td nowrap valign="top"><b>
int * _qfitsdumper_::ibuf
</b></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing=5 cellpadding=0 border=0>
<tr>
<td>
&nbsp;
</td>
<td>
<p>
Pointer to input integer pixel buffer </td>
</tr>
</table>
<a name="m1" doxytag="_qfitsdumper_::npix"></a><p>
<table width="100%" cellpadding="2" cellspacing="0" border="0">
<tr>
<td class="md">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td nowrap valign="top"><b>
int _qfitsdumper_::npix
</b></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing=5 cellpadding=0 border=0>
<tr>
<td>
&nbsp;
</td>
<td>
<p>
Number of pixels in the buffer to dump </td>
</tr>
</table>
<a name="m6" doxytag="_qfitsdumper_::out_ptype"></a><p>
<table width="100%" cellpadding="2" cellspacing="0" border="0">
<tr>
<td class="md">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td nowrap valign="top"><b>
int _qfitsdumper_::out_ptype
</b></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing=5 cellpadding=0 border=0>
<tr>
<td>
&nbsp;
</td>
<td>
<p>
Requested BITPIX in output FITS file </td>
</tr>
</table>
<a name="m2" doxytag="_qfitsdumper_::ptype"></a><p>
<table width="100%" cellpadding="2" cellspacing="0" border="0">
<tr>
<td class="md">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td nowrap valign="top"><b>
int _qfitsdumper_::ptype
</b></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing=5 cellpadding=0 border=0>
<tr>
<td>
&nbsp;
</td>
<td>
<p>
Buffer type: PTYPE_FLOAT, PTYPE_INT or PTYPE_DOUBLE </td>
</tr>
</table>
<hr>The documentation for this struct was generated from the following file:<ul>
<li><a class="el" href="qfits_h.html">qfits.h</a></ul>
</body>
</html>

View File

@ -0,0 +1,515 @@
<html>
<head>
<meta name="author" content="ndevil@eso.org">
<meta name="editor" content="ndevil@eso.org">
<meta name="maintainer" content="ndevil@eso.org">
<meta name="organisation" content="ESO, DMD">
<meta name="keywords" content="eso, FITS format, C library">
<link href="doxygen.css" rel="stylesheet" type="text/css">
<title>qfits 4.0</title>
</head>
<body text="#000000" bgcolor="#ffffff">
<!-- Generated by Doxygen 1.2.5 on Wed Jan 23 15:41:02 2002 -->
<h1>_qfitsloader_ Struct Reference</h1>qfits loader control object.
<a href="#_details">More...</a>
<p>
<code>#include &lt;qfits.h&gt;</code>
<p>
<table border=0 cellpadding=0 cellspacing=0>
<tr><td colspan=2><br><h2>Data Fields</h2></td></tr>
<tr><td nowrap align=right valign=top>int&nbsp;</td><td valign=bottom><a class="el" href="struct__qfitsloader_.html#m0">_init</a></td></tr>
<tr><td nowrap align=right valign=top>char*&nbsp;</td><td valign=bottom><a class="el" href="struct__qfitsloader_.html#m1">filename</a></td></tr>
<tr><td nowrap align=right valign=top>int&nbsp;</td><td valign=bottom><a class="el" href="struct__qfitsloader_.html#m2">xtnum</a></td></tr>
<tr><td nowrap align=right valign=top>int&nbsp;</td><td valign=bottom><a class="el" href="struct__qfitsloader_.html#m3">pnum</a></td></tr>
<tr><td nowrap align=right valign=top>int&nbsp;</td><td valign=bottom><a class="el" href="struct__qfitsloader_.html#m4">ptype</a></td></tr>
<tr><td nowrap align=right valign=top>int&nbsp;</td><td valign=bottom><a class="el" href="struct__qfitsloader_.html#m5">exts</a></td></tr>
<tr><td nowrap align=right valign=top>int&nbsp;</td><td valign=bottom><a class="el" href="struct__qfitsloader_.html#m6">lx</a></td></tr>
<tr><td nowrap align=right valign=top>int&nbsp;</td><td valign=bottom><a class="el" href="struct__qfitsloader_.html#m7">ly</a></td></tr>
<tr><td nowrap align=right valign=top>int&nbsp;</td><td valign=bottom><a class="el" href="struct__qfitsloader_.html#m8">np</a></td></tr>
<tr><td nowrap align=right valign=top>int&nbsp;</td><td valign=bottom><a class="el" href="struct__qfitsloader_.html#m9">bitpix</a></td></tr>
<tr><td nowrap align=right valign=top>int&nbsp;</td><td valign=bottom><a class="el" href="struct__qfitsloader_.html#m10">seg_start</a></td></tr>
<tr><td nowrap align=right valign=top>double&nbsp;</td><td valign=bottom><a class="el" href="struct__qfitsloader_.html#m11">bscale</a></td></tr>
<tr><td nowrap align=right valign=top>double&nbsp;</td><td valign=bottom><a class="el" href="struct__qfitsloader_.html#m12">bzero</a></td></tr>
<tr><td nowrap align=right valign=top>int*&nbsp;</td><td valign=bottom><a class="el" href="struct__qfitsloader_.html#m13">ibuf</a></td></tr>
<tr><td nowrap align=right valign=top>float*&nbsp;</td><td valign=bottom><a class="el" href="struct__qfitsloader_.html#m14">fbuf</a></td></tr>
<tr><td nowrap align=right valign=top>double*&nbsp;</td><td valign=bottom><a class="el" href="struct__qfitsloader_.html#m15">dbuf</a></td></tr>
</table>
<hr><a name="_details"></a><h2>Detailed Description</h2>
qfits loader control object.
<p>
<p>
This structure serves two purposes: input and output for the qfits pixel loading facility. To request pixels from a FITS file, you need to allocate (statically or dynamically) such a structure and fill up the input fields (filename, xtension number, etc.) to specify the pixels you want from the file.
<p>
Before performing the actual load, you must pass the initialized structure to <a class="el" href="qfits_h.html#a39">qfitsloader_init</a>() which will check whether the operation is feasible or not (check its returned value).
<p>
If the operation was deemed feasible, you can proceed to load the pixels, passing the same structure to <a class="el" href="qfits_h.html#a40">qfits_loadpix</a>() which will fill up the output fields of the struct. Notice that a pixel buffer will have been allocated (through malloc or mmap) and placed into the structure. You need to call free() on this pointer when you are done with it, typically in the image or cube destructor.
<p>
The <a class="el" href="qfits_h.html#a39">qfitsloader_init</a>() function is also useful to probe a FITS file for useful informations, like getting the size of images in the file, the pixel depth, or data offset.
<p>
Example of a code that prints out various informations about a plane to load, without actually loading it:
<p>
<div class="fragment"><pre><font class="keywordtype">int</font> main(<font class="keywordtype">int</font> argc, <font class="keywordtype">char</font> * argv[])<font class="keyword"></font>
<font class="keyword"></font>{
<a class="code" href="struct__qfitsloader_.html">qfitsloader</a> ql ;
ql.filename = argv[1] ;
ql.xtnum = 0 ;
ql.pnum = 0 ;
<font class="keywordflow">if</font> (<a class="code" href="qfits_h.html#a39">qfitsloader_init</a>(&amp;ql)!=0) {
printf(<font class="stringliteral">"cannot read info about %s\n"</font>, argv[1]);
<font class="keywordflow">return</font> -1 ;
}
printf( <font class="stringliteral">"file : %s"</font>
<font class="stringliteral">"xtnum : %d"</font>
<font class="stringliteral">"pnum : %d"</font>
<font class="stringliteral">"# xtensions : %d"</font>
<font class="stringliteral">"size X : %d"</font>
<font class="stringliteral">"size Y : %d"</font>
<font class="stringliteral">"planes : %d"</font>
<font class="stringliteral">"bitpix : %d"</font>
<font class="stringliteral">"datastart : %d"</font>
<font class="stringliteral">"bscale : %g"</font>
<font class="stringliteral">"bzero : %g"</font>,
ql.filename,
ql.xtnum,
ql.pnum,
ql.exts,
ql.lx,
ql.ly,
ql.np,
ql.bitpix,
ql.seg_start,
ql.bscale,
ql.bzero);
<font class="keywordflow">return</font> 0 ;
}</div></pre>
<p>
<hr><h2>Field Documentation</h2>
<a name="m0" doxytag="_qfitsloader_::_init"></a><p>
<table width="100%" cellpadding="2" cellspacing="0" border="0">
<tr>
<td class="md">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td nowrap valign="top"><b>
int _qfitsloader_::_init
</b></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing=5 cellpadding=0 border=0>
<tr>
<td>
&nbsp;
</td>
<td>
<p>
Private field to see if structure has been initialized </td>
</tr>
</table>
<a name="m9" doxytag="_qfitsloader_::bitpix"></a><p>
<table width="100%" cellpadding="2" cellspacing="0" border="0">
<tr>
<td class="md">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td nowrap valign="top"><b>
int _qfitsloader_::bitpix
</b></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing=5 cellpadding=0 border=0>
<tr>
<td>
&nbsp;
</td>
<td>
<p>
output: BITPIX for this extension </td>
</tr>
</table>
<a name="m11" doxytag="_qfitsloader_::bscale"></a><p>
<table width="100%" cellpadding="2" cellspacing="0" border="0">
<tr>
<td class="md">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td nowrap valign="top"><b>
double _qfitsloader_::bscale
</b></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing=5 cellpadding=0 border=0>
<tr>
<td>
&nbsp;
</td>
<td>
<p>
output: BSCALE found for this extension </td>
</tr>
</table>
<a name="m12" doxytag="_qfitsloader_::bzero"></a><p>
<table width="100%" cellpadding="2" cellspacing="0" border="0">
<tr>
<td class="md">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td nowrap valign="top"><b>
double _qfitsloader_::bzero
</b></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing=5 cellpadding=0 border=0>
<tr>
<td>
&nbsp;
</td>
<td>
<p>
output: BZERO found for this extension </td>
</tr>
</table>
<a name="m15" doxytag="_qfitsloader_::dbuf"></a><p>
<table width="100%" cellpadding="2" cellspacing="0" border="0">
<tr>
<td class="md">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td nowrap valign="top"><b>
double * _qfitsloader_::dbuf
</b></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing=5 cellpadding=0 border=0>
<tr>
<td>
&nbsp;
</td>
<td>
<p>
output: Pointer to pixel buffer loaded as double values </td>
</tr>
</table>
<a name="m5" doxytag="_qfitsloader_::exts"></a><p>
<table width="100%" cellpadding="2" cellspacing="0" border="0">
<tr>
<td class="md">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td nowrap valign="top"><b>
int _qfitsloader_::exts
</b></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing=5 cellpadding=0 border=0>
<tr>
<td>
&nbsp;
</td>
<td>
<p>
output: Total number of extensions found in file </td>
</tr>
</table>
<a name="m14" doxytag="_qfitsloader_::fbuf"></a><p>
<table width="100%" cellpadding="2" cellspacing="0" border="0">
<tr>
<td class="md">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td nowrap valign="top"><b>
float * _qfitsloader_::fbuf
</b></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing=5 cellpadding=0 border=0>
<tr>
<td>
&nbsp;
</td>
<td>
<p>
output: Pointer to pixel buffer loaded as float values </td>
</tr>
</table>
<a name="m1" doxytag="_qfitsloader_::filename"></a><p>
<table width="100%" cellpadding="2" cellspacing="0" border="0">
<tr>
<td class="md">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td nowrap valign="top"><b>
char * _qfitsloader_::filename
</b></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing=5 cellpadding=0 border=0>
<tr>
<td>
&nbsp;
</td>
<td>
<p>
input: Name of the file you want to read pixels from </td>
</tr>
</table>
<a name="m13" doxytag="_qfitsloader_::ibuf"></a><p>
<table width="100%" cellpadding="2" cellspacing="0" border="0">
<tr>
<td class="md">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td nowrap valign="top"><b>
int * _qfitsloader_::ibuf
</b></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing=5 cellpadding=0 border=0>
<tr>
<td>
&nbsp;
</td>
<td>
<p>
output: Pointer to pixel buffer loaded as integer values </td>
</tr>
</table>
<a name="m6" doxytag="_qfitsloader_::lx"></a><p>
<table width="100%" cellpadding="2" cellspacing="0" border="0">
<tr>
<td class="md">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td nowrap valign="top"><b>
int _qfitsloader_::lx
</b></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing=5 cellpadding=0 border=0>
<tr>
<td>
&nbsp;
</td>
<td>
<p>
output: Size in X of the requested plane </td>
</tr>
</table>
<a name="m7" doxytag="_qfitsloader_::ly"></a><p>
<table width="100%" cellpadding="2" cellspacing="0" border="0">
<tr>
<td class="md">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td nowrap valign="top"><b>
int _qfitsloader_::ly
</b></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing=5 cellpadding=0 border=0>
<tr>
<td>
&nbsp;
</td>
<td>
<p>
output: Size in Y of the requested plane </td>
</tr>
</table>
<a name="m8" doxytag="_qfitsloader_::np"></a><p>
<table width="100%" cellpadding="2" cellspacing="0" border="0">
<tr>
<td class="md">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td nowrap valign="top"><b>
int _qfitsloader_::np
</b></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing=5 cellpadding=0 border=0>
<tr>
<td>
&nbsp;
</td>
<td>
<p>
output: Number of planes present in this extension </td>
</tr>
</table>
<a name="m3" doxytag="_qfitsloader_::pnum"></a><p>
<table width="100%" cellpadding="2" cellspacing="0" border="0">
<tr>
<td class="md">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td nowrap valign="top"><b>
int _qfitsloader_::pnum
</b></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing=5 cellpadding=0 border=0>
<tr>
<td>
&nbsp;
</td>
<td>
<p>
input: Index of the plane you want, from 0 to np-1 </td>
</tr>
</table>
<a name="m4" doxytag="_qfitsloader_::ptype"></a><p>
<table width="100%" cellpadding="2" cellspacing="0" border="0">
<tr>
<td class="md">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td nowrap valign="top"><b>
int _qfitsloader_::ptype
</b></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing=5 cellpadding=0 border=0>
<tr>
<td>
&nbsp;
</td>
<td>
<p>
input: Pixel type you want (PTYPE_FLOAT, PTYPE_INT or PTYPE_DOUBLE) </td>
</tr>
</table>
<a name="m10" doxytag="_qfitsloader_::seg_start"></a><p>
<table width="100%" cellpadding="2" cellspacing="0" border="0">
<tr>
<td class="md">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td nowrap valign="top"><b>
int _qfitsloader_::seg_start
</b></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing=5 cellpadding=0 border=0>
<tr>
<td>
&nbsp;
</td>
<td>
<p>
output: Start of the data segment (in bytes) for your request </td>
</tr>
</table>
<a name="m2" doxytag="_qfitsloader_::xtnum"></a><p>
<table width="100%" cellpadding="2" cellspacing="0" border="0">
<tr>
<td class="md">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td nowrap valign="top"><b>
int _qfitsloader_::xtnum
</b></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing=5 cellpadding=0 border=0>
<tr>
<td>
&nbsp;
</td>
<td>
<p>
input: xtension number you want to read </td>
</tr>
</table>
<hr>The documentation for this struct was generated from the following file:<ul>
<li><a class="el" href="qfits_h.html">qfits.h</a></ul>
</body>
</html>

2301
qfits/include/qfits.h 100644

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,175 @@
/*-------------------------------------------------------------------------*/
/**
@file xmemory.h
@author Nicolas Devillard
@date Oct 2000
@version $Revision: 1.14 $
@brief POSIX-compatible extended memory handling.
xmemory is a small and efficient module offering memory
extension capabitilies to ANSI C programs running on
POSIX-compliant systems. If offers several useful features such
as memory leak detection, protection for free on NULL or
unallocated pointers, and virtually unlimited memory space.
xmemory requires the @c mmap() system call to be implemented in
the local C library to function. This module has been tested on
a number of current Unix flavours and is reported to work fine.
See the documentation attached to this module for more information.
*/
/*--------------------------------------------------------------------------*/
/*
$Id: xmemory.h,v 1.14 2002/01/10 08:53:43 ndevilla Exp $
$Author: ndevilla $
$Date: 2002/01/10 08:53:43 $
$Revision: 1.14 $
*/
#ifndef _XMEMORY_H_
#define _XMEMORY_H_
/*---------------------------------------------------------------------------
Includes
---------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*---------------------------------------------------------------------------
Defines
---------------------------------------------------------------------------*/
/*
The following symbol is useful to know if the current module has been
linked against xmemory.c or not.
*/
#define _XMEMORY_ 1
/*---------------------------------------------------------------------------
Macros
---------------------------------------------------------------------------*/
/*
Protect strdup redefinition on systems which #define it rather than
having it as a function.
*/
#ifdef strdup
#undef strdup
#endif
#define malloc(s) xmemory_malloc(s, __FILE__,__LINE__)
#define calloc(n,s) xmemory_calloc(n,s, __FILE__,__LINE__)
#define free(p) xmemory_free(p, __FILE__,__LINE__)
#define strdup(s) xmemory_strdup(s, __FILE__,__LINE__)
#define falloc(f,o,s) xmemory_falloc(f,o,s, __FILE__,__LINE__)
/*
Trick to have xmemory status display the file name and line where it has
been called.
*/
#define xmemory_status() xmemory_status_(__FILE__,__LINE__)
/*---------------------------------------------------------------------------
Function prototypes
---------------------------------------------------------------------------*/
void * xmemory_malloc(size_t, char *, int);
void * xmemory_calloc(size_t, size_t, char *, int);
void xmemory_free(void *, char *, int);
char * xmemory_strdup(char *, char *, int);
char * xmemory_falloc(char *, size_t, size_t *, char *, int);
/*-------------------------------------------------------------------------*/
/**
@brief Activate xmemory
@return void
This function activates xmemory activity. Make sure it is always
used consistently with xmemory_off().
*/
/*--------------------------------------------------------------------------*/
void xmemory_on(void);
/*-------------------------------------------------------------------------*/
/**
@brief Deactivate xmemory
@return void
This function deactivates xmemory activity. Make sure it is always
used consistently with xmemory_on().
*/
/*--------------------------------------------------------------------------*/
void xmemory_off(void);
/*-------------------------------------------------------------------------*/
/**
@brief Display memory status information.
@return void
This function is meant for debugging purposes, but it is recommended to
call it at the end of every executable making use of the extended memory
features. This function should be called through the xmemory_status()
macro, which provides automatically the name of the source file and line
number where the call happens.
*/
/*--------------------------------------------------------------------------*/
void xmemory_status_(char * filename, int lineno);
/*-------------------------------------------------------------------------*/
/**
@brief Set name of temporary directory for VM files.
@param dirname Name of assigned directory.
@return void
This function assigns a new value for the temporary directory name.
It does not check the directory existence or writability, this is
up to the caller to check that before calling this function.
Provide a directory name without trailing slash, e.g. "/tmp".
*/
/*--------------------------------------------------------------------------*/
void xmemory_settmpdir(char * dirname);
/*-------------------------------------------------------------------------*/
/**
@brief Get name of temporary directory for VM files.
@return pointer to statically allocated string within this module.
This function returns a pointer to an internal (static) string giving the
current name for temporary directory. Do not modify or try to free the
returned string.
*/
/*--------------------------------------------------------------------------*/
char * xmemory_gettmpdir(void);
/*-------------------------------------------------------------------------*/
/**
@brief Map a file's contents to memory as a char pointer.
@param name Name of the file to map
@param offs Offset to the first mapped byte in file.
@param size Returned size of the mapped file in bytes.
@param srcname Name of the source file making the call.
@param srclin Line # where the call was made.
@return A pointer to char, to be freed using xmemory_free().
This function takes in input the name of a file. It tries to map the
file into memory and if it succeeds, returns the file's contents as
a char pointer. It also modifies the input filesize variable to be
the size of the mapped file in bytes. This function is normally
never directly called but through the falloc() macro.
The offset indicates the starting point for the mapping, i.e. if you
are not interested in mapping the whole file but only from a given
place.
*/
/*--------------------------------------------------------------------------*/
char * xmemory_falloc(char * name, size_t offs, size_t * size, char * srcname, int srclin);
#endif
/* vim: set ts=4 et sw=4 tw=75 */

View File

View File

@ -0,0 +1,38 @@
#
# qfits tools Makefile
# N. Devillard
#
#
#
# General definitions
#
include ../config.make
RM = rm -f
CP = cp
MV = mv
BINDIR = ../bin
COMPF = $(CFLAGS) -I../include
LINKF = $(CFLAGS) -L../lib -lqfits
default: all
PROGS= $(BINDIR)/dtfits \
$(BINDIR)/flipx
all: $(PROGS)
veryclean:
@(echo "cleaning qfits programs...")
@($(RM) $(PROGS))
$(BINDIR)/dtfits: dtfits.c
$(CC) $(COMPF) -o $(BINDIR)/dtfits dtfits.c $(LINKF)
$(BINDIR)/flipx: flipx.c
$(CC) $(COMPF) -o $(BINDIR)/flipx flipx.c $(LINKF)

254
qfits/main/dtfits.c 100644
View File

@ -0,0 +1,254 @@
/*---------------------------------------------------------------------------
File name : dtfits.c
Author : N. Devillard
Created on : July 1999
Description : FITS table dump
*--------------------------------------------------------------------------*/
/*
$Id: dtfits.c,v 1.7 2001/12/18 09:32:52 yjung Exp $
$Author: yjung $
$Date: 2001/12/18 09:32:52 $
$Revision: 1.7 $
*/
/*---------------------------------------------------------------------------
Includes
---------------------------------------------------------------------------*/
#include <stdio.h>
#include <string.h>
#include "qfits.h"
/*---------------------------------------------------------------------------
Private declarations
---------------------------------------------------------------------------*/
static int dump_extension(qfits_table * tdesc, FILE * out, char separator,
int data_only, int use_zero_scale) ;
static void qfits_dump(char *, char *, int, char);
static void usage(char *pname) ;
static char prog_desc[] = "FITS table dump" ;
/*----------------------------------------------------------------------------
Main code
---------------------------------------------------------------------------*/
int main(int argc, char *argv[])
{
char name_i[FILENAMESZ] ;
char name_o[FILENAMESZ] ;
int i ;
int data_only ;
char separator ;
data_only = 0 ;
separator = '|' ;
if (argc<2) {
usage(argv[0]);
}
i=1 ;
while (i<argc) {
if (!strcmp(argv[i], "--help") ||
!strcmp(argv[i], "-h")) {
usage(argv[0]);
} else if (!strcmp(argv[i], "-d")) {
data_only=1 ;
} else if (!strcmp(argv[i], "-s")) {
if ((i+1)>=argc) {
fprintf(stderr, "option -s needs an argument\n");
return -1 ;
}
i++ ;
separator = argv[i][0] ;
} else {
break ;
}
i++ ;
}
if ((argc-i)<1) {
fprintf(stderr, "missing input file name\n");
return -1 ;
}
strcpy(name_i, argv[i]);
i++ ;
if ((argc-i)<1) {
name_o[0] = 0 ;
} else {
strcpy(name_o, argv[i]);
}
qfits_dump(name_i, name_o, data_only, separator);
return 0 ;
}
/* This function only gives the usage for the program */
static void usage(char *pname)
{
printf("%s -- %s\n", pname, prog_desc);
printf(
"use : %s [options] <FITS table> [out]\n"
"options are:\n"
"\t-d to dump data only (no headers)\n"
"\t-s <char> to output data with separator <char>\n"
"\n",
pname);
exit(0) ;
}
static void qfits_dump(
char * name_i,
char * name_o,
int data_only,
char separator)
{
qfits_table * tdesc ;
FILE * out ;
int xtnum ;
int n_ext ;
/* Set where to send the output */
if (name_o[0]==(char)0) {
out = stdout ;
} else {
if ((out = fopen(name_o, "w"))==NULL) {
fprintf(stderr, "cannot create output file [%s]\n", name_o);
return ;
}
}
if (!data_only) {
fprintf(out, "#\n");
fprintf(out, "# file %s\n", name_i);
}
/* Query number of extensions in the file */
n_ext = qfits_query_n_ext(name_i);
if (!data_only) {
fprintf(out, "# extensions %d\n", n_ext);
}
/* If no extension, bail out */
if (n_ext<1) {
if (out!=stdout) fclose(out) ;
return ;
}
/* Loop over all extensions */
for (xtnum=1 ; xtnum<=n_ext ; xtnum++) {
if (!data_only) {
fprintf(out, "# --------------------------------------------\n");
fprintf(out, "# XTENSION %d\n", xtnum);
}
if ((tdesc = qfits_table_open(name_i, xtnum)) == NULL) {
printf("cannot open table [%s]:[%d]\n", name_i, xtnum);
if (out!=stdout) fclose(out);
return ;
}
dump_extension(tdesc, out, separator, data_only, 1) ;
qfits_table_close(tdesc);
}
fclose(out) ;
return ;
}
static int dump_extension(
qfits_table * tdesc,
FILE * out,
char separator,
int data_only,
int use_zero_scale)
{
void ** array ;
qfits_col * col ;
char * stw ;
int * sizes ;
char format[512] ;
int i, j ;
if (!data_only) {
fprintf(out, "# Number of columns %d\n", tdesc->nc);
fprintf(out, "#\n");
}
/* Loop over all columns for the current extension */
array = malloc(tdesc->nc * sizeof(void*)) ;
for (i=0 ; i<tdesc->nc ; i++) {
/* Load the data of each column in array[] and find each */
/* column width to justify in the out file. */
if ((array[i] = qfits_query_column_data(tdesc, i, NULL)) == NULL) {
fprintf(stderr, "warning: cannot read column %d\n", i+1) ;
}
}
/* Get the sizes of the columns */
sizes = calloc(tdesc->nc, sizeof(int)) ;
for (i=0 ; i<tdesc->nc ; i++) {
if (array[i] == NULL) sizes[i] = 0 ;
else {
for (j=0 ; j<tdesc->col->nelem ; j++) {
if ((stw = qfits_table_field_to_string(tdesc,
i,
j,
array[i],
use_zero_scale)) == NULL) {
sizes[i] = 0 ;
break ;
} else {
if (sizes[i] < (int)strlen(stw)) {
sizes[i] = (int)strlen(stw) ;
}
}
}
}
}
/* Print out the column names */
if (!data_only) {
for (i=0 ; i<tdesc->nc ; i++) {
col = tdesc->col + i ;
if (sizes[i] != 0) {
if (sizes[i] < strlen(col->tlabel))
sizes[i] = (int)strlen(col->tlabel) ;
sprintf(format, "%%%ds", sizes[i]) ;
fprintf(out, format, col->tlabel);
if (i!=(tdesc->nc-1)) printf("%c", separator);
}
}
fprintf(out, "\n");
}
/* Dump all columns, line by line */
col = tdesc->col ;
for (j=0 ; j<col->nelem ; j++) {
for (i=0 ; i<tdesc->nc ; i++) {
col = tdesc->col + i ;
if ((stw = qfits_table_field_to_string(tdesc,
i,
j,
array[i],
use_zero_scale)) != NULL) {
sprintf(format, "%%%ds", sizes[i]) ;
fprintf(out, format, stw);
if (i!=(tdesc->nc-1)) printf("%c", separator);
}
}
fprintf(out, "\n");
}
for (i=0 ; i<tdesc->nc ; i++) {
if (array[i] != NULL) free(array[i]);
}
free(array) ;
free(sizes) ;
return 0 ;
}

189
qfits/main/flipx.c 100644
View File

@ -0,0 +1,189 @@
/*---------------------------------------------------------------------------
File name : flipx.c
Author : N. Devillard
Created on : July 2001
Description : flip x axis in a FITS image.
This is an example use of the qfits library. This program expects
a list of FITS file names in input. For each input file, it will
flip the image contained in the main data section in the X direction,
i.e. pixel (i,j) is swapped with pixel (lx-i, j).
The pixel loading mechanism is independent from endian-ness of the
local host or FITS pixel type. This program offers a good overview
of how to use qfits for pixel-level operations.
Notice that this program does not support cubes or image extensions,
but could be easily extended to support that case.
*--------------------------------------------------------------------------*/
/*
$Id: flipx.c,v 1.1 2001/12/14 09:53:21 ndevilla Exp $
$Author: ndevilla $
$Date: 2001/12/14 09:53:21 $
$Revision: 1.1 $
*/
/*---------------------------------------------------------------------------
Includes
---------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include "qfits.h"
/*---------------------------------------------------------------------------
Macros
---------------------------------------------------------------------------*/
#define ERRMSG(s) fprintf(stderr, "\tflipx error: %s\n", s)
/*---------------------------------------------------------------------------
Private functions
---------------------------------------------------------------------------*/
/*
* Swap pixels between position p1 and p2, regardless of the pixel
* type and endian-ness of the local host.
*/
static void swap_pix(char * buf, int p1, int p2, int psize)
{
int i ;
char c ;
for (i=0 ; i<psize ; i++) {
c = buf[p1+i] ;
buf[p1+i] = buf[p2+i];
buf[p2+i] = c ;
}
}
/*
* Main processing function. It expects one only file name
* and will flip pixels on the input frame.
*/
static int fits_flip(char * pname, char * filename)
{
char * sval ;
int dstart;
int lx, ly ;
int bpp ;
int i, j ;
char * buf ;
char * fbuf ;
int psize;
struct stat fileinfo ;
int fd ;
printf("%s: processing %s\n", pname, filename);
if (stat(filename, &fileinfo)!=0) {
return -1 ;
}
if (fileinfo.st_size<1) {
ERRMSG("cannot stat file");
return -1 ;
}
/* Retrieve image attributes */
if (is_fits_file(filename)!=1) {
ERRMSG("not a FITS file");
return -1 ;
}
sval = qfits_query_hdr(filename, "NAXIS1");
if (sval==NULL) {
ERRMSG("cannot read NAXIS1");
return -1 ;
}
lx = atoi(sval);
sval = qfits_query_hdr(filename, "NAXIS2");
if (sval==NULL) {
ERRMSG("cannot read NAXIS2");
return -1 ;
}
ly = atoi(sval);
sval = qfits_query_hdr(filename, "BITPIX");
if (sval==NULL) {
ERRMSG("cannot read BITPIX");
return -1 ;
}
bpp = atoi(sval);
psize = bpp/8 ;
if (psize<0) psize=-psize ;
/* Retrieve start of first data section */
if (qfits_get_hdrinfo(filename, 0, &dstart, NULL)!=0) {
ERRMSG("reading header information");
return -1 ;
}
/* Map the input file in read/write mode (input file is modified) */
if ((fd=open(filename, O_RDWR))==-1) {
perror("open");
ERRMSG("reading file");
return -1 ;
}
fbuf = (char*)mmap(0,
fileinfo.st_size,
PROT_READ | PROT_WRITE,
MAP_SHARED,
fd,
0);
if (fbuf==(char*)-1) {
perror("mmap");
ERRMSG("mapping file");
return -1 ;
}
buf = fbuf + dstart ;
/* Double loop */
for (j=0 ; j<ly ; j++) {
for (i=0 ; i<lx/2 ; i++) {
/* Swap bytes */
swap_pix(buf, i*psize, (lx-i-1)*psize, psize);
}
buf += lx * psize ;
}
if (munmap(fbuf, fileinfo.st_size)!=0) {
ERRMSG("unmapping file");
return -1 ;
}
return 0 ;
}
/*---------------------------------------------------------------------------
main()
---------------------------------------------------------------------------*/
int main(int argc, char * argv[])
{
int i ;
int err ;
if (argc<2) {
printf("use: %s <list of FITS files...>\n", argv[0]);
return 1 ;
}
err=0 ;
for (i=1 ; i<argc ; i++) {
err += fits_flip(argv[0], argv[i]) ;
}
if (err>0) {
fprintf(stderr, "%s: %d error(s) occurred\n", argv[0], err);
return -1 ;
}
return 0 ;
}

View File

@ -0,0 +1,319 @@
"""
Qfits.py: a module to read header information from a FITS file.
This module offers a function to read all headers in a given
FITS file and return them as a list of strings.
"""
# $Id: Qfits.py,v 1.9 2002/01/08 09:41:47 ndevilla Exp $
# $Author: ndevilla $
# $Date: 2002/01/08 09:41:47 $
# $Revision: 1.9 $
import qfits
def get_headers(filename):
"""
This function is the main operator in this module.
Given a file name, it returns all header informations
in a list of lists. The top list contains one element
per found header, i.e. if the given file has 8 extensions,
the top list contains 9 items (1 for the main header,
8 for the extension headers). Each list contains
in turn all informations about the corresponding
headers as a list of tuples like
(key, value, comment)
Example:
The given FITS file contains 1 main header and 2
extension headers given as follows:
--- main header
SIMPLE = T / FITS format
BITPIX = 8 / Bits per pixel
NAXIS = 0 / No data
...
END
--- extension 1
XTENSION = 'IMAGE' / Image extension
BITPIX = 16 / Bits per pixel
...
END
--- extension 2
XTENSION = 'IMAGE' / Image extension
BITPIX = -32 / Bits per pixel
...
END
The returned list contains three items.
The first one is a list corresponding to the
main header, then come the two extension
headers. The first list looks like:
[ ('SIMPLE','T','FITS format'),
('BITPIX', '8', 'Bits per pixel'),
('NAXIS', '0', 'No data'),
...
('END', '', '') ]
The extension lists look like this:
[ ('XTENSION', 'IMAGE', 'Image extension'),
('BITPIX', '16', 'Bits per pixel'),
...
('END', '', '') ]
[ ('XTENSION', 'IMAGE', 'Image extension'),
('BITPIX', '-32', 'Bits per pixel'),
...
('END', '', '') ]
In summary, if you want to get all FITS header informations
from a FITS file, call this function with:
hdr = qfits.get_headers(filename)
This function will raise an IOError exception if the provided
filename does not correspond to a valid file, and None if
the file is not FITS.
If the load succeeded, you can access individual keywords
with the following syntax:
hdr[extension][row][index]
Where:
extension runs from 0 to N_EXT (inclusive)
row is the row number of the card
index is 0 for the keyword, 1 for the value, 2 for the comment.
The number of FITS extensions found in the file is simply:
len(hdr)-1
"""
return qfits.get_headers(filename)
def expand_keyword(key):
"""
This function is useful to expand a given keyword into
its FITS equivalent. What it does is simply bring the
word to uppercase, then expand shortFITS words to HIERARCH
ESO notation, like:
simple -> SIMPLE
NaXiS -> NAXIS
det.dit -> HIERARCH ESO DET DIT
"""
return qfits.expand_keyword(key)
def datamd5(filename):
"""
This function computes the MD5 signature of all data parts in a FITS
file and returns a 32-char string containing the signature as an
hexadecimal number (128 bits). It raises an IOError exception if the
given filename does not correspond to a valid FITS file.
"""
return qfits.datamd5(filename)
def version():
"""
This function returns the version number of the
underlying qfits module.
"""
return qfits.version()
class fitsinfo:
"""
The fitsinfo class encapsulates queries into a FITS header.
Initialize an instance by giving the name of a file, the following
fields are then filled in:
- filename - Name of the file
- n_ext - Number of FITS extensions in file
- hdrs - List of headers
- xtnum - Current extension number for get()
The following methods are offered:
* get()
This method retrieves keyword information in a given instance.
Provide one or more keywords to look for and this function will
browse the hdrs list for matching keywords. This method returns a
string if you requested only 1 keyword or a list of strings if you
requested several keywords. A failed match returns None.
This method will only search for keywords in the xtnum extension.
get() supports the shortFITS notation, in which A.B.C is transformed
into HIERARCH ESO A B C before lookup in the FITS header. Notice that
the given strings are also converted to uppercase before the search
is launched. See the function expand_keyword() in this module.
Returned string values are always pretty-formatted, i.e. something
stored into a FITS string as 'o''hara' will be returned as o'hara.
Examples:
q = fitsinfo('vltframe.fits')
q.get('simple') # returns 'T'
q.get('simple', 'naxis') # returns ('T', '2')
To search for keywords in the 3rd extension:
q = fitsinfo('wfiframe.fits')
q.xtnum = 3
q.get('xtension') # returns 'IMAGE'
q.get('det.chip3.id', 'bitpix')
# returns ('ccd52', '16')
* datamd5()
This method computes the MD5 signature of all the data parts of the
given FITS file and returns it as a 32-char string containing a
hexadecimal number on 128 bits.
"""
def __init__(self, filename):
"""
Provide a filename to initialize the object.
"""
self.filename = filename
self.hdrs = qfits.get_headers(filename)
if not self.hdrs:
raise IOError, "not a FITS file"
self.n_ext = len(self.hdrs)-1
self.xtnum = 0
def get(self, *keywords):
"""
Get a list of keyword values and return it as a list. If only one
keyword is requested, the returned value is a single string (or
None if the keyword was not found). If several keywords are passed,
the returned value is a list of found values.
The search is only performed in the current extension (xtnum field
in the class).
"""
retval = []
for keyword in keywords:
keyword = qfits.expand_keyword(keyword)
if len(keyword)<1:
retval.append(None)
continue
found=0
for k in self.hdrs[self.xtnum]:
if k[0] == keyword:
found=1
retval.append(k[1])
break
if not found:
retval.append(None)
if len(retval)==1:
return retval[0]
return retval
def __repr__(self):
return "file: %s - %d extensions" % (self.filename, self.n_ext)
def datamd5(self):
return qfits.datamd5(self.filename)
if __name__ == '__main__':
# This short code demonstrates the module capabilities
import string, sys
if len(sys.argv)<2:
print "provide a FITS file name as first argument"
raise SystemExit
filename = sys.argv[1]
try:
# Try building an instance of fitsinfo
q = fitsinfo(filename)
except IOError:
print "cannot read file", filename
raise SystemExit
# Demonstrate string representation of the instance
print `q`
# Compute the DATAMD5 value for this file
print "computing DATAMD5 for", q.filename, "..."
md5hash = q.datamd5()
print "DATAMD5 = '"+md5hash+"'"
# Dump the first 3 cards in each header to console to show they have
# been correctly loaded.
xtnum=0
for h in q.hdrs:
print "-"*65
print "header beginning for %s (ext %d):" % (q.filename, xtnum)
print "-"*65
for card in [h[0], h[1], h[2]]:
print "key[%s] val[%s] com[%s]" % (card[0], card[1], card[2])
print "..."
print "-"*65
xtnum = xtnum+1
#
# And now, for something completely different...
#
# An interesting example: transform a list of fetched keywords into a
# dictionary for easier parsing. The idea is to build a dictionary-like
# object that will allow queries into FITS headers like:
# lx, ly = d["naxis1"], d["naxis2"]
# Get Python version
pyver = string.split(sys.version[:3], '.')
# Until Python 2.1, dictionaries (as all built-in types) cannot be
# directly subclassed but through the UserDict module.
if pyver < ['2','2']:
print "using Python version < 2.2 (%s)" % (sys.version[:3])
# Import the UserDict module to enable method overloading.
from UserDict import UserDict
# Build a class derived from the dictionary.
class FITSdic(UserDict):
# A query will pass the key through expand_keyword to make sure
# we can request something using lowercase and shortFITS
# notation.
def __getitem__(self, key):
return self.data[qfits.expand_keyword(key)]
else:
# Starting with Python 2.2, dictionaries can directly be subclassed.
print "using Python version >= 2.2 (%s)" % (sys.version[:3])
class FITSdic(dict):
# A query will pass the key through expand_keyword to make sure
# we can request something using lowercase and shortFITS
# notation.
def __getitem__(self, key):
return dict.__getitem__(self, qfits.expand_keyword(key))
# Create one instance
d = FITSdic()
# Fill it up with values from the previously loaded main header
for card in q.hdrs[0]:
d[card[0]] = card[1]
# Now show keywords stored in a dictionary.
# Protect against keys that are not in dictionary (raises KeyError):
print "Main header info:"
try:
print "SIMPLE=", d["simple"]
print "BITPIX=", d["bitpix"]
print "NAXIS =", d["naxis"]
print "RA =", d["ra"]
print "DEC =", d["dec"]
except KeyError, key:
print "Key", key, "not found in header"
# That's all folks
print "end of Qfits demo"

140
qfits/python/README 100644
View File

@ -0,0 +1,140 @@
python/qfits interface
----------------------
Installation
------------
qfits is interfaced to Python as a C module to compile
dynamically, and a high-level interface called Qfits.py. To build
the module, you need the distutils module from Python (standard
since version 2.0). The setup.py script takes care of all the
gory details related to the compilation of a dynamic module for
Python. To build, type:
% python setup.py build
This will create a build/ directory containing the compiled
objects and the dynamic library. You can test it by going into
the directory containing qfits.so, launching python and trying to
import the module. This is how it appears on our Linux box:
% cd build/lib.linux-i686-2.1
% python
Python 2.1 (#1, Apr 27 2001, 17:19:41)
[GCC 2.95.3 19991030 (prerelease)] on linux2
Type "copyright", "credits" or "license" for more information.
>>> import qfits
>>> print qfits.version()
>>> 4.0
To install the module in your Python installation, go back to the
qfits root directory (where the setup.py script lives) and type:
% python setup.py install
This will install the qfits.so and Qfits.py files into your
Python tree, provided you have the access rights to do so.
If you do not have the distutils module (e.g. your Python
installation is 1.5 or older), you are in trouble :-)
Simplest is probably either to switch to a newer Python release
or to install a recent version of distutils on your machine. If
you really cannot afford upgrading Python or installing
distutils, there is still a possible handcrafted solution: build
the shared library by yourself and install it where it should.
Something along the lines of:
1. Make the library normally (make).
2. Compile the Python wrapper in relocatable mode, something like:
% gcc -fpic -o src/qfits_wrap.o src/qfits_wrap.c [...]
You also need to specify a path to the Python include files in this
command-line, e.g. if Python lives under /usr/python on your machine,
you would add something like:
-I/usr/python/include/python1.5
3. Now you should have all qfits objects (src/*.o) compiled, including the
wrapper file. You are ready to build a shared library. On Linux, this
gives something like that:
% ld -shared -o lib/qfits.so src/*.o
4. Try it the newly compiled module:
% cd lib
% python
% import qfits
At that point, Python should load the qfits.so module in the current
directory without complaint. If everything is Ok, you should be able
to issue the following command:
>>> qfits.version()
5. Copy now the shared object and Qfits.py files to wherever your
Python installation expects libraries to be found. This can be
anywhere within your Python tree or any directory you like
provided it is declared in your PYTHONPATH. Try now:
% python
>>> import Qfits
If everything went fine, you should not get any error.
Usage
-----
The qfits.so shared library offers a number of FITS-header
parsing services from the qfits library. Not all functionalities
are present, though, only the ones related to FITS header parsing
and browsing. If you really need to access and modify pixels from
the Python level, you are doing something wrong: Python is a very
high-level language not intended for pixel-level operations. If
you need that level of functionality, do it in C.
To protect Python code from changes happening in the C library,
the interface to use is not "qfits" but "Qfits", so in your code
you should have written:
import Qfits
and not:
import qfits
The former is a pure Python interface offering a number of
functions and classes to deal with FITS headers. The latter is
the wrapper interface to the qfits C library. Any change
happening at low-level in qfits will be propagated to Qfits so as
to maintain a fixed programming interface. In theory, you should
never have to rewrite code depending on Qfits.py unless there are
major changes in there (as e.g. between qfits-3.0 and qfits-4.0).
Class documentation
-------------------
To get an overview of the classes and services offered by
Qfits.py, read its docstrings. Example:
>>> import Qfits
>>> print Qfits.__doc__
The docstrings are also readable from 'pydoc' if this tool is
installed on your machine. It allows to browse the documentation
in a Web browser on your local machine and supports complex
searches.
Enjoy Qfits!
N. Devillard
Mon Dec 10 14:00:05 CET 2001

View File

@ -0,0 +1,59 @@
#
# Stand-alone FITS tools Makefile
# N. Devillard
#
#
#
# General definitions
#
include ../config.make
RM = rm -f
CP = cp
MV = mv
BINDIR = ../bin
default: all
PROGS = $(BINDIR)/dfits \
$(BINDIR)/fitsort \
$(BINDIR)/hierarch28 \
$(BINDIR)/iofits \
$(BINDIR)/replacekey \
$(BINDIR)/fitsmd5
all: $(PROGS)
veryclean:
@(echo "cleaning saft programs...")
@($(RM) $(PROGS))
$(BINDIR)/dfits: dfits.c
@(echo "building $@ ...")
@($(CC) $(CFLAGS) $(LFLAGS) -o $(BINDIR)/dfits dfits.c)
$(BINDIR)/fitsort: fitsort.c
@(echo "building $@ ...")
@($(CC) $(CFLAGS) $(LFLAGS) -o $(BINDIR)/fitsort fitsort.c)
$(BINDIR)/hierarch28: hierarch28.c
@(echo "building $@ ...")
@($(CC) $(CFLAGS) $(LFLAGS) -o $(BINDIR)/hierarch28 hierarch28.c)
$(BINDIR)/iofits: iofits.c
@(echo "building $@ ...")
@($(CC) $(CFLAGS) $(LFLAGS) -o $(BINDIR)/iofits iofits.c)
$(BINDIR)/replacekey: replacekey.c
@(echo "building $@ ...")
@($(CC) $(CFLAGS) $(LFLAGS) -o $(BINDIR)/replacekey replacekey.c)
$(BINDIR)/fitsmd5: fitsmd5.c
@(echo "building $@ ...")
@($(CC) $(CFLAGS) $(LFLAGS) -o $(BINDIR)/fitsmd5 fitsmd5.c)

219
qfits/saft/dfits.c 100644
View File

@ -0,0 +1,219 @@
/*---------------------------------------------------------------------------
File name : dfits.c
Author : Nicolas Devillard
Created on : 30 Mar 2000
Description : FITS header display
Initial version from 1996.
Rewritten from scratch to support FITS extensions.
--------------------------------------------------------------------------*/
/*
$Id: dfits.c,v 1.1 2001/12/14 09:15:19 ndevilla Exp $
$Author: ndevilla $
$Date: 2001/12/14 09:15:19 $
$Revision: 1.1 $
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LGTH 80
#define MAGIC "SIMPLE ="
void usage(char * pname);
void parse_cmd_line(int, char **, int*, int*, int*);
int dump_fits_filter(FILE*, int);
int dump_fits(char *, int);
char * rstrip(char *);
/*--------------------------------------------------------------------------*/
int main(int argc, char *argv[])
{
int xtnum ;
int c_arg ;
int filter ;
int err ;
/* No arguments prints out a usage message */
if (argc<2) {
usage(argv[0]);
return 1 ;
}
/* Parse command-line options */
parse_cmd_line(argc, argv, &xtnum, &filter, &c_arg);
/* Filter mode: process data received from stdin */
if (filter)
return dump_fits_filter(stdin, xtnum);
/* Normal mode: loop on all file names given on command-line */
err = 0 ;
while (c_arg < argc) {
err += dump_fits(argv[c_arg], xtnum);
c_arg++;
}
return err ; /* Returns number of errors during process */
}
void usage(char * pname)
{
printf(
"\n\n"
"usage: %s [-x xtnum] <list of FITS files>\n"
"usage: %s [-x xtnum] -\n"
"\n"
"The former version expects file names.\n"
"The latter expects data coming in from stdin.\n"
"\n"
"-x xtnum specifies the extension header to print\n"
"-x 0 specifies main header + all extensions\n"
"\n\n",
pname, pname);
}
void parse_cmd_line(
int argc,
char ** argv,
int * xtnum,
int * filter,
int * c_arg
)
{
*filter = 0;
*xtnum = -1 ;
*c_arg = argc-1 ;
/* If '-' is on the command-line, it must be the last argument */
if (!strcmp(argv[argc-1], "-")) {
*filter = 1 ;
}
/*
* If -x xtnum is on the command-line, it must be the first two
* arguments
*/
if (!strcmp(argv[1], "-x")) {
*xtnum = atoi(argv[2]);
*c_arg = 3 ;
} else {
*c_arg = 1 ;
}
return ;
}
/*
* Strip off all blank characters in a string from the right-side.
*/
char * rstrip(char * s)
{
int len ;
if (s==NULL) return s ;
len = strlen(s);
if (len<1) return s ;
len -- ;
while (s[len]== ' ') {
s[len]=(char)0 ;
len --;
}
return s ;
}
/*
* Dump the requested header (main or extension) from a filename.
*/
int dump_fits(char * name, int xtnum)
{
FILE * in ;
int err ;
if ((in=fopen(name, "r"))==NULL) {
fprintf(stderr, "error: cannot open file [%s]\n", name);
return 1 ;
}
printf("====> file %s (main) <====\n", name) ;
err = dump_fits_filter(in, xtnum);
fclose(in);
return err ;
}
/*
* Dump the requested header (main or extension) from a FILE *
*/
int dump_fits_filter(FILE * in, int xtnum)
{
int n_xt ;
char buf[LGTH+1];
int err ;
/* Try getting the first 80 chars */
memset(buf, 0, LGTH+1);
if (fread(buf, sizeof(char), LGTH, in)!=LGTH) {
fprintf(stderr, "error reading input\n");
return 1;
}
/* Check that it is indeed FITS */
if (strncmp(buf, MAGIC, strlen(MAGIC))) {
fprintf(stderr, "not a FITS file\n");
return 1 ;
}
if (xtnum<1) {
/* Output main header */
printf("%s\n", rstrip(buf));
while ((err=fread(buf, sizeof(char), LGTH, in))==LGTH) {
printf("%s\n", rstrip(buf));
if (buf[0]=='E' &&
buf[1]=='N' &&
buf[2]=='D') {
break ;
}
}
if (err!=LGTH) /* Read error */
return 1 ;
}
if (xtnum<0)
return 0 ;
n_xt=0 ;
while (1) {
/* Look for next XTENSION keyword */
while ((err=fread(buf, sizeof(char), LGTH, in))==LGTH) {
if (buf[0]=='X' &&
buf[1]=='T' &&
buf[2]=='E' &&
buf[3]=='N' &&
buf[4]=='S' &&
buf[5]=='I' &&
buf[6]=='O' &&
buf[7]=='N') break ;
}
if (err==0) /* Nothing more to read */
break ;
if (err!=LGTH) /* Read error */
return 1 ;
n_xt++ ;
if (xtnum==0 || xtnum==n_xt) {
printf("====> xtension %d\n", n_xt) ;
printf("%s\n", rstrip(buf));
while ((err=fread(buf, sizeof(char), LGTH, in))==LGTH) {
printf("%s\n", rstrip(buf));
if (buf[0]=='E' &&
buf[1]=='N' &&
buf[2]=='D') break ;
}
}
if (n_xt==xtnum)
break ;
}
return 0 ;
}

View File

@ -0,0 +1,763 @@
/*----------------------------------------------------------------------------
File name : fitsmd5.c
Author : N. Devillard
Created on : May 2001
Description : Display/Add/Update the DATAMD5 keyword/value
This is a stand-alone utility. Compile it with any ANSI C compiler:
% cc -o fitsmd5 fitsmd5.c [optional optimization options]
---------------------------------------------------------------------------*/
/*
$Id: fitsmd5.c,v 1.1 2001/12/14 09:15:19 ndevilla Exp $
$Author: ndevilla $
$Date: 2001/12/14 09:15:19 $
$Revision: 1.1 $
*/
/*----------------------------------------------------------------------------
Includes
---------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
/*----------------------------------------------------------------------------
Defines
---------------------------------------------------------------------------*/
/* Definitions related to FITS */
#define FITSLINESZ 80 /* a FITS line is 80 chars */
#define FITSCARDS 36 /* 36 cards per block */
#define FITSBLOCKSZ (FITSLINESZ*FITSCARDS) /* FITS block size=2880 */
/* Definitions related to MD5 */
#define MD5HASHSZ 32 /* an MD5 key length is 32 bytes = 128 bits */
/* FITS keyword used to store MD5 key */
#define FITSMD5KEY "DATAMD5 "
/*----------------------------------------------------------------------------
New types
---------------------------------------------------------------------------*/
/* The following types defined for MD5 computation only */
typedef unsigned int word32 ;
struct MD5Context {
word32 buf[4];
word32 bits[2];
unsigned char in[64];
};
/*----------------------------------------------------------------------------
Private function prototypes
---------------------------------------------------------------------------*/
static void MD5Init(struct MD5Context *);
static void MD5Update(struct MD5Context *, unsigned char *, unsigned);
static void MD5Final(unsigned char *, struct MD5Context *);
static void MD5Transform(word32 *, word32 *);
static void byteReverse(unsigned char *, unsigned);
static int fits_md5_check(char *, int);
static char * fits_pretty_string(char *);
static char * fits_getvalue(char *);
static void usage(void);
/*----------------------------------------------------------------------------
Global variables
---------------------------------------------------------------------------*/
static char * pname = NULL ;
static char prog_desc[] = "Compute/Update the DATAMD5 keyword/value" ;
static int silent_process=0 ;
/*----------------------------------------------------------------------------
MD5 function code
---------------------------------------------------------------------------*/
/*
* Reverse bytes in a 32-bit word. This code is harmless on little endian
* machines.
*/
static void byteReverse(unsigned char *buf, unsigned longs)
{
word32 t;
do {
t = (word32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
((unsigned) buf[1] << 8 | buf[0]);
*(word32 *) buf = t;
buf += 4;
} while (--longs);
}
/*
* Start MD5 accumulation. Set bit count to 0 and buffer to MD5
* initialization constants.
*/
static void MD5Init(struct MD5Context *ctx)
{
ctx->buf[0] = 0x67452301;
ctx->buf[1] = 0xefcdab89;
ctx->buf[2] = 0x98badcfe;
ctx->buf[3] = 0x10325476;
ctx->bits[0] = 0;
ctx->bits[1] = 0;
}
/*
* Update context to reflect the concatenation of another buffer full
* of bytes.
*/
static void MD5Update(struct MD5Context *ctx, unsigned char *buf, unsigned len)
{
register word32 t;
/* Update bitcount */
t = ctx->bits[0];
if ((ctx->bits[0] = t + ((word32) len << 3)) < t)
ctx->bits[1]++; /* Carry from low to high */
ctx->bits[1] += len >> 29;
t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
/* Handle any leading odd-sized chunks */
if (t) {
unsigned char *p = (unsigned char *) ctx->in + t;
t = 64 - t;
if (len < t) {
memmove(p, buf, len);
return;
}
memmove(p, buf, t);
byteReverse(ctx->in, 16);
MD5Transform(ctx->buf, (word32 *) ctx->in);
buf += t;
len -= t;
}
/* Process data in 64-byte chunks */
while (len >= 64) {
memmove(ctx->in, buf, 64);
byteReverse(ctx->in, 16);
MD5Transform(ctx->buf, (word32 *) ctx->in);
buf += 64;
len -= 64;
}
/* Handle any remaining bytes of data. */
memmove(ctx->in, buf, len);
}
/*
* Final wrapup - pad to 64-byte boundary with the bit pattern
* 1 0* (64-bit count of bits processed, MSB-first)
*/
static void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
{
unsigned int count;
unsigned char *p;
/* Compute number of bytes mod 64 */
count = (ctx->bits[0] >> 3) & 0x3F;
/* Set the first char of padding to 0x80. This is safe since there is
always at least one byte free */
p = ctx->in + count;
*p++ = 0x80;
/* Bytes of padding needed to make 64 bytes */
count = 64 - 1 - count;
/* Pad out to 56 mod 64 */
if (count < 8) {
/* Two lots of padding: Pad the first block to 64 bytes */
memset(p, 0, count);
byteReverse(ctx->in, 16);
MD5Transform(ctx->buf, (word32 *) ctx->in);
/* Now fill the next block with 56 bytes */
memset(ctx->in, 0, 56);
} else {
/* Pad block to 56 bytes */
memset(p, 0, count - 8);
}
byteReverse(ctx->in, 14);
/* Append length in bits and transform */
((word32 *) ctx->in)[14] = ctx->bits[0];
((word32 *) ctx->in)[15] = ctx->bits[1];
MD5Transform(ctx->buf, (word32 *) ctx->in);
byteReverse((unsigned char *) ctx->buf, 4);
memmove(digest, ctx->buf, 16);
memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
}
/* The four core functions - F1 is optimized somewhat */
/* #define F1(x, y, z) (x & y | ~x & z) */
#define F1(x, y, z) (z ^ (x & (y ^ z)))
#define F2(x, y, z) F1(z, x, y)
#define F3(x, y, z) (x ^ y ^ z)
#define F4(x, y, z) (y ^ (x | ~z))
/* This is the central step in the MD5 algorithm. */
#define MD5STEP(f, w, x, y, z, data, s) \
( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
/*
* The core of the MD5 algorithm, this alters an existing MD5 hash to
* reflect the addition of 16 longwords of new data. MD5Update blocks
* the data and converts bytes into longwords for this routine.
*/
static void MD5Transform(word32 buf[4], word32 in[16])
{
register word32 a, b, c, d;
a = buf[0];
b = buf[1];
c = buf[2];
d = buf[3];
MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
buf[0] += a;
buf[1] += b;
buf[2] += c;
buf[3] += d;
}
/*----------------------------------------------------------------------------
FITS-related functions
---------------------------------------------------------------------------*/
/* Pretty-print a FITS string value */
static char * fits_pretty_string(char * s)
{
static char pretty[FITSLINESZ+1] ;
int i,j ;
if (s==NULL) return NULL ;
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;
}
/* Get the FITS value in a FITS card */
static char * fits_getvalue(char * line)
{
static char value[FITSLINESZ+1] ;
int i ;
int from, to ;
int inq ;
if (line==NULL) {
return NULL ;
}
memset(value, 0, FITSLINESZ+1);
/* Get past the keyword */
i=0 ;
while (line[i]!='=' && i<FITSLINESZ) i++ ;
if (i>FITSLINESZ) {
return NULL ;
}
i++ ;
while (line[i]==' ' && i<FITSLINESZ) i++ ;
if (i>FITSLINESZ) {
return NULL ;
}
from=i;
/*
* Now in the value section
* Look for the first slash '/' outside of a string
*/
inq = 0 ;
while (i<FITSLINESZ) {
if (line[i]=='\'')
inq=!inq ;
if (line[i]=='/')
if (!inq)
break ;
i++;
}
i-- ;
/* Backtrack on blanks */
while (line[i]==' ' && i>=0) i-- ;
if (i<0) {
return NULL ;
}
to=i ;
if (to<from) {
return NULL ;
}
/* Copy relevant characters into output buffer */
strncpy(value, line+from, to-from+1);
/* Null-terminate the string */
value[to-from+1] = (char)0;
/*
* Make it pretty: remove head and tail quote, change double
* quotes to simple ones.
*/
strcpy(value, fits_pretty_string(value));
return value ;
}
/* Replace the MD5 card in the input header */
static int fits_replace_card(char * filename, int off_md5, char * datamd5)
{
char * buf ;
int fd ;
struct stat sta ;
char card[FITSLINESZ];
int i ;
int err ;
/* Get file size */
if (stat(filename, &sta)==-1) {
fprintf(stderr, "%s: cannot stat file [%s]: no update done\n",
pname,
filename);
return 1 ;
}
/* Open file */
fd = open(filename, O_RDWR);
if (fd==-1) {
fprintf(stderr,
"%s: cannot open file [%s] for modification: no update done\n",
pname,
filename);
return 1 ;
}
/* Memory-map the file */
buf = (char*)mmap(0,
sta.st_size,
PROT_READ | PROT_WRITE,
MAP_SHARED,
fd,
0);
if (buf==(char*)-1 || buf==NULL) {
perror("mmap");
close(fd);
return 1 ;
}
/* sprintf should be safe, the MD5 signature size is 32 chars */
sprintf(card, "%s= '%s' / data MD5 signature", FITSMD5KEY, datamd5);
i=FITSLINESZ-1 ;
while (card[i]!='e') {
card[i]=' ';
i-- ;
}
/* Copy card into file */
memcpy(buf+off_md5, card, FITSLINESZ);
/* flush output, unmap buffer, close file and quit */
err=0 ;
sync();
if (close(fd)==-1) {
fprintf(stderr, "%s: error closing modified file [%s]",
pname,
filename);
err++ ;
}
if (munmap(buf, sta.st_size)==-1) {
perror("munmap");
err++ ;
}
return err;
}
/* Display or modify the DATAMD5 value. Returns the number of errors. */
static int fits_md5_check(char * filename, int update_header)
{
FILE * in ;
char buf[FITSBLOCKSZ];
char * buf_c ;
int i ;
int in_header ;
char * hdrmd5 ;
struct MD5Context ctx ;
unsigned char digest[16] ;
static char datamd5[MD5HASHSZ+1];
int off_md5 ;
int cur_off ;
int md5keysz ;
int err ;
int check_fits ;
struct stat sta ;
if (filename==NULL) return 1 ;
/* Try to stat file */
if (stat(filename, &sta)!=0) {
fprintf(stderr, "%s: cannot stat file %s\n", pname, filename);
return 1 ;
}
/* See if this is a regular file */
if (!S_ISREG(sta.st_mode)) {
fprintf(stderr, "%s: not a regular file: %s\n", pname, filename);
return 1 ;
}
/* Open input file */
if ((in=fopen(filename, "r"))==NULL) {
fprintf(stderr, "%s: cannot open file [%s]\n", pname, filename);
return 1 ;
}
/* Initialize all variables */
MD5Init(&ctx);
in_header=1 ;
hdrmd5=NULL ;
off_md5=0;
cur_off=0;
md5keysz = (int)strlen(FITSMD5KEY) ;
check_fits=0 ;
/* Loop over input file */
while (fread(buf, 1, FITSBLOCKSZ, in)==FITSBLOCKSZ) {
/* First time in the loop: check the file is FITS */
if (check_fits==0) {
/* Examine first characters in block */
if (buf[0]!='S' ||
buf[1]!='I' ||
buf[2]!='M' ||
buf[3]!='P' ||
buf[4]!='L' ||
buf[5]!='E' ||
buf[6]!=' ' ||
buf[7]!=' ' ||
buf[8]!='=') {
fprintf(stderr, "%s: file [%s] is not FITS\n",
pname,
filename);
fclose(in);
return 1 ;
} else {
check_fits=1 ;
}
}
/* If current block is a header block */
if (in_header) {
buf_c = buf ;
for (i=0 ; i<FITSCARDS ; i++) {
/* Try to locate MD5 keyword if not located already */
if (hdrmd5==NULL) {
if (!strncmp(buf_c, FITSMD5KEY, md5keysz)) {
hdrmd5 = fits_getvalue(buf_c) ;
off_md5 = cur_off ;
}
}
/* Try to locate an END key */
if (buf_c[0]=='E' &&
buf_c[1]=='N' &&
buf_c[2]=='D' &&
buf_c[3]==' ') {
in_header=0 ;
break ;
}
buf_c += FITSLINESZ ;
cur_off += FITSLINESZ ;
}
} else {
/* If current block is a data block */
/* Try to locate an extension header */
if (buf[0]=='X' &&
buf[1]=='T' &&
buf[2]=='E' &&
buf[3]=='N' &&
buf[4]=='S' &&
buf[5]=='I' &&
buf[6]=='O' &&
buf[7]=='N' &&
buf[8]=='=') {
in_header=1 ;
buf_c = buf ;
for (i=0 ; i<FITSCARDS ; i++) {
/* Try to find an END marker in this block */
if (buf_c[0]=='E' &&
buf_c[1]=='N' &&
buf_c[2]=='D' &&
buf_c[3]==' ') {
/* Found END marker in same block as XTENSION */
in_header=0 ;
break ;
}
buf_c += FITSLINESZ ;
}
} else {
/* Data block: accumulate for MD5 */
MD5Update(&ctx, (unsigned char *)buf, FITSBLOCKSZ);
}
}
}
fclose(in);
if (check_fits==0) {
/* Never went through the read loop: file is not FITS */
fprintf(stderr, "%s: file [%s] is not FITS\n",
pname,
filename);
return 1 ;
}
/* Got to the end of file: summarize */
MD5Final(digest, &ctx);
/* Write digest into a string */
sprintf(datamd5,
"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
digest[ 0], digest[ 1], digest[ 2], digest[ 3], digest[ 4],
digest[ 5], digest[ 6], digest[ 7], digest[ 8], digest[ 9],
digest[10], digest[11], digest[12], digest[13], digest[14],
digest[15]);
if (!silent_process) {
printf("filename : %s\n"
"MD5 declared: %s\n"
"MD5 computed: %s\n",
filename,
hdrmd5 ? hdrmd5 : "none",
datamd5);
}
/* Update header if requested */
err=0 ;
if (update_header) {
if (hdrmd5==NULL) {
fprintf(stderr, "%s: cannot update header: missing %s\n",
pname,
FITSMD5KEY);
return 1 ;
}
err = fits_replace_card(filename, off_md5, datamd5);
}
return err ;
}
/* Compute MD5 sum on the whole file and print out results on stdout */
static int compute_md5(char * filename)
{
struct MD5Context ctx ;
unsigned char digest[16] ;
struct stat sta ;
int fd ;
unsigned char * buf ;
/* Try to stat file */
if (stat(filename, &sta)!=0) {
fprintf(stderr, "%s: cannot stat file %s\n", pname, filename);
return 1 ;
}
/* See if this is a regular file */
if (!S_ISREG(sta.st_mode)) {
fprintf(stderr, "%s: not a regular file: %s\n", pname, filename);
return 1 ;
}
/* Open file */
if ((fd = open(filename, O_RDONLY))==-1) {
fprintf(stderr, "%s: cannot open file %s\n", pname, filename);
return 1 ;
}
/* Memory-map the file */
buf = (unsigned char*)mmap(0, sta.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (buf==(unsigned char*)-1 || buf==NULL) {
perror("mmap");
close(fd);
return 1 ;
}
/* Initialize MD5 context */
MD5Init(&ctx);
/* Compute MD5 on all bits in the file */
MD5Update(&ctx, buf, sta.st_size);
/* Finalize and print results */
close(fd);
munmap((char*)buf, sta.st_size);
MD5Final(digest, &ctx);
printf(
"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x %s\n",
digest[ 0], digest[ 1], digest[ 2], digest[ 3], digest[ 4],
digest[ 5], digest[ 6], digest[ 7], digest[ 8], digest[ 9],
digest[10], digest[11], digest[12], digest[13], digest[14],
digest[15],
filename);
return 0 ;
}
/* This function only gives the usage for the program */
static void usage(void)
{
printf(
"%s -- %s\n"
"version: $Revision: 1.1 $\n",
pname,
prog_desc);
printf(
"\n"
"use : %s [-u] [-s] [-a] <FITS files...>\n"
"options are:\n"
"\t-u update MD5 keyword in the file: %s\n"
"\t-s silent mode\n"
"\n"
"\t-a compute MD5 sum of the complete file (incl.header)\n"
"\n"
"This utility computes the MD5 checksum of all data sections\n"
"in a given FITS file, and compares it against the value\n"
"declared in DATAMD5 if present. It can also update the value\n"
"of this keyword (if present) with its own computed MD5 sum.\n"
"\n"
"You can also use it with the -a option to compute the MD5 sum\n"
"on the complete file (all bits). In this case, the file needs\n"
"not be FITS. This option is only provided to check this program\n"
"against other MD5 computation tools.\n"
"NB: Other options cannot be used together with -a.\n"
"\n",
pname,
FITSMD5KEY);
exit(0) ;
}
/*----------------------------------------------------------------------------
Main code
---------------------------------------------------------------------------*/
int main(int argc, char *argv[])
{
int i ;
int update_header ;
int total_md5 ;
int err ;
pname=argv[0];
update_header = 0 ;
total_md5 = 0 ;
if (argc<2) {
usage();
}
/* Parse arguments for options */
for (i=1 ; i<argc ; i++) {
if (!strcmp(argv[i], "-u")) {
update_header=1 ;
} else if (!strcmp(argv[i], "-s")) {
silent_process=1;
} else if (!strcmp(argv[i], "-a")) {
total_md5=1 ;
}
}
/* Loop on input file names */
err=0 ;
for (i=1 ; i<argc ; i++) {
/* If not a command-line option */
if (strcmp(argv[i], "-u") &&
strcmp(argv[i], "-s") &&
strcmp(argv[i], "-a")) {
/* Launch MD5 process on this file */
if (total_md5) {
err+=compute_md5(argv[i]);
} else {
err += fits_md5_check(argv[i], update_header);
}
}
}
if (err>0) {
fprintf(stderr, "%s: %d error(s) during process\n", pname, err);
}
return err ;
}

View File

@ -0,0 +1,448 @@
/*----------------------------------------------------------------------------
File name : fitsort.c
Author : Nicolas Devillard
Created on : May 1st, 1996
Description : Sorts out FITS keywords.
The input is a succession of FITS headers delivered
through stdin by 'dfits'. On the command line, specify
which keywords you wish to display, the output contains
for each file, the file name and the keyword values
in column format.
Example:
dfits *.fits | fitsort BITPIX NAXIS NAXIS1 NAXIS2 NAXIS3
The output would be like:
File BITPIX NAXIS NAXIS1 NAXIS2 NAXIS3
image1.fits 32 2 256 256
image2.fits -32 3 128 128 40
...
Using 'fitsort -d ...' would prevent printing the
first line (filename and keyword names).
The output format is simple: values are separated by
tabs, records by linefeeds. When no value is present
(no keyword in this header), only a tab is printed
out.
Example:
file1.fits contains NAXIS1=100 NAXIS2=200
file2.fits contains NAXIS1=20
dfits file1.fits file2.fits | fitsort NAXIS2 NAXIS1
would litterally print out (\t stands for tab, \n for linefeed):
file1.fits\t200\t100\n
file2.fits\t\t20\n
---------------------------------------------------------------------------*/
/*
$Id: fitsort.c,v 1.1 2001/12/14 09:15:19 ndevilla Exp $
$Author: ndevilla $
$Date: 2001/12/14 09:15:19 $
$Revision: 1.1 $
*/
/*----------------------------------------------------------------------------
Includes
---------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
/*----------------------------------------------------------------------------
Defines
---------------------------------------------------------------------------*/
#define MAX_STRING 128 /* Maximum string length */
#define MAX_KEY 512 /* Maximum number of keywords to search for */
#define FMT_STRING "%%-%ds\t"
/*----------------------------------------------------------------------------
New types
---------------------------------------------------------------------------*/
/* This holds a keyword value and a flag to indicate its presence */
typedef struct _KEYWORD_ {
char value[MAX_STRING] ;
int present ;
} keyword ;
/*
* Each detected file in input has such an associated structure, which
* contains the file name and a list of associated keywords.
*/
typedef struct _RECORD_ {
char filename[MAX_STRING] ;
keyword listkw[MAX_KEY] ;
} record ;
/*
* NB: Everything is deliberately allocated statically. As we are not
* dealing with huge amounts of data, works fine and makes it easier to
* read/write/modify.
*/
/*----------------------------------------------------------------------------
Function prototypes
See function descriptions below
---------------------------------------------------------------------------*/
static int
isfilename(char *string) ;
static void
getfilename(char *line, char *word) ;
static char *
expand_hierarch_keyword(
char * dotkey,
char * hierarchy
);
static int
isdetectedkeyword(char *line, char *keywords[], int nkeys) ;
static void
getkeywordvalue(char *line, char *word) ;
/*----------------------------------------------------------------------------
Function codes
---------------------------------------------------------------------------*/
int main(int argc, char *argv[])
{
char curline[MAX_STRING] ;
char word[MAX_STRING] ;
int i, j ;
int nfiles ;
record *allrecords ;
int kwnum ;
int len ;
int max_width[MAX_KEY] ;
int max_filnam ;
char fmt[8] ;
int flag ;
int printnames ;
int print_hdr ;
if (argc<2) {
printf("\n\nuse : %s [-d] KEY1 KEY2 ... KEYn\n", argv[0]) ;
printf("Input data is received from stdin\n") ;
printf("See man page for more details and examples\n\n") ;
return 0 ;
}
printnames = 0 ;
print_hdr = 1 ;
nfiles = 0 ;
allrecords = (record*)calloc(1, sizeof(record));
if (!strcmp(argv[1], "-d")) {
print_hdr = 0;
argv++ ;
argc-- ;
}
argv++ ;
/* Uppercase all inputs */
for (i=0 ; i<(argc-1) ; i++) {
j=0 ;
while (argv[i][j]!=0) {
argv[i][j] = toupper(argv[i][j]);
j++ ;
}
}
while (fgets(curline, MAX_STRING, stdin) != (char*)NULL) {
if ((flag=isfilename(curline))!=0) {
/* New file entry is detected */
if (flag==1) {
/* New file name is detected, get the new file name */
printnames = 1 ;
getfilename(curline, allrecords[nfiles].filename) ;
/* Absorb next line (contains SIMPLE=) */
fgets(curline, MAX_STRING, stdin);
} else {
/* New SIMPLE=T entry, no associated file name */
allrecords[nfiles].filename[0] = (char)0;
}
nfiles++ ;
/*
* Initialize a new record structure to store input data for
* this file.
*/
allrecords = (record*)realloc( allrecords,
(nfiles+1)*sizeof(record)) ;
for (i=0 ; i<MAX_KEY ; i++)
allrecords[nfiles].listkw[i].present = 0 ;
} else {
/* Is not a file name, is it a searched keyword? */
if ((kwnum = isdetectedkeyword( curline,
argv,
argc-1)) != -1) {
/* Is there anything allocated yet to store this? */
if (nfiles>0) {
/* It has been detected as a searched keyword. */
/* Get its value, store it, present flag up */
getkeywordvalue(curline, word) ;
strcpy(allrecords[nfiles-1].listkw[kwnum].value, word) ;
allrecords[nfiles-1].listkw[kwnum].present ++ ;
}
}
}
}
for (i=0 ; i<argc-1 ; i++) {
max_width[i] = (int)strlen(argv[i]) ;
}
/* Record the maximum width for each column */
max_filnam = 0 ;
for (i=0 ; i<nfiles ; i++) {
len = (int)strlen(allrecords[i].filename) ;
if (len>max_filnam) max_filnam=len ;
for (kwnum=0 ; kwnum<argc-1 ; kwnum++) {
if (allrecords[i].listkw[kwnum].present) {
len = (int)strlen(allrecords[i].listkw[kwnum].value) ;
} else {
len = 0 ;
}
if (len>max_width[kwnum])
max_width[kwnum] = len ;
}
}
/* Print out header line */
if (print_hdr) {
sprintf(fmt, FMT_STRING, max_filnam) ;
if (printnames) printf(fmt, "FILE");
for (i=0 ; i<argc-1 ; i++) {
sprintf(fmt, FMT_STRING, max_width[i]) ;
printf(fmt, argv[i]) ;
}
printf("\n") ;
}
/* Now print out stored data */
if (nfiles<1) {
printf("*** error: no input data corresponding to dfits output\n");
return -1 ;
}
for (i=0 ; i<nfiles ; i++) {
if (printnames) {
sprintf(fmt, FMT_STRING, max_filnam) ;
printf(fmt, allrecords[i].filename) ;
}
for (kwnum=0 ; kwnum<argc-1 ; kwnum++) {
sprintf(fmt, FMT_STRING, max_width[kwnum]);
if (allrecords[i].listkw[kwnum].present)
printf(fmt, allrecords[i].listkw[kwnum].value) ;
else
printf(fmt, " ");
}
printf("\n") ;
}
free(allrecords) ;
return 0 ;
}
/*----------------------------------------------------------------------------
Function : isfilename()
In : dfits output line
Out : integer
1 if the line contains a valid file name as produced
by dfits.
2 if the line starts with 'SIMPLE ='
0 else
Job : find out if an input line contains a file name or a
FITS magic number
Notice :
Filename recognition is based on 'dfits' output.
---------------------------------------------------------------------------*/
static int
isfilename(char *string)
{
if (!strncmp(string, "====>", 5)) return 1 ;
if (!strncmp(string, "SIMPLE =", 9)) return 2 ;
return 0 ;
}
/*----------------------------------------------------------------------------
Function : getfilename()
In : dfits output line
Out : second argument: file name
Job : returns a file name from a dfits output line
Notice : This is dfits dependent.
---------------------------------------------------------------------------*/
static void
getfilename(char *line, char *word)
{
/* get filename from a dfits output */
sscanf(line, "%*s %*s %s", word) ;
return ;
}
/*----------------------------------------------------------------------------
Function : isdetectedkeyword()
In : FITS line, set of keywords, number of kw in the set.
Out : keyword rank, -1 if unidentified
Job : detects a if a keyword is present in a FITS line.
Notice :
Feed this function a FITS line, a set of keywords in the
*argv[] fashion (*keywords[]).
If the provided line appears to contain one of the keywords
registered in the list, the rank of the keyword in the list
is returned, otherwise, -1 is returned.
---------------------------------------------------------------------------*/
static int
isdetectedkeyword( char *line,
char *keywords[],
int nkeys)
{
int i ;
char kw[MAX_STRING] ;
char esokw[MAX_STRING] ;
/*
* The keywors is defined as the input line, up to the equal character,
* with trailing blanks removed
*/
strcpy(kw, line) ;
strtok(kw, "=") ;
/* Now remove all trailing blanks (if any) */
i = (int)strlen(kw) -1 ;
while (kw[i] == ' ') i -- ;
kw[i+1] = (char)0 ;
/* Now compare what we got with what's available */
for (i=0 ; i<nkeys ; i++) {
if (strstr(keywords[i], ".")!=NULL) {
/*
* keyword contains a dot, it is a hierarchical keyword that
* must be expanded. Pattern is:
* A.B.C... becomes HIERARCH ESO A B C ...
*/
expand_hierarch_keyword(keywords[i], esokw) ;
if (!strcmp(kw, esokw)) {
return i ;
}
} else if (!strcmp(kw, keywords[i])) {
return i ;
}
}
/* Keyword not found */
return -1 ;
}
/*---------------------------------------------------------------------------
Function : expand_hierarch_keyword()
In : two allocated strings
Out : char *, pointer to second input string (modified)
Job : from a HIERARCH keyword in format A.B.C expand to
HIERARCH ESO A B C
Notice :
---------------------------------------------------------------------------*/
static char *
expand_hierarch_keyword(
char * dotkey,
char * hierarchy
)
{
char * token ;
char ws[MAX_STRING] ;
sprintf(hierarchy, "HIERARCH ESO");
strcpy(ws, dotkey) ;
token = strtok(ws, ".") ;
while (token!=NULL) {
strcat(hierarchy, " ") ;
strcat(hierarchy, token) ;
token = strtok(NULL, ".");
}
return hierarchy ;
}
/*----------------------------------------------------------------------------
Function : getkeywordvalue()
In : FITS line to process, char string to return result
Out : void, result returned in char *word
Job : Get a keyword value within a FITS line
Notice : No complex value is recognized
---------------------------------------------------------------------------*/
static void
getkeywordvalue(char *line, char *word)
{
int c, w ;
char tmp[MAX_STRING] ;
char *begin, *end ;
int length ;
int quote = 0 ;
int search = 1 ;
memset(tmp, (char)0, MAX_STRING) ;
memset(word, (char)0, MAX_STRING) ;
c = w = 0;
/* Parse the line till the equal '=' sign is found */
while (line[c] != '=') c++ ;
c++ ;
/* Copy the line till the slash '/' sign is found */
/* or the end of data is found. */
while (search == 1) {
if (c>=80) {
search = 0 ;
} else if ((line[c] == '/') && (quote == 0)) {
search = 0 ;
}
if (line[c] == '\'') {
quote = !quote ;
}
tmp[w++] = line[c++] ;
}
/* NULL termination of the string */
tmp[--w] = (char)0 ;
/* Return the keyword only : a difference is made between text fields */
/* and numbers. */
if ((begin = strchr(tmp, '\'')) != (char*)NULL) {
/* A quote has been found: it is a string value */
begin++ ;
end = strrchr(tmp, '\'') ;
length = (int)strlen(begin) - (int)strlen(end) ;
strncpy(word, begin, length) ;
} else {
/* No quote, just get the value (only one, no complex supported) */
sscanf(tmp, "%s", word) ;
}
return ;
}

View File

@ -0,0 +1,664 @@
/*----------------------------------------------------------------------------
File name : hierarch28.c
Author : N. Devillard
Created on : July 14th, 1998
Description : header conversion from ESO-FITS to standard FITS
---------------------------------------------------------------------------*/
/*
$Id: hierarch28.c,v 1.1 2001/12/14 09:15:19 ndevilla Exp $
$Author: ndevilla $
$Date: 2001/12/14 09:15:19 $
$Revision: 1.1 $
*/
/*----------------------------------------------------------------------------
Includes
---------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <string.h>
#include <ctype.h>
#define NM_SIZ 512
#define FITS_LINE 80
/*----------------------------------------------------------------------------
Private functions and module variables
---------------------------------------------------------------------------*/
static char prog_desc[] = "header conversion from ESO to standard FITS" ;
static void usage(char *) ;
static int convert_eso_to_std_FITS(char *, char *) ;
static void free_keys(char **, int n) ;
static void strip_beg_end(char *) ;
static int
search_and_replace_kw(
char * buf,
int bufsize,
char ** key_in,
char ** key_out,
int nk
);
static void search_rep(char *, char *, char *);
static void generate_default_convtab(void);
static char * convert_deg_to_str( double deg ) ;
static char CONVTAB_DEFAULT[] =
"#\n"
"# Example of conversion table for hierarch28\n"
"#\n"
"# A note about this file's format:\n"
"# Any blank line or line starting with a hash is ignored.\n"
"# Declare the keyword names to search and replace with:\n"
"#\n"
"# OLDKEYWORD1 = NEWKEYWORD1\n"
"# OLDKEYWORD2 = NEWKEYWORD2\n"
"# etc.\n"
"#\n"
"# Spaces are allowed within keyword names, to allow e.g.:\n"
"#\n"
"# HIERARCH ESO DET DIT = DETDIT\n"
"# HIERARCH ESO DET NDIT = DET NDIT\n"
"# HIERARCH ESO DET NINT = HIERARCH ESO NINT\n"
"#\n"
"# The most important restriction is that new keywords shall not be\n"
"# longer than the keywords they replace.\n"
"#\n"
"#\n"
"# Translation table for basic keywords used by IRAF\n"
"# -------------------------------------------------\n"
"#\n"
"# Note: hierarch28 will replace keywords in the main header\n"
"# and also in extensions.\n"
"#\n"
"# Disclaimer:\n"
"# this table has been compiled to best knowledge of present\n"
"# IRAF packages. Please let us know of any addition/change.\n"
"#\n"
"\n"
"UTC = UT\n"
"LST = ST\n"
"RA = RA\n"
"DEC = DEC\n"
"\n"
"HIERARCH ESO TEL AIRM START = AIRMASS\n"
"HIERARCH ESO DPR TYPE = IMAGETYP\n"
"HIERARCH ESO INS FILT1 NAME = FILTER1\n"
"HIERARCH ESO INS FILT2 NAME = FILTER2\n"
"HIERARCH ESO INS FILT3 NAME = FILTER3\n"
"HIERARCH ESO INS FILT4 NAME = FILTER4\n"
"HIERARCH ESO INS SLIT2 NAME = SLIT\n"
"HIERARCH ESO INS GRIS1 NAME = GRISM\n"
"HIERARCH ESO INS GRAT NAME = GRAT\n"
"HIERARCH ESO INS GRAT1 NAME = GRAT1\n"
"HIERARCH ESO INS GRAT2 NAME = GRAT2\n"
"HIERARCH ESO INS GRAT WLEN = WLEN\n"
"HIERARCH ESO INS GRAT1 WLEN = WLEN1\n"
"HIERARCH ESO INS GRAT2 WLEN = WLEN2\n"
"HIERARCH ESO INS GRAT ORDER = ORDER\n"
"\n"
"#\n"
"# A note for IRAF users:\n"
"# hierarch28 performs a translation to the IRAF convention on the\n"
"# following four keywords 'RA', 'DEC', 'UT' and 'ST'. IRAF requires\n"
"# these keywords to contain the string representation of their values.\n"
"#\n"
"# Be aware also that the ESO convention names the keywords UTC and\n"
"# LST, whereas the IRAF convention is 'UT' and 'ST'.\n"
"#\n"
"# e.g.\n"
"#\n"
"# RA = ' 09:45:14.594' / RA (J2000) pointing\n"
"# DEC = '-33:47:09.420' / DEC (J2000) pointing\n"
"# UT = ' 01:17:21.950' / UT at start\n"
"# ST = ' 08:19:59.688' / ST at start\n"
"#\n"
"# The ESO standard (see http://archive.eso.org/dicb) defines these\n"
"# keywords as floating point values with the units degrees for RA/DEC\n"
"# and elapsed seconds since midnight for UT/ST.\n"
"#\n"
"# In order to have this tranlation performed, add\n"
"#\n"
"# RA = RA\n"
"# DEC = DEC\n"
"# UTC = UT\n"
"# LST = ST\n"
"#\n"
"# to the conversion table.\n"
"#\n";
/*----------------------------------------------------------------------------
main()
---------------------------------------------------------------------------*/
int main(int argc, char *argv[])
{
char name_conv[NM_SIZ] ;
char name_in[NM_SIZ] ;
if (argc<2) usage(argv[0]) ;
if (!strcmp(argv[1], "-g")) {
generate_default_convtab() ;
return 0 ;
}
strcpy(name_in, argv[1]) ;
if (argc==3) {
strcpy(name_conv, argv[2]) ;
} else {
strcpy(name_conv, "table.conv") ;
}
if (convert_eso_to_std_FITS(name_in, name_conv) != 0) {
fprintf(stderr, "error during conversion: aborting\n") ;
}
return 0 ;
}
/*
* This function only gives the usage for the program
*/
static void usage(char *pname)
{
printf(
"\n\n"
"hierarch28 (hierarch-to-eight)\n"
"%s : %s\n"
"use : %s [options] <in> [table]\n"
"options are:\n"
"\t-g generates a generic table\n"
"\n"
"default conversion table name is 'table.conv'\n"
"\n"
"More help can be found in the comments included in\n"
"the default conversion table. Generate one with\n"
"the -g option and read it.\n"
"\n\n",
pname, prog_desc, pname);
exit(0) ;
}
/*-------------------------------------------------------------------------*/
/**
@name convert_eso_to_std_FITS
@memo Search and replace FITS keywords in main/extension headers.
@param name_in File to modify.
@param name_conv Conversion table name.
@return int 0 if Ok, non-zero if error occurred.
@doc
The input file is modified in place. Keyword names are replaced
according to the input conversion table. In some special cases, the
keyword values are also modified to follow the IRAF convention.
*/
/*--------------------------------------------------------------------------*/
static int convert_eso_to_std_FITS(char * name_in, char * name_conv)
{
FILE * convtab ;
int nkeys ;
int i ;
char ** key_in ;
char ** key_out ;
int fd ;
char * buf ;
char line[NM_SIZ] ;
char kw1[FITS_LINE],
kw2[FITS_LINE] ;
int lineno ;
int fs ;
struct
stat fileinfo ;
/*
* Read conversion table and translate it to key_in, key_out
*/
if ((convtab = fopen(name_conv, "r")) == NULL) {
fprintf(stderr, "cannot open conversion table: %s\n", name_conv) ;
return -1 ;
}
/*
* First, count how many keywords we need to translate
*/
nkeys = 0 ;
while (fgets(line, FITS_LINE, convtab)!=NULL) {
if ((line[0] != '#') && (line[0] != '\n')) {
nkeys ++ ;
}
}
rewind(convtab) ;
/*
* Allocate space to store keyword info
*/
key_in = malloc(nkeys * sizeof(char*)) ;
key_out = malloc(nkeys * sizeof(char*)) ;
/*
* Now read the file through and get the keywords
*/
i = 0 ;
lineno = 0 ;
while (fgets(line, FITS_LINE, convtab)!=NULL) {
lineno++ ;
if ((line[0]!='#') && (line[0]!='\n')) {
if (sscanf(line, "%[^=] = %[^;#]", kw1, kw2)!=2) {
fprintf(stderr,
"*** error parsing table file %s\n", name_conv);
fprintf(stderr, "line: %d\n", lineno) ;
free_keys(key_in, i) ;
free_keys(key_out, i) ;
fclose(convtab) ;
return -1 ;
}
strip_beg_end(kw1) ;
strip_beg_end(kw2) ;
if (strlen(kw2)>strlen(kw1)) {
fprintf(stderr,
"*** error in conversion table %s (line %d)\n",
name_conv, lineno);
fprintf(stderr,
"*** error: dest keyword is longer than original\n");
fprintf(stderr, "orig: [%s] dest: [%s]\n", kw1, kw2);
fclose(convtab) ;
free_keys(key_in, i) ;
free_keys(key_out, i) ;
return -1 ;
}
key_in[i] = strdup(kw1) ;
key_out[i] = strdup(kw2) ;
i++ ;
}
}
fclose(convtab) ;
/*
* Print out some information about what is being done
*/
printf("\n\n") ;
printf("*** hierarch28\n") ;
printf("\n") ;
printf("searching %s and replacing the following keywords:\n",
name_in) ;
for (i=0 ; i<nkeys ; i++) {
printf("\t[%s]\t=>\t[%s]\n", key_in[i], key_out[i]) ;
}
printf("\n\n") ;
/*
* mmap the input file entirely
*/
if (stat(name_in, &fileinfo)!=0) {
fprintf(stderr, "*** error: accessing file [%s]\n", name_in);
free_keys(key_in, nkeys) ;
free_keys(key_out, nkeys) ;
return -1 ;
}
fs = (int)fileinfo.st_size ;
if (fs < 1) {
fprintf(stderr, "error getting FITS header size for %s\n", name_in);
free_keys(key_in, nkeys) ;
free_keys(key_out, nkeys) ;
return -1 ;
}
fd = open(name_in, O_RDWR) ;
if (fd == -1) {
fprintf(stderr, "cannot open %s: aborting\n", name_in) ;
free_keys(key_in, nkeys) ;
free_keys(key_out, nkeys) ;
return -1 ;
}
buf = (char*)mmap(0,
fs,
PROT_READ | PROT_WRITE,
MAP_SHARED,
fd,
0) ;
if (buf == (char*)-1) {
perror("mmap") ;
fprintf(stderr, "cannot mmap file: %s\n", name_in) ;
free_keys(key_in, nkeys) ;
free_keys(key_out, nkeys) ;
close(fd) ;
return -1 ;
}
/*
* Apply search and replace for the input keyword lists
*/
if (search_and_replace_kw(buf, fs, key_in, key_out, nkeys) != 0) {
fprintf(stderr, "error while doing search and replace\n") ;
}
free_keys(key_in, nkeys) ;
free_keys(key_out, nkeys) ;
close(fd) ;
munmap(buf, fs) ;
return 0 ;
}
/*-------------------------------------------------------------------------*/
/**
@name strip_beg_end
@memo Strips out blank characters off a character string.
@param s NULL-terminated string to process.
@return void
@doc
This function removes heading and trailing blanks from a
NULL-terminated character string. The input string is modified. The
input string is assumed to contain only blanks or alphanumeric
characters (like FITS keywords).
*/
/*--------------------------------------------------------------------------*/
static void strip_beg_end(char * s)
{
int beg, len ;
beg = 0 ;
while (!isalnum(s[beg])) beg++ ;
len = (int)strlen(s) -1 ;
while (!isalnum(s[len])) len -- ;
strncpy(s, s+beg, len-beg+1) ;
s[len-beg+1] = (char)0 ;
return ;
}
/*-------------------------------------------------------------------------*/
/**
@name free_keys
@memo Free memory associated to an array of keys.
@param keyt Key table.
@param n Number of keys in the table.
@return void
@doc
Memory was initially allocated using strdup(). This frees all the
keys and the master table pointer.
*/
/*--------------------------------------------------------------------------*/
static void free_keys(char ** keyt, int n)
{
int i ;
if (n<1) return ;
for (i=0 ; i<n ; i++) {
free(keyt[i]) ;
}
free(keyt) ;
}
/*-------------------------------------------------------------------------*/
/**
@name search_and_replace_kw
@memo Search keywords and replace them over a whole buffer.
@param buf Buffer to modify.
@param bufsize Buffer size in bytes.
@param key_in Input key table.
@param key_out Output key table.
@param nk Number of keys in each table (same).
@return int 0 if Ok, non-zero if error occurred.
@doc
Main replace function: it browses through the entire file to support
keyword changes in extensions too. Heavily optimized for speed.
*/
/*--------------------------------------------------------------------------*/
static int search_and_replace_kw(
char * buf,
int bufsize,
char ** key_in,
char ** key_out,
int nk
)
{
char * w ;
int i, j ;
int in_header ;
int match_flag ;
int * keysizes ;
/* Pre-compute key sizes to gain time */
keysizes = malloc(nk * sizeof(int));
for (i=0 ; i<nk ; i++) {
keysizes[i] = (int)strlen(key_in[i]);
}
/* Browse through file line by line */
w = buf ;
in_header=1 ;
while ((w-buf+FITS_LINE)<bufsize) {
if (in_header) { /* Currently browsing a header */
if (w[0]=='E' &&
w[1]=='N' &&
w[2]=='D' &&
w[3]==' ') {
/* Found an END keyword: exit from header */
in_header=0 ;
} else {
/* Compare the current line with all searched keys */
for (i=0 ; i<nk ; i++) {
match_flag=1 ;
for (j=0 ; j<keysizes[i] ; j++) {
if (key_in[i][j]!=w[j]) {
match_flag=0 ;
break ;
}
}
if (match_flag) {
search_rep(w, key_in[i], key_out[i]);
}
}
}
} else {
/* Currently out of header, look for next extension */
if (w[0]=='X' &&
w[1]=='T' &&
w[2]=='E' &&
w[3]=='N' &&
w[4]=='S' &&
w[5]=='I' &&
w[6]=='O' &&
w[7]=='N') {
/* Found a header start */
in_header=1 ;
}
}
w+=FITS_LINE ;
}
free(keysizes);
return 0 ;
}
/*-------------------------------------------------------------------------*/
/**
@name search_rep
@memo Atomic keyword replacement.
@param line Line to work on.
@param key_i Input key.
@param key_o Output key.
@return void
@doc
Replace in 'line' the keyword name 'key_i' by 'key_o'. In some
special cases, the value is also modified to reflect the IRAF
conventions.
*/
/*--------------------------------------------------------------------------*/
static void search_rep(char * line, char * key_i, char * key_o)
{
int i, j ;
char * equal ;
int to_copy ;
char * p ;
char tmp[FITS_LINE+1];
char comment[FITS_LINE+1];
equal = strstr(line, "=");
to_copy = FITS_LINE - (equal-line);
for (i=0 ; i<(int)strlen(key_o) ; i++) {
line[i] = key_o[i] ;
}
if (strlen(key_o)<=8) {
/* Blank-pad until equal sign is reached */
for ( ; i<8 ; i++) {
line[i]=' ';
}
/* Add equal sign */
line[i] = '=' ;
i++ ;
/* Handle special cases: the value also needs conversion */
if(!strcmp(key_o, "RA")) {
if (*(equal+2)!='\'') {
/* out key is RA, translate to ' HH:MM:SS.SSS' */
p = strchr(line+i, '/');
if (p)
strncpy(comment, p, line+FITS_LINE-p);
sprintf(tmp, " %-29.29s %-40.40s",
convert_deg_to_str(atof(equal+1)/15.),
(p)? comment : "/ Right Ascension");
memcpy(line+i, tmp, 71);
}
} else if(!strcmp(key_o, "DEC")) {
if( *(equal+2)!='\'') {
/* out key is DEC, translate to '+DD:MM:SS.SSS' */
p = strchr(line+i, '/');
if (p)
strncpy(comment, p, line+FITS_LINE-p);
sprintf(tmp, " %-29.29s %-40.40s",
convert_deg_to_str(atof(equal+1)),
(p)? comment : "/ Declination");
memcpy(line+i, tmp, 71);
}
} else if(!strcmp(key_o, "UT")) {
if( *(equal+2)!='\'') {
/* out key is UT, translate to ' HH:MM:SS.SSS' */
p = strchr(line+i, '/');
if (p)
strncpy(comment, p, line+FITS_LINE-p);
sprintf(tmp, " %-29.29s %-40.40s",
convert_deg_to_str(atof(equal+1)/3600.),
(p)? comment : "/ UT");
memcpy(line+i, tmp, 71);
}
} else if(!strcmp(key_o, "ST")) {
if( *(equal+2)!='\'') {
/* out key is ST, translate to ' HH:MM:SS.SSS' */
p = strchr(line+i, '/');
if (p)
strncpy(comment, p, line+FITS_LINE-p);
sprintf(tmp, " %-29.29s %-40.40s",
convert_deg_to_str(atof(equal+1)/3600.),
(p)? comment : "/ ST");
memcpy(line+i, tmp, 71);
}
} else {
/* Copy line from first char after real equal sign */
for (j=0 ; j<to_copy ; j++) {
line[i+j] = equal[j+1];
}
i+=to_copy-1 ;
/* Blank padding */
for ( ; i<FITS_LINE ; i++) {
line[i]=' ';
}
}
} else {
/* Blank padding */
for (i=(int)strlen(key_o) ; i<(int)strlen(key_i) ; i++) {
line[i]=' ';
}
}
return ;
}
/*-------------------------------------------------------------------------*/
/**
@name generate_default_convtab
@memo Create a default conversion table.
@param ins Table name.
@return void
@doc
Creates a translation table for the requested instrument. If no
instrument is specified (ins==NULL) a default table is generated.
*/
/*--------------------------------------------------------------------------*/
static void generate_default_convtab(void)
{
FILE * convtab ;
if ((convtab = fopen("table.conv", "w")) == NULL) {
fprintf(stderr, "*** error: cannot create table.conv: aborting\n") ;
return ;
}
fprintf(convtab, CONVTAB_DEFAULT);
fclose(convtab) ;
return ;
}
/*-------------------------------------------------------------------------*/
/**
@name convert_deg_to_str
@memo Convert decimal degrees to ASCII representation.
@param d Double value, decimal degrees in [-90 ; +90].
@return Pointer to statically allocated character string.
@doc
Converts an angle value from degrees to ASCII representation
following the IRAF convention. Do not free or modify the returned
string.
*/
/*--------------------------------------------------------------------------*/
static char * convert_deg_to_str( double deg )
{
int d, m;
double s;
int sign;
static char buf[13];
sign = 1;
if(deg < 0.) sign = -1;
deg *= sign;
d = (int)deg;
m = (int)( (deg - d) * 60);
s = (deg - d) * 3600. - m * 60;
sprintf(buf, "'%c%02d:%02d:%06.3f'", (sign<0)? '-' : ' ', d, m, s);
return(buf);
}

1480
qfits/saft/iofits.c 100644

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,219 @@
/*----------------------------------------------------------------------------
File name : replacekey.c
Author : N. Devillard
Created on : July 14th, 1998
Description : Search & Replace operations in FITS headers
---------------------------------------------------------------------------*/
/*
$Id: replacekey.c,v 1.1 2001/12/14 09:15:19 ndevilla Exp $
$Author: ndevilla $
$Date: 2001/12/14 09:15:19 $
$Revision: 1.1 $
*/
/*----------------------------------------------------------------------------
Includes
---------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <string.h>
#include <ctype.h>
/*----------------------------------------------------------------------------
Defines
---------------------------------------------------------------------------*/
#define NM_SIZ 512
#define DEFAULT_PLACEHOLDER "COMMENT PLACEHOLDER"
/*----------------------------------------------------------------------------
Private functions and module variables
---------------------------------------------------------------------------*/
static char prog_desc[] = "replace keyholder in a FITS header" ;
static void usage(char *) ;
static int replace_placeholder(char *, char *, char*) ;
static int get_FITS_header_size(char *) ;
/*----------------------------------------------------------------------------
main()
---------------------------------------------------------------------------*/
int main(int argc, char *argv[])
{
char name_in[NM_SIZ] ;
char placeholder[NM_SIZ] ;
char card[NM_SIZ] ;
if (argc<3) usage(argv[0]) ;
strncpy(name_in, argv[1], NM_SIZ) ;
strncpy(card, argv[2], NM_SIZ) ;
if (argc==4) {
strncpy(placeholder, argv[3], NM_SIZ) ;
} else {
strncpy(placeholder, DEFAULT_PLACEHOLDER, NM_SIZ);
}
/*
* Sanity tests
*/
if (strlen(card)>80) {
fprintf(stderr, "requested card is too long: %d chars\n",strlen(card));
return -1;
}
if (replace_placeholder(name_in, card, placeholder) != 0) {
fprintf(stderr, "error during placeholder replacement: aborting\n") ;
}
return 0 ;
}
/*
* This function only gives the usage for the program
*/
static void usage(char *pname)
{
printf("%s : %s\n", pname, prog_desc) ;
printf("use : %s <in> <card> [placeholder]\n", pname) ;
printf("\n\n") ;
exit(0) ;
}
/*---------------------------------------------------------------------------
Function : replace_placeholder()
In : name of the FITS file to modify, card to insert,
name of the placeholder
Out : int 0 if Ok, anything else otherwise
Job : replaces a placeholder by a given FITS card
Notice : modifies the input FITS file
Does not check the validity of the given FITS card
---------------------------------------------------------------------------*/
static int replace_placeholder(
char * name_in,
char * card,
char * placeholder)
{
int fd ;
char * buf ;
char * where ;
int hs ;
/*
* mmap the FITS header of the input file
*/
hs = get_FITS_header_size(name_in) ;
if (hs < 1) {
fprintf(stderr, "error getting FITS header size for %s\n", name_in);
return -1 ;
}
fd = open(name_in, O_RDWR) ;
if (fd == -1) {
fprintf(stderr, "cannot open %s: aborting\n", name_in) ;
return -1 ;
}
buf = (char*)mmap(0,
hs,
PROT_READ | PROT_WRITE,
MAP_SHARED,
fd,
0) ;
if (buf == (char*)-1) {
perror("mmap") ;
fprintf(stderr, "cannot mmap file: %s\n", name_in) ;
close(fd) ;
return -1 ;
}
/*
* Apply search and replace for the input keyword lists
*/
where = buf ;
do {
where = strstr(where, placeholder);
if (where == NULL) {
fprintf(stderr, "not found in input: [%s]\n", placeholder) ;
close(fd);
munmap(buf,hs);
return -1 ;
}
} while ((where-buf)%80) ;
/* Replace current placeholder by blanks */
memset(where, ' ', 80);
/* Copy card into placeholder */
memcpy(where, card, strlen(card));
close(fd) ;
munmap(buf, hs) ;
return 0 ;
}
/*---------------------------------------------------------------------------
Function : get_FITS_header_size()
In : FITS file name
Out : unsigned long
Job : compute the size (in bytes) of a FITS header
Notice : should always be a multiple of 2880. This implementation
assumes only that 80 characters are found per line.
---------------------------------------------------------------------------*/
#define FITS_BLSZ 2880
static int get_FITS_header_size(char * name)
{
FILE * in ;
char line[81] ;
int found = 0 ;
int count ;
int hs ;
if ((in = fopen(name, "r")) == NULL) {
fprintf(stderr, "cannot open %s: aborting\n", name) ;
return 0 ;
}
count = 0 ;
while (!found) {
if (fread(line, 1, 80, in)!=80) {
break ;
}
count ++ ;
if (!strncmp(line, "END ", 4)) {
found = 1 ;
}
}
fclose(in);
if (!found) return 0 ;
/*
* The size is the number of found cards times 80,
* rounded to the closest higher multiple of 2880.
*/
hs = count * 80 ;
if ((hs % FITS_BLSZ) != 0) {
hs = (1+(hs/FITS_BLSZ)) * FITS_BLSZ ;
}
return hs ;
}
#undef FITS_BLSZ
/*------------------------------ end of file ------------------------------*/

View File

@ -0,0 +1,365 @@
/*---------------------------------------------------------------------------
File name : stripfits.c
Author : N. Devillard
Created on : January 1999
Description : Strip off FITS header to dump pixels only
Notice : stand-alone
Compile with:
gcc -o stripfits stripfits.c -O
This program dumps all the pixels from a FITS header into another file.
It has been written in less than 10 minutes (reusing most of the code
from iofits.c) to help the guys working on the ISAAC detector that day.
Since it is a good example of how to write a stand-alone FITS command, I
leave it here in the distribution.
*--------------------------------------------------------------------------*/
/*
$Id: stripfits.c,v 1.1 2001/12/14 09:15:19 ndevilla Exp $
$Author: ndevilla $
$Date: 2001/12/14 09:15:19 $
$Revision: 1.1 $
*/
/*---------------------------------------------------------------------------
Includes
---------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <string.h>
#include <ctype.h>
/*---------------------------------------------------------------------------
Defines
---------------------------------------------------------------------------*/
#define NM_SIZ 512
#define FITS_BLSZ 2880
#define ONE_MEGABYTE (1024 * 1024)
#ifndef SEEK_SET
#define SEEK_SET 0
#endif
/*---------------------------------------------------------------------------
Function prototypes
---------------------------------------------------------------------------*/
/*
* All functions are private
*/
static int dump_pix(char*, char*);
static int get_FITS_header_size(char *) ;
static int filesize(char*) ;
static int get_bitpix(char*) ;
static int get_npix(char*) ;
/*---------------------------------------------------------------------------
main()
---------------------------------------------------------------------------*/
int main(int argc, char *argv[])
{
if (argc<3) {
printf("\n\n") ;
printf("use: %s <in> <out>\n", argv[0]) ;
printf("\n") ;
printf("\t<in> is a valid FITS file in the current directory\n") ;
printf("\t<out> is the name of the output file\n") ;
printf("\n\n") ;
return 0 ;
}
if (!strcmp(argv[1], argv[2])) {
fprintf(stderr, "cannot convert a file to itself\n") ;
fprintf(stderr, "specify another name for the output\n") ;
return -1 ;
}
return dump_pix(argv[1], argv[2]);
}
/*---------------------------------------------------------------------------
Function : dump_pix()
In : name in, name out
Out : int 0 if Ok, anything else otherwise
Job : dump pixels from a FITS file to a binary file
Notice : heavy use of mmap() to speed up the process
---------------------------------------------------------------------------*/
static int
dump_pix(
char * name_in,
char * name_out
)
{
int fd_in,
fd_out ;
char * buf_in ;
char * buf_out ;
int fsize_in,
fsize_out,
header_size ;
int npix ;
/*
* Open input file and get information we need:
* - pixel depth
* - number of pixels
*/
fsize_in = filesize(name_in) ;
header_size = get_FITS_header_size(name_in) ;
if ((fd_in = open(name_in, O_RDONLY)) == -1) {
fprintf(stderr, "cannot open file %s: aborting\n", name_in) ;
return -1 ;
}
buf_in = (char*)mmap(0, fsize_in, PROT_READ, MAP_SHARED, fd_in, 0) ;
if (buf_in == (char*)-1) {
perror("mmap") ;
fprintf(stderr, "cannot mmap file: %s\n", name_in) ;
close(fd_in) ;
return -1 ;
}
if (get_bitpix(buf_in) != -32) {
fprintf(stderr, "only 32-bit IEEE floating point format supported\n");
close(fd_in) ; munmap(buf_in, fsize_in) ;
return -1 ;
}
/*
* Compute the size of the output file
* same header size, + pixel area + blank padding
*/
npix = get_npix(buf_in) ;
if (npix < 1) {
fprintf(stderr, "cannot compute number of pixels\n");
close(fd_in) ;
munmap(buf_in, fsize_in) ;
return -1 ;
}
fsize_out = npix * 4 ;
/*
* Now create the output file and fill it with zeros, then mmap it.
* The permissions are rw-rw-r-- by default.
*/
if ((fd_out=creat(name_out,S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH))==-1){
perror("creat") ;
fprintf(stderr, "cannot create file %s: aborting\n", name_out) ;
close(fd_in) ; munmap(buf_in, fsize_in) ;
return -1 ;
}
buf_out = malloc(fsize_out) ;
if (buf_out == NULL) {
fprintf(stderr, "not enough memory\n");
fprintf(stderr, "failed to allocate %d bytes\n", fsize_out);
close(fd_in) ; munmap(buf_in, fsize_in) ;
return -1;
}
write(fd_out, buf_out, fsize_out);
close(fd_out);
free(buf_out);
fd_out = open(name_out, O_RDWR);
if (fd_out==-1) {
fprintf(stderr, "error opening file %s\n", name_out);
close(fd_in) ; munmap(buf_in, fsize_in) ;
return -1;
}
buf_out = (char*)mmap(0,
fsize_out,
PROT_READ | PROT_WRITE,
MAP_SHARED,
fd_out,
0) ;
if (buf_out == (char*)-1) {
perror("mmap") ;
fprintf(stderr, "cannot mmap file: %s\n", name_out) ;
munmap(buf_in, fsize_in) ; close(fd_in) ; close(fd_out) ;
return -1 ;
}
/*
* Copy FITS header from input to output, modify BITPIX
*/
memcpy(buf_out, buf_in+header_size, fsize_out) ;
/*
* Close, unmap, goodbye
*/
close(fd_in) ;
close(fd_out) ;
munmap(buf_in, fsize_in) ;
munmap(buf_out, fsize_out) ;
return 0 ;
}
/*---------------------------------------------------------------------------
Function : get_FITS_header_size()
In : FITS file name
Out : unsigned long
Job : compute the size (in bytes) of a FITS header
Notice : should always be a multiple of 2880. This implementation
assumes only that 80 characters are found per line.
---------------------------------------------------------------------------*/
static int get_FITS_header_size(char * name)
{
FILE * in ;
char line[81] ;
int found = 0 ;
int count ;
int hs ;
if ((in = fopen(name, "r")) == NULL) {
fprintf(stderr, "cannot open %s: aborting\n", name) ;
return 0 ;
}
count = 0 ;
while (!found) {
if (fread(line, 1, 80, in)!=80) {
break ;
}
count ++ ;
if (!strncmp(line, "END ", 4)) {
found = 1 ;
}
}
fclose(in);
if (!found) return 0 ;
/*
* The size is the number of found cards times 80,
* rounded to the closest higher multiple of 2880.
*/
hs = count * 80 ;
if ((hs % FITS_BLSZ) != 0) {
hs = (1+(hs/FITS_BLSZ)) * FITS_BLSZ ;
}
return hs ;
}
/*---------------------------------------------------------------------------
* Function : filesize()
* In : filename
* Out : size of the file in bytes
* Job : strongly non portable. Only on Unix systems!
* Notice : Looks strange, but there is no portable way to answer
* the question: how many bytes can I read from this file?
*--------------------------------------------------------------------------*/
static int filesize(char *filename)
{
int size ;
struct stat fileinfo ;
/* POSIX compliant */
if (stat(filename, &fileinfo) != 0) {
size = (int)0 ;
} else {
size = (int)fileinfo.st_size ;
}
return size ;
}
/*---------------------------------------------------------------------------
Function : get_bitpix()
In : allocated char buffer containing the whole FITS header
Out : int 8 16 32 -32 or -64
Job : gets the value of BITPIX from a FITS header
Notice : returns 0 if cannot find it
---------------------------------------------------------------------------*/
static
int get_bitpix(char * buf)
{
int bitpix ;
char * where ;
where = strstr(buf, "BITPIX") ;
if (where == NULL) {
fprintf(stderr, "cannot find BITPIX in header: aborting\n") ;
return 0 ;
}
sscanf(where, "%*[^=] = %d", &bitpix) ;
/*
* Check the returned value makes sense
*/
if ((bitpix != 8) &&
(bitpix != 16) &&
(bitpix != 32) &&
(bitpix != -32) &&
(bitpix != -64)) {
bitpix = 0 ;
}
return bitpix ;
}
/*---------------------------------------------------------------------------
Function : get_npix()
In : allocated char buffer containing the complete FITS header
Out : unsigned long: # of pixels in the file
Job : retrieves how many pixels in a FITS file from the header
Notice : does not support extensions!
---------------------------------------------------------------------------*/
static
int get_npix(char * buf)
{
int naxes ;
int npix ;
int naxis ;
char * where ;
char lookfor[80] ;
int i ;
where = strstr(buf, "NAXIS") ;
if (where == NULL) {
fprintf(stderr, "cannot find NAXIS in header: aborting\n") ;
return 0 ;
}
sscanf(where, "%*[^=] = %d", &naxes) ;
if ((naxes<1) || (naxes>999)) {
fprintf(stderr, "illegal value for %s: %d\n", lookfor, naxes) ;
return 0 ;
}
npix = 1 ;
for (i=1 ; i<=naxes ; i++) {
sprintf(lookfor, "NAXIS%d", i) ;
where = strstr(buf, lookfor) ;
if (where == NULL) {
fprintf(stderr, "cannot find %s in header: aborting\n",
lookfor) ;
return 0 ;
}
sscanf(where, "%*[^=] = %d", &naxis) ;
if (naxis<1) {
fprintf(stderr, "error: found %s=%d\n", lookfor, naxis);
return 0 ;
}
npix *= (int)naxis ;
}
return npix ;
}

25
qfits/setup.py 100644
View File

@ -0,0 +1,25 @@
#!/usr/bin/env python
"""Setup script for the Qfits module distribution."""
from distutils.core import setup, Extension
import glob
import os.path
setup (# Distribution meta-data
name = "Qfits",
version = "4.0",
description = "FITS header parsing module",
author = "Nicolas Devillard",
author_email = "nDevil at eso dot org",
url = "http://archive.eso.org/saft/qfits",
# Description of the modules and packages in the distribution
# packages = [''],
package_dir = {'': 'python'},
py_modules = ['Qfits'],
ext_modules =
[Extension('qfits', glob.glob(os.path.join('src', '*.c')),
include_dirs=["./include"],
library_dirs=[''],
libraries=[''],),
]
)

View File

@ -0,0 +1 @@
config.h

View File

@ -0,0 +1,149 @@
/*-------------------------------------------------------------------------*/
/**
@file byteswap.c
@author N. Devillard
@date Sep 1999
@version $Revision: 1.6 $
@brief Low-level byte-swapping routines
This module offers access to byte-swapping routines.
Generic routines are offered that should work everywhere.
Assembler is also included for x86 architectures, and dedicated
assembler calls for processors > 386.
*/
/*--------------------------------------------------------------------------*/
/*
$Id: byteswap.c,v 1.6 2002/01/22 14:49:08 ndevilla Exp $
$Author: ndevilla $
$Date: 2002/01/22 14:49:08 $
$Revision: 1.6 $
*/
/*---------------------------------------------------------------------------
Includes
---------------------------------------------------------------------------*/
#include "config.h"
/*---------------------------------------------------------------------------
Defines
---------------------------------------------------------------------------*/
/** Potential tracing feature for gcc > 2.95 */
#if (__GNUC__>2) || ((__GNUC__ == 2) && (__GNUC_MINOR__ > 95))
#define __NOTRACE__ __attribute__((__no_instrument_function__))
#else
#define __NOTRACE__
#endif
/*---------------------------------------------------------------------------
Function codes
---------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------*/
/**
@brief Swap a 16-bit number
@param w A 16-bit (short) number to byte-swap.
@return The swapped version of w, w is untouched.
This function swaps a 16-bit number, returned the swapped value without
modifying the passed argument. Assembler included for x86 architectures.
*/
/*--------------------------------------------------------------------------*/
unsigned short __NOTRACE__ swap_bytes_16(unsigned short w)
{
#ifdef CPU_X86
__asm("xchgb %b0,%h0" :
"=q" (w) :
"0" (w));
return w ;
#else
return (((w) & 0x00ff) << 8 | ((w) & 0xff00) >> 8);
#endif
}
/*-------------------------------------------------------------------------*/
/**
@brief Swap a 32-bit number
@param dw A 32-bit (long) number to byte-swap.
@return The swapped version of dw, dw is untouched.
This function swaps a 32-bit number, returned the swapped value without
modifying the passed argument. Assembler included for x86 architectures
and optimized for processors above 386.
*/
/*--------------------------------------------------------------------------*/
unsigned int __NOTRACE__ swap_bytes_32(unsigned int dw)
{
#ifdef CPU_X86
#if CPU_X86 > 386
__asm("bswap %0":
"=r" (dw) :
#else
__asm("xchgb %b0,%h0\n"
" rorl $16,%0\n"
" xchgb %b0,%h0":
"=q" (dw) :
#endif
"0" (dw));
return dw ;
#else
return ((((dw) & 0xff000000) >> 24) | (((dw) & 0x00ff0000) >> 8) |
(((dw) & 0x0000ff00) << 8) | (((dw) & 0x000000ff) << 24));
#endif
}
/*-------------------------------------------------------------------------*/
/**
@fn swap_bytes
@brief Swaps bytes in a variable of given size
@param p pointer to void (generic pointer)
@param s size of the element to swap, pointed to by p
@return void
This byte-swapper is portable and works for any even variable size.
It is not truly the most efficient ever, but does its job fine
everywhere this file compiles.
*/
/*--------------------------------------------------------------------------*/
void __NOTRACE__ swap_bytes(void * p, int s)
{
unsigned char tmp, *a, *b ;
a = (unsigned char*)p ;
b = a + s ;
while (a<b) {
tmp = *a ;
*a++ = *--b ;
*b = tmp ;
}
}
/*-------------------------------------------------------------------------*/
/**
@brief Find out if the local machine is big or little endian
@return int 1 if local machine needs byteswapping (INTEL), 0 else.
This function determines at run-time the endian-ness of the local
machine. An INTEL-like processor needs byte-swapping, a
MOTOROLA-like one does not.
*/
/*--------------------------------------------------------------------------*/
int need_byteswapping(void)
{
short ps = 0xFF ;
return ((*((char*)(&ps))) ? 1 : 0 ) ;
}
/* vim: set ts=4 et sw=4 tw=75 */

View File

@ -0,0 +1,95 @@
/*-------------------------------------------------------------------------*/
/**
@file byteswap.h
@author N. Devillard
@date Sep 1999
@version $Revision: 1.4 $
@brief Low-level byte-swapping routines
This module offers access to byte-swapping routines.
Generic routines are offered that should work everywhere.
Assembler is also included for x86 architectures, and dedicated
assembler calls for processors > 386.
*/
/*--------------------------------------------------------------------------*/
/*
$Id: byteswap.h,v 1.4 2002/01/22 14:38:37 ndevilla Exp $
$Author: ndevilla $
$Date: 2002/01/22 14:38:37 $
$Revision: 1.4 $
*/
#ifndef _BYTESWAP_H_
#define _BYTESWAP_H_
#include <stdlib.h>
/*---------------------------------------------------------------------------
Function ANSI C prototypes
---------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------*/
/**
@brief Swap a 16-bit number
@param w A 16-bit (short) number to byte-swap.
@return The swapped version of w, w is untouched.
This function swaps a 16-bit number, returned the swapped value without
modifying the passed argument. Assembler included for x86 architectures.
*/
/*--------------------------------------------------------------------------*/
unsigned short swap_bytes_16(unsigned short w);
/*-------------------------------------------------------------------------*/
/**
@brief Swap a 32-bit number
@param dw A 32-bit (long) number to byte-swap.
@return The swapped version of dw, dw is untouched.
This function swaps a 32-bit number, returned the swapped value without
modifying the passed argument. Assembler included for x86 architectures
and optimized for processors above 386.
*/
/*--------------------------------------------------------------------------*/
unsigned int swap_bytes_32(unsigned int dw);
/*-------------------------------------------------------------------------*/
/**
@brief Swaps bytes in a variable of given size
@param p pointer to void (generic pointer)
@param s size of the element to swap, pointed to by p
@return void
This byte-swapper is portable and works for any even variable size.
It is not truly the most efficient ever, but does its job fine
everywhere this file compiles.
*/
/*--------------------------------------------------------------------------*/
void swap_bytes(void * p, int s);
/*-------------------------------------------------------------------------*/
/**
@brief Find out if the local machine is big or little endian
@return int 1 if local machine needs byteswapping (INTEL), 0 else.
This function determines at run-time the endian-ness of the local
machine. An INTEL-like processor needs byte-swapping, a
MOTOROLA-like one does not.
*/
/*--------------------------------------------------------------------------*/
int need_byteswapping(void);
#ifdef __cplusplus
}
#endif
#endif
/* vim: set ts=4 et sw=4 tw=75 */

731
qfits/src/cache.c 100644
View File

@ -0,0 +1,731 @@
/*-------------------------------------------------------------------------*/
/**
@file cache.c
@author N. Devillard
@date Mar 2001
@version $Revision: 1.2 $
@brief FITS caching capabilities
This modules implements a cache for FITS access routines.
The first time a FITS file is seen by the library, all corresponding
pointers are cached here. This speeds up multiple accesses to large
files by magnitudes.
*/
/*--------------------------------------------------------------------------*/
/*
$Id: cache.c,v 1.2 2002/01/10 08:53:08 ndevilla Exp $
$Author: ndevilla $
$Date: 2002/01/10 08:53:08 $
$Revision: 1.2 $
*/
/*---------------------------------------------------------------------------
Includes
---------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "static_sz.h"
#include "cache.h"
#include "fits_p.h"
#include "fits_std.h"
/*---------------------------------------------------------------------------
Defines
---------------------------------------------------------------------------*/
/** Define this symbol to get debug symbols -- not recommended! */
#define QFITS_CACHE_DEBUG 0
#if QFITS_CACHE_DEBUG
#define qdebug( code ) { code }
#else
#define qdebug( code )
#endif
/**
* Minimum cache size: this avoids repeated mallocs to increase
* the cache size for every new file. The first table already contains
* space for MINSZ entries, and its size is doubled every time it is
* overflowed.
*/
#define QFITS_CACHE_MINSZ 128
/**
* Maximum cache size: the cache will be purged every time the number of
* input FITS files reaches above this limit. This avoids having the cache
* grow infinitely.
*/
#define QFITS_CACHE_MAXSZ 4096
/**
* This static definition declares the maximum possible number of
* extensions in a FITS file. It only has effects in the qfits_cache_add
* function where a table is statically allocated for efficiency reasons.
* If the number of extensions grows over this limit, change the value of
* this constant. If the number of extensions is a priori unknown but can
* grow much larger than a predictable value, the best solution is to
* implement a dynamic memory allocation in qfits_cache_add.
*/
#define QFITS_MAX_EXTS 128
/*---------------------------------------------------------------------------
New types
---------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------*/
/**
@brief Cache cell (private)
This structure stores all informations about a given FITS file.
It is strictly internal to this module.
*/
/*-------------------------------------------------------------------------*/
typedef struct _qfits_cache_cell_ {
char * name ; /* File name */
unsigned hash ;
time_t mtime; /* Last modification date */
time_t ctime; /* Last modification date */
int exts ; /* # of extensions in file */
int * ohdr ; /* Offsets to headers */
int * shdr ; /* Header sizes */
int * data ; /* Offsets to data */
int * dsiz ; /* Data sizes */
} qfits_cache_cell ;
static qfits_cache_cell * qfits_cache = NULL ;
static int qfits_cache_last = -1 ;
static int qfits_cache_size = 0 ;
/*---------------------------------------------------------------------------
Globals (private to this module)
---------------------------------------------------------------------------*/
static void * mem_double(void * ptr, int size);
static void qfits_cache_activate(void);
static unsigned qfits_cache_hash(char * key);
static int qfits_is_cached(char * filename);
static int qfits_cache_add(char * name);
/*---------------------------------------------------------------------------
Function codes
---------------------------------------------------------------------------*/
/* Doubles the allocated size associated to a pointer */
/* 'size' is the current allocated size. */
static void * mem_double(void * ptr, int size)
{
void * newptr ;
newptr = calloc(2*size, 1);
memcpy(newptr, ptr, size);
free(ptr);
return newptr ;
}
/*
* Activate cache: initialize cache buffer with minimum size
*/
static void qfits_cache_activate(void)
{
qdebug(
printf("qfits: activating cache...\n");
);
/* Allocate new array for cache cells */
qfits_cache = malloc(QFITS_CACHE_MINSZ * sizeof(qfits_cache_cell));
qfits_cache_size = QFITS_CACHE_MINSZ ;
/* Register purge function with atexit */
atexit(qfits_cache_purge);
return ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Purge the qfits cache.
@return void
This function is useful for programs running for a long period,
to clean up the cache. Ideally in a daemon, it should be called
by a timer at regular intervals. Notice that since the cache is
fairly small, you should not need to care too much about this.
*/
/*--------------------------------------------------------------------------*/
void qfits_cache_purge(void)
{
int i ;
if (qfits_cache==NULL)
return ;
qdebug(
printf("qfits: purging cache...\n");
);
for (i=0 ; i<qfits_cache_last ; i++) {
if (qfits_cache[i].name!=NULL)
free(qfits_cache[i].name);
if (qfits_cache[i].ohdr!=NULL)
free(qfits_cache[i].ohdr);
if (qfits_cache[i].data!=NULL)
free(qfits_cache[i].data);
if (qfits_cache[i].shdr!=NULL)
free(qfits_cache[i].shdr);
if (qfits_cache[i].dsiz!=NULL)
free(qfits_cache[i].dsiz);
}
free(qfits_cache);
qfits_cache = NULL ;
qfits_cache_size = 0 ;
qfits_cache_last = -1 ;
return ;
}
/*
* Simple hash function to speed up name lookups
*/
static unsigned qfits_cache_hash(char * key)
{
int len ;
unsigned hash ;
int i ;
len = strlen(key);
for (hash=0, i=0 ; i<len ; i++) {
hash += (unsigned)key[i] ;
hash += (hash<<10);
hash ^= (hash>>6) ;
}
hash += (hash <<3);
hash ^= (hash >>11);
hash += (hash <<15);
return hash ;
}
/*
* Find out if a file is in the cache already
*/
static int qfits_is_cached(char * filename)
{
int i ;
unsigned h ;
struct stat sta ;
if (stat(filename, &sta)!=0) {
return -1 ;
}
h = qfits_cache_hash(filename);
for (i=0 ; i<=qfits_cache_last ; i++) {
if (qfits_cache[i].hash == h) {
if (!strcmp(qfits_cache[i].name, filename)) {
if ((qfits_cache[i].mtime == sta.st_mtime) &&
(qfits_cache[i].ctime == sta.st_ctime)) {
return i ;
}
}
}
}
return -1 ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Query a FITS file offset from the cache.
@param filename Name of the file to examine.
@param what What should be queried (see below).
@return an integer offset, or -1 if an error occurred.
This function queries the cache for FITS offset information. If the
requested file name has never been seen before, it is completely parsed
to extract all offset informations, which are then stored in the cache.
The next query will get the informations from the cache, avoiding
a complete re-parsing of the file. This is especially useful for large
FITS files with lots of extensions, because querying the extensions
is an expensive operation.
This operation has side-effects: the cache is an automatically
allocated structure in memory, that can only grow. Every request
on a new FITS file will make it grow. The structure is pretty
light-weight in memory, but nonetheless this is an issue for daemon-type
programs which must run over long periods. The solution is to clean
the cache using qfits_cache_purge() at regular intervals. This is left
to the user of this library.
To request information about a FITS file, you must pass an integer
built from the following symbols:
- @c QFITS_QUERY_N_EXT
- @c QFITS_QUERY_HDR_START
- @c QFITS_QUERY_DAT_START
- @c QFITS_QUERY_HDR_SIZE
- @c QFITS_QUERY_DAT_SIZE
Querying the number of extensions present in a file is done
simply with:
@code
next = qfits_query(filename, QFITS_QUERY_N_EXT);
@endcode
Querying the offset to the i-th extension header is done with:
@code
off = qfits_query(filename, QFITS_QUERY_HDR_START | i);
@endcode
i.e. you must OR (|) the extension number with the
@c QFITS_QUERY_HDR_START symbol. Requesting offsets to extension data is
done in the same way:
@code
off = qfits_query(filename, QFITS_QUERY_DAT_START | i);
@endcode
Notice that extension 0 is the main header and main data part
of the FITS file.
*/
/*--------------------------------------------------------------------------*/
int qfits_query(char * filename, int what)
{
int rank ;
int which ;
int answer ;
if (qfits_cache==NULL)
qfits_cache_activate();
if (qfits_cache_last > QFITS_CACHE_MAXSZ) {
/* Call a purge of the cache */
qfits_cache_purge();
qfits_cache_activate();
}
qdebug(
printf("qfits: cache req %s\n", filename);
);
if ((rank=qfits_is_cached(filename))==-1) {
rank = qfits_cache_add(filename);
}
if (rank==-1) {
qdebug(
printf("qfits: error adding %s to cache\n", filename);
);
return -1 ;
}
/* See what was requested */
answer=-1 ;
if (what & QFITS_QUERY_N_EXT) {
qdebug(
printf("qfits: query n_exts\n");
);
answer = qfits_cache[rank].exts ;
} else if (what & QFITS_QUERY_HDR_START) {
which = what & (~QFITS_QUERY_HDR_START);
if (which>=0 && which<=qfits_cache[rank].exts) {
answer = qfits_cache[rank].ohdr[which] * FITS_BLOCK_SIZE ;
}
qdebug(
printf("qfits: query offset to header %d\n", which);
);
} else if (what & QFITS_QUERY_DAT_START) {
which = what & (~QFITS_QUERY_DAT_START);
if (which>=0 && which<=qfits_cache[rank].exts) {
answer = qfits_cache[rank].data[which] * FITS_BLOCK_SIZE ;
}
qdebug(
printf("qfits: query offset to data %d\n", which);
);
} else if (what & QFITS_QUERY_HDR_SIZE) {
which = what & (~QFITS_QUERY_HDR_SIZE);
if (which>=0 && which<=qfits_cache[rank].exts) {
answer = qfits_cache[rank].shdr[which] * FITS_BLOCK_SIZE ;
}
qdebug(
printf("qfits: query sizeof header %d\n", which);
);
} else if (what & QFITS_QUERY_DAT_SIZE) {
which = what & (~QFITS_QUERY_DAT_SIZE);
if (which>=0 && which<=qfits_cache[rank].exts) {
answer = qfits_cache[rank].dsiz[which] * FITS_BLOCK_SIZE ;
}
qdebug(
printf("qfits: query sizeof data %d\n", which);
);
}
return answer ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Add pointer information about a file into the qfits cache.
@param filename Name of the file to examine.
@return index to the file information in the cache, or -1 if failure.
This is the meat of this whole caching business.
This function picks a file name, and examines the corresponding FITS file
to deduce all relevant pointers in the file (byte offsets). These byte
offsets are later used to speed up header lookups. Example: requesting
some keyword information in the header of the n-th extension will first
fseek the file to the header start, then search from this position
onwards. This means that the input FITS file is only parsed for extension
positions once.
What this function does is:
- Open the file, read the first FITS block (@c FITS_BLOCK_SIZE bytes)
- Check the file is FITS (must have SIMPLE = at top)
- Register start of first header at offset 0.
- Look for END keyword, register start of first data section
if NAXIS>0.
- If the EXTEND=T line was found, continue looking for extensions.
- For each consecutive extension, register extension header start
and extension data start.
The initial implementation of this module made use of an mmap() call
to make the whole file available for search, but this is highly
unefficient on HPUX, probably because of a weak mmap() implementation
combined with very slow filesystems. The current implementation makes
block reads, which should be much faster.
*/
/*--------------------------------------------------------------------------*/
static int qfits_cache_add(char * filename)
{
FILE * in ;
int off_hdr[QFITS_MAX_EXTS];
int off_dat[QFITS_MAX_EXTS];
int i ;
char buf[FITS_BLOCK_SIZE] ;
char * buf_c ;
int n_blocks ;
int found_it ;
int xtend ;
int naxis ;
char * read_val ;
int last ;
int end_of_file ;
int npix ;
int skip_blocks ;
struct stat sta ;
qfits_cache_cell * qc ;
/* Stat file to get its size */
if (stat(filename, &sta)!=0) {
qdebug(
printf("qfits: cannot stat file %s\n", filename);
);
return -1 ;
}
/* Open input file */
if ((in=fopen(filename, "r"))==NULL) {
qdebug(
printf("qfits: cannot open file %s\n", filename);
);
return -1 ;
}
/* Read first block in */
if (fread(buf, 1, FITS_BLOCK_SIZE, in)!=FITS_BLOCK_SIZE) {
qdebug(
printf("qfits: error reading first block from %s\n", filename);
);
fclose(in);
return -1 ;
}
/* Identify FITS magic number */
if (buf[0]!='S' ||
buf[1]!='I' ||
buf[2]!='M' ||
buf[3]!='P' ||
buf[4]!='L' ||
buf[5]!='E' ||
buf[6]!=' ' ||
buf[7]!=' ' ||
buf[8]!='=') {
qdebug(
printf("qfits: file %s is not FITS\n", filename);
);
fclose(in);
return -1 ;
}
/*
* Browse through file to identify primary HDU size and see if there
* might be some extensions. The size of the primary data zone will
* also be estimated from the gathering of the NAXIS?? values and
* BITPIX.
*/
/* Rewind input file, END card might be in first block */
rewind(in);
/* Initialize all counters */
n_blocks = 0 ;
found_it = 0 ;
xtend = 0 ;
naxis = 0 ;
npix = 1 ;
/* Start looking for END card */
while (found_it==0) {
/* Read one FITS block */
if (fread(buf, 1, FITS_BLOCK_SIZE, in)!=FITS_BLOCK_SIZE) {
qdebug(
printf("qfits: error reading file %s\n", filename);
);
fclose(in);
return -1 ;
}
/* Browse through current block */
buf_c = buf ;
for (i=0 ; i<FITS_NCARDS ; i++) {
/* Look for BITPIX keyword */
if (buf_c[0]=='B' &&
buf_c[1]=='I' &&
buf_c[2]=='T' &&
buf_c[3]=='P' &&
buf_c[4]=='I' &&
buf_c[5]=='X' &&
buf_c[6]==' ') {
read_val = qfits_getvalue(buf_c);
npix *= (int)atoi(read_val) / 8 ;
if (npix<0) {
npix=-npix ;
}
} else
/* Look for NAXIS keyword */
if (buf_c[0]=='N' &&
buf_c[1]=='A' &&
buf_c[2]=='X' &&
buf_c[3]=='I' &&
buf_c[4]=='S') {
if (buf_c[5]==' ') {
/* NAXIS keyword */
read_val = qfits_getvalue(buf_c);
naxis = (int)atoi(read_val);
} else {
/* NAXIS?? keyword (axis size) */
read_val = qfits_getvalue(buf_c);
npix *= (int)atoi(read_val);
}
} else
/* Look for EXTEND keyword */
if (buf_c[0]=='E' &&
buf_c[1]=='X' &&
buf_c[2]=='T' &&
buf_c[3]=='E' &&
buf_c[4]=='N' &&
buf_c[5]=='D' &&
buf_c[6]==' ') {
/* The EXTEND keyword is present: might be some extensions */
read_val = qfits_getvalue(buf_c);
if (read_val[0]=='T' || read_val[0]=='1') {
xtend=1 ;
}
} else
/* Look for END keyword */
if (buf_c[0] == 'E' &&
buf_c[1] == 'N' &&
buf_c[2] == 'D' &&
buf_c[3] == ' ') {
found_it = 1 ;
}
buf_c += FITS_LINESZ ;
}
n_blocks ++ ;
}
/*
* Prepare qfits cache for addition of a new entry
*/
qfits_cache_last++ ;
if (qfits_cache_last==qfits_cache_size) {
/* New entry goes over allocated size: double the cache size */
qdebug(
printf("qfits: doubling cache size\n");
);
qfits_cache =
mem_double(qfits_cache,
2 * qfits_cache_size * sizeof(qfits_cache_cell));
qfits_cache_size *= 2 ;
}
/* Alias to current pointer in cache for easier reading */
qc = &(qfits_cache[qfits_cache_last]);
/* Initialize cache cell */
qc->exts=0 ;
qc->name = strdup(filename);
qc->hash = qfits_cache_hash(filename);
/* Set first HDU offsets */
off_hdr[0] = 0 ;
off_dat[0] = n_blocks ;
/* Last is the pointer to the last added extension, plus one. */
last = 1 ;
if (xtend) {
/* Look for extensions */
qdebug(
printf("qfits: searching for extensions in %s\n", filename);
);
/*
* Skip the first data section if pixels were declared
*/
if (naxis>0) {
/* Skip as many blocks as there are declared pixels */
skip_blocks = npix/FITS_BLOCK_SIZE ;
if ((npix % FITS_BLOCK_SIZE)!=0) {
skip_blocks ++ ;
}
fseek(in, skip_blocks*FITS_BLOCK_SIZE, SEEK_CUR);
/* Increase counter of current seen blocks. */
n_blocks += skip_blocks ;
}
/*
* Register all extension offsets
*/
end_of_file = 0 ;
while (end_of_file==0) {
/* Look for extension start */
found_it=0 ;
while ((found_it==0) && (end_of_file==0)) {
if (fread(buf, 1, FITS_BLOCK_SIZE, in)!=FITS_BLOCK_SIZE) {
/* Reached end of file */
end_of_file=1 ;
break ;
}
/* Search for XTENSION at block top */
if (buf[0]=='X' &&
buf[1]=='T' &&
buf[2]=='E' &&
buf[3]=='N' &&
buf[4]=='S' &&
buf[5]=='I' &&
buf[6]=='O' &&
buf[7]=='N' &&
buf[8]=='=') {
/* Got an extension */
found_it=1 ;
off_hdr[last] = n_blocks ;
}
n_blocks ++ ;
}
if (end_of_file && found_it) {
/* Reached end of file but was expecting an END */
qdebug(
printf("qfits: XTENSION without END in %s\n", filename);
);
break ;
}
/*
* Look for extension END
* Rewind one block backwards, END might be in same section as
* XTENSION start.
*/
if (fseek(in, -FITS_BLOCK_SIZE, SEEK_CUR)!=0) {
qdebug(
printf("qfits: error fseeking file backwards\n");
) ;
fclose(in);
return -1 ;
}
n_blocks -- ;
found_it=0 ;
while ((found_it==0) && (end_of_file==0)) {
if (fread(buf, 1, FITS_BLOCK_SIZE, in)!=FITS_BLOCK_SIZE) {
qdebug(
printf("qfits: XTENSION without END in %s\n", filename);
);
end_of_file=1;
break ;
}
/* Browse current block for END */
buf_c = buf ;
for (i=0 ; i<FITS_NCARDS ; i++) {
if (buf_c[0]=='E' &&
buf_c[1]=='N' &&
buf_c[2]=='D' &&
buf_c[3]==' ') {
/* Got the END card */
found_it=1 ;
/* Update registered extension list */
off_dat[last] = n_blocks+1 ;
last ++ ;
qc->exts ++ ;
break ;
}
buf_c+=FITS_LINESZ ;
}
n_blocks++ ;
}
}
}
/* Close file */
fclose(in);
/* Allocate buffers in cache */
qc->ohdr = malloc(last * sizeof(int));
qc->data = malloc(last * sizeof(int));
qc->shdr = malloc(last * sizeof(int));
qc->dsiz = malloc(last * sizeof(int));
/* Store retrieved pointers in the cache */
for (i=0 ; i<last ; i++) {
/* Offsets to start */
qc->ohdr[i] = off_hdr[i];
qc->data[i] = off_dat[i];
/* Sizes */
qc->shdr[i] = off_dat[i] - off_hdr[i] ;
if (i==last-1) {
qc->dsiz[i] = (sta.st_size/FITS_BLOCK_SIZE) - off_dat[i];
} else {
qc->dsiz[i] = off_hdr[i+1] - off_dat[i];
}
}
/* Add last modification date */
qc->mtime = sta.st_mtime ;
qc->ctime = sta.st_ctime ;
/* Return index of the added file in the cache */
return qfits_cache_last ;
}
/* vim: set ts=4 et sw=4 tw=75 */

127
qfits/src/cache.h 100644
View File

@ -0,0 +1,127 @@
/*-------------------------------------------------------------------------*/
/**
@file cache.h
@author N. Devillard
@date Mar 2001
@version $Revision: 1.3 $
@brief FITS caching capabilities
This modules implements a cache for FITS access routines.
The first time a FITS file is seen by the library, all corresponding
pointers are cached here. This speeds up multiple accesses to large
files by magnitudes.
*/
/*--------------------------------------------------------------------------*/
/*
$Id: cache.h,v 1.3 2002/01/10 08:53:08 ndevilla Exp $
$Author: ndevilla $
$Date: 2002/01/10 08:53:08 $
$Revision: 1.3 $
*/
#ifndef _CACHE_H_
#define _CACHE_H_
/*---------------------------------------------------------------------------
Includes
---------------------------------------------------------------------------*/
#include <stdio.h>
/*---------------------------------------------------------------------------
Defines
---------------------------------------------------------------------------*/
/** Query the number of extensions */
#define QFITS_QUERY_N_EXT (1<<30)
/** Query the offset to header start */
#define QFITS_QUERY_HDR_START (1<<29)
/** Query the offset to data start */
#define QFITS_QUERY_DAT_START (1<<28)
/** Query header size in bytes */
#define QFITS_QUERY_HDR_SIZE (1<<27)
/** Query data size in bytes */
#define QFITS_QUERY_DAT_SIZE (1<<26)
/* <dox> */
/*-------------------------------------------------------------------------*/
/**
@brief Purge the qfits cache.
@return void
This function is useful for programs running for a long period,
to clean up the cache. Ideally in a daemon, it should be called
by a timer at regular intervals. Notice that since the cache is
fairly small, you should not need to care too much about this.
*/
/*--------------------------------------------------------------------------*/
void qfits_cache_purge(void);
/* </dox> */
/*-------------------------------------------------------------------------*/
/**
@brief Query a FITS file offset from the cache.
@param filename Name of the file to examine.
@param what What should be queried (see below).
@return an integer offset, or -1 if an error occurred.
This function queries the cache for FITS offset information. If the
requested file name has never been seen before, it is completely parsed
to extract all offset informations, which are then stored in the cache.
The next query will get the informations from the cache, avoiding
a complete re-parsing of the file. This is especially useful for large
FITS files with lots of extensions, because querying the extensions
is an expensive operation.
This operation has side-effects: the cache is an automatically
allocated structure in memory, that can only grow. Every request
on a new FITS file will make it grow. The structure is pretty
light-weight in memory, but nonetheless this is an issue for daemon-type
programs which must run over long periods. The solution is to clean
the cache using qfits_cache_purge() at regular intervals. This is left
to the user of this library.
To request information about a FITS file, you must pass an integer
built from the following symbols:
- @c QFITS_QUERY_N_EXT
- @c QFITS_QUERY_HDR_START
- @c QFITS_QUERY_DAT_START
- @c QFITS_QUERY_HDR_SIZE
- @c QFITS_QUERY_DAT_SIZE
Querying the number of extensions present in a file is done
simply with:
@code
next = qfits_query(filename, QFITS_QUERY_N_EXT);
@endcode
Querying the offset to the i-th extension header is done with:
@code
off = qfits_query(filename, QFITS_QUERY_HDR_START | i);
@endcode
i.e. you must OR (|) the extension number with the
@c QFITS_QUERY_HDR_START symbol. Requesting offsets to extension data is
done in the same way:
@code
off = qfits_query(filename, QFITS_QUERY_DAT_START | i);
@endcode
Notice that extension 0 is the main header and main data part
of the FITS file.
*/
/*--------------------------------------------------------------------------*/
int qfits_query(char * filename, int what);
#endif
/* vim: set ts=4 et sw=4 tw=75 */

103
qfits/src/expkey.c 100644
View File

@ -0,0 +1,103 @@
/*-------------------------------------------------------------------------*/
/**
@file expkey.c
@author N. Devillard
@date Feb 2001
@version $Revisions$
@brief Expand keyword from shortFITS to HIERARCH notation
This module offers a function that is reused in a number of different
places.
*/
/*--------------------------------------------------------------------------*/
/*
$Id: expkey.c,v 1.4 2002/01/10 08:53:08 ndevilla Exp $
$Author: ndevilla $
$Date: 2002/01/10 08:53:08 $
$Revision: 1.4 $
*/
/*---------------------------------------------------------------------------
Includes
---------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "static_sz.h"
/*---------------------------------------------------------------------------
Function codes
---------------------------------------------------------------------------*/
/* Static: uppercase a string */
static char * expkey_strupc(char * s)
{
static char l[ASCIILINESZ+1];
int i ;
if (s==NULL) return NULL ;
memset(l, 0, ASCIILINESZ+1);
i=0 ;
while (s[i] && i<ASCIILINESZ) {
l[i] = (char)toupper((int)s[i]);
i++ ;
}
l[ASCIILINESZ]=(char)0;
return l ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Expand a keyword from shortFITS to HIERARCH notation.
@param keyword Keyword to expand.
@return 1 pointer to statically allocated string.
This function expands a given keyword from shortFITS to HIERARCH
notation, bringing it to uppercase at the same time.
Examples:
@verbatim
det.dit expands to HIERARCH ESO DET DIT
ins.filt1.id expands to HIERARCH ESO INS FILT1 ID
@endverbatim
If the input keyword is a regular FITS keyword (i.e. it contains
not dots '.') the result is identical to the input.
*/
/*--------------------------------------------------------------------------*/
char * qfits_expand_keyword(char * keyword)
{
static char expanded[81];
char ws[81];
char * token ;
/* Bulletproof entries */
if (keyword==NULL) return NULL ;
/* If regular keyword, copy the uppercased input and return */
if (strstr(keyword, ".")==NULL) {
strcpy(expanded, expkey_strupc(keyword));
return expanded ;
}
/* Regular shortFITS keyword */
sprintf(expanded, "HIERARCH ESO");
strcpy(ws, expkey_strupc(keyword));
token = strtok(ws, ".");
while (token!=NULL) {
strcat(expanded, " ");
strcat(expanded, token);
token = strtok(NULL, ".");
}
return expanded ;
}
/* vim: set ts=4 et sw=4 tw=75 */

54
qfits/src/expkey.h 100644
View File

@ -0,0 +1,54 @@
/*-------------------------------------------------------------------------*/
/**
@file expkey.h
@author N. Devillard
@date Feb 2001
@version $Revisions$
@brief Expand keyword from shortFITS to HIERARCH notation
This module offers a function that is reused in a number of different
places.
*/
/*--------------------------------------------------------------------------*/
/*
$Id: expkey.h,v 1.3 2002/01/10 08:53:08 ndevilla Exp $
$Author: ndevilla $
$Date: 2002/01/10 08:53:08 $
$Revision: 1.3 $
*/
#ifndef _EXPKEY_H_
#define _EXPKEY_H_
/*---------------------------------------------------------------------------
Function prototypes
---------------------------------------------------------------------------*/
/* <dox> */
/*-------------------------------------------------------------------------*/
/**
@brief Expand a keyword from shortFITS to HIERARCH notation.
@param keyword Keyword to expand.
@return 1 pointer to statically allocated string.
This function expands a given keyword from shortFITS to HIERARCH
notation, bringing it to uppercase at the same time.
Examples:
@verbatim
det.dit expands to HIERARCH ESO DET DIT
ins.filt1.id expands to HIERARCH ESO INS FILT1 ID
@endverbatim
If the input keyword is a regular FITS keyword (i.e. it contains
not dots '.') the result is identical to the input.
*/
/*--------------------------------------------------------------------------*/
char * qfits_expand_keyword(char * keyword);
/* </dox> */
#endif
/* vim: set ts=4 et sw=4 tw=75 */

1404
qfits/src/fits_h.c 100644

File diff suppressed because it is too large Load Diff

495
qfits/src/fits_h.h 100644
View File

@ -0,0 +1,495 @@
/*-------------------------------------------------------------------------*/
/**
@file fits_h.h
@author N. Devillard
@date Mar 2000
@version $Revision: 1.4 $
@brief FITS header handling
This file contains definition and related methods for the FITS header
structure. This structure is meant to remain opaque to the user, who
only accesses it through the dedicated functions offered in this module.
*/
/*--------------------------------------------------------------------------*/
/*
$Id: fits_h.h,v 1.4 2002/01/10 08:53:08 ndevilla Exp $
$Author: ndevilla $
$Date: 2002/01/10 08:53:08 $
$Revision: 1.4 $
*/
#ifndef _FITS_HEADER_H_
#define _FITS_HEADER_H_
#ifdef __cplusplus
extern "C" {
#endif
/*---------------------------------------------------------------------------
Includes
---------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
/*---------------------------------------------------------------------------
New types
---------------------------------------------------------------------------*/
/* <dox> */
/*-------------------------------------------------------------------------*/
/**
@brief FITS header object
This structure represents a FITS header in memory. It is actually no
more than a thin layer on top of the keytuple object. No field in this
structure should be directly modifiable by the user, only through
accessor functions.
*/
/*-------------------------------------------------------------------------*/
typedef struct _qfits_header_ {
void * first ; /* Pointer to list start */
void * last ; /* Pointer to list end */
int n ; /* Number of cards in list */
} qfits_header ;
/*---------------------------------------------------------------------------
Function ANSI prototypes
---------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------*/
/**
@brief FITS header constructor
@return 1 newly allocated (empty) FITS header object.
This is the main constructor for a qfits_header object. It returns
an allocated linked-list handler with an empty card list.
*/
/*--------------------------------------------------------------------------*/
qfits_header * qfits_header_new(void);
/*-------------------------------------------------------------------------*/
/**
@brief FITS header default constructor.
@return 1 newly allocated qfits_header object.
This is a secondary constructor for a qfits_header object. It returns
an allocated linked-list handler containing two cards: the first one
(SIMPLE=T) and the last one (END).
*/
/*--------------------------------------------------------------------------*/
qfits_header * qfits_header_default(void);
/*-------------------------------------------------------------------------*/
/**
@brief Add a new card to a FITS header
@param hdr qfits_header object to modify
@param key FITS key
@param val FITS value
@param com FITS comment
@param lin FITS original line if exists
@return void
This function adds a new card into a header, at the one-before-last
position, i.e. the entry just before the END entry if it is there.
The key must always be a non-NULL string, all other input parameters
are allowed to get NULL values.
*/
/*--------------------------------------------------------------------------*/
void qfits_header_add(
qfits_header * hdr,
char * key,
char * val,
char * com,
char * lin);
/*-------------------------------------------------------------------------*/
/**
@brief add a new card to a FITS header
@param hdr qfits_header object to modify
@param after Key to specify insertion place
@param key FITS key
@param val FITS value
@param com FITS comment
@param lin FITS original line if exists
@return void
Adds a new card to a FITS header, after the specified key. Nothing
happens if the specified key is not found in the header. All fields
can be NULL, except after and key.
*/
/*--------------------------------------------------------------------------*/
void qfits_header_add_after(
qfits_header * hdr,
char * after,
char * key,
char * val,
char * com,
char * lin);
/*-------------------------------------------------------------------------*/
/**
@brief Append a new card to a FITS header.
@param hdr qfits_header object to modify
@param key FITS key
@param val FITS value
@param com FITS comment
@param lin FITS original line if exists
@return void
Adds a new card in a FITS header as the last one. All fields can be
NULL except key.
*/
/*--------------------------------------------------------------------------*/
void qfits_header_append(
qfits_header * hdr,
char * key,
char * val,
char * com,
char * lin);
/*-------------------------------------------------------------------------*/
/**
@brief Delete a card in a FITS header.
@param hdr qfits_header to modify
@param key specifies which card to remove
@return void
Removes a card from a FITS header. The first found card that matches
the key is removed.
*/
/*--------------------------------------------------------------------------*/
void qfits_header_del(qfits_header * hdr, char * key);
/*-------------------------------------------------------------------------*/
/**
@brief Modifies a FITS card.
@param hdr qfits_header to modify
@param key FITS key
@param val FITS value
@param com FITS comment
@return void
Finds the first card in the header matching 'key', and replaces its
value and comment fields by the provided values. The initial FITS
line is set to NULL in the card.
*/
/*--------------------------------------------------------------------------*/
void qfits_header_mod(qfits_header * hdr, char * key, char * val, char * com);
/*-------------------------------------------------------------------------*/
/**
@brief Updates a given header with another one.
@param base Base header to update.
@param update Updating header.
@return Newly allocated qfits_header object.
@doc
A new header is created from both input headers. It contains:
- All keywords present in 'base' and not in 'update'.
- All keywords present in 'update' and not in 'base'.
- All keywords present in both headers with the same value.
- In case of conflict (a keyword present in both headers but with
different values), the key from the 'update' keyword is used.
The returned header must be freed using qfits_header_destroy.
*/
/*--------------------------------------------------------------------------*/
qfits_header * qfits_header_merge(qfits_header * base, qfits_header * update);
/*-------------------------------------------------------------------------*/
/**
@brief Copy a FITS header
@param src Header to replicate
@return Pointer to newly allocated qfits_header object.
Makes a strict copy of all information contained in the source
header. The returned header must be freed using qfits_header_destroy.
*/
/*--------------------------------------------------------------------------*/
qfits_header * qfits_header_copy(qfits_header * src);
/*-------------------------------------------------------------------------*/
/**
@brief Touch all cards in a FITS header
@param hdr qfits_header to modify
@return void
Touches all cards in a FITS header, i.e. all original FITS lines are
freed and set to NULL. Useful when a header needs to be reformatted.
*/
/*--------------------------------------------------------------------------*/
void qfits_header_touchall(qfits_header * hdr);
/*-------------------------------------------------------------------------*/
/**
@brief Dump a FITS header to stdout
@param hdr qfits_header to dump
@return void
Dump a FITS header to stdout. Mostly for debugging purposes.
*/
/*--------------------------------------------------------------------------*/
void qfits_header_consoledump(qfits_header * hdr);
/*-------------------------------------------------------------------------*/
/**
@brief qfits_header destructor
@param hdr qfits_header to deallocate
@return void
Frees all memory associated to a given qfits_header object.
*/
/*--------------------------------------------------------------------------*/
void qfits_header_destroy(qfits_header * hdr);
/*-------------------------------------------------------------------------*/
/**
@brief Return the value associated to a key, as a string
@param hdr qfits_header to parse
@param key key to find
@return pointer to statically allocated string
Finds the value associated to the given key and return it as a
string. The returned pointer is statically allocated, so do not
modify its contents or try to free it.
Returns NULL if no matching key is found or no value is attached.
*/
/*--------------------------------------------------------------------------*/
char * qfits_header_getstr(qfits_header * hdr, char * key);
/*-------------------------------------------------------------------------*/
/**
@brief Find a matching key in a header.
@param hdr qfits_header to parse
@param key Key prefix to match
@return pointer to statically allocated string.
This function finds the first keyword in the given header for
which the given 'key' is a prefix, and returns the full name
of the matching key (NOT ITS VALUE). This is useful to locate
any keyword starting with a given prefix. Careful with HIERARCH
keywords, the shortFITS notation is not likely to be accepted here.
Examples:
@verbatim
s = qfits_header_findmatch(hdr, "SIMP") returns "SIMPLE"
s = qfits_header_findmatch(hdr, "HIERARCH ESO DET") returns
the first detector keyword among the HIERACH keys.
@endverbatim
*/
/*--------------------------------------------------------------------------*/
char * qfits_header_findmatch(qfits_header * hdr, char * key);
/*-------------------------------------------------------------------------*/
/**
@brief Return the i-th key/val/com/line tuple in a header.
@param hdr Header to consider
@param idx Index of the requested card
@param key Output key
@param val Output value
@param com Output comment
@param lin Output initial line
@return int 0 if Ok, -1 if error occurred.
This function is useful to browse a FITS header object card by card.
By iterating on the number of cards (available in the 'n' field of
the qfits_header struct), you can retrieve the FITS lines and their
components one by one. Indexes run from 0 to n-1. You can pass NULL
values for key, val, com or lin if you are not interested in a
given field.
@code
int i ;
char key[80], val[80], com[80], lin[80] ;
for (i=0 ; i<hdr->n ; i++) {
qfits_header_getitem(hdr, i, key, val, com, lin);
printf("card[%d] key[%s] val[%s] com[%s]\n", i, key, val, com);
}
@endcode
*/
/*--------------------------------------------------------------------------*/
int qfits_header_getitem(
qfits_header * hdr,
int idx,
char * key,
char * val,
char * com,
char * lin
);
/*-------------------------------------------------------------------------*/
/**
@brief Return the FITS line associated to a key, as a string
@param hdr qfits_header to parse
@param key key to find
@return pointer to statically allocated string
Finds the FITS line associated to the given key and return it as a
string. The returned pointer is statically allocated, so do not
modify its contents or try to free it.
Returns NULL if no matching key is found or no line is attached.
*/
/*--------------------------------------------------------------------------*/
char * qfits_header_getline(qfits_header * hdr, char * key);
/*-------------------------------------------------------------------------*/
/**
@brief Return the comment associated to a key, as a string
@param hdr qfits_header to parse
@param key key to find
@return pointer to statically allocated string
@doc
Finds the comment associated to the given key and return it as a
string. The returned pointer is statically allocated, so do not
modify its contents or try to free it.
Returns NULL if no matching key is found or no comment is attached.
*/
/*--------------------------------------------------------------------------*/
char * qfits_header_getcom(qfits_header * hdr, char * key);
/*-------------------------------------------------------------------------*/
/**
@brief Return the value associated to a key, as an int
@param hdr qfits_header to parse
@param key key to find
@param errval default value to return if nothing is found
@return int
Finds the value associated to the given key and return it as an
int. Returns errval if no matching key is found or no value is
attached.
*/
/*--------------------------------------------------------------------------*/
int qfits_header_getint(qfits_header * hdr, char * key, int errval);
/*-------------------------------------------------------------------------*/
/**
@brief Return the value associated to a key, as a double
@param hdr qfits_header to parse
@param key key to find
@param errval default value to return if nothing is found
@return double
Finds the value associated to the given key and return it as a
double. Returns errval if no matching key is found or no value is
attached.
*/
/*--------------------------------------------------------------------------*/
double qfits_header_getdouble(qfits_header * hdr, char * key, double errval);
/*-------------------------------------------------------------------------*/
/**
@brief Return the value associated to a key, as a boolean (int).
@param hdr qfits_header to parse
@param key key to find
@param errval default value to return if nothing is found
@return int
Finds the value associated to the given key and return it as a
boolean. Returns errval if no matching key is found or no value is
attached. A boolean is here understood as an int taking the value 0
or 1. errval can be set to any other integer value to reflect that
nothing was found.
errval is returned if no matching key is found or no value is
attached.
A true value is any character string beginning with a 'y' (yes), a
't' (true) or the digit '1'. A false value is any character string
beginning with a 'n' (no), a 'f' (false) or the digit '0'.
*/
/*--------------------------------------------------------------------------*/
int qfits_header_getboolean(qfits_header * hdr, char * key, int errval);
/*-------------------------------------------------------------------------*/
/**
@brief Write out a key tuple to a string on 80 chars.
@param line Allocated output character buffer.
@param key Key to write.
@param val Value to write.
@param com Comment to write.
@return void
Write out a key, value and comment into an allocated character buffer.
The buffer must be at least 80 chars to receive the information.
Formatting is done according to FITS standard.
*/
/*--------------------------------------------------------------------------*/
void keytuple2str(char * line, char * key, char * val, char * com);
/*-------------------------------------------------------------------------*/
/**
@brief Dump a FITS header to an opened file.
@param hdr FITS header to dump
@param out Opened file pointer
@return int 0 if Ok, -1 otherwise
Dumps a FITS header to an opened file pointer.
*/
/*--------------------------------------------------------------------------*/
int qfits_header_dump(qfits_header * hdr, FILE * out);
/*-------------------------------------------------------------------------*/
/**
@brief Dump a fits header into a memory block.
@param fh FITS header to dump
@param hsize Size of the returned header, in bytes (output).
@return 1 newly allocated memory block containing the FITS header.
This function dumps a FITS header structure into a newly allocated
memory block. The block is composed of characters, just as they would
appear in a FITS file. This function is useful to make a FITS header
in memory.
The returned block size is indicated in the passed output variable
'hsize'. The returned block must be deallocated using free().
*/
/*--------------------------------------------------------------------------*/
char * qfits_header_to_memblock(qfits_header * fh, int * hsize);
/* </dox> */
#ifdef __cplusplus
}
#endif
#endif
/* vim: set ts=4 et sw=4 tw=75 */

View File

@ -0,0 +1,181 @@
/*-------------------------------------------------------------------------*/
/**
@file fits_md5.c
@author N. Devillard
@date May 2001
@version $Revision: 1.4 $
@brief FITS data block MD5 computation routine.
This module offers MD5 computation over all data areas of a FITS file.
*/
/*--------------------------------------------------------------------------*/
/*
$Id: fits_md5.c,v 1.4 2002/01/10 08:53:08 ndevilla Exp $
$Author: ndevilla $
$Date: 2002/01/10 08:53:08 $
$Revision: 1.4 $
*/
/*---------------------------------------------------------------------------
Includes
---------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "md5.h"
#include "fits_std.h"
#include "qerror.h"
/*---------------------------------------------------------------------------
Defines
---------------------------------------------------------------------------*/
/** Size of an MD5 hash in bytes (32 bytes are 128 bits) */
#define MD5HASHSZ 32
/*---------------------------------------------------------------------------
Function code
---------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------*/
/**
@brief Compute the MD5 hash of data zones in a FITS file.
@param filename Name of the FITS file to examine.
@return 1 statically allocated character string, or NULL.
This function expects the name of a FITS file.
It will compute the MD5 hash on all data blocks in the main data section
and possibly extensions (including zero-padding blocks if necessary) and
return it as a string suitable for inclusion into a FITS keyword.
The returned string is statically allocated inside this function,
so do not free it or modify it. This function returns NULL in case
of error.
*/
/*--------------------------------------------------------------------------*/
char * qfits_datamd5(char * filename)
{
static char datamd5[MD5HASHSZ+1] ;
struct MD5Context ctx ;
unsigned char digest[16] ;
FILE * in ;
char buf[FITS_BLOCK_SIZE];
char * buf_c ;
int i ;
int in_header ;
int check_fits ;
/* Check entries */
if (filename==NULL) return NULL ;
/* Open input file */
if ((in=fopen(filename, "r"))==NULL) {
qfits_error("cannot open file %s", filename);
return NULL ;
}
/* Initialize all variables */
MD5Init(&ctx);
in_header=1 ;
check_fits=0 ;
/* Loop over input file */
while (fread(buf, 1, FITS_BLOCK_SIZE, in)==FITS_BLOCK_SIZE) {
/* First time in the loop: check the file is FITS */
if (check_fits==0) {
/* Examine first characters in block */
if (buf[0]!='S' ||
buf[1]!='I' ||
buf[2]!='M' ||
buf[3]!='P' ||
buf[4]!='L' ||
buf[5]!='E' ||
buf[6]!=' ' ||
buf[7]!=' ' ||
buf[8]!='=') {
qfits_error("file [%s] is not FITS\n", filename);
fclose(in);
return NULL ;
} else {
check_fits=1 ;
}
}
if (in_header) {
buf_c = buf ;
for (i=0 ; i<FITS_NCARDS ; i++) {
if (buf_c[0]=='E' &&
buf_c[1]=='N' &&
buf_c[2]=='D' &&
buf_c[3]==' ') {
in_header=0 ;
break ;
}
buf_c += FITS_LINESZ ;
}
} else {
/* If current block is a data block */
/* Try to locate an extension header */
if (buf[0]=='X' &&
buf[1]=='T' &&
buf[2]=='E' &&
buf[3]=='N' &&
buf[4]=='S' &&
buf[5]=='I' &&
buf[6]=='O' &&
buf[7]=='N' &&
buf[8]=='=') {
in_header=1 ;
buf_c = buf ;
for (i=0 ; i<FITS_NCARDS ; i++) {
/* Try to find an END marker in this block */
if (buf_c[0]=='E' &&
buf_c[1]=='N' &&
buf_c[2]=='D' &&
buf_c[3]==' ') {
/* Found END marker in same block as XTENSION */
in_header=0;
break ;
}
buf_c += FITS_LINESZ ;
}
} else {
MD5Update(&ctx, (unsigned char *)buf, FITS_BLOCK_SIZE);
}
}
}
fclose(in);
if (check_fits==0) {
/* Never went through the read loop: file is not FITS */
qfits_error("file [%s] is not FITS", filename);
return NULL ;
}
/* Got to the end of file: summarize */
MD5Final(digest, &ctx);
/* Write digest into a string */
sprintf(datamd5,
"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
digest[ 0],
digest[ 1],
digest[ 2],
digest[ 3],
digest[ 4],
digest[ 5],
digest[ 6],
digest[ 7],
digest[ 8],
digest[ 9],
digest[10],
digest[11],
digest[12],
digest[13],
digest[14],
digest[15]);
return datamd5 ;
}
/* vim: set ts=4 et sw=4 tw=75 */

View File

@ -0,0 +1,57 @@
/*-------------------------------------------------------------------------*/
/**
@file fits_md5.h
@author N. Devillard
@date May 2001
@version $Revision: 1.3 $
@brief FITS data block MD5 computation routine.
This module offers MD5 computation over all data areas of a FITS file.
*/
/*--------------------------------------------------------------------------*/
/*
$Id: fits_md5.h,v 1.3 2002/01/10 08:53:08 ndevilla Exp $
$Author: ndevilla $
$Date: 2002/01/10 08:53:08 $
$Revision: 1.3 $
*/
#ifndef _FITS_MD5_H_
#define _FITS_MD5_H_
/*---------------------------------------------------------------------------
Includes
---------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*---------------------------------------------------------------------------
Function ANSI prototypes
---------------------------------------------------------------------------*/
/* <dox> */
/*-------------------------------------------------------------------------*/
/**
@brief Compute the MD5 hash of data zones in a FITS file.
@param filename Name of the FITS file to examine.
@return 1 statically allocated character string, or NULL.
This function expects the name of a FITS file.
It will compute the MD5 hash on all data blocks in the main data section
and possibly extensions (including zero-padding blocks if necessary) and
return it as a string suitable for inclusion into a FITS keyword.
The returned string is statically allocated inside this function,
so do not free it or modify it. This function returns NULL in case
of error.
*/
/*--------------------------------------------------------------------------*/
char * qfits_datamd5(char * filename);
/* </dox> */
#endif
/* vim: set ts=4 et sw=4 tw=75 */

354
qfits/src/fits_p.c 100644
View File

@ -0,0 +1,354 @@
/*-------------------------------------------------------------------------*/
/**
@file fits_p.c
@author N. Devillard
@date Mar 2000
@version $Revision: 1.3 $
@brief FITS parser for a single card
This module contains various routines to help parsing a single FITS
card into its components: key, value, comment.
*/
/*--------------------------------------------------------------------------*/
/*
$Id: fits_p.c,v 1.3 2002/01/10 08:53:08 ndevilla Exp $
$Author: ndevilla $
$Date: 2002/01/10 08:53:08 $
$Revision: 1.3 $
*/
/*---------------------------------------------------------------------------
Includes
---------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "simple.h"
/*---------------------------------------------------------------------------
Defines
---------------------------------------------------------------------------*/
/* Define the following to get zillions of debug messages */
/* #define DEBUG_FITSHEADER */
/*---------------------------------------------------------------------------
Function codes
---------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------*/
/**
@brief Find the keyword in a key card (80 chars)
@param line allocated 80-char line from a FITS header
@return statically allocated char *
Find out the part of a FITS line corresponding to the keyword.
Returns NULL in case of error. The returned pointer is statically
allocated in this function, so do not modify or try to free it.
*/
/*--------------------------------------------------------------------------*/
char * qfits_getkey(char * line)
{
static char key[81];
int i ;
if (line==NULL) {
#ifdef DEBUG_FITSHEADER
printf("qfits_getkey: NULL input line\n");
#endif
return NULL ;
}
/* Special case: blank keyword */
if (!strncmp(line, " ", 8)) {
strcpy(key, " ");
return key ;
}
/*
* Sort out special cases: HISTORY, COMMENT and END do not have
* equal signs on the line.
*/
if (!strncmp(line, "HISTORY ", 8)) {
strcpy(key, "HISTORY");
return key ;
}
if (!strncmp(line, "COMMENT ", 8)) {
strcpy(key, "COMMENT");
return key ;
}
if (!strncmp(line, "END ", 4)) {
strcpy(key, "END");
return key ;
}
memset(key, 0, 81);
/* General case: look for the first equal sign */
i=0 ;
while (line[i]!='=' && i<80) i++ ;
if (i>=80) {
#ifdef DEBUG_FITSHEADER
printf("qfits_getkey: cannot find equal sign\n");
#endif
return NULL ;
}
i-- ;
/* Equal sign found, now backtrack on blanks */
while (line[i]==' ' && i>=0) i-- ;
if (i<=0) {
#ifdef DEBUG_FITSHEADER
printf("qfits_getkey: error backtracking on blanks\n");
#endif
return NULL ;
}
i++ ;
/* Copy relevant characters into output buffer */
strncpy(key, line, i) ;
/* Null-terminate the string */
key[i+1] = (char)0;
return key ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Find the value in a key card (80 chars)
@param line allocated 80-char line from a FITS header
@return statically allocated char *
Find out the part of a FITS line corresponding to the value.
Returns NULL in case of error, or if no value can be found. The
returned pointer is statically allocated in this function, so do not
modify or try to free it.
*/
/*--------------------------------------------------------------------------*/
char * qfits_getvalue(char * line)
{
static char value[81] ;
int i ;
int from, to ;
int inq ;
if (line==NULL) {
#ifdef DEBUG_FITSHEADER
printf("qfits_getvalue: NULL input line\n");
#endif
return NULL ;
}
/* Special cases */
/* END has no associated value */
if (!strncmp(line, "END ", 4)) {
return NULL ;
}
/*
* HISTORY has for value everything else on the line, stripping
* blanks before and after. Blank HISTORY is also accepted.
*/
memset(value, 0, 81);
if (!strncmp(line, "HISTORY ", 8) || !strncmp(line, " ", 8)) {
i=7 ;
/* Strip blanks from the left side */
while (line[i]==' ' && i<80) i++ ;
if (i>=80) return NULL ; /* Blank HISTORY */
from=i ;
/* Strip blanks from the right side */
to=79 ;
while (line[to]==' ') to-- ;
/* Copy relevant characters into output buffer */
strncpy(value, line+from, to-from+1);
/* Null-terminate the string */
value[to-from+1] = (char)0;
return value ;
} else if (!strncmp(line, "COMMENT ", 8)) {
/*
* COMMENT is like HISTORY
*/
/* Strip blanks from the left side */
i=7 ;
while (line[i]==' ' && i<80) i++ ;
if (i>=80) return NULL ;
from=i ;
/* Strip blanks from the right side */
to=79 ;
while (line[to]==' ') to-- ;
if (to<from) {
#ifdef DEBUG_FITSHEADER
printf("qfits_getvalue: inconsistent value search in COMMENT\n");
#endif
return NULL ;
}
/* Copy relevant characters into output buffer */
strncpy(value, line+from, to-from+1);
/* Null-terminate the string */
value[to-from+1] = (char)0;
return value ;
}
/*
* General case
* Get past the keyword
*/
i=0 ;
while (line[i]!='=' && i<80) i++ ;
if (i>80) {
#ifdef DEBUG_FITSHEADER
printf("qfits_getvalue: no equal sign found on line\n");
#endif
return NULL ;
}
i++ ;
while (line[i]==' ' && i<80) i++ ;
if (i>80) {
#ifdef DEBUG_FITSHEADER
printf("qfits_getvalue: no value past the equal sign\n");
#endif
return NULL ;
}
from=i;
/*
* Now in the value section
* Look for the first slash '/' outside of a string
*/
inq = 0 ;
while (i<80) {
if (line[i]=='\'')
inq=!inq ;
if (line[i]=='/')
if (!inq)
break ;
i++;
}
i-- ;
/* Backtrack on blanks */
while (line[i]==' ' && i>=0) i-- ;
if (i<0) {
#ifdef DEBUG_FITSHEADER
printf("qfits_getvalue: error backtracking on blanks\n");
#endif
return NULL ;
}
to=i ;
if (to<from) {
#ifdef DEBUG_FITSHEADER
printf("qfits_getvalue: from>to?\n");
printf("line=[%s]\n", line);
#endif
return NULL ;
}
/* Copy relevant characters into output buffer */
strncpy(value, line+from, to-from+1);
/* Null-terminate the string */
value[to-from+1] = (char)0;
return value ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Find the comment in a key card (80 chars)
@param line allocated 80-char line from a FITS header
@return statically allocated char *
Find out the part of a FITS line corresponding to the comment.
Returns NULL in case of error, or if no comment can be found. The
returned pointer is statically allocated in this function, so do not
modify or try to free it.
*/
/*--------------------------------------------------------------------------*/
char * qfits_getcomment(char * line)
{
static char comment[81];
int i ;
int from, to ;
int inq ;
if (line==NULL) {
#ifdef DEBUG_FITSHEADER
printf("qfits_getcomment: null line in input\n");
#endif
return NULL ;
}
/* Special cases: END, HISTORY, COMMENT and blank have no comment */
if (!strncmp(line, "END ", 4)) return NULL ;
if (!strncmp(line, "HISTORY ", 8)) return NULL ;
if (!strncmp(line, "COMMENT ", 8)) return NULL ;
if (!strncmp(line, " ", 8)) return NULL ;
memset(comment, 0, 81);
/* Get past the keyword */
i=0 ;
while (line[i]!='=' && i<80) i++ ;
if (i>=80) {
#ifdef DEBUG_FITSHEADER
printf("qfits_getcomment: no equal sign on line\n");
#endif
return NULL ;
}
i++ ;
/* Get past the value until the slash */
inq = 0 ;
while (i<80) {
if (line[i]=='\'')
inq = !inq ;
if (line[i]=='/')
if (!inq)
break ;
i++ ;
}
if (i>=80) {
#ifdef DEBUG_FITSHEADER
printf("qfits_getcomment: no slash found on line\n");
#endif
return NULL ;
}
i++ ;
/* Get past the first blanks */
while (line[i]==' ') i++ ;
from=i ;
/*
* Now backtrack from the end of the line to the first non-blank
* character.
*/
to=79 ;
while (line[to]==' ') to-- ;
if (to<from) {
#ifdef DEBUG_FITSHEADER
printf("qfits_getcomment: from>to?\n");
#endif
return NULL ;
}
/* Copy relevant characters into output buffer */
strncpy(comment, line+from, to-from+1);
/* Null-terminate the string */
comment[to-from+1] = (char)0;
return comment ;
}
/* vim: set ts=4 et sw=4 tw=75 */

89
qfits/src/fits_p.h 100644
View File

@ -0,0 +1,89 @@
/*-------------------------------------------------------------------------*/
/**
@file fits_p.h
@author N. Devillard
@date Mar 2000
@version $Revision: 1.3 $
@brief FITS parser for a single card
This module contains various routines to help parsing a single FITS
card into its components: key, value, comment.
*/
/*--------------------------------------------------------------------------*/
/*
$Id: fits_p.h,v 1.3 2002/01/10 08:53:08 ndevilla Exp $
$Author: ndevilla $
$Date: 2002/01/10 08:53:08 $
$Revision: 1.3 $
*/
#ifndef _FITSEP_H_
#define _FITSEP_H_
#ifdef __cplusplus
extern "C" {
#endif
/*---------------------------------------------------------------------------
Includes
---------------------------------------------------------------------------*/
/* <dox> */
/*---------------------------------------------------------------------------
Function ANSI C prototypes
---------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------*/
/**
@brief Find the keyword in a key card (80 chars)
@param line allocated 80-char line from a FITS header
@return statically allocated char *
Find out the part of a FITS line corresponding to the keyword.
Returns NULL in case of error. The returned pointer is statically
allocated in this function, so do not modify or try to free it.
*/
/*--------------------------------------------------------------------------*/
char * qfits_getkey(char * line);
/*-------------------------------------------------------------------------*/
/**
@brief Find the value in a key card (80 chars)
@param line allocated 80-char line from a FITS header
@return statically allocated char *
Find out the part of a FITS line corresponding to the value.
Returns NULL in case of error, or if no value can be found. The
returned pointer is statically allocated in this function, so do not
modify or try to free it.
*/
/*--------------------------------------------------------------------------*/
char * qfits_getvalue(char * line);
/*-------------------------------------------------------------------------*/
/**
@brief Find the comment in a key card (80 chars)
@param line allocated 80-char line from a FITS header
@return statically allocated char *
Find out the part of a FITS line corresponding to the comment.
Returns NULL in case of error, or if no comment can be found. The
returned pointer is statically allocated in this function, so do not
modify or try to free it.
*/
/*--------------------------------------------------------------------------*/
char * qfits_getcomment(char * line);
/* </dox> */
#ifdef __cplusplus
}
#endif
#endif
/* vim: set ts=4 et sw=4 tw=75 */

309
qfits/src/fits_rw.c 100644
View File

@ -0,0 +1,309 @@
/*-------------------------------------------------------------------------*/
/**
@file fits_rw.c
@author N. Devillard
@date Mar 2000
@version $Revision: 1.6 $
@brief FITS header reading/writing.
*/
/*--------------------------------------------------------------------------*/
/*
$Id: fits_rw.c,v 1.6 2002/01/10 08:53:08 ndevilla Exp $
$Author: ndevilla $
$Date: 2002/01/10 08:53:08 $
$Revision: 1.6 $
*/
/*---------------------------------------------------------------------------
Includes
---------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "fits_rw.h"
#include "fits_h.h"
#include "fits_p.h"
#include "simple.h"
#include "xmemory.h"
#include "qerror.h"
/*---------------------------------------------------------------------------
Private to this module
---------------------------------------------------------------------------*/
static int is_blank_line(char * s)
{
int i ;
for (i=0 ; i<(int)strlen(s) ; i++) {
if (s[i]!=' ') return 0 ;
}
return 1 ;
}
/*---------------------------------------------------------------------------
Function codes
---------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------*/
/**
@brief Read a FITS header from a file to an internal structure.
@param filename Name of the file to be read
@return Pointer to newly allocated qfits_header
This function parses a FITS (main) header, and returns an allocated
qfits_header object. The qfits_header object contains a linked-list of
key "tuples". A key tuple contains:
- A keyword
- A value
- A comment
- An original FITS line (as read from the input file)
Direct access to the structure is not foreseen, use accessor
functions in fits_h.h
Value, comment, and original line might be NULL pointers.
The qfits_header type is an alias for the llist_t type from the list
module, which should remain opaque.
Returns NULL in case of error.
*/
/*--------------------------------------------------------------------------*/
qfits_header * qfits_header_read(char * filename)
{
qfits_header* hdr ;
char line[81];
char * start ;
char * where ;
char * key,
* val,
* com ;
size_t fsize ;
start = falloc(filename, 0, &fsize);
if (start==NULL) return NULL ;
hdr = qfits_header_new();
if (hdr==NULL) {
free(start);
return NULL ;
}
where = start ;
while (1) {
memcpy(line, where, 80);
line[80] = (char)0;
/* Rule out blank lines */
if (!is_blank_line(line)) {
/* Get key, value, comment for current line */
key = qfits_getkey(line);
val = qfits_getvalue(line);
com = qfits_getcomment(line);
/* Any NULL response key triggers an error */
if (key==NULL) {
qfits_error("in header: cannot read key from\n[%s]", line);
qfits_header_destroy(hdr);
hdr = NULL ;
break ;
}
/* Append current card to linked-list */
qfits_header_append(hdr, key, val, com, line);
/* Check for END keyword */
if (strlen(key)==3)
if (key[0]=='E' &&
key[1]=='N' &&
key[2]=='D')
break ;
}
/* Move out to next line */
where += 80 ;
/* If reaching the end of the file, trigger an error */
if ((int)(where-start)>=(int)(fsize+80)) {
qfits_header_destroy(hdr);
hdr = NULL ;
break ;
}
}
free(start);
return hdr ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Read an extension header from a FITS file.
@param filename Name of the FITS file to read
@param xtnum Extension number to read, starting from 1.
@return Newly allocated qfits_header structure.
Strictly similar to qfits_header_read() but reads headers from
extensions instead.
Returns NULL in case of error.
*/
/*--------------------------------------------------------------------------*/
qfits_header * qfits_header_readext(char * filename, int xtnum)
{
qfits_header* hdr ;
int n_ext ;
int hdrstart ;
char line[81];
char * where ;
char * start ;
char * key,
* val,
* com ;
size_t fsize ;
/* Check input */
if (xtnum<1) return NULL ;
/* Check that there are enough extensions */
n_ext = qfits_query_n_ext(filename);
if (xtnum>n_ext) return NULL ;
/* Get offset to the extension header */
if (qfits_get_hdrinfo(filename, xtnum, &hdrstart, NULL)!=0) {
return NULL ;
}
/* Memory-map the input file */
start = falloc(filename, hdrstart, &fsize) ;
if (start==NULL) return NULL ;
hdr = qfits_header_new() ;
where = start ;
while (1) {
memcpy(line, where, 80);
line[80] = (char)0;
/* Rule out blank lines */
if (!is_blank_line(line)) {
/* Get key, value, comment for the current line */
key = qfits_getkey(line);
val = qfits_getvalue(line);
com = qfits_getcomment(line);
/* If key or value cannot be found, trigger an error */
if (key==NULL) {
qfits_header_destroy(hdr);
hdr = NULL ;
break ;
}
/* Append card to linked-list */
qfits_header_append(hdr, key, val, com, line);
/* Check for END keyword */
if (strlen(key)==3)
if (key[0]=='E' &&
key[1]=='N' &&
key[2]=='D')
break ;
}
where += 80 ;
/* If reaching the end of file, trigger an error */
if ((int)(where-start)>=(int)(fsize+80)) {
qfits_header_destroy(hdr);
hdr = NULL ;
break ;
}
}
free(start);
return hdr ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Pad an existing file with zeros to a multiple of 2880.
@param filename Name of the file to pad.
@return void
This function simply pads an existing file on disk with enough zeros
for the file size to reach a multiple of 2880, as required by FITS.
*/
/*--------------------------------------------------------------------------*/
void qfits_zeropad(char * filename)
{
struct stat sta ;
int size ;
int remaining;
FILE * out ;
char * buf;
if (filename==NULL) return ;
/* Get file size in bytes */
if (stat(filename, &sta)!=0) {
return ;
}
size = (int)sta.st_size ;
/* Compute number of zeros to pad */
remaining = size % FITS_BLOCK_SIZE ;
if (remaining==0) return ;
remaining = FITS_BLOCK_SIZE - remaining ;
/* Open file, dump zeros, exit */
if ((out=fopen(filename, "a"))==NULL)
return ;
buf = calloc(remaining, sizeof(char));
fwrite(buf, 1, remaining, out);
fclose(out);
free(buf);
return ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Identify if a file is a FITS file.
@param filename name of the file to check
@return int 0, 1, or -1
Returns 1 if the file name looks like a valid FITS file. Returns
0 else. If the file does not exist, returns -1.
*/
/*--------------------------------------------------------------------------*/
int is_fits_file(char *filename)
{
FILE *fp ;
char *magic ;
int isfits ;
if (filename==NULL) return -1 ;
if ((fp = fopen(filename, "r"))==NULL) {
qfits_error("cannot open file [%s]", filename) ;
return -1 ;
}
magic = calloc(FITS_MAGIC_SZ+1, sizeof(char)) ;
fread(magic, 1, FITS_MAGIC_SZ, fp) ;
fclose(fp) ;
magic[FITS_MAGIC_SZ] = (char)0 ;
if (strstr(magic, FITS_MAGIC)!=NULL)
isfits = 1 ;
else
isfits = 0 ;
free(magic) ;
return isfits ;
}
/* vim: set ts=4 et sw=4 tw=75 */

115
qfits/src/fits_rw.h 100644
View File

@ -0,0 +1,115 @@
/*-------------------------------------------------------------------------*/
/**
@file fits_rw.h
@author N. Devillard
@date Mar 2000
@version $Revision: 1.4 $
@brief FITS header reading/writing.
*/
/*--------------------------------------------------------------------------*/
/*
$Id: fits_rw.h,v 1.4 2002/01/10 08:53:08 ndevilla Exp $
$Author: ndevilla $
$Date: 2002/01/10 08:53:08 $
$Revision: 1.4 $
*/
#ifndef _FITS_RW_H_
#define _FITS_RW_H_
#ifdef __cplusplus
extern "C" {
#endif
/*---------------------------------------------------------------------------
Includes
---------------------------------------------------------------------------*/
#include "fits_std.h"
#include "fits_h.h"
/*---------------------------------------------------------------------------
Function ANSI prototypes
---------------------------------------------------------------------------*/
/* <dox> */
/*-------------------------------------------------------------------------*/
/**
@brief Read a FITS header from a file to an internal structure.
@param filename Name of the file to be read
@return Pointer to newly allocated qfits_header
This function parses a FITS (main) header, and returns an allocated
qfits_header object. The qfits_header object contains a linked-list of
key "tuples". A key tuple contains:
- A keyword
- A value
- A comment
- An original FITS line (as read from the input file)
Direct access to the structure is not foreseen, use accessor
functions in fits_h.h
Value, comment, and original line might be NULL pointers.
The qfits_header type is an alias for the llist_t type from the list
module, which should remain opaque.
Returns NULL in case of error.
*/
/*--------------------------------------------------------------------------*/
qfits_header * qfits_header_read(char * filename);
/*-------------------------------------------------------------------------*/
/**
@brief Read an extension header from a FITS file.
@param filename Name of the FITS file to read
@param xtnum Extension number to read, starting from 1.
@return Newly allocated qfits_header structure.
Strictly similar to fits_read_header() but reads headers from
extensions instead.
Returns NULL in case of error.
*/
/*--------------------------------------------------------------------------*/
qfits_header * qfits_header_readext(char * filename, int xtnum);
/*-------------------------------------------------------------------------*/
/**
@brief Pad an existing file with zeros to a multiple of 2880.
@param filename Name of the file to pad.
@return void
This function simply pads an existing file on disk with enough zeros
for the file size to reach a multiple of 2880, as required by FITS.
*/
/*--------------------------------------------------------------------------*/
void qfits_zeropad(char * filename);
/*-------------------------------------------------------------------------*/
/**
@brief Identify if a file is a FITS file.
@param filename name of the file to check
@return int 0, 1, or -1
Returns 1 if the file name looks like a valid FITS file. Returns
0 else. If the file does not exist, returns -1.
*/
/*--------------------------------------------------------------------------*/
int is_fits_file(char *filename);
/* </dox> */
#ifdef __cplusplus
}
#endif
#endif
/* vim: set ts=4 et sw=4 tw=75 */

View File

@ -0,0 +1,74 @@
/*-------------------------------------------------------------------------*/
/**
@file fits_std.h
@author N. Devillard
@date November 2001
@version $Revision: 1.3 $
@brief
This header file gathers a number of definitions strictly related
to the FITS format. Include it if you need to get definitions for
a FITS line size, header metrics, and other FITS-only symbols.
*/
/*--------------------------------------------------------------------------*/
/*
$Id: fits_std.h,v 1.3 2002/01/10 08:53:08 ndevilla Exp $
$Author: ndevilla $
$Date: 2002/01/10 08:53:08 $
$Revision: 1.3 $
*/
#ifndef _FITS_STD_H_
#define _FITS_STD_H_
/*---------------------------------------------------------------------------
Defines
---------------------------------------------------------------------------*/
/* <dox> */
/* FITS header constants */
/** FITS block size */
#define FITS_BLOCK_SIZE (2880)
/** FITS number of cards per block */
#define FITS_NCARDS (36)
/** FITS size of each line in bytes */
#define FITS_LINESZ (80)
/** FITS magic number */
#define FITS_MAGIC "SIMPLE"
/** Size of the FITS magic number */
#define FITS_MAGIC_SZ 6
/* FITS pixel depths */
/** FITS BITPIX=8 */
#define BPP_8_UNSIGNED (8)
/** FITS BITPIX=16 */
#define BPP_16_SIGNED (16)
/** FITS BITPIX=32 */
#define BPP_32_SIGNED (32)
/** FITS BITPIX=-32 */
#define BPP_IEEE_FLOAT (-32)
/** FITS BITPIX=-64 */
#define BPP_IEEE_DOUBLE (-64)
/** Default BITPIX for output */
#define BPP_DEFAULT BPP_IEEE_FLOAT
/** Compute the number of bytes per pixel for a given BITPIX value */
#define BYTESPERPIXEL(x) ( ((x) == BPP_8_UNSIGNED) ? 1 : \
((x) == BPP_16_SIGNED) ? 2 : \
((x) == BPP_32_SIGNED) ? 4 : \
((x) == BPP_IEEE_FLOAT) ? 4 : \
((x) == BPP_IEEE_DOUBLE) ? 8 : 0 )
/* </dox> */
#endif
/* vim: set ts=4 et sw=4 tw=75 */

243
qfits/src/md5.c 100644
View File

@ -0,0 +1,243 @@
/*
* This code implements the MD5 message-digest algorithm.
* The algorithm is due to Ron Rivest. This code was
* written by Colin Plumb in 1993, no copyright is claimed.
* This code is in the public domain; do with it what you wish.
*
* Equivalent code is available from RSA Data Security, Inc.
* This code has been tested against that, and is equivalent,
* except that you don't need to include two pages of legalese
* with every copy.
*
* To compute the message digest of a chunk of bytes, declare an
* MD5Context structure, pass it to MD5Init, call MD5Update as
* needed on buffers full of bytes, and then call MD5Final, which
* will fill a supplied 16-byte array with the digest.
*/
#include "md5.h"
#include <string.h> /* To get definition of memmove */
static void byteReverse(unsigned char *buf, unsigned longs);
/*
* Note: this code is harmless on little-endian machines.
*/
static void byteReverse(unsigned char *buf, unsigned longs)
{
word32 t;
do {
t = (word32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
((unsigned) buf[1] << 8 | buf[0]);
*(word32 *) buf = t;
buf += 4;
} while (--longs);
}
/*
* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
* initialization constants.
*/
void MD5Init(struct MD5Context *ctx)
{
ctx->buf[0] = 0x67452301;
ctx->buf[1] = 0xefcdab89;
ctx->buf[2] = 0x98badcfe;
ctx->buf[3] = 0x10325476;
ctx->bits[0] = 0;
ctx->bits[1] = 0;
}
/*
* Update context to reflect the concatenation of another buffer full
* of bytes.
*/
void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
{
register word32 t;
/* Update bitcount */
t = ctx->bits[0];
if ((ctx->bits[0] = t + ((word32) len << 3)) < t)
ctx->bits[1]++; /* Carry from low to high */
ctx->bits[1] += len >> 29;
t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
/* Handle any leading odd-sized chunks */
if (t) {
unsigned char *p = (unsigned char *) ctx->in + t;
t = 64 - t;
if (len < t) {
memmove(p, buf, len);
return;
}
memmove(p, buf, t);
byteReverse(ctx->in, 16);
MD5Transform(ctx->buf, (word32 *) ctx->in);
buf += t;
len -= t;
}
/* Process data in 64-byte chunks */
while (len >= 64) {
memmove(ctx->in, buf, 64);
byteReverse(ctx->in, 16);
MD5Transform(ctx->buf, (word32 *) ctx->in);
buf += 64;
len -= 64;
}
/* Handle any remaining bytes of data. */
memmove(ctx->in, buf, len);
}
/*
* Final wrapup - pad to 64-byte boundary with the bit pattern
* 1 0* (64-bit count of bits processed, MSB-first)
*/
void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
{
unsigned int count;
unsigned char *p;
/* Compute number of bytes mod 64 */
count = (ctx->bits[0] >> 3) & 0x3F;
/* Set the first char of padding to 0x80. This is safe since there is
always at least one byte free */
p = ctx->in + count;
*p++ = 0x80;
/* Bytes of padding needed to make 64 bytes */
count = 64 - 1 - count;
/* Pad out to 56 mod 64 */
if (count < 8) {
/* Two lots of padding: Pad the first block to 64 bytes */
memset(p, 0, count);
byteReverse(ctx->in, 16);
MD5Transform(ctx->buf, (word32 *) ctx->in);
/* Now fill the next block with 56 bytes */
memset(ctx->in, 0, 56);
} else {
/* Pad block to 56 bytes */
memset(p, 0, count - 8);
}
byteReverse(ctx->in, 14);
/* Append length in bits and transform */
((word32 *) ctx->in)[14] = ctx->bits[0];
((word32 *) ctx->in)[15] = ctx->bits[1];
MD5Transform(ctx->buf, (word32 *) ctx->in);
byteReverse((unsigned char *) ctx->buf, 4);
memmove(digest, ctx->buf, 16);
memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
}
/* The four core functions - F1 is optimized somewhat */
/* #define F1(x, y, z) (x & y | ~x & z) */
#define F1(x, y, z) (z ^ (x & (y ^ z)))
#define F2(x, y, z) F1(z, x, y)
#define F3(x, y, z) (x ^ y ^ z)
#define F4(x, y, z) (y ^ (x | ~z))
/* This is the central step in the MD5 algorithm. */
#define MD5STEP(f, w, x, y, z, data, s) \
( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
/*
* The core of the MD5 algorithm, this alters an existing MD5 hash to
* reflect the addition of 16 longwords of new data. MD5Update blocks
* the data and converts bytes into longwords for this routine.
*/
void MD5Transform(word32 buf[4], word32 const in[16])
{
register word32 a, b, c, d;
a = buf[0];
b = buf[1];
c = buf[2];
d = buf[3];
MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
buf[0] += a;
buf[1] += b;
buf[2] += c;
buf[3] += d;
}
/* vim: set ts=4 et sw=4 tw=75 */

25
qfits/src/md5.h 100644
View File

@ -0,0 +1,25 @@
#ifndef MD5_H
#define MD5_H
typedef unsigned int word32 ;
struct MD5Context {
word32 buf[4];
word32 bits[2];
unsigned char in[64];
};
void MD5Init(struct MD5Context *context);
void MD5Update(struct MD5Context *context, unsigned char const *buf,
unsigned len);
void MD5Final(unsigned char digest[16], struct MD5Context *context);
void MD5Transform(word32 buf[4], word32 const in[16]);
/*
* This is needed to make RSAREF happy on some MS-DOS compilers.
*/
typedef struct MD5Context MD5_CTX;
#endif /* !MD5_H */
/* vim: set ts=4 et sw=4 tw=75 */

1228
qfits/src/pixio.c 100644

File diff suppressed because it is too large Load Diff

465
qfits/src/pixio.h 100644
View File

@ -0,0 +1,465 @@
/*-------------------------------------------------------------------------*/
/**
@file pixload.h
@author N. Devillard
@date Nov 2001
@version $Revision: 1.3 $
@brief Pixel loader for FITS images.
*/
/*--------------------------------------------------------------------------*/
/*
$Id: pixio.h,v 1.3 2002/01/21 15:23:52 ndevilla Exp $
$Author: ndevilla $
$Date: 2002/01/21 15:23:52 $
$Revision: 1.3 $
*/
#ifndef _PIXLOAD_H_
#define _PIXLOAD_H_
/*---------------------------------------------------------------------------
Includes
---------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "xmemory.h"
/* <dox> */
/*---------------------------------------------------------------------------
Defines
---------------------------------------------------------------------------*/
/** Symbol to set returned pixel type to float */
#define PTYPE_FLOAT 0
/** Symbol to set returned pixel type to int */
#define PTYPE_INT 1
/** Symbol to set returned pixel type to double */
#define PTYPE_DOUBLE 2
/** FITS BITPIX=8 */
#define BPP_8_UNSIGNED (8)
/** FITS BITPIX=16 */
#define BPP_16_SIGNED (16)
/** FITS BITPIX=32 */
#define BPP_32_SIGNED (32)
/** FITS BITPIX=-32 */
#define BPP_IEEE_FLOAT (-32)
/** FITS BITPIX=-64 */
#define BPP_IEEE_DOUBLE (-64)
/** Default BITPIX for output */
#define BPP_DEFAULT BPP_IEEE_FLOAT
/** Compute the number of bytes per pixel for a given BITPIX value */
#define BYTESPERPIXEL(x) ( ((x) == BPP_8_UNSIGNED) ? 1 : \
((x) == BPP_16_SIGNED) ? 2 : \
((x) == BPP_32_SIGNED) ? 4 : \
((x) == BPP_IEEE_FLOAT) ? 4 : \
((x) == BPP_IEEE_DOUBLE) ? 8 : 0 )
/*---------------------------------------------------------------------------
New types
---------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------*/
/**
@brief qfits loader control object
This structure serves two purposes: input and output for the qfits
pixel loading facility. To request pixels from a FITS file, you
need to allocate (statically or dynamically) such a structure and
fill up the input fields (filename, xtension number, etc.) to specify
the pixels you want from the file.
Before performing the actual load, you must pass the initialized
structure to qfitsloader_init() which will check whether the operation
is feasible or not (check its returned value).
If the operation was deemed feasible, you can proceed to load the pixels,
passing the same structure to qfits_loadpix() which will fill up the
output fields of the struct. Notice that a pixel buffer will have been
allocated (through malloc or mmap) and placed into the structure. You
need to call free() on this pointer when you are done with it,
typically in the image or cube destructor.
The qfitsloader_init() function is also useful to probe a FITS file
for useful informations, like getting the size of images in the file,
the pixel depth, or data offset.
Example of a code that prints out various informations about
a plane to load, without actually loading it:
@code
int main(int argc, char * argv[])
{
qfitsloader ql ;
ql.filename = argv[1] ;
ql.xtnum = 0 ;
ql.pnum = 0 ;
if (qfitsloader_init(&ql)!=0) {
printf("cannot read info about %s\n", argv[1]);
return -1 ;
}
printf( "file : %s"
"xtnum : %d"
"pnum : %d"
"# xtensions : %d"
"size X : %d"
"size Y : %d"
"planes : %d"
"bitpix : %d"
"datastart : %d"
"bscale : %g"
"bzero : %g",
ql.filename,
ql.xtnum,
ql.pnum,
ql.exts,
ql.lx,
ql.ly,
ql.np,
ql.bitpix,
ql.seg_start,
ql.bscale,
ql.bzero);
return 0 ;
}
@endcode
*/
/*-------------------------------------------------------------------------*/
typedef struct _qfitsloader_ {
/** Private field to see if structure has been initialized */
int _init ;
/** input: Name of the file you want to read pixels from */
char * filename ;
/** input: xtension number you want to read */
int xtnum ;
/** input: Index of the plane you want, from 0 to np-1 */
int pnum ;
/** input: Pixel type you want (PTYPE_FLOAT, PTYPE_INT or PTYPE_DOUBLE) */
int ptype ;
/** output: Total number of extensions found in file */
int exts ;
/** output: Size in X of the requested plane */
int lx ;
/** output: Size in Y of the requested plane */
int ly ;
/** output: Number of planes present in this extension */
int np ;
/** output: BITPIX for this extension */
int bitpix ;
/** output: Start of the data segment (in bytes) for your request */
int seg_start ;
/** output: BSCALE found for this extension */
double bscale ;
/** output: BZERO found for this extension */
double bzero ;
/** output: Pointer to pixel buffer loaded as integer values */
int * ibuf ;
/** output: Pointer to pixel buffer loaded as float values */
float * fbuf ;
/** output: Pointer to pixel buffer loaded as double values */
double * dbuf ;
} qfitsloader ;
/*-------------------------------------------------------------------------*/
/**
@brief qfits dumper control object
This structure offers various control parameters to dump a pixel
buffer to a FITS file. The buffer will be dumped as requested
to the requested file in append mode. Of course, the requested file
must be writeable for the operation to succeed.
The following example demonstrates how to save a linear ramp sized
100x100 to a FITS file with BITPIX=16. Notice that this code only
dumps the pixel buffer, no header information is provided in this
case.
@code
int i, j ;
int * ibuf ;
qfitsdumper qd ;
// Fill a buffer with 100x100 int pixels
ibuf = malloc(100 * 100 * sizeof(int));
for (j=0 ; j<100 ; j++) {
for (i=0 ; i<100 ; i++) {
ibuf[i+j*100] = i+j ;
}
}
qd.filename = "out.fits" ; // Output file name
qd.npix = 100 * 100 ; // Number of pixels
qd.ptype = PTYPE_INT ; // Input buffer type
qd.ibuf = ibuf ; // Set buffer pointer
qd.out_ptype = BPP_16_SIGNED ; // Save with BITPIX=16
// Dump buffer to file (error checking omitted for clarity)
qfits_pixdump(&qd);
free(ibuf);
@endcode
If the provided output file name is "STDOUT" (all capitals), the
function will dump the pixels to the stdout steam (usually the console,
could have been re-directed).
*/
/*-------------------------------------------------------------------------*/
typedef struct _qfitsdumper_ {
/** Name of the file to dump to, "STDOUT" to dump to stdout */
char * filename ;
/** Number of pixels in the buffer to dump */
int npix ;
/** Buffer type: PTYPE_FLOAT, PTYPE_INT or PTYPE_DOUBLE */
int ptype ;
/** Pointer to input integer pixel buffer */
int * ibuf ;
/** Pointer to input float pixel buffer */
float * fbuf ;
/** Pointer to input double pixel buffer */
double * dbuf ;
/** Requested BITPIX in output FITS file */
int out_ptype ;
} qfitsdumper ;
/*---------------------------------------------------------------------------
Function prototypes
---------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------*/
/**
@brief Initialize a qfitsloader control object.
@param ql qfitsloader object to initialize.
@return int 0 if Ok, -1 if error occurred.
This function expects a qfitsloader object with a number of input
fields correctly filled in. The minimum fields to set are:
- filename: Name of the file to examine.
- xtnum: Extension number to examine (0 for main section).
- pnum: Plane number in the requested extension.
You can go ahead with these fields only if you only want to get
file information for this plane in this extension. If you want
to later load the plane, you must additionally fill the 'ptype'
field to a correct value (PTYPE_INT, PTYPE_FLOAT, PTYPE_DOUBLE)
before calling qfits_loadpix() so that it knows which conversion
to perform.
This function is basically a probe sent on a FITS file to ask
qfits if loading these data would be Ok or not. The actual loading
is performed by qfits_loadpix() afterwards.
*/
/*--------------------------------------------------------------------------*/
int qfitsloader_init(qfitsloader * ql);
/*-------------------------------------------------------------------------*/
/**
@brief Load a pixel buffer for one image.
@param ql Allocated and initialized qfitsloader control object.
@return int 0 if Ok, -1 if error occurred.
This function performs a load of a pixel buffer into memory. It
expects an allocated and initialized qfitsloader object in input.
See qfitsloader_init() about initializing the object.
This function will fill up the ibuf/fbuf/dbuf field, depending
on the requested pixel type (resp. int, float or double).
The returned buffer has been allocated using one of the special
memory operators present in xmemory.c. To deallocate the buffer,
you must call the version of free() offered by xmemory, not the
usual system free(). It is enough to include "xmemory.h" in your
code before you make calls to the pixel loader here.
*/
/*--------------------------------------------------------------------------*/
int qfits_loadpix(qfitsloader * ql);
/*-------------------------------------------------------------------------*/
/**
@brief Load a pixel buffer as floats.
@param p_source Pointer to source buffer (as bytes).
@param npix Number of pixels to load.
@param bitpix FITS BITPIX in original file.
@param bscale FITS BSCALE in original file.
@param bzero FITS BZERO in original file.
@return 1 pointer to a newly allocated buffer of npix floats.
This function takes in input a pointer to a byte buffer as given
in the original FITS file (big-endian format). It converts the
buffer to an array of float (whatever representation is used for
floats by this platform is used) and returns the newly allocated
buffer, or NULL if an error occurred.
The returned buffer must be deallocated using the free() offered
by xmemory. It is enough to #include "xmemory.h" before calling
free on the returned pointer.
*/
/*--------------------------------------------------------------------------*/
float * qfits_pixin_float (char *, int, int, double, double);
/*-------------------------------------------------------------------------*/
/**
@brief Load a pixel buffer as ints.
@param p_source Pointer to source buffer (as bytes).
@param npix Number of pixels to load.
@param bitpix FITS BITPIX in original file.
@param bscale FITS BSCALE in original file.
@param bzero FITS BZERO in original file.
@return 1 pointer to a newly allocated buffer of npix ints.
This function takes in input a pointer to a byte buffer as given
in the original FITS file (big-endian format). It converts the
buffer to an array of int (whatever representation is used for
int by this platform is used) and returns the newly allocated
buffer, or NULL if an error occurred.
The returned buffer must be deallocated using the free() offered
by xmemory. It is enough to #include "xmemory.h" before calling
free on the returned pointer.
*/
/*--------------------------------------------------------------------------*/
int * qfits_pixin_int (char *, int, int, double, double);
/*-------------------------------------------------------------------------*/
/**
@brief Load a pixel buffer as doubles.
@param p_source Pointer to source buffer (as bytes).
@param npix Number of pixels to load.
@param bitpix FITS BITPIX in original file.
@param bscale FITS BSCALE in original file.
@param bzero FITS BZERO in original file.
@return 1 pointer to a newly allocated buffer of npix doubles.
This function takes in input a pointer to a byte buffer as given
in the original FITS file (big-endian format). It converts the
buffer to an array of double (whatever representation is used for
int by this platform is used) and returns the newly allocated
buffer, or NULL if an error occurred.
The returned buffer must be deallocated using the free() offered
by xmemory. It is enough to #include "xmemory.h" before calling
free on the returned pointer.
*/
/*--------------------------------------------------------------------------*/
double * qfits_pixin_double(char *, int, int, double, double);
/*-------------------------------------------------------------------------*/
/**
@brief Dump a pixel buffer to an output FITS file in append mode.
@param qd qfitsdumper control object.
@return int 0 if Ok, -1 otherwise.
This function takes in input a qfitsdumper control object. This object
must be allocated beforehand and contain valid references to the data
to save, and how to save it.
The minimum fields to fill are:
- filename: Name of the FITS file to dump to.
- npix: Number of pixels in the buffer to be dumped.
- ptype: Type of the passed buffer (PTYPE_FLOAT, PTYPE_INT, PTYPE_DOUBLE)
- out_ptype: Requested FITS BITPIX for the output.
One of the following fields must point to the corresponding pixel
buffer:
- ibuf for an int pixel buffer (ptype=PTYPE_INT)
- fbuf for a float pixel buffer (ptype=PTYPE_FLOAT)
- dbuf for a double pixel buffer (ptype=PTYPE_DOUBLE)
This is a fairly low-level function, in the sense that it does not
check that the output file already contains a proper header or even
that the file it is appending to is indeed a FITS file. It will
convert the pixel buffer to the requested BITPIX type and append
the data to the file, without padding with zeros. See qfits_zeropad()
about padding.
If the given output file name is "STDOUT" (all caps), the dump
will be performed to stdout.
*/
/*--------------------------------------------------------------------------*/
int qfits_pixdump(qfitsdumper * qd) ;
/*-------------------------------------------------------------------------*/
/**
@brief Convert a float pixel buffer to a byte buffer.
@param buf Input float buffer.
@param npix Number of pixels in the input buffer.
@param ptype Requested output BITPIX type.
@return 1 pointer to a newly allocated byte (char) buffer.
This function converts the given float buffer to a buffer of bytes
suitable for dumping to a FITS file (i.e. big-endian, in the
requested pixel type). The returned pointer must be deallocated
using the free() function offered by xmemory.
*/
/*--------------------------------------------------------------------------*/
char * qfits_pixdump_float(float * buf, int npix, int ptype);
/*-------------------------------------------------------------------------*/
/**
@brief Convert an int pixel buffer to a byte buffer.
@param buf Input int buffer.
@param npix Number of pixels in the input buffer.
@param ptype Requested output BITPIX type.
@return 1 pointer to a newly allocated byte (char) buffer.
This function converts the given int buffer to a buffer of bytes
suitable for dumping to a FITS file (i.e. big-endian, in the
requested pixel type). The returned pointer must be deallocated
using the free() function offered by xmemory.
*/
/*--------------------------------------------------------------------------*/
char * qfits_pixdump_int(int * buf, int npix, int ptype);
/*-------------------------------------------------------------------------*/
/**
@brief Convert a double pixel buffer to a byte buffer.
@param buf Input double buffer.
@param npix Number of pixels in the input buffer.
@param ptype Requested output BITPIX type.
@return 1 pointer to a newly allocated byte (char) buffer.
This function converts the given double buffer to a buffer of bytes
suitable for dumping to a FITS file (i.e. big-endian, in the
requested pixel type). The returned pointer must be deallocated
using the free() function offered by xmemory.
*/
/*--------------------------------------------------------------------------*/
char * qfits_pixdump_double(double * buf, int npix, int ptype);
/* </dox> */
#endif
/* vim: set ts=4 et sw=4 tw=75 */

123
qfits/src/ptrace.c 100644
View File

@ -0,0 +1,123 @@
/*-------------------------------------------------------------------------*/
/**
@file ptrace.c
@author N. Devillard
@date May 2001
@version $Revision: 2.6 $
@brief Add tracing capability to any program compiled with gcc.
This module is only compiled when using gcc and tracing has been
activated. It allows the compiled program to output messages whenever
a function is entered or exited.
To activate this feature, your version of gcc must support
the -finstrument-functions flag.
The printed messages yield function addresses, not human-readable
names. To link both, you need to get a list of symbols from the
program. There are many (unportable) ways of doing that, see the
'etrace' project on freshmeat for more information about how to dig
the information.
*/
/*--------------------------------------------------------------------------*/
/*
$Id: ptrace.c,v 2.6 2002/01/22 14:52:40 ndevilla Exp $
$Author: ndevilla $
$Date: 2002/01/22 14:52:40 $
$Revision: 2.6 $
*/
#if (__GNUC__>2) || ((__GNUC__ == 2) && (__GNUC_MINOR__ > 95))
/*---------------------------------------------------------------------------
Includes
---------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
/*---------------------------------------------------------------------------
Defines
---------------------------------------------------------------------------*/
#define PTRACE_PIPENAME "TRACE"
/*---------------------------------------------------------------------------
Function codes
---------------------------------------------------------------------------*/
/** Final trace close */
static void
__attribute__((__no_instrument_function__))
gnu_ptrace_close(void)
{
FILE * trace ;
if ((trace=fopen(PTRACE_PIPENAME, "a"))==NULL) return ;
fprintf(trace, "EXIT %ld\n", (long)getpid());
fclose(trace);
return ;
}
/** Trace initialization */
static int
__attribute__((__no_instrument_function__))
gnu_ptrace_init(void)
{
struct stat sta ;
/* See if a trace file exists */
if (stat(PTRACE_PIPENAME, &sta)!=0) {
/* No trace file: do not trace at all */
return 0 ;
}
/* Tracing requested: a trace file was found */
atexit(gnu_ptrace_close);
return 1 ;
}
/** Function called by every function event */
void
__attribute__((__no_instrument_function__))
gnu_ptrace(char * what, void * p)
{
static int first=1 ;
static int active=1 ;
FILE * trace ;
if (first) {
active = gnu_ptrace_init();
first=0 ;
}
if (active==0)
return ;
if ((trace=fopen(PTRACE_PIPENAME, "a"))==NULL) {
return ;
}
fprintf(trace, "%s %p\n", what, p);
fclose(trace);
return ;
}
/** According to gcc documentation: called upon function entry */
void __attribute__((__no_instrument_function__))
__cyg_profile_func_enter(void *this_fn, void *call_site)
{
gnu_ptrace("enter", this_fn);
}
/** According to gcc documentation: called upon function exit */
void __attribute__((__no_instrument_function__))
__cyg_profile_func_exit(void *this_fn, void *call_site)
{
gnu_ptrace("exit", this_fn);
}
#endif
/* vim: set ts=4 et sw=4 tw=75 */

217
qfits/src/qerror.c 100644
View File

@ -0,0 +1,217 @@
/*-------------------------------------------------------------------------*/
/**
@file qerror.c
@author N. Devillard
@date Aug 2001
@version $Revision: 1.5 $
@brief
This module is responsible for error message display. It allows
to re-direct all messages to a given set of functions for display.
*/
/*--------------------------------------------------------------------------*/
/*
$Id: qerror.c,v 1.5 2002/01/15 10:18:38 ndevilla Exp $
$Author: ndevilla $
$Date: 2002/01/15 10:18:38 $
$Revision: 1.5 $
*/
/*---------------------------------------------------------------------------
Includes
---------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdarg.h>
/*---------------------------------------------------------------------------
Defines
---------------------------------------------------------------------------*/
/* Max number of error handling functions registered */
#define QFITS_ERR_MAXERRDISP 8
/* Max size of an error message */
#define QFITS_ERR_MSGSIZE 1024
/*---------------------------------------------------------------------------
Private stuff
---------------------------------------------------------------------------*/
/* Type of a display function only defined for legibility here */
typedef void (*qfits_err_dispfunc)(char *) ;
/* Default display function prints out msg to stderr */
static void qfits_err_display_stderr(char * s)
{ fprintf(stderr, "qfits: %s\n", s); }
/* Static control structure, completely private */
static struct {
qfits_err_dispfunc disp[QFITS_ERR_MAXERRDISP] ;
int n ;
int active ;
} qfits_err_control = {{qfits_err_display_stderr}, 1, 1} ;
/*---------------------------------------------------------------------------
Function codes
---------------------------------------------------------------------------*/
/*
* Private: this is the main function used for message display.
* It calls registered display functions one after another.
*/
static void qfits_err_main_display(char * msg)
{
int i ;
/* Check if there is a message in input */
if (msg==NULL)
return ;
/* Loop on all registered functions and call them */
for (i=0 ; i<qfits_err_control.n ; i++) {
if (qfits_err_control.disp[i]) {
qfits_err_control.disp[i](msg);
}
}
return ;
}
/*-------------------------------------------------------------------------*/
/**
@name qfits_err_statget
@memo Get the current status of error display.
@return int 1 if error display is active, 0 if not.
@doc
This function returns the current error display status. If it returns 1,
it means that all calls to qfits_error/qfits_warning will display
messages using the registered functions, otherwise they do nothing.
*/
/*--------------------------------------------------------------------------*/
int qfits_err_statget(void)
{
return qfits_err_control.active ;
}
/*-------------------------------------------------------------------------*/
/**
@name qfits_err_statset
@memo Set the current status of error display.
@param sta New status to be set.
@return int giving the previous display status.
@doc
This function sets the current error display status to the required
value, and returns the previous value. It is useful to store the
previous value, in view of restoring it afterwards, e.g. to make a
function silent on all its errors. Example:
@code
int prev_stat = qfits_err_statset(0) ;
function_call() ;
qfits_err_statset(prev_stat);
@endcode
*/
/*--------------------------------------------------------------------------*/
int qfits_err_statset(int sta)
{
int prev ;
prev = qfits_err_control.active ;
qfits_err_control.active=sta ;
return prev ;
}
/*-------------------------------------------------------------------------*/
/**
@name qfits_err_register
@memo Register a function to display error/warning messages.
@param dispfn Display function (see doc below).
@return int 0 if function was registered, -1 if not.
@doc
This function registers a display function into the error-handling
module. Display functions have the following prototype:
@code
void display_function(char * msg);
@endcode
They are simple functions that expect a ready-made error message
and return void. They can do whatever they want with the message
(log it to a file, send it to a GUI, to the syslog, ...). The
message is built using a printf-like statement in qfits_error and
qfits_warning, then passed to all registered display functions.
A maximum of QFITS_ERR_MAXERRDISP can be registered (see source code).
If the limit has been reached, this function will signal it by
returning -1.
*/
/*--------------------------------------------------------------------------*/
int qfits_err_register(qfits_err_dispfunc dispfn)
{
if (qfits_err_control.n==QFITS_ERR_MAXERRDISP) {
/* Cannot register any more function */
return -1 ;
}
qfits_err_control.disp[qfits_err_control.n] = dispfn ;
qfits_err_control.n ++ ;
return 0 ;
}
/* Public warning/error functions */
void qfits_warning(char *fmt, ...)
{
char msg[QFITS_ERR_MSGSIZE] ;
char all[QFITS_ERR_MSGSIZE] ;
va_list ap ;
/* Check if display is activated */
if (qfits_err_control.active==0) {
return ;
}
va_start(ap, fmt) ;
vsprintf(msg, fmt, ap) ;
va_end(ap);
sprintf(all, "*** %s", msg);
qfits_err_main_display(all);
return ;
}
void qfits_error(char *fmt, ...)
{
char msg[QFITS_ERR_MSGSIZE] ;
char all[QFITS_ERR_MSGSIZE] ;
va_list ap ;
/* Check if display is activated */
if (qfits_err_control.active==0) {
return ;
}
va_start(ap, fmt) ;
vsprintf(msg, fmt, ap) ;
va_end(ap);
sprintf(all, "error: %s", msg);
qfits_err_main_display(all);
return ;
}
/* vim: set ts=4 et sw=4 tw=75 */

107
qfits/src/qerror.h 100644
View File

@ -0,0 +1,107 @@
/*-------------------------------------------------------------------------*/
/**
@file qerror.h
@author N. Devillard
@date Nov 2001
@version $Revision: 1.4 $
@brief qfits error handling
*/
/*--------------------------------------------------------------------------*/
/*
$Id: qerror.h,v 1.4 2002/01/10 08:53:08 ndevilla Exp $
$Author: ndevilla $
$Date: 2002/01/10 08:53:08 $
$Revision: 1.4 $
*/
#ifndef _QERROR_H_
#define _QERROR_H_
/*---------------------------------------------------------------------------
Includes
---------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdarg.h>
/*---------------------------------------------------------------------------
Function prototypes
---------------------------------------------------------------------------*/
/* <dox> */
/*-------------------------------------------------------------------------*/
/**
@name qfits_err_statget
@memo Get the current status of error display.
@return int 1 if error display is active, 0 if not.
@doc
This function returns the current error display status. If it returns 1,
it means that all calls to qfits_error/qfits_warning will display
messages using the registered functions, otherwise they do nothing.
*/
/*--------------------------------------------------------------------------*/
int qfits_err_statget(void);
/*-------------------------------------------------------------------------*/
/**
@name qfits_err_statset
@memo Set the current status of error display.
@param sta New status to be set.
@return int giving the previous display status.
@doc
This function sets the current error display status to the required
value, and returns the previous value. It is useful to store the
previous value, in view of restoring it afterwards, e.g. to make a
function silent on all its errors. Example:
\begin{verbatim}
int prev_stat = qfits_err_statset(0) ;
function_call() ;
qfits_err_statset(prev_stat);
\end{verbatim}
*/
/*--------------------------------------------------------------------------*/
int qfits_err_statset(int sta);
/*-------------------------------------------------------------------------*/
/**
@name qfits_err_register
@memo Register a function to display error/warning messages.
@param dispfn Display function (see doc below).
@return int 0 if function was registered, -1 if not.
@doc
This function registers a display function into the error-handling
module. Display functions have the following prototype:
\begin{verbatim}
void display_function(char * msg);
\end{verbatim}
They are simple functions that expect a ready-made error message
and return void. They can do whatever they want with the message
(log it to a file, send it to a GUI, to the syslog, ...). The
message is built using a printf-like statement in qfits_error and
qfits_warning, then passed to all registered display functions.
A maximum of QFITS_ERR_MAXERRDISP can be registered (see source code).
If the limit has been reached, this function will signal it by
returning -1.
*/
/*--------------------------------------------------------------------------*/
int qfits_err_register( void (*dispfn)(char*) ) ;
/* </dox> */
/* Public warning/error functions */
void qfits_warning(char *fmt, ...);
void qfits_error(char *fmt, ...);
#endif
/* vim: set ts=4 et sw=4 tw=75 */

View File

@ -0,0 +1,146 @@
/*-------------------------------------------------------------------------*/
/**
@file qfits_wrap.c
@author N. Devillard
@date Nov 2001
@version $Revision: 1.10 $
@brief
Interface file between python and the qfits library.
All symbols are exported as the 'qfits' module under Python.
*/
/*--------------------------------------------------------------------------*/
/*
$Id: qfits_wrap.c,v 1.10 2002/01/11 09:52:55 ndevilla Exp $
$Author: ndevilla $
$Date: 2002/01/11 09:52:55 $
$Revision: 1.10 $
*/
/*---------------------------------------------------------------------------
Includes
---------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "Python.h"
#include "qfits.h"
static PyObject * _wrap_qfits_get_headers(PyObject * self, PyObject * args)
{
struct stat sta ;
qfits_header * qh ;
char * filename ;
int xtnum ;
int n_ext ;
int i ;
char key[FITS_LINESZ],
val[FITS_LINESZ],
com[FITS_LINESZ];
char * pval ;
PyObject * hlist ;
PyObject * hcur ;
if (!PyArg_ParseTuple(args, "s", &filename)) {
return NULL ;
}
/* Check file's existence */
if (stat(filename, &sta)!=0) {
/* raise IOError exception */
PyErr_SetString(PyExc_IOError, "cannot stat file");
return NULL ;
}
/* Check file is FITS */
if (is_fits_file(filename)!=1) {
/* return None */
return Py_BuildValue("") ;
}
/* Get number of extensions */
n_ext = qfits_query_n_ext(filename);
if (n_ext<0) {
PyErr_SetString(PyExc_IOError, "cannot get number of FITS extensions");
return NULL ;
}
hlist = PyList_New(1+n_ext) ;
for (xtnum=0 ; xtnum<=n_ext ; xtnum++) {
/* Query header */
if (xtnum==0) {
qh = qfits_header_read(filename);
} else {
qh = qfits_header_readext(filename, xtnum);
}
if (qh==NULL) {
PyErr_SetString(PyExc_IOError, "cannot read header");
return NULL ;
}
/* Build up a list of tuples (key,val,com) */
hcur = PyList_New(qh->n) ;
for (i=0 ; i<qh->n ; i++) {
qfits_header_getitem(qh, i, key, val, com, NULL);
pval = qfits_pretty_string(val);
PyList_SetItem(hcur,i,Py_BuildValue("(sss)",key,pval,com)) ;
}
qfits_header_destroy(qh);
/* Assign list into main list */
PyList_SetItem(hlist, xtnum, hcur);
}
return hlist ;
}
static PyObject * _wrap_qfits_expand_keyword(PyObject * self, PyObject * args)
{
char * key ;
if (!PyArg_ParseTuple(args, "s", &key)) {
return NULL ;
}
return Py_BuildValue("s", qfits_expand_keyword(key));
}
static PyObject * _wrap_qfits_datamd5(PyObject * self, PyObject * args)
{
char * filename ;
char * md5hash ;
if (!PyArg_ParseTuple(args, "s", &filename)) {
return NULL ;
}
md5hash = qfits_datamd5(filename);
if (md5hash==NULL) {
PyErr_SetString(PyExc_IOError, "cannot compute data MD5");
return NULL ;
}
return Py_BuildValue("s", md5hash);
}
static PyObject * _wrap_qfits_version(PyObject * self, PyObject * args)
{
return Py_BuildValue("s", qfits_version());
}
static PyMethodDef qfits_methods[] = {
{"get_headers", _wrap_qfits_get_headers, METH_VARARGS},
{"expand_keyword", _wrap_qfits_expand_keyword, METH_VARARGS},
{"datamd5", _wrap_qfits_datamd5, METH_VARARGS},
{"version", _wrap_qfits_version, METH_VARARGS},
{NULL, NULL}
};
void initqfits(void)
{
PyObject * m ;
m = Py_InitModule("qfits", qfits_methods);
}
/* vim: set ts=4 et sw=4 tw=75 */

761
qfits/src/simple.c 100644
View File

@ -0,0 +1,761 @@
/*-------------------------------------------------------------------------*/
/**
@file simple.c
@author N. Devillard
@date Jan 1999
@version $Revision: 1.4 $
@brief Simple FITS access routines.
This module offers a number of very basic low-level FITS access
routines.
*/
/*--------------------------------------------------------------------------*/
/*
$Id: simple.c,v 1.4 2002/01/22 15:16:57 ndevilla Exp $
$Author: ndevilla $
$Date: 2002/01/22 15:16:57 $
$Revision: 1.4 $
*/
/*---------------------------------------------------------------------------
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 "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]+)([eE][+-]?[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]+)([eE][+-]?[0-9]+)?[ ]+[+-]?([0-9]+[.]?[0-9]*|[.][0-9]+)([eE][+-]?[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, char * keyword)
{
char * where ;
char * start ;
char * value ;
char test1, test2 ;
int i ;
int len ;
int different ;
struct stat fileinfo ;
long int bufcount;
char * exp_key ;
/* Bulletproof entries */
if (filename==NULL || keyword==NULL) return NULL ;
/* Switch to uppercase and switch shortFITS notation to HIERARCH */
exp_key = qfits_expand_keyword(keyword);
start = falloc(filename, 0, NULL) ;
if (start==NULL) return NULL ;
stat(filename, &fileinfo);
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 the 2 characters after the keyword */
test1 = where[len] ;
test2 = where[len+1] ;
/* If first subsequent character is the equal sign, bingo. */
if (test1=='=') break ;
/*
* If first subsequent character is a blank and the one after is
* equal or another blank, bingo.
*/
if (test1==' ' && (test2=='=' || test2==' ')) break ;
}
if ((where[0]=='E') &&
(where[1]=='N') &&
(where[2]=='D') &&
(where[3]==' ')) {
/* End of header detected */
free(start);
return NULL ;
}
/* Go to next line in header */
where += 80 ;
bufcount +=80;
if (bufcount>=fileinfo.st_size){
/* file damaged or not a fits file, avoid segmentation
* fault */
free(start);
return NULL ;
}
}
/* Found the keyword, now get its value */
value = qfits_getvalue(where);
free(start);
return value;
}
/*-------------------------------------------------------------------------*/
/**
@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 the required extension is 0, this
function calls qfits_query_hdr().
*/
/*--------------------------------------------------------------------------*/
char * qfits_query_ext(char * filename, char * keyword, int xtnum)
{
char * exp_key ;
char * where ;
char * start ;
char * value ;
char test1, test2 ;
int seg_start ;
int seg_size ;
if (xtnum==0) return qfits_query_hdr(filename, keyword);
/* Bulletproof entries */
if (filename==NULL || keyword==NULL) 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 ;
}
/*
* Memory-map the input file and jump to start of xtension
*/
start = falloc(filename, seg_start, NULL);
if (start==NULL) return NULL ;
/*
* Look for keyword in xtension
*/
while (1) {
where = strstr(start, exp_key);
if (where==NULL) {
free(start);
return NULL ;
}
if ((int)(where - start) > seg_size) {
free(start);
return NULL ;
}
test1 = where[(int)strlen(exp_key)] ;
test2 = where[(int)strlen(exp_key)+1] ;
/* If first subsequent character is the equal sign, found it */
if (test1=='=') break ;
/*
* If first subsequent character is a blank and the one after is
* equal or another blank, found it
*/
if (test1==' ' && (test2=='=' || test2==' ')) break ;
/* Not found */
start = where+1 ;
}
/* Found the keyword, now get its value */
value = qfits_getvalue(where);
free(start);
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 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]
*/
/*--------------------------------------------------------------------------*/
char * qfits_pretty_string(char * s)
{
static char pretty[81] ;
int i,j ;
/* bulletproof */
if (s==NULL) return NULL ;
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;
}
/*-------------------------------------------------------------------------*/
/**
@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)
{
static int first=1;
static regex_t re_int;
if (s==NULL) return 0 ;
if (s[0]==0) return 0 ;
/* Compile the rule for integer pattern matching the first time */
if (first) {
first=0;
if (regcomp(&re_int, &regex_int[0], REG_EXTENDED|REG_NOSUB)!=0) {
fprintf(stderr, "internal error: compiling int rule\n");
exit(-1);
}
}
return regexec(&re_int, s, 0, NULL, 0) ? 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)
{
static int first=1;
static regex_t re_float;
if (s==NULL) return 0 ;
if (s[0]==0) return 0 ;
/* Compile the rule for float pattern matching the first time */
if (first) {
first=0;
if (regcomp(&re_float, &regex_float[0], REG_EXTENDED|REG_NOSUB)!=0) {
fprintf(stderr, "internal error: compiling float rule\n");
exit(-1);
}
}
return regexec(&re_float, s, 0, NULL, 0) ? 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)
{
static int first=1;
static regex_t re_cmp;
if (s==NULL) return 0 ;
if (s[0]==0) return 0 ;
/* Compile the rule for complex pattern matching the first time */
if (first) {
first=0;
if (regcomp(&re_cmp, &regex_cmp[0], REG_EXTENDED|REG_NOSUB)!=0) {
fprintf(stderr, "internal error: compiling complex rule\n");
exit(-1);
}
}
return regexec(&re_cmp, s, 0, NULL, 0) ? 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 (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 ;
if (qfits_is_string(s)) return QFITS_STRING ;
return QFITS_UNKNOWN ;
}
/*-------------------------------------------------------------------------*/
/**
@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 Retrieve the card containing a keyword in the main header.
@param filename Name of the FITS file to examine.
@param keyword Keyword to look for in header.
@return Pointer to statically allocated character string
Retrieve the whole FITS line associated to a given keyword in the
main header. The returned string is statically allocated, so do not
modify it or try to free it. Returns NULL if an error occurred or
the keyword cannot be found.
The input keyword is first converted to upper case and expanded to
the HIERARCH scheme if given in the shortFITS notation.
*/
/*--------------------------------------------------------------------------*/
char *
qfits_query_card_in_header(char * filename, char * keyword)
{
char * exp_key ;
char * where ;
char * start ;
static char value[81] ;
/* Bulletproof entries */
if (filename==NULL || keyword==NULL) return NULL ;
exp_key = qfits_expand_keyword(keyword);
start = falloc(filename, 0, NULL) ;
if (start==NULL) return NULL ;
while (1) {
where = strstr(start, exp_key);
if (where==NULL) {
free(start);
return NULL ;
}
if (((where-start)%80) == 0) /* found */ break ;
/* Not found */
start = where+1 ;
}
/* Found the keyword, now get the corresponding FITS card */
memcpy(value, where, 80);
free(start);
value[80] = (char)0 ;
return value;
}
/*-------------------------------------------------------------------------*/
/**
@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,
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) {
fprintf(stderr, "error getting FITS header size for %s\n", 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 ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Replace a placeholder in a FITS header by a given card.
@param filename Name of the FITS file to modify.
@param placeholder Name of the placeholder to replace.
@param substitute What to replace the line with.
@return int 0 if Ok, -1 otherwise
Similar to qfits_replace_card, but to replace placeholder in FITS
(main) headers. A placeholder is defined as being something like:
COMMENT %s
In the search process to look for placeholders, %s is replaced with
the given character string. The default placeholder to look for is
simply 'PLACEHOLDER'.
*/
/*--------------------------------------------------------------------------*/
int qfits_replace_placeholder(
char * filename,
char * placeholder,
char * substitute
)
{
char to_find[FITS_LINESZ] ;
if (filename==NULL ||
placeholder==NULL ||
substitute==NULL) {
return -1 ;
}
/* Format string to search for */
sprintf(to_find, "COMMENT %s", placeholder) ;
/* Replace card */
return qfits_replace_card(filename, to_find, substitute) ;
}
/* vim: set ts=4 et sw=4 tw=75 */

339
qfits/src/simple.h 100644
View File

@ -0,0 +1,339 @@
/*-------------------------------------------------------------------------*/
/**
@file simple.h
@author N. Devillard
@date Jan 1999
@version $Revision: 1.5 $
@brief Simple FITS access routines.
This module offers a number of very basic low-level FITS access
routines.
*/
/*--------------------------------------------------------------------------*/
/*
$Id: simple.h,v 1.5 2002/01/22 15:16:57 ndevilla Exp $
$Author: ndevilla $
$Date: 2002/01/22 15:16:57 $
$Revision: 1.5 $
*/
#ifndef _SIMPLE_H_
#define _SIMPLE_H_
#ifdef __cplusplus
extern "C" {
#endif
/*---------------------------------------------------------------------------
Includes
---------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* <dox> */
/*---------------------------------------------------------------------------
Defines
---------------------------------------------------------------------------*/
/** Unknown type for FITS value */
#define QFITS_UNKNOWN 0
/** Boolean type for FITS value */
#define QFITS_BOOLEAN 1
/** Int type for FITS value */
#define QFITS_INT 2
/** Float type for FITS value */
#define QFITS_FLOAT 3
/** Complex type for FITS value */
#define QFITS_COMPLEX 4
/** String type for FITS value */
#define QFITS_STRING 5
/** Default name of a place holder, as a character string */
#define QFITS_PLACEHOLDER "PLACEHOLDER"
/*---------------------------------------------------------------------------
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 mmap'ed 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, char * keyword) ;
/*-------------------------------------------------------------------------*/
/**
@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 the required extension is 0, this
function calls qfits_query_hdr().
*/
/*--------------------------------------------------------------------------*/
char * qfits_query_ext(char * filename, char * keyword, int xtnum);
/*-------------------------------------------------------------------------*/
/**
@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);
/*-------------------------------------------------------------------------*/
/**
@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]
*/
/*--------------------------------------------------------------------------*/
char * qfits_pretty_string(char * s);
/*-------------------------------------------------------------------------*/
/**
@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);
/*-------------------------------------------------------------------------*/
/**
@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);
/*-------------------------------------------------------------------------*/
/**
@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);
/*-------------------------------------------------------------------------*/
/**
@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);
/*-------------------------------------------------------------------------*/
/**
@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);
/*-------------------------------------------------------------------------*/
/**
@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);
/*-------------------------------------------------------------------------*/
/**
@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
);
/*-------------------------------------------------------------------------*/
/**
@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
);
/*-------------------------------------------------------------------------*/
/**
@brief Retrieve the card containing a keyword in the main header.
@param filename Name of the FITS file to examine.
@param keyword Keyword to look for in header.
@return Pointer to statically allocated character string
Retrieve the whole FITS line associated to a given keyword in the
main header. The returned string is statically allocated, so do not
modify it or try to free it. Returns NULL if an error occurred or
the keyword cannot be found.
The input keyword is first converted to upper case and expanded to
the HIERARCH scheme if given in the shortFITS notation.
*/
/*--------------------------------------------------------------------------*/
char * qfits_query_card_in_header(char * filename, char * keyword);
/*-------------------------------------------------------------------------*/
/**
@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, char * keyword, char * substitute) ;
/*-------------------------------------------------------------------------*/
/**
@brief Replace a placeholder in a FITS header by a given card.
@param filename Name of the FITS file to modify.
@param placeholder Name of the placeholder to replace.
@param substitute What to replace the line with.
@return int 0 if Ok, -1 otherwise
Similar to fits_replace_card, but to replace placeholder in FITS
(main) headers. A placeholder is defined as being something like:
COMMENT %s
In the search process to look for placeholders, %s is replaced with
the given character string. The default placeholder to look for is
simply 'PLACEHOLDER'.
*/
/*--------------------------------------------------------------------------*/
int qfits_replace_placeholder(
char * filename,
char * placeholder,
char * substitute
);
/* </dox> */
#ifdef __cplusplus
}
#endif
#endif
/* vim: set ts=4 et sw=4 tw=75 */

View File

@ -0,0 +1,44 @@
/*-------------------------------------------------------------------------*/
/**
@file static_sz.h
@author N. Devillard
@date Dec 1999
@version $Revision: 1.3 $
@brief Definitions for various fixed sizes.
*/
/*--------------------------------------------------------------------------*/
/*
$Id: static_sz.h,v 1.3 2002/01/10 08:53:08 ndevilla Exp $
$Author: ndevilla $
$Date: 2002/01/10 08:53:08 $
$Revision: 1.3 $
*/
#ifndef _STATIC_SZ_H_
#define _STATIC_SZ_H_
#ifdef __cplusplus
extern "C" {
#endif
/* <dox> */
/*---------------------------------------------------------------------------
Defines
---------------------------------------------------------------------------*/
/** Maximum supported file name size */
#define FILENAMESZ 512
/** Maximum number of characters per line in an ASCII file */
#define ASCIILINESZ 1024
/* </dox> */
#ifdef __cplusplus
}
#endif
#endif
/* vim: set ts=4 et sw=4 tw=75 */

View File

@ -0,0 +1,282 @@
/*-------------------------------------------------------------------------*/
/**
@file t_iso8601.c
@author N. Devillard
@date Aug 1999
@version $Revision: 1.2 $
@brief Get date/time, possibly in ISO8601 format.
This module contains various utilities to get the current date/time,
and possibly format it according to the ISO 8601 format.
*/
/*--------------------------------------------------------------------------*/
/*
$Id: t_iso8601.c,v 1.2 2002/01/10 08:53:08 ndevilla Exp $
$Author: ndevilla $
$Date: 2002/01/10 08:53:08 $
$Revision: 1.2 $
*/
/*---------------------------------------------------------------------------
Includes
---------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <sys/time.h>
#include "t_iso8601.h"
/*---------------------------------------------------------------------------
Macros
---------------------------------------------------------------------------*/
/** Get century from a date in long format */
#define GET_CENTURY(d) (int) ( (d) / 1000000L)
/** Get century year from a date in long format */
#define GET_CCYEAR(d) (int) ( (d) / 10000L)
/** Get year from a date in long format */
#define GET_YEAR(d) (int) (((d) % 1000000L) / 10000L)
/** Get month from a date in long format */
#define GET_MONTH(d) (int) (((d) % 10000L) / 100)
/** Get day from a date in long format */
#define GET_DAY(d) (int) ( (d) % 100)
/** Get hours from a date in long format */
#define GET_HOUR(t) (int) ( (t) / 1000000L)
/** Get minutes from a date in long format */
#define GET_MINUTE(t) (int) (((t) % 1000000L) / 10000L)
/** Get seconds from a date in long format */
#define GET_SECOND(t) (int) (((t) % 10000L) / 100)
/** Get centi-seconds from a date in long format */
#define GET_CENTI(t) (int) ( (t) % 100)
/** Make date in long format from its components */
#define MAKE_DATE(c,y,m,d) (long) (c) * 1000000L + \
(long) (y) * 10000L + \
(long) (m) * 100 + (d)
/** Make time in long format from its components */
#define MAKE_TIME(h,m,s,c) (long) (h) * 1000000L + \
(long) (m) * 10000L + \
(long) (s) * 100 + (c)
/** Interval values, specified in centiseconds */
#define INTERVAL_CENTI 1
#define INTERVAL_SEC 100
#define INTERVAL_MIN 6000
#define INTERVAL_HOUR 360000L
#define INTERVAL_DAY 8640000L
/*---------------------------------------------------------------------------
Private to this module
---------------------------------------------------------------------------*/
static long timer_to_date(time_t time_secs);
static long timer_to_time(time_t time_secs);
/*---------------------------------------------------------------------------
Function ANSI C prototypes
---------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------*/
/**
@brief Returns the current date as a long (CCYYMMDD).
@return The current date as a long number.
Returns the current date as a long value (CCYYMMDD). Since most
system clocks do not return a century, this function assumes that
all years 80 and above are in the 20th century, and all years 00 to
79 are in the 21st century. For best results, consume before 1 Jan
2080.
Example: 19 Oct 2000 is returned as 20001019
*/
/*--------------------------------------------------------------------------*/
long date_now (void)
{
return (timer_to_date (time (NULL)));
}
/*-------------------------------------------------------------------------*/
/**
@brief Returns the current time as a long (HHMMSSCC).
@return The current time as a long number.
Returns the current time as a long value (HHMMSSCC). If the system
clock does not return centiseconds, these are set to zero.
Example: 15:36:12.84 is returned as 15361284
*/
/*--------------------------------------------------------------------------*/
long time_now(void)
{
struct timeval time_struct;
gettimeofday (&time_struct, 0);
return (timer_to_time (time_struct.tv_sec)
+ time_struct.tv_usec / 10000);
}
/*-------------------------------------------------------------------------*/
/**
@brief Converts a timer value to a date.
@param time_secs Current time definition in seconds.
@return Current date as a long (CCYYMMDD).
Converts the supplied timer value into a long date value. Dates are
stored as long values: CCYYMMDD. If the supplied value is zero,
returns zero. If the supplied value is out of range, returns 1
January, 1970 (19700101). The timer value is assumed to be UTC
(GMT).
*/
/*--------------------------------------------------------------------------*/
static long timer_to_date(time_t time_secs)
{
struct tm *time_struct;
if (time_secs == 0) {
return 0;
} else {
/* Convert into a long value CCYYMMDD */
time_struct = localtime (&time_secs);
if (time_struct) {
time_struct-> tm_year += 1900;
return (MAKE_DATE ( time_struct-> tm_year / 100,
time_struct-> tm_year % 100,
time_struct-> tm_mon + 1,
time_struct-> tm_mday));
} else {
return (19700101);
}
}
}
/*-------------------------------------------------------------------------*/
/**
@brief Convert a timer value to a time.
@param time_secs Current time definition in seconds.
@return Current time as a long.
Converts the supplied timer value into a long time value. Times are
stored as long values: HHMMSS00. Since the timer value does not
hold centiseconds, these are set to zero. If the supplied value was
zero or invalid, returns zero. The timer value is assumed to be UTC
(GMT).
*/
/*--------------------------------------------------------------------------*/
static long timer_to_time(time_t time_secs)
{
struct tm *time_struct;
if (time_secs == 0) {
return 0;
} else {
/* Convert into a long value HHMMSS00 */
time_struct = localtime (&time_secs);
if (time_struct) {
return (MAKE_TIME (time_struct-> tm_hour,
time_struct-> tm_min,
time_struct-> tm_sec,
0));
} else {
return 0;
}
}
}
/*---------------------------------------------------------------------------
Function codes
---------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
/**
@brief Returns the current date as a static string.
@return Pointer to statically allocated string.
Build and return a string containing the date of today in ISO8601
format. The returned pointer points to a statically allocated string
in the function, so no need to free it.
*/
/*--------------------------------------------------------------------------*/
char * get_date_iso8601(void)
{
static char date_iso8601[20] ;
long curdate ;
curdate = date_now() ;
sprintf(date_iso8601, "%04d-%02d-%02d",
GET_CCYEAR(curdate),
GET_MONTH(curdate),
GET_DAY(curdate));
return date_iso8601 ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Returns the current date and time as a static string.
@return Pointer to statically allocated string
Build and return a string containing the date of today and the
current time in ISO8601 format. The returned pointer points to a
statically allocated string in the function, so no need to free it.
*/
/*-------------------------------------------------------------------------*/
char * get_datetime_iso8601(void)
{
static char date_iso8601[20] ;
long curdate ;
long curtime ;
curdate = date_now() ;
curtime = time_now() ;
sprintf(date_iso8601, "%04d-%02d-%02dT%02d:%02d:%02d",
GET_CCYEAR(curdate),
GET_MONTH(curdate),
GET_DAY(curdate),
GET_HOUR(curtime),
GET_MINUTE(curtime),
GET_SECOND(curtime));
return date_iso8601 ;
}
#ifdef TEST
int main(int argc, char *argv[])
{
printf( "date now %ld\n"
"time now %ld\n"
"date iso8601 %s\n"
"date/time iso 8601 %s\n",
date_now(),
time_now(),
get_date_iso8601(),
get_datetime_iso8601());
return 0 ;
}
#endif
/* vim: set ts=4 et sw=4 tw=75 */

View File

@ -0,0 +1,96 @@
/*-------------------------------------------------------------------------*/
/**
@file t_iso8601.h
@author N. Devillard
@date Aug 1999
@version $Revision: 1.3 $
@brief Get date/time, possibly in ISO8601 format.
This module contains various utilities to get the current date/time,
and possibly format it according to the ISO 8601 format.
*/
/*--------------------------------------------------------------------------*/
/*
$Id: t_iso8601.h,v 1.3 2002/01/10 08:53:08 ndevilla Exp $
$Author: ndevilla $
$Date: 2002/01/10 08:53:08 $
$Revision: 1.3 $
*/
#ifndef _T_ISO8601_H_
#define _T_ISO8601_H_
#ifdef __cplusplus
extern "C" {
#endif
/* <dox> */
/*---------------------------------------------------------------------------
Function ANSI C prototypes
---------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------*/
/**
@brief Returns the current date as a long (CCYYMMDD).
@return The current date as a long number.
Returns the current date as a long value (CCYYMMDD). Since most
system clocks do not return a century, this function assumes that
all years 80 and above are in the 20th century, and all years 00 to
79 are in the 21st century. For best results, consume before 1 Jan
2080.
Example: 19 Oct 2000 is returned as 20001019
*/
/*--------------------------------------------------------------------------*/
long date_now (void);
/*-------------------------------------------------------------------------*/
/**
@brief Returns the current time as a long (HHMMSSCC).
@return The current time as a long number.
Returns the current time as a long value (HHMMSSCC). If the system
clock does not return centiseconds, these are set to zero.
Example: 15:36:12.84 is returned as 15361284
*/
/*--------------------------------------------------------------------------*/
long time_now(void);
/*--------------------------------------------------------------------------*/
/**
@brief Returns the current date as a static string.
@return Pointer to statically allocated string.
Build and return a string containing the date of today in ISO8601
format. The returned pointer points to a statically allocated string
in the function, so no need to free it.
*/
/*--------------------------------------------------------------------------*/
char * get_date_iso8601(void);
/*-------------------------------------------------------------------------*/
/**
@brief Returns the current date and time as a static string.
@return Pointer to statically allocated string
Build and return a string containing the date of today and the
current time in ISO8601 format. The returned pointer points to a
statically allocated string in the function, so no need to free it.
*/
/*-------------------------------------------------------------------------*/
char * get_datetime_iso8601(void);
/* </dox> */
#ifdef __cplusplus
}
#endif
#endif
/* vim: set ts=4 et sw=4 tw=75 */

1418
qfits/src/tfits.c 100644

File diff suppressed because it is too large Load Diff

407
qfits/src/tfits.h 100644
View File

@ -0,0 +1,407 @@
/*-------------------------------------------------------------------------*/
/**
@file tfits.h
@author Yves Jung
@date July 1999
@version $Revision: 1.5 $
@brief FITS table handling
*/
/*--------------------------------------------------------------------------*/
/*
$Id: tfits.h,v 1.5 2002/01/10 08:53:08 ndevilla Exp $
$Author: ndevilla $
$Date: 2002/01/10 08:53:08 $
$Revision: 1.5 $
*/
#ifndef _TFITS_H_
#define _TFITS_H_
#ifdef __cplusplus
extern "C" {
#endif
/*---------------------------------------------------------------------------
Includes
---------------------------------------------------------------------------*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include "fits_h.h"
#include "static_sz.h"
/* <dox> */
/*---------------------------------------------------------------------------
Defines
---------------------------------------------------------------------------*/
/* The following defines the maximum acceptable size for a FITS value */
#define FITSVALSZ 60
#define QFITS_INVALIDTABLE 0
#define QFITS_BINTABLE 1
#define QFITS_ASCIITABLE 2
/*---------------------------------------------------------------------------
New types
---------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------*/
/**
@brief Column object
This structure contains all information needed to read a column in a table.
These informations come from the header.
The qfits_table object contains a list of qfits_col objects.
This structure has to be created from scratch and filled if one want to
generate a FITS table.
*/
/*-------------------------------------------------------------------------*/
typedef struct _qfits_col_
{
/**
Number of rows in the column. In a same table, all columns have
the same nelem value.
*/
int nelem ;
/**
Number of elements in one field. There are some differences according
types
- If the field contains a string, natoms = 1. In this case, the number
of characters is given by ascii_size.
- If the field contains elements of types 'L', 'I', 'J', 'E', 'D' or
'B', natoms is simply the number of elements.
- For complex types ('C' or 'M') natoms is the number of double or
float (number of complex * 2).
- If the field contains elements of type P (pair of int), natoms is
the number of int (nb of 'P' element * 2)
*/
int natoms ;
/**
Size of one element in bytes. In ASCII tables, atom_size is the size
of the element once it has been converted in its 'destination' type.
For example, if "123" is contained in an ASCII table in a column
defined as I type, natoms=1, ascii_size=3, atom_size=4.
In ASCII tables:
- type 'A' : atom_size = ascii_size = number of chars
- type 'I', 'F' or 'E' : atom_size = 4
- type 'D' : atom_size = 8
In BIN tables :
- type 'A' : atom_size = ascii_size = atom_nb = number of chars
- type 'L', 'X', B' : atom_size = 1
- type 'I' : atom_size = 2
- type 'E', 'J', 'C', 'P' : atom_size = 4
- type 'D', 'M' : atom_size = 8
*/
int atom_size ;
/**
Only for ASCII fields (0 otherwise). Nb of characters of the field.
*/
int ascii_size ;
/**
Type of data in the column as specified in TFORM keyword
In ASCII tables : A, I, F, E or D
In BIN tables : L, X, B, I, J, A, E, D, C, M or P
*/
char atom_type ;
/**
Number of atoms per field as specified in TFORM keyword
Differ from natoms for ASCII table fields of type different from A:
you can have the string "1234" (natoms = 1) specified as I4
(atom_nb = 4)
*/
int atom_nb ;
/**
Label of the column
*/
char tlabel[FITSVALSZ] ;
/**
Unit of the data
*/
char tunit[FITSVALSZ] ;
/**
Null value
*/
char nullval[FITSVALSZ] ;
/**
Display format
*/
char disp[FITSVALSZ] ;
/**
zero and scale are used when the quantity in the field does not
represent a true physical quantity. Basically, thez should be used
when they are present: physical_value = zero + scale * field_value
They are read from TZERO and TSCAL in the header
*/
int zero_present ;
float zero ;
int scale_present ;
float scale ;
/**
Offset between the beg. of the table and the beg. of the column.
*/
int off_beg ;
/**
Width of the table in bytes
*/
int off_jmp ;
/**
Flag to know if the column is readable. An empty col is not readable
*/
int readable ;
} qfits_col ;
/*-------------------------------------------------------------------------*/
/**
@brief Table object
This structure contains all information needed to read a FITS table.
These information come from the header. The object is created by
qfits_open().
To read a FITS table, here is a code example:
@code
int main(int argc, char* argv[])
{
qfits_table * table ;
int n_ext ;
int i ;
n_ext = qfits_query_n_ext(argv[1]);
for (i=0 ; i<n_ext ; i++) {
if ((table = qfits_table_open(argv[1], i+1)) == NULL) {
printf("cannot open table [%s]:[%d]\n", argv[1], i+1);
} else {
dump_extension(table, stdout, '|', 1, 1) ;
qfits_table_close(table) ;
}
}
return ;
}
@endcode
*/
/*-------------------------------------------------------------------------*/
typedef struct _qfits_table_
{
/**
Name of the file the table comes from or it is intended to end to
*/
char filename[FILENAMESZ] ;
/**
Table type. Possible values are QFITS_INVALIDTABLE, QFITS_BINTABLE
or QFITS_ASCIITABLE
*/
int tab_t ;
/**
Number of columns
*/
int nc ;
/**
Array of qfits_col objects
*/
qfits_col * col ;
} qfits_table ;
/*---------------------------------------------------------------------------
Function prototypes
---------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------*/
/**
@brief Identify a file as containing a FITS table in extension.
@param filename Name of the FITS file to examine.
@param xtnum Extension number to check (starting from 1).
@return int 1 if the extension contains a table, 0 else.
Examines the requested extension and identifies the presence of a
FITS table.
*/
/*--------------------------------------------------------------------------*/
int qfits_is_table(char * filename, int xtnum) ;
/*-------------------------------------------------------------------------*/
/**
@brief Read a FITS extension.
@param filename Name of the FITS file to examine.
@param xtnum Extension number to read (starting from 1).
@return Pointer to newly allocated qfits_table structure.
Read a FITS table from a given file name and extension, and return a
newly allocated qfits_table structure. This structure contains the
following informations:
- Name of the FITS file associated to table
- Table type
- Number of columns in table
- Array of qfits_col objects
The table type is an int taking the following values:
- QFITS_BINTABLE for binary tables
- QFITS_ASCIITABLE for ascii tables
*/
/*--------------------------------------------------------------------------*/
qfits_table * qfits_table_open(char * filename, int xtnum) ;
/*-------------------------------------------------------------------------*/
/**
@brief Free a FITS table and associated pointers
@param t qfits_table to free
@return void
Frees all memory associated to a qfits_table structure.
*/
/*--------------------------------------------------------------------------*/
void qfits_table_close(qfits_table * t) ;
/*-------------------------------------------------------------------------*/
/**
@brief Extract data from a column in a FITS table
@param th Allocated qfits_table
@param colnum Number of the column to extract (from 0 to colnum-1)
@return unsigned char array
Extract a column from a FITS table and return the data as a bytes
array. The returned array type and size are determined by the
column object in the qfits_table.
Returned array size in bytes is:
col->nelem * col->natoms * col->atom_size
Numeric types are correctly understood and byte-swapped if needed,
to be converted to the local machine type.
NULL values have to be handled by the caller
*/
/*--------------------------------------------------------------------------*/
unsigned char * qfits_query_column(
qfits_table * th,
int colnum) ;
/*-------------------------------------------------------------------------*/
/**
@brief Extract binary data from a column in a FITS table
@param th Allocated qfits_table
@param colnum Number of the column to extract (from 0 to colnum-1)
@param null_value Value to return when a NULL value comes
@return Pointer to void *
Extract a column from a FITS table and return the data as a generic
void* array. The returned array type and size are determined by the
column object in the qfits_table.
Returned array size in bytes is:
col->nelem * col->atom_nb * col->atom_size
NULL values are recognized and replaced by the specified value.
*/
/*--------------------------------------------------------------------------*/
void * qfits_query_column_data(
qfits_table * th,
int colnum,
void * null_value) ;
/*-------------------------------------------------------------------------*/
/**
@brief Save a table to a FITS file with a given FITS header.
@param array Data array.
@param table table
@param filename Name of the image on disk.
@param fh FITS header to insert in the output file.
@return -1 in error case, 0 otherwise
*/
/*--------------------------------------------------------------------------*/
int qfits_save_table_hdrdump(
void ** array,
qfits_table * table,
char * filename,
qfits_header * fh) ;
/*-------------------------------------------------------------------------*/
/**
@brief given a col and a row, find out the string to write for display
@param table table structure
@param col_id col id (0 -> nbcol-1)
@param row_id row id (0 -> nrow-1)
@param column array that contains the column data
@param use_zero_scale Flag to use or not zero and scale
@return the string to write
*/
/*--------------------------------------------------------------------------*/
char * qfits_table_field_to_string(
qfits_table * table,
int col_id,
int row_id,
void * column,
int use_zero_scale) ;
/*-------------------------------------------------------------------------*/
/**
@brief given a col and a row, find out the string to write for display
@param table table structure
@param col_id col id (0 -> nbcol-1)
@param row_id row id (0 -> nrow-1)
@param column array that contains the column data
@param use_zero_scale Flag to use or not zero and scale
@return the string to write
ASCII tables specific
*/
/*--------------------------------------------------------------------------*/
char * qfits_asciitable_field_to_string(
qfits_table * table,
int col_id,
int row_id,
void * column,
int use_zero_scale) ;
/*-------------------------------------------------------------------------*/
/**
@brief given a col and a row, find out the string to write for display
@param table table structure
@param col_id col id (0 -> nbcol-1)
@param row_id row id (0 -> nrow-1)
@param column array that contains the column data
@param use_zero_scale Flag to use or not zero and scale
@return the string to write
BIN tables specific
*/
/*--------------------------------------------------------------------------*/
char * qfits_bintable_field_to_string(
qfits_table * table,
int col_id,
int row_id,
void * column,
int use_zero_scale) ;
/* </dox> */
#ifdef __cplusplus
}
#endif
#endif
/* vim: set ts=4 et sw=4 tw=75 */

View File

@ -0,0 +1,10 @@
/* Library version */
static char *
_qfits_version = "4.0.2" ;
char * qfits_version(void)
{
return _qfits_version ;
}
/* vim: set ts=4 et sw=4 tw=75 */

1383
qfits/src/xmemory.c 100644

File diff suppressed because it is too large Load Diff

759
qfits/sysconf.c 100644
View File

@ -0,0 +1,759 @@
/*---------------------------------------------------------------------------
File name : sysconf.c
Author : Nicolas Devillard
Created on : February 2001
Description : configure-like in C.
---------------------------------------------------------------------------*/
/*
$Id: sysconf.c,v 1.17 2002/01/22 14:47:55 ndevilla Exp $
$Author: ndevilla $
$Date: 2002/01/22 14:47:55 $
$Revision: 1.17 $
*/
/*---------------------------------------------------------------------------
Includes
---------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include <sys/utsname.h>
#define MAXSTRSZ 512
#define MACROS_FILE "config.make"
#define HEADER_FILE "config.h"
#define PREFIX_DEFAULT "/opt/qfits"
#define COMPILER_AUTO 0
#define COMPILER_CC 1
#define COMPILER_GCC 2
/* Global variable */
struct {
/* List of supported OS's */
enum {
os_linux,
os_hp08,
os_hp09,
os_hp10,
os_hp11,
os_solaris,
os_aix,
os_dec,
os_bsd,
os_darwin
} local_os ;
char sysname[MAXSTRSZ];
char release[MAXSTRSZ];
char machine[MAXSTRSZ];
/* Bits per byte on this machine */
int bits_per_byte ;
/* Big endian machine? */
int big_endian ;
/* x86 architecture? */
int arch_x86 ;
/* CPU type: 386, 486, 586, 686 */
int cpu_x86 ;
/* Compile with debug options on */
int debug_compile ;
/* Compile with warnings on */
int lint_compile ;
/* Compiler type: native cc or gcc */
int compiler ;
/* Compile with tracing (gcc only >= 2.95) */
int with_trace ;
/* Compile with threads */
int with_threads ;
/* Number of detected CPUs */
int ncpus ;
/* Compile with gcc3 (pollux only) */
int gcc3 ;
/* Compile static library */
int lib_static ;
/* Compile dynamic library */
int lib_dynamic ;
/* Prefix for installation */
char * prefix ;
} config ;
/* Guess local OS name and potentially release number */
detect_config()
{
struct utsname name ;
int i ;
unsigned char c ;
int x ;
if (config.sysname[0]==0) {
printf("detecting local OS............. ");
/* Get machine OS type and release number */
if (uname(&name)==-1) {
printf("error calling uname\n");
exit(-1);
}
printf("%s %s", name.sysname, name.release);
strcpy(config.sysname, name.sysname);
strcpy(config.release, name.release);
strcpy(config.machine, name.machine);
} else {
printf("forcing config for OS.......... %s %s",
config.sysname,
config.release);
}
/* Lowercase everything */
i=0 ;
while(config.sysname[i]!=0) {
config.sysname[i] = tolower(config.sysname[i]);
i++ ;
}
i=0 ;
while(config.release[i]!=0) {
config.release[i] = tolower(config.release[i]);
i++ ;
}
/* Switch on OS type and release number */
if (strstr(config.sysname, "linux")!=NULL) {
config.local_os = os_linux ;
printf(" - linux\n");
} else if (strstr(config.sysname, "hp")!=NULL) {
if (strstr(config.release, "8.")!=NULL) {
config.local_os = os_hp08 ;
printf(" - hpux_08\n");
} else if (strstr(config.release, "9.")!=NULL) {
config.local_os = os_hp09 ;
printf(" - hpux_09\n");
} else if (strstr(config.release, "10.")!=NULL) {
config.local_os = os_hp10 ;
printf(" - hpux_10\n");
} else if (strstr(config.release, "11.")!=NULL) {
config.local_os = os_hp11 ;
printf(" - hpux_11\n");
}
} else if ((strstr(config.sysname, "sun")!=NULL) ||
(strstr(config.sysname, "solaris")!=NULL)) {
config.local_os = os_solaris ;
printf(" - solaris\n");
} else if (strstr(config.sysname, "aix")!=NULL) {
config.local_os = os_aix ;
printf(" - aix\n");
} else if (strstr(config.sysname, "osf")!=NULL) {
config.local_os = os_dec ;
printf(" - osf/1\n");
} else if (strstr(config.sysname, "bsd")!=NULL) {
config.local_os = os_bsd ;
printf(" - %s\n", config.sysname);
} else if (strstr(config.sysname, "darwin")!=NULL) {
config.local_os = os_darwin ;
printf(" - %s\n", config.sysname);
} else {
printf("cannot identify your OS\n");
printf("Use the option --os=NAME to force an OS type\n");
exit(-1);
}
/* Find out about x86 architectures */
if ((config.machine[0]=='i') && (strstr(config.machine, "86")!=NULL)) {
config.arch_x86 = 1 ;
config.cpu_x86 = atoi(config.machine+1) ;
printf("detected x86 architecture...... %d\n", config.cpu_x86);
} else {
config.arch_x86 = 0 ;
printf("detected x86 architecture...... no\n");
}
/* Compute number of bits in a byte on this machine */
printf("computing bits per byte........ ");
c=1 ; i=0 ;
while (c) {
c<<=1 ; i++ ;
}
config.bits_per_byte = i ;
printf("%d\n", i);
/* Detect endian-ness */
printf("detecting byte-order........... ");
x = 1 ;
x = (*(char*)&x) ;
config.big_endian = !x ;
if (config.big_endian) {
printf("big endian (motorola)\n");
} else {
printf("little endian (intel)\n");
}
return ;
}
/* Locate a program in the user's PATH */
int locate_program(pname)
char * pname ;
{
int i, j, lg;
char * path ;
char buf[MAXSTRSZ];
path = getenv("PATH");
if (path!=NULL) {
for (i=0; path[i]; ) {
for (j=i ; (path[j]) && (path[j]!=':') ; j++);
lg = j - i;
strncpy(buf, path + i, lg);
if (lg == 0) buf[lg++] = '.';
buf[lg++] = '/';
strcpy(buf + lg, pname);
if (access(buf, X_OK) == 0) {
printf("using [%s]\n", buf);
return 1 ;
}
buf[0] = 0;
i = j;
if (path[i] == ':') i++ ;
}
} else {
/* No PATH variable: abort with an error */
return -1 ;
}
/* If the buffer is still empty, the command was not found */
if (buf[0] == 0) return 0 ;
/* Otherwise Ok */
return 1 ;
}
make_config_make()
{
FILE * sysc ;
/* Set compiler name */
printf("looking for a C compiler....... ");
if (getenv("PATH")==NULL) {
printf("error: undefined PATH variable, cannot locate a compiler\n");
exit(-1) ;
}
/* Open output sysconf */
if ((sysc=fopen(MACROS_FILE, "w"))==NULL) {
printf("cannot create %s: aborting compilation", MACROS_FILE);
exit(-1) ;
}
/* In automatic mode, find out which compiler to use */
if (config.compiler==COMPILER_AUTO) {
switch (config.local_os) {
/* Linux and BSD use gcc always */
case os_linux:
case os_bsd:
config.compiler = COMPILER_GCC ;
break ;
/* All others use 'cc' (default) */
default:
config.compiler = COMPILER_CC ;
break ;
}
}
/* Make sure the compiler can be found */
if (config.compiler==COMPILER_CC) {
if (locate_program("cc")!=1) {
printf("cannot locate cc\n");
/* Try out with gcc */
config.compiler = COMPILER_GCC ;
}
}
if (config.compiler==COMPILER_GCC) {
if (locate_program("gcc")!=1) {
printf("cannot locate gcc\n");
exit(-1);
}
}
/* Set compiler name and cflags */
switch (config.compiler) {
case COMPILER_CC:
fprintf(sysc, "CC = cc\n");
fprintf(sysc, "CFLAGS = ");
switch (config.local_os) {
case os_hp08:
case os_hp09:
case os_hp10:
if (config.with_threads) {
printf("threads not supported on this platform\n");
}
if (config.debug_compile) {
fprintf(sysc, "-Ae -g\n");
} else {
fprintf(sysc, "-Ae -O\n");
}
fprintf(sysc, "RELOC = +z\n");
fprintf(sysc, "SHARED = -b\n");
break ;
case os_hp11:
if (config.with_threads) {
fprintf(sysc, "-lpthread ");
}
if (config.debug_compile) {
fprintf(sysc, "-g\n");
} else {
fprintf(sysc, "-O\n");
}
fprintf(sysc, "RELOC = +z\n");
fprintf(sysc, "SHARED = -b\n");
break ;
case os_solaris:
if (config.with_threads) {
fprintf(sysc, "-mt -lpthread ");
}
if (config.debug_compile) {
fprintf(sysc, "-g\n");
} else {
fprintf(sysc, "-xO5\n");
}
fprintf(sysc, "RELOC = -G\n");
fprintf(sysc, "SHARED = -G\n");
break ;
case os_dec:
if (config.with_threads) {
printf("threads not supported on this platform\n");
}
if (config.debug_compile) {
fprintf(sysc, "-g\n");
} else {
fprintf(sysc, "-O\n");
}
fprintf(sysc, "RELOC =\n");
fprintf(sysc, "SHARED = -shared -expect_unresolved \"*\"\n");
break ;
case os_aix:
case os_bsd:
if (config.with_threads) {
printf("threads not supported on this platform\n");
}
if (config.debug_compile) {
fprintf(sysc, "-g\n");
} else {
fprintf(sysc, "-O\n");
}
fprintf(sysc, "RELOC =\n");
fprintf(sysc, "SHARED =\n");
break ;
case os_linux:
/* cc with Linux? Why not! */
if (config.with_threads) {
fprintf(sysc, "-pthread ");
}
if (config.debug_compile) {
fprintf(sysc, "-g\n");
} else {
fprintf(sysc, "-O3\n");
}
fprintf(sysc, "RELOC = -fpic\n");
fprintf(sysc, "SHARED = -shared\n");
break ;
case os_darwin:
/* Darwin uses gcc but calls it 'cc' */
fprintf(sysc, "-DOS_DARWIN=1 -Dsrand48=srandom -Ddrand48=random ");
if (config.with_threads) {
fprintf(sysc, "-pthread ");
}
if (config.debug_compile) {
fprintf(sysc, "-g\n");
} else {
fprintf(sysc, "-O3\n");
}
fprintf(sysc, "RELOC = -fPIC\n");
fprintf(sysc, "SHARED = -shared\n");
break ;
default:
printf("error: unsupported OS\n");
exit(-1) ;
}
break ;
case COMPILER_GCC:
if (config.gcc3) {
fprintf(sysc, "CC = /opt/gcc3/bin/gcc\n");
} else {
fprintf(sysc, "CC = gcc\n");
}
fprintf(sysc, "CFLAGS = ");
if (config.with_threads) {
fprintf(sysc, "-pthread ");
}
if (config.lint_compile) {
fprintf(sysc, " -Wall -pedantic ");
}
if (config.debug_compile) {
fprintf(sysc, "-g\n");
} else {
fprintf(sysc, "-O3\n");
}
if (config.with_trace) {
fprintf(sysc, "FTRACE = -finstrument-functions\n");
} else {
fprintf(sysc, "FTRACE =\n");
}
fprintf(sysc, "RELOC = -fpic\n");
fprintf(sysc, "SHARED = -shared\n");
break ;
default:
printf("error in compiler option switch: aborting\n");
exit(-1);
break ;
}
if (config.debug_compile) {
printf(" in debug mode\n");
} else {
printf(" all optimizations on\n");
}
if (config.lint_compile) {
printf(" with all warnings\n");
}
if (config.with_trace) {
printf(" with function tracing\n");
}
/* LFLAGS */
switch (config.local_os) {
case os_hp10:
case os_hp11:
fprintf(sysc, "# Shut up HPUX 11 linker\n");
fprintf(sysc, "LFLAGS = -Wl,+vnocompatwarnings\n");
break ;
default:
fprintf(sysc, "LFLAGS =\n");
break ;
}
/* RANLIB */
switch (config.local_os) {
case os_hp08:
case os_hp09:
case os_hp10:
case os_hp11:
fprintf(sysc, "RANLIB = ranlib\n");
fprintf(sysc, "DYNSUF = sl\n");
break ;
case os_darwin:
fprintf(sysc, "RANLIB = ranlib\n");
fprintf(sysc, "DYNSUF = so\n");
break ;
default:
fprintf(sysc, "RANLIB = true\n");
fprintf(sysc, "DYNSUF = so\n");
break ;
}
/* STRIP */
if (config.debug_compile) {
fprintf(sysc, "STRIP = true\n");
} else {
fprintf(sysc, "STRIP = strip\n");
}
/* TARGETS */
fprintf(sysc, "TARGETS =");
printf("static library................. %s\n",
config.lib_static ? "yes" : "no");
if (config.lib_static) {
fprintf(sysc, " static");
}
printf("shared library................. %s\n",
config.lib_dynamic ? "yes" : "no");
if (config.lib_dynamic) {
fprintf(sysc, " dynamic");
}
fprintf(sysc,"\n");
/* PREFIX */
fprintf(sysc, "prefix = %s\n",
config.prefix ? config.prefix : PREFIX_DEFAULT);
printf("setting installation prefix as: [%s]\n",
config.prefix ? config.prefix : PREFIX_DEFAULT);
fclose(sysc);
}
make_config_h()
{
FILE * out ;
out = fopen(HEADER_FILE, "w");
if (out==NULL) {
printf("cannot create header file %s: aborting", HEADER_FILE);
return ;
}
fprintf(out,
"/* This file automatically generated */\n"
"#ifndef _CONFIG_H_\n"
"#define _CONFIG_H_\n"
"\n"
"%s",
config.big_endian ? "#define WORDS_BIGENDIAN 1\n" : "\n"
);
/* Generate SIZEOF macros for basic types */
printf("detecting basic size types\n");
fprintf(out,
"#define SIZEOF_CHAR %d\n"
"#define SIZEOF_SHORT %d\n"
"#define SIZEOF_INT %d\n"
"#define SIZEOF_LONG %d\n"
"#define SIZEOF_FLOAT %d\n"
"#define SIZEOF_DOUBLE %d\n",
sizeof(char),
sizeof(short),
sizeof(int),
sizeof(long),
sizeof(float),
sizeof(double));
printf(
"sizeof(char)................... %d\n"
"sizeof(short).................. %d\n"
"sizeof(int).................... %d\n"
"sizeof(long)................... %d\n"
"sizeof(float).................. %d\n"
"sizeof(double)................. %d\n",
sizeof(char),
sizeof(short),
sizeof(int),
sizeof(long),
sizeof(float),
sizeof(double));
/* Do not output CHAR_BIT on AIX */
if (config.local_os!=os_aix) {
fprintf(out,
"\n"
"#ifndef CHAR_BIT\n"
"#define CHAR_BIT\t%d\n"
"#endif\n"
"\n\n",
config.bits_per_byte);
}
if (config.arch_x86) {
fprintf(out, "#define CPU_X86 %d\n", config.cpu_x86);
}
if (config.with_threads) {
fprintf(out, "#define HAS_PTHREADS 1\n\n");
}
switch (config.local_os) {
case os_hp08:
case os_hp09:
case os_hp10:
case os_hp11:
fprintf(out, "#define OS_HPUX 1\n");
break ;
case os_linux:
fprintf(out, "#define OS_LINUX 1\n");
break ;
case os_aix:
fprintf(out, "#define OS_AIX 1\n");
break ;
case os_dec:
fprintf(out, "#define OS_DEC 1\n");
break ;
case os_solaris:
fprintf(out, "#define OS_SOLARIS 1\n");
break ;
case os_bsd:
fprintf(out, "#define OS_BSD 1\n");
break ;
case os_darwin:
fprintf(out, "#define OS_DARWIN 1\n");
break ;
default:
fprintf(out, "#define OS_UNKNOWN 1\n");
break ;
}
fprintf(out, "#endif\n");
fclose(out);
printf("done\n");
return ;
}
help()
{
printf(
"\n\n"
"***** qfits configure help\n"
"Use: configure [options]\n"
"\n"
"options are:\n"
"\t--debug Compile modules in debug mode\n"
"\t--help Get this help\n"
"\n"
"\t--with-cc Force compilation with local cc\n"
"\t--with-gcc Force compilation with gcc\n"
"\n"
"\t--enable-static Compile static library (default)\n"
"\t--enable-shared Compile shared library\n"
"\t--disable-shared Do not compile shared library (default)\n"
"\t--disable-static Do not compile static library\n"
"\n"
"\t--prefix=PATH Install in PATH (must be absolute)\n"
"\t--mt Compile with multithreading support\n"
"\n"
"options specific to compilation with gcc (for developers):\n"
"\t--lint Compile with -Wall\n"
"\t--trace Compile function tracing capabilities\n"
"\t--gcc3 Compile with gcc3 in /opt/gcc3\n"
"\n"
"If your platform is not or incorrectly recognized, you\n"
"can force a given configuration with this option:\n"
"\n"
"\t--os=NAME Where NAME is one of the following:\n"
"\n"
"\tlinux - Linux systems (any processor type)\n"
"\thp08 - HPUX version 8.x\n"
"\thp09 - HPUX version 9.x\n"
"\thp10 - HPUX version 10.x\n"
"\thp11 - HPUX version 11.x\n"
"\taix - IBM AIX (any version)\n"
"\tdec - Dec OSF/1 or Tru64 Unix\n"
"\tsolaris - Sun Solaris >=2.5\n"
"\tbsd - BSD compatible Unix\n"
"\tdarwin - Darwin (BSD compatible on Mac)\n"
"\n"
);
}
int main(argc, argv)
int argc ;
char * argv[];
{
char sysname[MAXSTRSZ];
int i ;
config.debug_compile = 0;
config.lint_compile = 0 ;
config.compiler = COMPILER_AUTO ;
config.with_threads = 0 ;
config.with_trace = 0 ;
config.gcc3 = 0 ;
config.lib_static = 1 ;
config.lib_dynamic = 0 ;
config.prefix = NULL ;
memset(config.sysname, 0, MAXSTRSZ);
memset(config.release, 0, MAXSTRSZ);
memset(config.machine, 0, MAXSTRSZ);
for (i=0 ; i<argc ; i++) {
if (!strcmp(argv[i], "--help")) {
help() ;
return 1 ;
} else if (!strcmp(argv[i], "--debug")) {
config.debug_compile = 1 ;
} else if (!strcmp(argv[i], "--with-cc")) {
config.compiler = COMPILER_CC ;
} else if (!strcmp(argv[i], "--with-gcc")) {
config.compiler = COMPILER_GCC ;
} else if (!strcmp(argv[i], "--lint")) {
config.lint_compile = 1 ;
} else if (!strcmp(argv[i], "--mt")) {
config.with_threads=1 ;
} else if (!strcmp(argv[i], "--trace")) {
config.with_trace = 1 ;
} else if (!strcmp(argv[i], "--gcc3")) {
config.gcc3=1 ;
} else if (!strcmp(argv[i], "--enable-shared")) {
config.lib_dynamic = 1;
} else if (!strcmp(argv[i], "--disable-shared")) {
config.lib_dynamic = 0;
} else if (!strcmp(argv[i], "--enable-static")) {
config.lib_static = 1;
} else if (!strcmp(argv[i], "--disable-static")) {
config.lib_static = 0;
} else if (!strncmp(argv[i], "--prefix=", 9)) {
config.prefix = strchr(argv[i], '=') + 1 ;
} else if (!strncmp(argv[i], "--os=", 5)) {
strcpy(sysname, argv[i]+5);
if (!strcmp(sysname, "linux")) {
strcpy(config.sysname, "Linux");
} else if (!strcmp(sysname, "hp08")) {
strcpy(config.sysname, "HPUX");
strcpy(config.release, "8.x");
} else if (!strcmp(sysname, "hp09")) {
strcpy(config.sysname, "HPUX");
strcpy(config.release, "9.x");
} else if (!strcmp(sysname, "hp10")) {
strcpy(config.sysname, "HPUX");
strcpy(config.release, "10.x");
} else if (!strcmp(sysname, "hp11")) {
strcpy(config.sysname, "HPUX");
strcpy(config.release, "11.x");
} else if (!strcmp(sysname, "aix")) {
strcpy(config.sysname, "AIX");
} else if (!strcmp(sysname, "dec")) {
strcpy(config.sysname, "Dec OSF/1 or Tru64");
} else if (!strcmp(sysname, "solaris")) {
strcpy(config.sysname, "Solaris");
strcpy(config.release, ">= 2.5");
} else if (!strcmp(sysname, "bsd")) {
strcpy(config.sysname, "BSD compatible");
} else if (!strcmp(sysname, "darwin")) {
strcpy(config.sysname, "Darwin");
} else {
printf("unsupported OS: %s\n", sysname);
return -1 ;
}
}
}
detect_config();
make_config_make();
make_config_h();
return 0 ;
}

View File

@ -0,0 +1,23 @@
#
# Makefile for qfits test modules
#
include ../config.make
RM = rm -f
# Compile rules
SUFFIXES = .o .c .h .a .so .sl
COMPILE.c = $(CC) $(CFLAGS) $(FTRACE) -L../lib -I../include -o $@ $< -lqfits $(LFLAGS)
.c:
$(COMPILE.c)
default: all
all: test_qfits
clean veryclean:
$(RM) test_qfits

View File

@ -0,0 +1,768 @@
/*---------------------------------------------------------------------------
qfits test suite
---------------------------------------------------------------------------*/
/*
$Id: test_qfits.c,v 1.4 2002/01/15 15:10:59 ndevilla Exp $
$Author: ndevilla $
$Date: 2002/01/15 15:10:59 $
$Revision: 1.4 $
*/
/*---------------------------------------------------------------------------
Includes
---------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "qfits.h"
#include "xmemory.h"
#define QFITSTESTFILENAME "QFITS.fits"
#define BINDUMPNAME "bindump.dat"
#define say(s) fprintf(stderr, "qtest:\t\t%s\n", s)
#define _fail(s,l) fprintf(stderr, "qtest(%d): %s\n", l, s)
#define fail(s) _fail(s,__LINE__)
#define REFSIG "6569daba7b124febfa0cd7813f555774"
typedef unsigned char byte ;
static float float_array_orig[] =
{
1.0, 2.0, 0.0, -1.0, -2.0, 1e-4, -1e-4, 1e-6, -1e-6,
1.2345678, 3.1415926535, 19.71
};
static byte float_array_byte[] =
{
0x3f, 0x80, 0x00, 0x00,
0x40, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0xbf, 0x80, 0x00, 0x00,
0xc0, 0x00, 0x00, 0x00,
0x38, 0xd1, 0xb7, 0x17,
0xb8, 0xd1, 0xb7, 0x17,
0x35, 0x86, 0x37, 0xbd,
0xb5, 0x86, 0x37, 0xbd,
0x3f, 0x9e, 0x06, 0x51,
0x40, 0x49, 0x0f, 0xdb,
0x41, 0x9d, 0xae, 0x14
};
static int int_array_orig[] =
{
-32768, -16384, -8192, -4096, -1023, 0,
1023, 2048, 8191, 16387, 32767, 65536
};
static byte int_array_byte[] =
{
0xff, 0xff, 0x80, 0x00,
0xff, 0xff, 0xc0, 0x00,
0xff, 0xff, 0xe0, 0x00,
0xff, 0xff, 0xf0, 0x00,
0xff, 0xff, 0xfc, 0x01,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x03, 0xff,
0x00, 0x00, 0x08, 0x00,
0x00, 0x00, 0x1f, 0xff,
0x00, 0x00, 0x40, 0x03,
0x00, 0x00, 0x7f, 0xff,
0x00, 0x01, 0x00, 0x00
};
static double double_array_orig[] =
{
1.0, 2.0, 0.0, -1.0, -2.0, 1e-4, -1e-4, 1e-6, -1e-6,
1.2345678, 3.1415926535, 19.71
};
static byte double_array_byte[] =
{
0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xbf, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x3f, 0x1a, 0x36, 0xe2, 0xeb, 0x1c, 0x43, 0x2d,
0xbf, 0x1a, 0x36, 0xe2, 0xeb, 0x1c, 0x43, 0x2d,
0x3e, 0xb0, 0xc6, 0xf7, 0xa0, 0xb5, 0xed, 0x8d,
0xbe, 0xb0, 0xc6, 0xf7, 0xa0, 0xb5, 0xed, 0x8d,
0x3f, 0xf3, 0xc0, 0xca, 0x2a, 0x5b, 0x1d, 0x5d,
0x40, 0x09, 0x21, 0xfb, 0x54, 0x41, 0x17, 0x44,
0x40, 0x33, 0xb5, 0xc2, 0x8f, 0x5c, 0x28, 0xf6
};
/*---------------------------------------------------------------------------
main
---------------------------------------------------------------------------*/
int test_qfitsheader_create(void)
{
qfits_header * qh ;
FILE * out ;
say("-----> Header creation test");
/* Test qfits_header creation */
say("creating blank header");
qh = qfits_header_new();
if (qh==NULL) {
fail("qfits_header_new() failed");
return 1 ;
}
say("destroying blank header");
/* Destroy header now */
qfits_header_destroy(qh);
/* Create minimal header (SIMPLE/END) */
say("creating minimal header");
qh = qfits_header_default();
if (qh==NULL) {
fail("qfits_header_default() failed");
return 1 ;
}
say("inserting primary keywords");
/* Insert XTENSION marker */
qfits_header_add(qh, "EXTEND", "T", "xtension might be present", NULL);
/* Insert a string */
qfits_header_add(qh, "KEY01", "value01", "comment 01", NULL);
/* Insert an int */
qfits_header_add(qh, "KEY02", "2", "comment 02", NULL);
/* Insert a double */
qfits_header_add(qh, "KEY03", "3.0", "comment 03", NULL);
/* Insert a complex */
qfits_header_add(qh, "KEY04", "4.0 4.2", "comment 04", NULL);
/* Insert a boolean */
qfits_header_add(qh, "KEY05", "T", "comment 05", NULL);
say("inserting history keywords");
/* Insert HISTORY keys */
qfits_header_add(qh, "HISTORY", "1 history field", NULL, NULL);
qfits_header_add(qh, "HISTORY", "2 history field", NULL, NULL);
qfits_header_add(qh, "HISTORY", "3 history field", NULL, NULL);
qfits_header_add(qh, "HISTORY", "4 history field", NULL, NULL);
say("inserting comment keywords");
/* Insert COMMENT keys */
qfits_header_add(qh, "COMMENT", "1 comment field", NULL, NULL);
qfits_header_add(qh, "COMMENT", "2 comment field", NULL, NULL);
qfits_header_add(qh, "COMMENT", "3 comment field", NULL, NULL);
qfits_header_add(qh, "COMMENT", "4 comment field", NULL, NULL);
say("inserting hierarch keywords");
/* Insert HIERARCH ESO keys in reverse DICB order */
qfits_header_add(qh, "HIERARCH ESO NULL A", "0.0", "not DICB", NULL);
qfits_header_add(qh, "HIERARCH ESO NULL B", "0.0", "not DICB", NULL);
qfits_header_add(qh, "HIERARCH ESO NULL C", "0.0", "not DICB", NULL);
qfits_header_add(qh, "PRO.A", "0.0", "DICB compliant", NULL);
qfits_header_add(qh, "PRO.B", "0.0", "DICB compliant", NULL);
qfits_header_add(qh, "PRO.C", "0.0", "DICB compliant", NULL);
qfits_header_add(qh, "HIERARCH ESO LOG A", "0.0", "DICB compliant", NULL);
qfits_header_add(qh, "HIERARCH ESO LOG B", "0.0", "DICB compliant", NULL);
qfits_header_add(qh, "HIERARCH ESO LOG C", "0.0", "DICB compliant", NULL);
qfits_header_add(qh, "INS.A", "0.0", "DICB compliant", NULL);
qfits_header_add(qh, "INS.B", "0.0", "DICB compliant", NULL);
qfits_header_add(qh, "INS.C", "0.0", "DICB compliant", NULL);
qfits_header_add(qh, "HIERARCH ESO TEL A", "0.0", "DICB compliant", NULL);
qfits_header_add(qh, "HIERARCH ESO TEL B", "0.0", "DICB compliant", NULL);
qfits_header_add(qh, "HIERARCH ESO TEL C", "0.0", "DICB compliant", NULL);
qfits_header_add(qh, "GEN.A", "0.0", "DICB compliant", NULL);
qfits_header_add(qh, "GEN.B", "0.0", "DICB compliant", NULL);
qfits_header_add(qh, "GEN.C", "0.0", "DICB compliant", NULL);
qfits_header_add(qh, "HIERARCH ESO TPL A", "0.0", "DICB compliant", NULL);
qfits_header_add(qh, "HIERARCH ESO TPL B", "0.0", "DICB compliant", NULL);
qfits_header_add(qh, "HIERARCH ESO TPL C", "0.0", "DICB compliant", NULL);
qfits_header_add(qh, "OBS.A", "0.0", "DICB compliant", NULL);
qfits_header_add(qh, "OBS.B", "0.0", "DICB compliant", NULL);
qfits_header_add(qh, "OBS.C", "0.0", "DICB compliant", NULL);
say("inserting mandatory keywords");
/* Insert mandatory keys in reverse order */
qfits_header_add(qh, "NAXIS2", "10", "NAXIS2 comment", NULL);
qfits_header_add(qh, "NAXIS1", "11", "NAXIS1 comment", NULL);
qfits_header_add(qh, "NAXIS", "2", "NAXIS comment", NULL);
qfits_header_add(qh, "BITPIX", "-32", "BITPIX comment", NULL);
/* qfits_header_consoledump(qh); */
/* Dump header to file */
say("opening file for output");
out = fopen(QFITSTESTFILENAME, "w");
if (out==NULL) {
fail("cannot create test file");
qfits_header_destroy(qh);
return 1 ;
}
say("dumping header to file");
if (qfits_header_dump(qh, out)!=0) {
fail("cannot dump header");
qfits_header_destroy(qh);
return 1 ;
}
fclose(out);
say("destroying built header");
qfits_header_destroy(qh);
return 0 ;
}
int check_key(qfits_header * qh, char * key, char * expval)
{
char * val ;
int err=0 ;
val = qfits_header_getstr(qh, key);
if (val==NULL) {
fail("missing key in header");
err++ ;
} else {
val = qfits_pretty_string(val);
if (strcmp(val, expval)) {
fail("wrong value for key in header");
err++ ;
}
}
return err ;
}
int test_qfitsheader_read(void)
{
qfits_header * qh ;
char * val ;
int err ;
int keytype ;
err=0 ;
say("-----> Header reading test");
/* Read header from source */
say("reading header from file");
qh = qfits_header_read(QFITSTESTFILENAME);
if (qh==NULL) {
fail("cannot read test file");
return 1 ;
}
say("querying mandatory keys");
err += check_key(qh, "SIMPLE", "T");
err += check_key(qh, "NAXIS", "2");
err += check_key(qh, "NAXIS1", "11");
err += check_key(qh, "NAXIS2", "10");
err += check_key(qh, "BITPIX", "-32");
say("querying base keys");
err += check_key(qh, "KEY01", "value01");
err += check_key(qh, "KEY02", "2");
err += check_key(qh, "KEY03", "3.0");
err += check_key(qh, "KEY04", "4.0 4.2");
err += check_key(qh, "KEY05", "T");
say("checking key types");
val = qfits_header_getstr(qh, "KEY01");
keytype = qfits_get_type(val);
if (keytype!=QFITS_STRING) {
printf("val=[%s] type is %d\n", val, keytype);
fail("wrong identified type for KEY01 (string)");
err++;
}
val = qfits_header_getstr(qh, "KEY02");
keytype = qfits_get_type(val);
if (keytype!=QFITS_INT) {
fail("wrong identified type for KEY02 (int)");
err++;
}
val = qfits_header_getstr(qh, "KEY03");
keytype = qfits_get_type(val);
if (keytype!=QFITS_FLOAT) {
fail("wrong identified type for KEY03 (float)");
err++;
}
val = qfits_header_getstr(qh, "KEY04");
keytype = qfits_get_type(val);
if (keytype!=QFITS_COMPLEX) {
fail("wrong identified type for KEY04 (complex)");
err++;
}
val = qfits_header_getstr(qh, "KEY05");
keytype = qfits_get_type(val);
if (keytype!=QFITS_BOOLEAN) {
fail("wrong identified type for KEY05 (boolean)");
err++;
}
say("querying hierarch keys");
err += check_key(qh, "HIERARCH ESO PRO A", "0.0");
err += check_key(qh, "PRO.B", "0.0");
err += check_key(qh, "pro.c", "0.0");
err += check_key(qh, "ins.a", "0.0");
err += check_key(qh, "ins.b", "0.0");
err += check_key(qh, "ins.c", "0.0");
err += check_key(qh, "gen.a", "0.0");
err += check_key(qh, "gen.b", "0.0");
err += check_key(qh, "gen.c", "0.0");
err += check_key(qh, "obs.a", "0.0");
err += check_key(qh, "obs.b", "0.0");
err += check_key(qh, "obs.c", "0.0");
err += check_key(qh, "tpl.a", "0.0");
err += check_key(qh, "tpl.b", "0.0");
err += check_key(qh, "tpl.c", "0.0");
err += check_key(qh, "tel.a", "0.0");
err += check_key(qh, "tel.b", "0.0");
err += check_key(qh, "tel.c", "0.0");
err += check_key(qh, "log.a", "0.0");
err += check_key(qh, "log.b", "0.0");
err += check_key(qh, "log.c", "0.0");
err += check_key(qh, "null.a", "0.0");
err += check_key(qh, "null.b", "0.0");
err += check_key(qh, "null.c", "0.0");
say("removing keys");
qfits_header_del(qh, "PRO.A");
qfits_header_del(qh, "pro.b");
qfits_header_del(qh, "HIERARCH ESO PRO C");
if (qfits_header_getstr(qh, "HIERARCH ESO PRO A")!=NULL)
err ++ ;
if (qfits_header_getstr(qh, "PRO.B")!=NULL)
err ++ ;
if (qfits_header_getstr(qh, "pro.c")!=NULL)
err ++ ;
say("modifying keys");
qfits_header_destroy(qh);
return err ;
}
int test_qfitsheader_browse(void)
{
qfits_header * qh ;
char key[80], val[80], com[80] ;
int i ;
int err ;
say("-----> Header browsing test");
/* Read header from source */
say("reading header from file");
qh = qfits_header_read(QFITSTESTFILENAME);
if (qh==NULL) {
fail("cannot read test file");
return 1 ;
}
err=0 ;
for (i=0 ; i<qh->n ; i++) {
if (qfits_header_getitem(qh, i, key, val, com, NULL)!=0) {
fail("cannot read header item");
err++ ;
}
}
qfits_header_destroy(qh);
return err ;
}
int test_qfitspix_dump(void)
{
qfitsdumper qd ;
FILE * testfile ;
byte testbuf[96] ;
int i ;
int err ;
/* Test various dumps to check pixel conversion works fine */
say("-----> Pixel dumping tests: float pix");
qd.filename = BINDUMPNAME;
qd.npix = 12 ;
/* Test float dump */
qd.ptype = PTYPE_FLOAT ;
qd.fbuf = float_array_orig ;
qd.out_ptype= -32 ;
say("dumping dat file");
remove(BINDUMPNAME);
if (qfits_pixdump(&qd)!=0) {
fail("cannot save test buffer");
return 1 ;
}
say("opening dat file");
if ((testfile=fopen(BINDUMPNAME, "r"))==NULL) {
fail("cannot open test file");
return 1 ;
}
say("reading dat file");
fread(testbuf, 4, 12, testfile);
fclose(testfile);
remove(BINDUMPNAME);
/* Compare arrays */
say("comparing arrays");
err=0 ;
for (i=0 ; i<48 ; i++) {
if (testbuf[i]!=float_array_byte[i]) {
printf("failed: expected %02x got %02x\n",
float_array_byte[i],
testbuf[i]);
err++ ;
}
}
/* Test int dump */
say("-----> Pixel dumping tests: int pix");
qd.ptype = PTYPE_INT ;
qd.ibuf = int_array_orig ;
qd.out_ptype = 32 ;
say("dumping dat file");
if (qfits_pixdump(&qd)!=0) {
fail("cannot save test buffer");
return 1 ;
}
say("opening dat file");
if ((testfile=fopen(BINDUMPNAME, "r"))==NULL) {
fail("cannot open test file");
return 1 ;
}
say("reading dat file");
fread(testbuf, 4, 12, testfile);
fclose(testfile);
remove(BINDUMPNAME);
/* Compare arrays */
say("comparing arrays");
err=0 ;
for (i=0 ; i<48 ; i++) {
if (testbuf[i]!=int_array_byte[i]) {
printf("failed: expected %02x got %02x\n",
int_array_byte[i],
testbuf[i]);
err++ ;
}
}
remove(BINDUMPNAME);
/* Test double dump */
say("-----> Pixel dumping tests: double pix");
qd.ptype = PTYPE_DOUBLE ;
qd.dbuf = double_array_orig ;
qd.out_ptype = -64 ;
say("dumping dat file");
if (qfits_pixdump(&qd)!=0) {
fail("cannot save test buffer");
return 1 ;
}
say("opening dat file");
if ((testfile=fopen(BINDUMPNAME, "r"))==NULL) {
fail("cannot open test file");
return 1 ;
}
say("reading dat file");
fread(testbuf, 8, 12, testfile);
fclose(testfile);
remove(BINDUMPNAME);
/* Compare arrays */
say("comparing arrays");
err=0 ;
for (i=0 ; i<96 ; i++) {
if (testbuf[i]!=double_array_byte[i]) {
printf("failed: expected %02x got %02x\n",
double_array_byte[i],
testbuf[i]);
err++ ;
}
}
remove(BINDUMPNAME);
return err ; ;
}
int test_qfitsdata_dump(void)
{
qfitsdumper qd ;
int i ;
say("-----> Data dumping test");
/* Allocate data segment and save it to FITS file */
qd.fbuf = malloc(11 * 10 * sizeof(float));
for (i=0 ; i<(11*10) ; i++) {
qd.fbuf[i]=i*0.2 ;
}
qd.filename = QFITSTESTFILENAME ;
qd.npix = 11 * 10 ;
qd.ptype = PTYPE_FLOAT ;
qd.out_ptype = -32 ;
if (qfits_pixdump(&qd)!=0) {
fail("cannot save data to test file");
free(qd.fbuf);
return 1 ;
}
free(qd.fbuf);
/* Zero-pad the output file */
qfits_zeropad(QFITSTESTFILENAME);
return 0 ;
}
int test_qfitsdata_load(void)
{
qfitsloader ql ;
int i ;
int err ;
float diff ;
err=0 ;
say("-----> Data loading test");
ql.filename = QFITSTESTFILENAME ;
ql.xtnum = 0 ;
ql.pnum = 0 ;
ql.ptype = PTYPE_FLOAT ;
say("initializing loader");
if (qfitsloader_init(&ql)!=0) {
fail("cannot initialize loader on test file");
return 1 ;
}
if (ql.lx != 11) {
fail("wrong size in X");
err++ ;
}
if (ql.ly != 10) {
fail("wrong size in Y");
err++ ;
}
say("loading pixel buffer");
if (qfits_loadpix(&ql)!=0) {
fail("cannot load data from test file");
return 1 ;
}
for (i=0 ; i<(11*10) ; i++) {
diff = ql.fbuf[i] - (float)i * 0.2 ;
if (diff>1e-4) {
fail("diff in pix value");
err++ ;
}
}
free(ql.fbuf);
return err ;
}
int test_qfits_extdump(void)
{
qfits_header * qh ;
qfitsdumper qd ;
FILE * out ;
char * sig ;
say("-----> File with multiple extensions");
/* Create minimal FITS header for main */
say("creating default header");
qh = qfits_header_default() ;
if (qh==NULL) {
fail("cannot create default header");
return 1 ;
}
qfits_header_add(qh, "BITPIX", "8", "no data in main section", NULL);
qfits_header_add(qh, "NAXIS", "0", "no data in main section", NULL);
qfits_header_add(qh, "EXTEND", "T", "Extensions are present", NULL);
say("dumping header to test file");
out = fopen(QFITSTESTFILENAME, "w");
if (out==NULL) {
fail("cannot create test file");
qfits_header_destroy(qh);
return 1 ;
}
qfits_header_dump(qh, out);
fclose(out);
qfits_header_destroy(qh);
say("creating first extension with float pixels");
qh = qfits_header_new();
if (qh==NULL) {
fail("cannot create extension header 1");
return 1 ;
}
qfits_header_append(qh, "XTENSION", "T", "Ext 1", NULL);
qfits_header_append(qh, "BITPIX", "-32", "bpp", NULL);
qfits_header_append(qh, "NAXIS", "2", "axes", NULL);
qfits_header_append(qh, "NAXIS1", "6", "size in x", NULL);
qfits_header_append(qh, "NAXIS2", "2", "size in y", NULL);
qfits_header_append(qh, "END", NULL, NULL, NULL);
say("dumping ext header 1 to test file");
out = fopen(QFITSTESTFILENAME, "a");
if (out==NULL) {
fail("cannot append to test file");
qfits_header_destroy(qh);
return 1 ;
}
qfits_header_dump(qh, out);
fclose(out);
qfits_header_destroy(qh);
say("dumping float array");
qd.filename = QFITSTESTFILENAME ;
qd.npix = 12 ;
qd.ptype = PTYPE_FLOAT ;
qd.out_ptype = -32 ;
qd.fbuf = float_array_orig ;
if (qfits_pixdump(&qd)!=0) {
fail("cannot save data to test file");
free(qd.fbuf);
return 1 ;
}
/* Zero-pad the output file */
qfits_zeropad(QFITSTESTFILENAME);
say("creating second extension with int pixels");
qh = qfits_header_new();
if (qh==NULL) {
fail("cannot create extension header 1");
return 1 ;
}
qfits_header_append(qh, "XTENSION", "T", "Ext 1", NULL);
qfits_header_append(qh, "BITPIX", "32", "bpp", NULL);
qfits_header_append(qh, "NAXIS", "2", "axes", NULL);
qfits_header_append(qh, "NAXIS1", "6", "size in x", NULL);
qfits_header_append(qh, "NAXIS2", "2", "size in y", NULL);
qfits_header_append(qh, "END", NULL, NULL, NULL);
say("dumping ext header 2 to test file");
out = fopen(QFITSTESTFILENAME, "a");
if (out==NULL) {
fail("cannot append to test file");
qfits_header_destroy(qh);
return 1 ;
}
qfits_header_dump(qh, out);
fclose(out);
qfits_header_destroy(qh);
say("dumping int array");
qd.filename = QFITSTESTFILENAME ;
qd.npix = 12 ;
qd.ptype = PTYPE_INT ;
qd.out_ptype = 32 ;
qd.ibuf = int_array_orig ;
if (qfits_pixdump(&qd)!=0) {
fail("cannot save data to test file");
free(qd.fbuf);
return 1 ;
}
/* Zero-pad the output file */
qfits_zeropad(QFITSTESTFILENAME);
say("creating third extension with double pixels");
qh = qfits_header_new();
if (qh==NULL) {
fail("cannot create extension header 3");
return 1 ;
}
qfits_header_append(qh, "XTENSION", "T", "Ext 1", NULL);
qfits_header_append(qh, "BITPIX", "-64", "bpp", NULL);
qfits_header_append(qh, "NAXIS", "2", "axes", NULL);
qfits_header_append(qh, "NAXIS1", "6", "size in x", NULL);
qfits_header_append(qh, "NAXIS2", "2", "size in y", NULL);
qfits_header_append(qh, "END", NULL, NULL, NULL);
say("dumping ext header 3 to test file");
out = fopen(QFITSTESTFILENAME, "a");
if (out==NULL) {
fail("cannot append to test file");
qfits_header_destroy(qh);
return 1 ;
}
qfits_header_dump(qh, out);
fclose(out);
qfits_header_destroy(qh);
say("dumping double array");
qd.filename = QFITSTESTFILENAME ;
qd.npix = 12 ;
qd.ptype = PTYPE_DOUBLE ;
qd.out_ptype = -64 ;
qd.dbuf = double_array_orig ;
if (qfits_pixdump(&qd)!=0) {
fail("cannot save data to test file");
free(qd.fbuf);
return 1 ;
}
/* Zero-pad the output file */
qfits_zeropad(QFITSTESTFILENAME);
/* Get MD5 for the test file */
sig = qfits_datamd5(QFITSTESTFILENAME);
if (strcmp(sig, REFSIG)) {
fail("test file signature does not match");
return 1 ;
}
say("file DATAMD5 signature is Ok");
return 0 ;
}
int main(int argc, char * argv[])
{
int err ;
err=0 ;
/* Header tests */
err += test_qfitsheader_create();
err += test_qfitsheader_read();
err += test_qfitsheader_browse();
/* Data tests */
err += test_qfitsdata_dump();
err += test_qfitsdata_load();
err += test_qfitspix_dump() ;
/* Extension tests */
err += test_qfits_extdump();
remove(QFITSTESTFILENAME);
fprintf(stderr, "total error(s): %d\n", err);
return err ;
}