]> begriffs open source - sa-parse/blob - src/ical_parser.c
ical parser
[sa-parse] / src / ical_parser.c
1 #include "ical_parser.h"
2 #include "ical.tab.h"
3
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <stdbool.h>
8
9 /* Forward declaration of flex scanner functions */
10 int icallex_init(void **scanner);
11 int icallex_destroy(void *scanner);
12 void icalset_in(FILE *input_file, void *scanner);
13 int icalparse(void *parser_state, void *scanner);
14
15 /* Destructor function declarations for vector cleanup */
16 static void ical_property_destructor(void *property_ptr, void *aux);
17 static void ical_component_destructor(void *component_ptr, void *aux);
18
19 typedef struct {
20     void *scanner;
21     FILE *string_input;
22 } ical_scanner_state_t;
23
24 /* Buffer for input string parsing */
25 typedef struct {
26     const char *data;
27     size_t size;
28     size_t pos;
29 } string_buffer_t;
30
31 /* Parser state structure */
32 struct ical_parser {
33     ical_component_t *result;
34     char *error_message;
35     int error_line;
36     int error_column;
37     bool has_error;
38     string_buffer_t *string_buffer;
39 };
40
41 /* Custom input function for string parsing */
42 static int string_input_function(char *buf, int max_size, void *user_data)
43 {
44     string_buffer_t *buffer = (string_buffer_t*)user_data;
45     
46     if (buffer->pos >= buffer->size) {
47         return 0;  /* EOF */
48     }
49     
50     size_t remaining = buffer->size - buffer->pos;
51     size_t to_copy = (remaining < (size_t)max_size) ? remaining : (size_t)max_size;
52     
53     memcpy(buf, buffer->data + buffer->pos, to_copy);
54     buffer->pos += to_copy;
55     
56     return (int)to_copy;
57 }
58
59 ical_parser_t *ical_parser_create(void)
60 {
61     ical_parser_t *parser = calloc(1, sizeof(ical_parser_t));
62     if (!parser) return NULL;
63     
64     return parser;
65 }
66
67 void ical_parser_destroy(ical_parser_t *parser)
68 {
69     if (!parser) return;
70     
71     if (parser->result) {
72         ical_component_free(parser->result);
73     }
74     
75     free(parser->error_message);
76     free(parser->string_buffer);
77     free(parser);
78 }
79
80 ical_error_t ical_parser_parse_string(ical_parser_t *parser, const char *input, ical_component_t **calendar)
81 {
82     if (!parser || !input || !calendar) {
83         return ICAL_ERROR_INVALID_PARAMETER;
84     }
85     
86     *calendar = NULL;
87     
88     /* Clear previous state */
89     if (parser->result) {
90         ical_component_free(parser->result);
91         parser->result = NULL;
92     }
93     free(parser->error_message);
94     parser->error_message = NULL;
95     parser->has_error = false;
96     
97     /* Set up string buffer */
98     if (!parser->string_buffer) {
99         parser->string_buffer = malloc(sizeof(string_buffer_t));
100         if (!parser->string_buffer) {
101             return ICAL_ERROR_MEMORY;
102         }
103     }
104     
105     parser->string_buffer->data = input;
106     parser->string_buffer->size = strlen(input);
107     parser->string_buffer->pos = 0;
108     
109     /* Initialize scanner */
110     void *scanner;
111     if (icallex_init(&scanner) != 0) {
112         return ICAL_ERROR_MEMORY;
113     }
114     
115     /* Parse the input */
116     int parse_result = icalparse(parser, scanner);
117     
118     /* Clean up scanner */
119     icallex_destroy(scanner);
120     
121     if (parse_result != 0 || parser->has_error) {
122         return ICAL_ERROR_PARSE;
123     }
124     
125     *calendar = parser->result;
126     parser->result = NULL;  /* Transfer ownership */
127     
128     return ICAL_SUCCESS;
129 }
130
131 ical_error_t ical_parser_parse_file(ical_parser_t *parser, FILE *file, ical_component_t **calendar)
132 {
133     if (!parser || !file || !calendar) {
134         return ICAL_ERROR_INVALID_PARAMETER;
135     }
136     
137     *calendar = NULL;
138     
139     /* Clear previous state */
140     if (parser->result) {
141         ical_component_free(parser->result);
142         parser->result = NULL;
143     }
144     free(parser->error_message);
145     parser->error_message = NULL;
146     parser->has_error = false;
147     
148     /* Initialize scanner */
149     void *scanner;
150     if (icallex_init(&scanner) != 0) {
151         return ICAL_ERROR_MEMORY;
152     }
153     
154     /* Set input file */
155     icalset_in(file, scanner);
156     
157     /* Parse the input */
158     int parse_result = icalparse(parser, scanner);
159     
160     /* Clean up scanner */
161     icallex_destroy(scanner);
162     
163     if (parse_result != 0 || parser->has_error) {
164         return ICAL_ERROR_PARSE;
165     }
166     
167     *calendar = parser->result;
168     parser->result = NULL;  /* Transfer ownership */
169     
170     return ICAL_SUCCESS;
171 }
172
173 ical_error_info_t ical_parser_get_error_info(ical_parser_t *parser)
174 {
175     ical_error_info_t info = {0};
176     
177     if (parser && parser->has_error) {
178         info.message = parser->error_message;
179         info.line = parser->error_line;
180         info.column = parser->error_column;
181         info.has_location = (parser->error_line > 0 || parser->error_column > 0);
182     }
183     
184     return info;
185 }
186
187 const char *ical_error_string(ical_error_t error)
188 {
189     switch (error) {
190         case ICAL_SUCCESS:
191             return "Success";
192         case ICAL_ERROR_MEMORY:
193             return "Memory allocation failed";
194         case ICAL_ERROR_PARSE:
195             return "Parse error";
196         case ICAL_ERROR_INVALID_PARAMETER:
197             return "Invalid parameter";
198         case ICAL_ERROR_IO:
199             return "I/O error";
200         default:
201             return "Unknown error";
202     }
203 }
204
205 void ical_component_free(ical_component_t *component)
206 {
207     if (!component) return;
208     
209     free(component->type);
210     
211     if (component->properties) {
212         v_free(component->properties);
213     }
214     
215     if (component->subcomponents) {
216         v_free(component->subcomponents);
217     }
218     
219     free(component);
220 }
221
222 void ical_property_free(ical_property_t *property)
223 {
224     if (!property) return;
225     
226     free(property->name);
227     free(property->value);
228     
229     if (property->parameters) {
230         v_free(property->parameters);
231     }
232     
233     free(property);
234 }
235
236 void ical_parameter_free(ical_parameter_t *parameter)
237 {
238     if (!parameter) return;
239     
240     free(parameter->name);
241     free(parameter->value);
242     free(parameter);
243 }
244
245 /* Interface functions called by the parser */
246 void ical_parser_add_component(void *parser_state, const char *type, vector *properties, vector *subcomponents)
247 {
248     ical_parser_t *parser = (ical_parser_t*)parser_state;
249     
250     if (!parser) return;
251     
252     /* Create new component */
253     ical_component_t *component = malloc(sizeof(ical_component_t));
254     if (!component) {
255         parser->has_error = true;
256         parser->error_message = strdup("Memory allocation failed");
257         return;
258     }
259     
260     component->type = strdup(type);
261     component->properties = properties;
262     component->subcomponents = subcomponents;
263     
264     /* Set up destructors for automatic cleanup */
265     if (component->properties) {
266         v_dtor(component->properties, ical_property_destructor, NULL);
267     }
268     if (component->subcomponents) {
269         v_dtor(component->subcomponents, ical_component_destructor, NULL);
270     }
271     
272     parser->result = component;
273 }
274
275 void ical_parser_add_property(void *parser_state, const char *name, vector *parameters, const char *value)
276 {
277     ical_parser_t *parser = (ical_parser_t*)parser_state;
278     
279     if (!parser) return;
280     
281     /* This function would be used if we were building properties incrementally */
282     /* For now, properties are built directly in the parser rules */
283     (void)name;
284     (void)parameters;
285     (void)value;
286 }
287
288 void ical_parser_set_error_with_location(void *parser_state, const char *error, int line, int column)
289 {
290     ical_parser_t *parser = (ical_parser_t*)parser_state;
291     
292     if (!parser) return;
293     
294     parser->has_error = true;
295     parser->error_line = line;
296     parser->error_column = column;
297     
298     free(parser->error_message);
299     parser->error_message = strdup(error ? error : "Unknown error");
300 }
301
302 /* Destructor functions for vector cleanup */
303 static void ical_property_destructor(void *property_ptr, void *aux)
304 {
305     (void)aux;  /* Unused parameter */
306     ical_property_free((ical_property_t*)property_ptr);
307 }
308
309 static void ical_component_destructor(void *component_ptr, void *aux)
310 {
311     (void)aux;  /* Unused parameter */
312     ical_component_free((ical_component_t*)component_ptr);
313 }