LAL 7.7.0.1-678514e
StreamSeriesOutput.c
Go to the documentation of this file.
1/**
2 * \defgroup StreamSeriesOutput_c Module StreamSeriesOutput.c
3 * \ingroup StreamOutput_h
4 * \author Creighton, T. D.
5 *
6 * \brief Writes a time or frequency series to an output stream.
7 *
8 * ### Prototypes ###
9 *
10 * \code
11 * void
12 * LAL<typecode>WriteTSeries( LALStatus *stat,
13 * FILE *stream,
14 * <datatype>TimeSeries *series )
15 *
16 * void
17 * LAL<typecode>WriteTVectorSeries( LALStatus *stat,
18 * FILE *stream,
19 * <datatype>TimeVectorSeries *series )
20 *
21 * void
22 * LAL<typecode>WriteTArraySeries( LALStatus *stat,
23 * FILE *stream,
24 * <datatype>TimeArraySeries *series )
25 *
26 * void
27 * LAL<typecode>WriteFSeries( LALStatus *stat,
28 * FILE *stream,
29 * <datatype>FrequencySeries *series )
30 * \endcode
31 *
32 * ### Description ###
33 *
34 * These routines write the data and metadata in a time or frequency
35 * series <tt>*series</tt> to an output stream <tt>*stream</tt> in a standard
36 * format, described below. It returns an error if any attempt to write
37 * to the stream failed; <tt>*stream</tt> may then be left in a
38 * partially-written state.
39 *
40 * For each of these prototype templates there are in fact 10 separate
41 * routines corresponding to all the atomic datatypes <tt><datatype></tt>
42 * (except \c CHAR) referred to by <tt><typecode></tt>:
43 *
44 * <table><tr><th><typecode></th><th><datatype></th><th><typecode></th><th><datatype></th></tr>
45 * <tr><td> I2</td><td> INT2</td><td> U2</td><td> UINT2</td></tr>
46 * <tr><td> I4</td><td> INT4</td><td> U4</td><td> UINT4</td></tr>
47 * <tr><td> I8</td><td> INT8</td><td> U8</td><td> UINT8</td></tr>
48 * <tr><td> S</td><td> REAL4</td><td> C</td><td> COMPLEX8</td></tr>
49 * <tr><td> D</td><td> REAL8</td><td> Z</td><td> COMPLEX16</td></tr>
50 * </table>
51 *
52 * \par Format for <tt>*stream</tt>:
53 * The data written to the
54 * output stream will be formatted in a manner consistent with the input
55 * routines in \ref StreamSeriesInput.c. That is, it will begin with a
56 * metadata header, consisting of multiple lines of the form:
57 *
58 * \code
59 * # fieldname=value
60 * \endcode
61 *
62 * where \e fieldname is the name of a field in
63 * <tt>*series</tt> and \e value is the value of that metadata field,
64 * in some standard format (below). The following metadata fields will
65 * be written, one per line, based on the type of <tt>*series</tt>:
66 *
67 * <dl>
68 * <dt><tt><datatype>TimeSeries</tt>:</dt><dd> \c datatype, \c name,\c epoch, \c deltaT, \c f0, \c sampleUnits,\c length</dd>
69 * <dt><tt><datatype>TimeVectorSeries</tt>:</dt><dd> \c datatype,\c name, \c epoch, \c deltaT, \c f0,\c sampleUnits, \c length, \c vectorLength</dd>
70 * <dt><tt><datatype>TimeArraySeries</tt>:</dt><dd> \c datatype,\c name, \c epoch, \c deltaT, \c f0,\c sampleUnits, \c length, \c dimLength, \c arrayDim</dd>
71 * <dt><tt><datatype>FrequencySeries</tt>:</dt><dd> \c datatype,\c name, \c epoch, \c deltaT, \c f0, \c deltaF,\c sampleUnits, \c length</dd>
72 * </dl>
73 *
74 * After all metadata have been written, the contents of
75 * <tt>series->data->data</tt> will be written in standard integer or
76 * floating-point notation, according to <tt><datatype></tt>: integers will
77 * be written to full precision, while floating-point numbers will be
78 * written in exponential notation with sufficient digits to ensure that
79 * they represent a unique binary floating-point number under the IEEE
80 * Standard 754 (this means 9 digits for \c REAL4s and 17 digits for
81 * \c REAL8s). Complex datatypes are represented by pairs of
82 * floating-point numbers representing alternately the real and imaginary
83 * parts.
84 *
85 * The body of the file will be formatted with newlines <tt>'\\n'</tt>
86 * separating individual base, complex, vector, or array valued elements
87 * of the sequence <tt>series->data</tt>. Within each element, integer or
88 * floating-point components will be separated by single <tt>' '</tt>
89 * characters. Thus the value of <tt>series->data->length</tt> will always
90 * equal the number of lines following the metadata header.
91 *
92 * \par Format for metadata fields:
93 * Here we summarize briefly the
94 * format for the individual field values in the metadata header.
95 *
96 * <dl>
97 * <dt>datatype:</dt><dd> \e value is a string (\e not
98 * surrounded by quotes) corresponding to the type of <tt>*series</tt>;
99 * e.g.\ COMPLEX8FrequencySeries.</dd>
100 *
101 * <dt>name:</dt><dd> \e value is a string surrounded by double-quotes
102 * representing <tt>series->name</tt>. Standard C-language string
103 * literal notation is used: printable characters are written directly
104 * except for double-quotes and <tt>\</tt> (rendered as <tt>\</tt>),
105 * characters with special C escape sequences are written
106 * as those sequences (e.g.\ <tt>\\t</tt> for tab and <tt>\\n</tt> for
107 * newline), and all other character bytes are written as three-digit
108 * octal codes <tt>\</tt>ooo. Writing stops at the first null byte
109 * <tt>\\0</tt>.</dd>
110 *
111 * <dt>epoch:</dt><dd> \e value is a single \c INT8 number
112 * representing <tt>series->epoch</tt> in GPS nanoseconds.</dd>
113 *
114 * <dt>deltaT</dt><dd> (any time series): \e value is a single
115 * \c REAL8 number representing <tt>series->deltaT</tt>.</dd>
116 *
117 * <dt>f0:</dt><dd> \e value is a single \c REAL8 number
118 * representing <tt>series->f0</tt>.</dd>
119 *
120 * <dt>deltaF</dt><dd> (\c FrequencySeries only): \e value
121 * is a single \c REAL8 number representing <tt>series->deltaF</tt>.</dd>
122 *
123 * <dt>sampleUnits:</dt><dd> \e value is string surrounded by
124 * double-quotes; inside the quotes is a unit string corresponding to
125 * <tt>series->sampleUnits</tt> as converted by the routine
126 * XLALUnitAsString().</dd>
127 *
128 * <dt>length:</dt><dd> \e value is a single \c UINT4
129 * representing <tt>series->data->length</tt>.</dd>
130 *
131 * <dt>vectorLength</dt><dd> (\c TimeVectorSeries only):
132 * \e value is a single \c UINT4 representing
133 * <tt>series->data->vectorLength</tt>.</dd>
134 *
135 * <dt>dimLength</dt><dd> (\c TimeArraySeries only):
136 * \e value consists of a sequence of \c UINT4s separated by
137 * single <tt>' '</tt> characters, representing the components of
138 * <tt>series->data->dimLength->data</tt>. The value of
139 * <tt>series->data->dimLength->length</tt> must be inferred from the
140 * number of components; it is not given as separate metadata.</dd>
141 *
142 * <dt>arrayDim</dt><dd> (\c TimeArraySeries only): \e value
143 * is a single \c UINT4 representing <tt>series->data->arrayDim</tt>.
144 * If the array sequence was properly constructed, this will equal the
145 * product of the components of \c dimLength, above.</dd>
146 * </dl>
147 *
148 */
149
150#include <complex.h>
151#include <stdio.h>
152#include <ctype.h>
153#include <lal/LALStdlib.h>
154#include <lal/Units.h>
155#include <lal/AVFactories.h>
156#include <lal/StringInput.h>
157#include <lal/StreamOutput.h>
158#include <lal/Date.h>
159
160/* Define a function for printing a string as a literal. */
161static int
162LALWriteLiteral( FILE *stream, const CHAR *string )
163{
164 CHAR c; /* Current character being considered. */
165
166 /* Open literal and start parsing string. */
167 if ( putc( '"', stream ) == EOF ) return 1;
168 while ( ( c = *(string++) ) != '\0' ) {
169
170 /* Characters with named escape sequences. */
171 if ( c == '\a' ) {
172 if ( fputs( "\\a", stream ) == EOF ) return 1;
173 } else if ( c == '\b' ) {
174 if ( fputs( "\\b", stream ) == EOF ) return 1;
175 } else if ( c == '\f' ) {
176 if ( fputs( "\\f", stream ) == EOF ) return 1;
177 } else if ( c == '\n' ) {
178 if ( fputs( "\\n", stream ) == EOF ) return 1;
179 } else if ( c == '\r' ) {
180 if ( fputs( "\\r", stream ) == EOF ) return 1;
181 } else if ( c == '\t' ) {
182 if ( fputs( "\\t", stream ) == EOF ) return 1;
183 } else if ( c == '\v' ) {
184 if ( fputs( "\\v", stream ) == EOF ) return 1;
185 } else if ( c == '"' ) {
186 if ( fputs( "\\\"", stream ) == EOF ) return 1;
187 } else if ( c == '\\' ) {
188 if ( fputs( "\\\\", stream ) == EOF ) return 1;
189 }
190
191 /* Printable characters. */
192 else if ( isprint( c ) ) {
193 if ( putc( c, stream ) == EOF ) return 1;
194 }
195
196 /* Other characters are given 3-digit octal escape sequences. */
197 else {
198 if ( fprintf( stream, "\\%03o", (UCHAR)( c ) ) < 0 )
199 return 1;
200 }
201 }
202
203 /* Close literal and exit. */
204 if ( putc( '"', stream ) == EOF ) return 1;
205 return 0;
206}
207
208/* tell GNU C compiler to ignore warnings about the `ll' length modifier */
209#ifdef __GNUC__
210#define fprintf __extension__ fprintf
211#endif
212
213#define TYPECODE Z
214#define TYPE COMPLEX16
215#define FMT "%.16e"
216#define COMPLEX 1
217#include "StreamSeriesOutput_source.c"
218#undef TYPECODE
219#undef TYPE
220#undef FMT
221#undef COMPLEX
222
223#define TYPECODE C
224#define TYPE COMPLEX8
225#define FMT "%.8e"
226#define COMPLEX 1
227#include "StreamSeriesOutput_source.c"
228#undef TYPECODE
229#undef TYPE
230#undef FMT
231#undef COMPLEX
232
233#define TYPECODE D
234#define TYPE REAL8
235#define FMT "%.16e"
236#define COMPLEX 0
237#include "StreamSeriesOutput_source.c"
238#undef TYPECODE
239#undef TYPE
240#undef FMT
241#undef COMPLEX
242
243#define TYPECODE S
244#define TYPE REAL4
245#define FMT "%.8e"
246#define COMPLEX 0
247#include "StreamSeriesOutput_source.c"
248#undef TYPECODE
249#undef TYPE
250#undef FMT
251#undef COMPLEX
252
253#define TYPECODE I2
254#define TYPE INT2
255#define FMT "%"LAL_INT2_FORMAT
256#define COMPLEX 0
257#include "StreamSeriesOutput_source.c"
258#undef TYPECODE
259#undef TYPE
260#undef FMT
261#undef COMPLEX
262
263#define TYPECODE I4
264#define TYPE INT4
265#define FMT "%"LAL_INT4_FORMAT
266#define COMPLEX 0
267#include "StreamSeriesOutput_source.c"
268#undef TYPECODE
269#undef TYPE
270#undef FMT
271#undef COMPLEX
272
273#define TYPECODE I8
274#define TYPE INT8
275#define FMT "%"LAL_INT8_FORMAT
276#define COMPLEX 0
277#include "StreamSeriesOutput_source.c"
278#undef TYPECODE
279#undef TYPE
280#undef FMT
281#undef COMPLEX
282
283#define TYPECODE U2
284#define TYPE UINT2
285#define FMT "%"LAL_UINT2_FORMAT
286#define COMPLEX 0
287#include "StreamSeriesOutput_source.c"
288#undef TYPECODE
289#undef TYPE
290#undef FMT
291#undef COMPLEX
292
293#define TYPECODE U4
294#define TYPE UINT4
295#define FMT "%"LAL_UINT4_FORMAT
296#define COMPLEX 0
297#include "StreamSeriesOutput_source.c"
298#undef TYPECODE
299#undef TYPE
300#undef FMT
301#undef COMPLEX
302
303#define TYPECODE U8
304#define TYPE UINT8
305#define FMT "%"LAL_UINT8_FORMAT
306#define COMPLEX 0
307#include "StreamSeriesOutput_source.c"
308#undef TYPECODE
309#undef TYPE
310#undef FMT
311#undef COMPLEX
static int LALWriteLiteral(FILE *stream, const CHAR *string)
#define fprintf
unsigned char UCHAR
One-byte unsigned integer, see Headers LAL(Atomic)Datatypes.h for more details.
char CHAR
One-byte signed integer, see Headers LAL(Atomic)Datatypes.h for more details.