#include "ical_parser.h" #include "ical.tab.h" #include #include #include #include /* Forward declaration of flex scanner functions */ int icallex_init(void **scanner); int icallex_destroy(void *scanner); void icalset_in(FILE *input_file, void *scanner); int icalparse(void *parser_state, void *scanner); /* Destructor function declarations for vector cleanup */ static void ical_property_destructor(void *property_ptr, void *aux); static void ical_component_destructor(void *component_ptr, void *aux); typedef struct { void *scanner; FILE *string_input; } ical_scanner_state_t; /* Buffer for input string parsing */ typedef struct { const char *data; size_t size; size_t pos; } string_buffer_t; /* Parser state structure */ struct ical_parser { ical_component_t *result; char *error_message; int error_line; int error_column; bool has_error; string_buffer_t *string_buffer; }; /* Custom input function for string parsing */ static int string_input_function(char *buf, int max_size, void *user_data) { string_buffer_t *buffer = (string_buffer_t*)user_data; if (buffer->pos >= buffer->size) { return 0; /* EOF */ } size_t remaining = buffer->size - buffer->pos; size_t to_copy = (remaining < (size_t)max_size) ? remaining : (size_t)max_size; memcpy(buf, buffer->data + buffer->pos, to_copy); buffer->pos += to_copy; return (int)to_copy; } ical_parser_t *ical_parser_create(void) { ical_parser_t *parser = calloc(1, sizeof(ical_parser_t)); if (!parser) return NULL; return parser; } void ical_parser_destroy(ical_parser_t *parser) { if (!parser) return; if (parser->result) { ical_component_free(parser->result); } free(parser->error_message); free(parser->string_buffer); free(parser); } ical_error_t ical_parser_parse_string(ical_parser_t *parser, const char *input, ical_component_t **calendar) { if (!parser || !input || !calendar) { return ICAL_ERROR_INVALID_PARAMETER; } *calendar = NULL; /* Clear previous state */ if (parser->result) { ical_component_free(parser->result); parser->result = NULL; } free(parser->error_message); parser->error_message = NULL; parser->has_error = false; /* Set up string buffer */ if (!parser->string_buffer) { parser->string_buffer = malloc(sizeof(string_buffer_t)); if (!parser->string_buffer) { return ICAL_ERROR_MEMORY; } } parser->string_buffer->data = input; parser->string_buffer->size = strlen(input); parser->string_buffer->pos = 0; /* Initialize scanner */ void *scanner; if (icallex_init(&scanner) != 0) { return ICAL_ERROR_MEMORY; } /* Parse the input */ int parse_result = icalparse(parser, scanner); /* Clean up scanner */ icallex_destroy(scanner); if (parse_result != 0 || parser->has_error) { return ICAL_ERROR_PARSE; } *calendar = parser->result; parser->result = NULL; /* Transfer ownership */ return ICAL_SUCCESS; } ical_error_t ical_parser_parse_file(ical_parser_t *parser, FILE *file, ical_component_t **calendar) { if (!parser || !file || !calendar) { return ICAL_ERROR_INVALID_PARAMETER; } *calendar = NULL; /* Clear previous state */ if (parser->result) { ical_component_free(parser->result); parser->result = NULL; } free(parser->error_message); parser->error_message = NULL; parser->has_error = false; /* Initialize scanner */ void *scanner; if (icallex_init(&scanner) != 0) { return ICAL_ERROR_MEMORY; } /* Set input file */ icalset_in(file, scanner); /* Parse the input */ int parse_result = icalparse(parser, scanner); /* Clean up scanner */ icallex_destroy(scanner); if (parse_result != 0 || parser->has_error) { return ICAL_ERROR_PARSE; } *calendar = parser->result; parser->result = NULL; /* Transfer ownership */ return ICAL_SUCCESS; } ical_error_info_t ical_parser_get_error_info(ical_parser_t *parser) { ical_error_info_t info = {0}; if (parser && parser->has_error) { info.message = parser->error_message; info.line = parser->error_line; info.column = parser->error_column; info.has_location = (parser->error_line > 0 || parser->error_column > 0); } return info; } const char *ical_error_string(ical_error_t error) { switch (error) { case ICAL_SUCCESS: return "Success"; case ICAL_ERROR_MEMORY: return "Memory allocation failed"; case ICAL_ERROR_PARSE: return "Parse error"; case ICAL_ERROR_INVALID_PARAMETER: return "Invalid parameter"; case ICAL_ERROR_IO: return "I/O error"; default: return "Unknown error"; } } void ical_component_free(ical_component_t *component) { if (!component) return; free(component->type); if (component->properties) { v_free(component->properties); } if (component->subcomponents) { v_free(component->subcomponents); } free(component); } void ical_property_free(ical_property_t *property) { if (!property) return; free(property->name); free(property->value); if (property->parameters) { v_free(property->parameters); } free(property); } void ical_parameter_free(ical_parameter_t *parameter) { if (!parameter) return; free(parameter->name); free(parameter->value); free(parameter); } /* Interface functions called by the parser */ void ical_parser_add_component(void *parser_state, const char *type, vector *properties, vector *subcomponents) { ical_parser_t *parser = (ical_parser_t*)parser_state; if (!parser) return; /* Create new component */ ical_component_t *component = malloc(sizeof(ical_component_t)); if (!component) { parser->has_error = true; parser->error_message = strdup("Memory allocation failed"); return; } component->type = strdup(type); component->properties = properties; component->subcomponents = subcomponents; /* Set up destructors for automatic cleanup */ if (component->properties) { v_dtor(component->properties, ical_property_destructor, NULL); } if (component->subcomponents) { v_dtor(component->subcomponents, ical_component_destructor, NULL); } parser->result = component; } void ical_parser_add_property(void *parser_state, const char *name, vector *parameters, const char *value) { ical_parser_t *parser = (ical_parser_t*)parser_state; if (!parser) return; /* This function would be used if we were building properties incrementally */ /* For now, properties are built directly in the parser rules */ (void)name; (void)parameters; (void)value; } void ical_parser_set_error_with_location(void *parser_state, const char *error, int line, int column) { ical_parser_t *parser = (ical_parser_t*)parser_state; if (!parser) return; parser->has_error = true; parser->error_line = line; parser->error_column = column; free(parser->error_message); parser->error_message = strdup(error ? error : "Unknown error"); } /* Destructor functions for vector cleanup */ static void ical_property_destructor(void *property_ptr, void *aux) { (void)aux; /* Unused parameter */ ical_property_free((ical_property_t*)property_ptr); } static void ical_component_destructor(void *component_ptr, void *aux) { (void)aux; /* Unused parameter */ ical_component_free((ical_component_t*)component_ptr); }