CARMA C++
input.h
1 #ifndef input_h
2 #define input_h
3 
4 #include <stdarg.h>
5 #include <stdio.h> /* (FILE *) */
6 #include "carma/szaarrayutils/freelist.h"
7 
8 /* Declare the tag for a generic input stream. */
9 
10 typedef struct InputStream InputStream;
11 
12 /* Declare the tag for a generic input source. */
13 
14 typedef struct InputSource InputSource;
15 
16 /* List iterator-specific method function declarations */
17 
18 /*
19  * Read a single character from an input source and place it in
20  * InputSource::nextc.
21  *
22  * Input:
23  * source InputSource * The input source to read from.
24  * Output:
25  * return int 0 - OK.
26  * 1 - EOF reached.
27  */
28 #define INPUT_READ_FN(fn) int (fn)(InputSource *source)
29 
30 /*
31  * Delete a source context (as recorded in InputSource::data).
32  *
33  * Input:
34  * data void * The context data to be deleted.
35  * Output:
36  * return void * The deleted context data (always NULL).
37  */
38 #define INPUT_DEL_FN(fn) void *(fn)(void *data)
39 
40 /*
41  * Perform the equivalent of clearerr() on a source.
42  *
43  * Input:
44  * source InputSource * The input source to be reset.
45  * Output:
46  * return int 0 - OK.
47  * 1 - Couldn't clear error status.
48  */
49 #define INPUT_CLR_FN(fn) int (fn)(InputSource *source)
50 
51 /*
52  * Report the source and position of the stream to stderr in a form
53  * that is suitable to be used as the prefix of an error message.
54  *
55  * Input:
56  * source InputSource * The input source to describe.
57  * Output:
58  * return int 0 - OK.
59  * 1 - Error.
60  */
61 #define INPUT_ERR_FN(fn) int (fn)(InputSource *source)
62 
63 /* Set the maximum length of any input token */
64 
65 enum {INPUT_WORKLEN=10240};
66 
67 /* Set the length of the error-message buffer */
68 
69 enum {INPUT_ERR_LEN=81};
70 
71 /* Define the distinguishing members of a specific input-stream */
72 
73 struct InputSource {
74  INPUT_READ_FN(*read_fn); /* Function to read one character into nextc */
75  INPUT_CLR_FN(*clr_fn); /* Function to reset the input stream */
76  INPUT_ERR_FN(*err_fn); /* Function that generates an error prefix */
77  INPUT_DEL_FN(*del_fn); /* Iterator destructor */
78  int nextc; /* The next character in the input source */
79  int was_escape; /* True if last character was an unescaped '\' */
80  int escaped; /* The escaped character */
81  void *data; /* Source-specific data */
82  InputSource *next; /* The input source that created this one */
83 };
84 
85 /* Declare a generic input stream container */
86 
87 struct InputStream {
88  InputSource *source; /* The top of a stack of input sources */
89  FreeList *source_mem; /* A free-list of InputSource objects */
90  int nextc; /* The next character in the input stream */
91  int in_string; /* True while reading chars from within a string */
92  char work[INPUT_WORKLEN]; /* Work buffer for decoding lexical components */
93 };
94 
95 /*
96  * Construct an initially closed input-stream, ready to be connected
97  * to an input source with open_InputStream().
98  */
99 InputStream *new_InputStream(void);
100 
101 /*
102  * Declare a generic stream destructor.
103  * Note that this will call close_InputStream() if the stream is
104  * connected to an input source.
105  */
106 InputStream *del_InputStream(InputStream *stream);
107 
108 /*
109  * Connect an input stream to a specific input source. This function
110  * should only be called from type-specific stream open_*()
111  * functions (see below). Note that if another input source is currently
112  * connected, it will be pushed down a stack of input sources, and reading
113  * will resume from it when the end of new input source has been reached.
114  */
115 int open_InputStream(InputStream *stream, void *data,
116  INPUT_READ_FN(*read_fn), INPUT_CLR_FN(*clr_fn),
117  INPUT_ERR_FN(*err_fn), INPUT_DEL_FN(*del_fn));
118 
119 /*
120  * Close all input sources of an input stream. Future reads will return
121  * an error until the stream is successfully re-opened to another input source.
122  */
123 void close_InputStream(InputStream *stream);
124 
125 /*
126  * Declare functions that connect generic input streams to
127  * specific types of input sources.
128  */
129 int open_FileInputStream(InputStream *stream, char *dir, char *name);
130 int open_StringInputStream(InputStream *stream, int copy,char *string);
131 int open_StdioInputStream(InputStream *stream, int do_close, FILE *fp);
132 
133 /*
134  * The following function resets a stream by clearing its error
135  * flags if possible, and reading up to the first character of
136  * the next line. On failure it returns non-zero.
137  */
138 int reset_InputStream(InputStream *stream);
139 
140 /*
141  * The following function reads the next character from the input stream.
142  * In the process it removes escaped newline characters and comments.
143  * The tell argument should be 1 if parse errors are to be reported to
144  * stderr.
145  */
146 int read_InputStream(InputStream *stream, int tell);
147 
148 /*
149  * Canned lexical input functions.
150  */
151 int input_skip_to_eol(InputStream *stream, int tell);
152 int input_skip_past_eol(InputStream *stream, int tell);
153 int input_skip_space(InputStream *stream, int tell, int advance);
154 int input_skip_white(InputStream *stream, int tell, int advance);
155 
156 /*
157  * Read an ASCII keyword from an input stream. Keywords must commence
158  * with an alphabetical character continue with alphanumeric
159  * and underscore characters. The output keyword will be left in
160  * stream->work[], where it will have been converted to lower case
161  * if the fold argument is true.
162  */
163 int input_keyword(InputStream *stream, int tell, int fold);
164 int inputEnumKeyword(InputStream *stream, int tell, int fold);
165 int input_regexp_keyword(InputStream *stream, int tell, int fold);
166 int input_board_regexp_keyword(InputStream *stream, int tell, int fold);
167 
168 /*
169  * Read a string that is enclosed in double quotes. All C-style
170  * escape sequences (eg. \n) are recognized. The string will be
171  * left in stream->work[].
172  */
173 int input_quoted_string(InputStream *stream, int tell);
174 
175 /*
176  * The following macro defines the prototype of functions like
177  * isspace(), to be used by input_literal() to identify characters
178  * to include in the string.
179  */
180 #define IS_LITERAL_FN(fn) int (fn)(int c)
181 
182 /*
183  * Read an unquoted string. The chararacters listed in opn[] and cls[]
184  * are treated as open and close parentheses. The string will be
185  * terminated when the provided is_literal() function returns 0
186  * outside of sub-strings and unmatched parentheses. The only
187  * exception to this is if the terminating character is a newline
188  * character and this character was preceded (ignoring intervening
189  * spaces) by one of the characters in nl_escapes[]. The string will
190  * be left in stream->work[]. The terminating character will be left
191  * in the stream.
192  */
193 int input_literal(InputStream *stream, int tell, char *opn, char *cls,
194  IS_LITERAL_FN(*is_literal), char *nl_escapes);
195 
196 /*
197  * Read an ASCII word from an input stream. A word is defined as a string
198  * of printable characters excluding white-space. If fold is true, fold
199  * upper case characters to lower case. The string will be left in
200  * stream->work[].
201  */
202 int input_word(InputStream *stream, int tell, int fold);
203 
204 /*
205  * Read a signed integer. If anybase is true, interpret a number
206  * that starts with a zero as octal, one that starts with 0x as
207  * hexadecimal and one that starts with 0b as binary. Otherwise only
208  * accept base 10 numbers.
209  */
210 int input_long(InputStream *stream, int tell, int anybase, long *lval);
211 
212 /*
213  * Read an unsigned integer. If anybase is true, interpret a number
214  * that starts with a zero as octal, one that starts with 0x as
215  * hexadecimal and one that starts with 0b as binary. Otherwise only
216  * accept base 10 numbers.
217  */
218 int input_ulong(InputStream *stream, int tell, int anybase, unsigned long *ulval);
219 
220 /*
221  * Read a double precision number.
222  */
223 int input_double(InputStream *stream, int tell, double *dval);
224 
225 typedef struct {
226  enum {
227  NUM_DOUBLE, /* Number was written as an int with no exponent */
228  NUM_INT /* Number was written as floating point and/or with exponent*/
229  } type;
230  int sign; /* Sign of number as -1 or 1 */
231  union {
232  double dval; /* Use if type==NUM_DOUBLE */
233  int ival; /* Use if type==NUM_INT */
234  } value;
235 } Number;
236 
237 int input_number(InputStream *stream, int tell, int sign_ok, Number *number);
238 
239 /*
240  * Read one or more sexagesimal components separated by ':' characters.
241  * The first number can have any integral value and can be signed. The
242  * last number can have a fractional part. The intervening parts must
243  * be integers between 0 and 59. The resulting number has the dimensions
244  * of the first number. Thus 23:30 can also be entered as 23.5.
245  */
246 int input_sexagesimal(InputStream *stream, int tell, double *result);
247 
248 /*
249  * Read a date like 23-JAN-1997.
250  */
251 int input_date(InputStream *stream, int tell, int *year, int *month, int *day);
252 
253 /*
254  * Read a time from an input stream. The following are valid time
255  * specifications along with their interpretations:
256  *
257  * 23:34:04.5 -> 23:34:04.5
258  * 23:34:4.5 -> 23:34:04.5
259  * 23:34:10 -> 23:34:10
260  * 23:34 -> 23:34:00
261  * 23 -> 23:00:00
262  */
263 int input_time(InputStream *stream, int tell, int *hour, int *min, double *sec);
264 
265 /*
266  * Read a date and optional time. The following are valid specifications
267  * and their interpretations.
268  *
269  * 12-DEC-1998 -> 12-DEC-1998 00:00:00.0
270  * 12-DEC-1998:13 -> 12-DEC-1998 13:00:00.0
271  * 12-DEC-1998:13:34 -> 12-DEC-1998 13:34:00.0
272  * 12-DEC-1998:13:34:23 -> 12-DEC-1998 13:34:23.0
273  * 12-DEC-1998:13:34:23.5 -> 12-DEC-1998 13:34:23.5
274  *
275  * The following are also valid if nospace!=0.
276  *
277  * 12-DEC-1998 13 -> 12-DEC-1998 13:00:00.0
278  * 12-DEC-1998 13:34 -> 12-DEC-1998 13:34:00.0
279  * 12-DEC-1998 13:34:23 -> 12-DEC-1998 13:34:23.0
280  * 12-DEC-1998 13:34:23.5 -> 12-DEC-1998 13:34:23.5
281  */
282 int input_date_and_time(InputStream *stream, int tell, int nospace, int *year,
283  int *month, int *day, int *hour, int *min, double *sec);
284 
285 /*
286  * Read a time interval written like the following example:
287  *
288  * 23d:14h:16m:2.32s (ie. 23 days, 14 hours, 16 minutes, 2.32 seconds)
289  *
290  * Any of the components can be omitted, but each trailing colon is taken
291  * as evidence that another component follows. The result is returned in
292  * seconds, via the *interval argument.
293  */
294 int input_interval(InputStream *stream, int tell, double *interval);
295 
296 /*-----------------------------------------------------------------------
297  * Error management conventions and facilities.
298  *
299  * When the above input_whatever() functions detect an error they
300  * optionally report the source of the error to stderr and then return
301  * non-zero to indicate that an error occured. The input_error()
302  * function is designed with this in mind. It is a printf-style
303  * function takes an argument that says whether to report the error
304  * message or to discard it, and that returns 1 for use as a non-zero
305  * error code. One statement can then be used both to conditionally
306  * report the error and to return from the calling function with an
307  * error code. For example:
308  *
309  * int input_ulong(InputStream *stream, int tell, unsigned long *ul)
310  * {
311  * if(!isdigit(stream->nextc))
312  * return input_error(stream, tell, "Not an unsigned integer");
313  * ...
314  * }
315  *
316  * Where possible input_error() reports the location of the errant input.
317  * For example, if the input stream is connected to a file then it reports
318  * the file name and line number at which the error was encountered.
319  *
320  * Note that if an input_xxx() function itself calls an input_yyy()
321  * function then it should set the tell argument of input_yyy() to 0
322  * if it intends to report the error itself.
323  */
324 
325 /*
326  * When this header is compiled with gcc, the following macro
327  * is expanded at the end of the prototype of input_error(). The
328  * result informs gcc that the format and trailing arguments should
329  * be checked as though the function were printf().
330  */
331 #ifdef __GNUC__
332 #define CHECK_FORMAT __attribute__ ((format (printf, 3, 4)))
333 #else
334 #define CHECK_FORMAT
335 #endif
336 
337 /*
338  * An fprintf-like function for optionally reporting error messages.
339  * If 'tell' is non-zero the message is reported to stderr. Otherwise
340  * the message is discarded. The input_error() function always returns
341  * 1, for use by calling functions as an error-return code (see above).
342  */
343 int input_error(InputStream *stream, int tell, const char *fmt, ...) CHECK_FORMAT;
344 #undef CHECK_FORMAT
345 void input_verror(InputStream *stream, const char *fmt, va_list args);
346 
347 IS_LITERAL_FN(isHostName);
348 
349 #endif