summaryrefslogtreecommitdiff
path: root/src/libical/icalparser.h
blob: 7d3c4dd55efc0d49961f6b63263f62b8163224d1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
/*======================================================================
 FILE: icalparser.h
 CREATOR: eric 20 April 1999

 SPDX-FileCopyrightText: 2000, Eric Busboom <eric@civicknowledge.com>

 SPDX-License-Identifier: LGPL-2.1-only OR MPL-2.0

  The original code is icalparser.h
======================================================================*/

#ifndef ICALPARSER_H
#define ICALPARSER_H

#include "libical_ical_export.h"
#include "icalcomponent.h"

/**
 * @file  icalparser.h
 * @brief Line-oriented parsing.
 *
 * This file provides methods to parse iCalendar-formatted data
 * into the structures provided by this library.
 *
 * @par Usage
 * Create a new parser via icalparser_new_parser(), then add lines one at
 * a time with icalparser_add_line(). icalparser_add_line() will return
 * non-zero when it has finished with a component.
 */

/**
 * @struct icalparser_impl
 * @typedef icalparser
 * @private
 *
 * Implementation of the icalparser struct, which holds the
 * state for the current parsing operation.
 */
typedef struct icalparser_impl icalparser;

/**
 * @enum icalparser_state
 * @typedef icalparser_state
 * @brief Represents the current state of the parser
 */
typedef enum icalparser_state
{
    /** An error occurred while parsing. */
    ICALPARSER_ERROR,

    /** Parsing was successful. */
    ICALPARSER_SUCCESS,

    /** Currently parsing the begin of a component. */
    ICALPARSER_BEGIN_COMP,

    /** Currently parsing the end of the component. */
    ICALPARSER_END_COMP,

    /** Parsing is currently in progress. */
    ICALPARSER_IN_PROGRESS
} icalparser_state;

typedef char *(*icalparser_line_gen_func) (char *s, size_t size, void *d);

/**
 * @brief Creates a new icalparser.
 * @return An icalparser object
 *
 * @par Error handling
 * On error, it returns `NULL` and sets ::icalerrno to
 * ::ICAL_NEWFAILED_ERROR.
 *
 * @par Ownership
 * All icalparser objects created with this function need to be
 * freed using the icalparser_free() function.
 *
 * @par Usage
 * ```c
 * // create new parser
 * icalparser *parser = icalparser_new();
 *
 * // do something with it...
 *
 * // free parser
 * icalparser_free(parser);
 * ```
 */
LIBICAL_ICAL_EXPORT icalparser *icalparser_new(void);

/**
 * @brief Adds a single line to be parsed by the icalparser.
 * @param parser The parser to use
 * @param str A string representing a single line of RFC5545-formatted iCalendar data
 * @return When this was the last line of the component to be parsed,
 *  it returns the icalcomponent, otherwise it returns `NULL`.
 * @sa icalparser_parse()
 *
 * @par Error handling
 * -   If @a parser is `NULL`, it returns `NULL` and sets ::icalerrno to
 *     ::ICAL_BADARG_ERROR.
 * -   If @a line is empty, if returns `NULL`
 * -   If @a line is `NULL`, it returns `NULL` and sets the @a parser's ::icalparser_state to
 *     ::ICALPARSER_ERROR.
 * -   For errors during parsing, the functions can set the ::icalparser_state to
 *     ::ICALPARSER_ERROR and/or return components of the type ICAL_XLICINVALID_COMPONENT,
 *     or components with properties of the type ICAL_XLICERROR_PROPERTY.
 *
 * @par Ownership
 * Ownership of the @a str is transferred to libical upon calling this
 * method. The returned icalcomponent is owned by the caller and needs
 * to be `free()`d with the appropriate method after it's no longer needed.
 *
 * @par Example
 * ```c
 * char* read_stream(char *s, size_t size, void *d)
 * {
       return fgets(s, (int)size, (FILE*)d);
 * }
 *
 * void parse()
 * {
 *     char* line;
 *     FILE* stream;
 *     icalcomponent *component;
 *
 *     icalparser *parser = icalparser_new();
 *     stream = fopen(argv[1],"r");
 *
 *     icalparser_set_gen_data(parser, stream);
 *
 *     do{
 *         // get a single content line
 *         line = icalparser_get_line(parser, read_stream);
 *
 *         // add that line to the parser
 *         c = icalparser_add_line(parser,line);
 *
 *         // once we parsed a component, print it
 *         if (c != 0) {
 *             printf("%s", icalcomponent_as_ical_string(c));
 *             icalcomponent_free(c);
 *         }
 *     } while (line != 0);
 *
 *     icalparser_free(parser);
 * }
 * ```
 */
LIBICAL_ICAL_EXPORT icalcomponent *icalparser_add_line(icalparser *parser, char *str);

/**
 * @brief Cleans out an icalparser and returns whatever it has parsed so far.
 * @param parser The icalparser to clean
 * @return The parsed icalcomponent
 *
 * @par Error handling
 * If @a parser is `NULL`, it returns `NULL` and sets ::icalerrno to
 * ::ICAL_BADARG_ERROR. For parsing errors, it inserts an `X-LIC-ERROR`
 * property into the affected components.
 *
 * @par Ownership
 * The returned icalcomponent is property of the caller and needs to be
 * free'd with icalcomponent_free() after use.
 *
 * This will parse components even if it hasn't encountered a proper
 * `END` tag for it yet and return them, as well as clearing any intermediate
 * state resulting from being in the middle of parsing something so the
 * parser can be used to parse something new.
 */
