1 #include "ical_parser.h"
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);
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);
22 } ical_scanner_state_t;
24 /* Buffer for input string parsing */
31 /* Parser state structure */
33 ical_component_t *result;
38 string_buffer_t *string_buffer;
41 /* Custom input function for string parsing */
42 static int string_input_function(char *buf, int max_size, void *user_data)
44 string_buffer_t *buffer = (string_buffer_t*)user_data;
46 if (buffer->pos >= buffer->size) {
50 size_t remaining = buffer->size - buffer->pos;
51 size_t to_copy = (remaining < (size_t)max_size) ? remaining : (size_t)max_size;
53 memcpy(buf, buffer->data + buffer->pos, to_copy);
54 buffer->pos += to_copy;
59 ical_parser_t *ical_parser_create(void)
61 ical_parser_t *parser = calloc(1, sizeof(ical_parser_t));
62 if (!parser) return NULL;
67 void ical_parser_destroy(ical_parser_t *parser)
72 ical_component_free(parser->result);
75 free(parser->error_message);
76 free(parser->string_buffer);
80 ical_error_t ical_parser_parse_string(ical_parser_t *parser, const char *input, ical_component_t **calendar)
82 if (!parser || !input || !calendar) {
83 return ICAL_ERROR_INVALID_PARAMETER;
88 /* Clear previous state */
90 ical_component_free(parser->result);
91 parser->result = NULL;
93 free(parser->error_message);
94 parser->error_message = NULL;
95 parser->has_error = false;
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;
105 parser->string_buffer->data = input;
106 parser->string_buffer->size = strlen(input);
107 parser->string_buffer->pos = 0;
109 /* Initialize scanner */
111 if (icallex_init(&scanner) != 0) {
112 return ICAL_ERROR_MEMORY;
115 /* Parse the input */
116 int parse_result = icalparse(parser, scanner);
118 /* Clean up scanner */
119 icallex_destroy(scanner);
121 if (parse_result != 0 || parser->has_error) {
122 return ICAL_ERROR_PARSE;
125 *calendar = parser->result;
126 parser->result = NULL; /* Transfer ownership */
131 ical_error_t ical_parser_parse_file(ical_parser_t *parser, FILE *file, ical_component_t **calendar)
133 if (!parser || !file || !calendar) {
134 return ICAL_ERROR_INVALID_PARAMETER;
139 /* Clear previous state */
140 if (parser->result) {
141 ical_component_free(parser->result);
142 parser->result = NULL;
144 free(parser->error_message);
145 parser->error_message = NULL;
146 parser->has_error = false;
148 /* Initialize scanner */
150 if (icallex_init(&scanner) != 0) {
151 return ICAL_ERROR_MEMORY;
155 icalset_in(file, scanner);
157 /* Parse the input */
158 int parse_result = icalparse(parser, scanner);
160 /* Clean up scanner */
161 icallex_destroy(scanner);
163 if (parse_result != 0 || parser->has_error) {
164 return ICAL_ERROR_PARSE;
167 *calendar = parser->result;
168 parser->result = NULL; /* Transfer ownership */
173 ical_error_info_t ical_parser_get_error_info(ical_parser_t *parser)
175 ical_error_info_t info = {0};
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);
187 const char *ical_error_string(ical_error_t error)
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";
201 return "Unknown error";
205 void ical_component_free(ical_component_t *component)
207 if (!component) return;
209 free(component->type);
211 if (component->properties) {
212 v_free(component->properties);
215 if (component->subcomponents) {
216 v_free(component->subcomponents);
222 void ical_property_free(ical_property_t *property)
224 if (!property) return;
226 free(property->name);
227 free(property->value);
229 if (property->parameters) {
230 v_free(property->parameters);
236 void ical_parameter_free(ical_parameter_t *parameter)
238 if (!parameter) return;
240 free(parameter->name);
241 free(parameter->value);
245 /* Interface functions called by the parser */
246 void ical_parser_add_component(void *parser_state, const char *type, vector *properties, vector *subcomponents)
248 ical_parser_t *parser = (ical_parser_t*)parser_state;
252 /* Create new component */
253 ical_component_t *component = malloc(sizeof(ical_component_t));
255 parser->has_error = true;
256 parser->error_message = strdup("Memory allocation failed");
260 component->type = strdup(type);
261 component->properties = properties;
262 component->subcomponents = subcomponents;
264 /* Set up destructors for automatic cleanup */
265 if (component->properties) {
266 v_dtor(component->properties, ical_property_destructor, NULL);
268 if (component->subcomponents) {
269 v_dtor(component->subcomponents, ical_component_destructor, NULL);
272 parser->result = component;
275 void ical_parser_add_property(void *parser_state, const char *name, vector *parameters, const char *value)
277 ical_parser_t *parser = (ical_parser_t*)parser_state;
281 /* This function would be used if we were building properties incrementally */
282 /* For now, properties are built directly in the parser rules */
288 void ical_parser_set_error_with_location(void *parser_state, const char *error, int line, int column)
290 ical_parser_t *parser = (ical_parser_t*)parser_state;
294 parser->has_error = true;
295 parser->error_line = line;
296 parser->error_column = column;
298 free(parser->error_message);
299 parser->error_message = strdup(error ? error : "Unknown error");
302 /* Destructor functions for vector cleanup */
303 static void ical_property_destructor(void *property_ptr, void *aux)
305 (void)aux; /* Unused parameter */
306 ical_property_free((ical_property_t*)property_ptr);
309 static void ical_component_destructor(void *component_ptr, void *aux)
311 (void)aux; /* Unused parameter */
312 ical_component_free((ical_component_t*)component_ptr);