LAL  7.5.0.1-8083555
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. */
161 static int
162 LALWriteLiteral( 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.