LIBICAL_ICAL_EXPORT icalcomponent *icalparser_clean(icalparser *parser);

/**
 * @brief Returns current state of the icalparser
 * @param parser The (valid, non-`NULL`) parser object
 * @return The current state of the icalparser, as an ::icalparser_state
 *
 * @par Example
 * ```c
 * icalparser *parser = icalparser_new();
 *
 * // use icalparser...
 *
 * if(icalparser_get_state(parser) == ICALPARSER_ERROR) {
 *     // handle error
 * } else {
 *     // ...
 * }
 * ```
 *
 * icalparser_free(parser);
 */
LIBICAL_ICAL_EXPORT icalparser_state icalparser_get_state(icalparser *parser);

/**
 * @brief Frees an icalparser object.
 * @param parser The icalparser to be freed.
 *
 * @par Example
 * ```c
 * icalparser *parser = icalparser_new();
 *
 * // use parser ...
 *
 * icalparser_free(parser);
 * ```
 */
LIBICAL_ICAL_EXPORT void icalparser_free(icalparser *parser);

/**
 * @brief Message oriented parsing.
 * @param parser The parser to use
 * @param line_gen_func A function that returns one content line per invocation
 * @return The parsed icalcomponent
 * @sa icalparser_parse_string()
 *
 * Reads an icalcomponent using the supplied @a line_gen_func, returning the parsed
 * component (or `NULL` on error).
 *
 * @par Error handling
 * -   If @a parser is `NULL`, it returns `NULL` and sets ::icalerrno to ::ICAL_BADARG_ERROR.
 * -   If data read by @a line_gen_func is empty, if returns `NULL`
 * -   If data read by @a line_gen_func is `NULL`, it returns `NULL`
 *     and sets the @a parser's ::icalparser_state to ::ICALPARSER_ERROR.
 * -   For errors during parsing, the functions can set the ::icalparser_state to
 *     ::ICALPARSER_ERROR and/or return components of the type ICAL_XLICINVALID_COMPONENT,
 *     or components with properties of the type ICAL_XLICERROR_PROPERTY.
 *
 * @par Ownership
 * The returned icalcomponent is owned by the caller of the function, and
 * needs to be `free()`d with the appropriate method when no longer needed.
 *
 * @par Example
 * ```c
 * char* read_stream(char *s, size_t size, void *d)
 * {
       return fgets(s, (int)size, (FILE*)d);
 * }
 *
 * void parse()
 * {
 *     char* line;
 *     FILE* stream;
 *     icalcomponent *component;
 *
 *     icalparser *parser = icalparser_new();
 *     stream = fopen(argv[1],"r");
 *
 *     icalparser_set_gen_data(parser, stream);
 *
 *     // use the parse method to parse the input data
 *     component = icalparser_parse(parser, read_stream);
 *
 *     // once we parsed a component, print it
 *     printf("%s", icalcomponent_as_ical_string(c));
 *     icalcomponent_free(c);
 *
 *     icalparser_free(parser);
 * }
 * ```
 */
LIBICAL_ICAL_EXPORT icalcomponent *icalparser_parse(icalparser *parser,
                                                    icalparser_line_gen_func line_gen_func);

/**
 * @brief Sets the data that icalparser_parse will give to the line_gen_func
 * as the parameter 'd'.
 * @param parser The icalparser this applies to
 * @param data The pointer which will be passed to the line_gen_func as argument `d`
 *
 * If you use any of the icalparser_parser() or icalparser_get_line() functions,
 * the @a line_gen_func that they expect has a third `void *d` argument. This function
 * sets what will be passed to your @a line_gen_function as such argument.
 */
LIBICAL_ICAL_EXPORT void icalparser_set_gen_data(icalparser *parser, void *data);

/**
 * @brief Parses a string and returns the parsed icalcomponent.
 * @param str The iCal formatted data to be parsed
 * @return An icalcomponent representing the iCalendar
 *
 * @par Error handling
 * On error, returns `NULL` and sets ::icalerrno
 *
 * @par Ownership
 * The returned icalcomponent is owned by the caller of the function, and
 * needs to be free'd with the appropriate functions after use.
 *
 * @par Example
 * ```c
 * char *ical_string;
 *
 * // parse ical_string
 * icalcomponent *component = icalparser_parse_string(ical_string);
 *
 * if(!icalerrno || component == NULL) {
 *     // use component ...
 * }
 *
 * // release component
 * icalcomponent_free(component);
 * ```
 */
LIBICAL_ICAL_EXPORT icalcomponent *icalparser_parse_string(const char *str);

/***********************************************************************
 * Parser support functions
 ***********************************************************************/

/**
 * @brief Given a line generator function, returns a single iCal content line.
 * @return A pointer to a single line of data or `NULL` if it reached
 *  end of file reading from the @a line_gen_func. Note that the pointer
 *  returned is owned by libical and must not be `free()`d by the user.
 * @param parser The parser object to use
 * @param line_gen_func The function to use for reading data
 *
 * This function uses the supplied @a line_gen_func to read data in,
 * until it has read a full line, and returns the full line.
 * It includes any continuation lines, which start with a space after a newline.
 * To supply arbitrary data (as the parameter @a d) to your @a line_gen_func,
 * call icalparser_set_gen_data().
 */
LIBICAL_ICAL_EXPORT char *icalparser_get_line(icalparser *parser,
                                              icalparser_line_gen_func line_gen_func);

LIBICAL_ICAL_EXPORT char *icalparser_string_line_generator(char *out, size_t buf_size, void *d);

#endif /* !ICALPARSE_H */