#include #include // size_t #include "sok.h" #define UNUSED(a) ((void) (a)) void sok_level_parser_init( sok_level_parser_t * const parser, const sok_level_parser_cbs_t * const cbs, void * const user_data ) { parser->cbs = cbs; parser->user_data = user_data; } bool sok_level_parser_parse( sok_level_parser_t * const parser, const char * const buf, const size_t buf_len ) { sok_pos_t size = { .x = 0, .y = 0 }; for (size_t i = 0, w = 0; i < buf_len; i++) { if (buf[i] == '|') { if (w > size.x) { size.x = w; } // reset column position, increment row count w = 0; size.y++; } else { w++; } } // increment row count size.y++; // emit level size if ( parser->cbs->on_size && !parser->cbs->on_size(parser, size) ) { // return failure return false; } sok_pos_t pos = { 0, 0 }; for (size_t i = 0; i < buf_len; i++) { switch (buf[i]) { case '|': // new line pos.x = 0; pos.y++; break; case '-': case '_': case ' ': // advance pos.x++; break; case '+': // emit goal if (parser->cbs->on_goal && !parser->cbs->on_goal(parser, pos)) { // return failure return false; } // emit home if (parser->cbs->on_home && !parser->cbs->on_home(parser, pos)) { // return failure return false; } // advance pos.x++; break; case '@': // emit home if (parser->cbs->on_home && !parser->cbs->on_home(parser, pos)) { // return failure return false; } // advance pos.x++; break; case '#': // emit wall if (parser->cbs->on_wall && !parser->cbs->on_wall(parser, pos)) { // return failure return false; } // advance pos.x++; break; case '*': // emit goal if (parser->cbs->on_goal && !parser->cbs->on_goal(parser, pos)) { // return failure return false; } // emit box if (parser->cbs->on_box && !parser->cbs->on_box(parser, pos)) { // return failure return false; } // advance pos.x++; break; case '.': // emit goal if (parser->cbs->on_goal && !parser->cbs->on_goal(parser, pos)) { // return failure return false; } // advance pos.x++; break; case '$': // emit box if (parser->cbs->on_box && !parser->cbs->on_box(parser, pos)) { // return failure return false; } // advance pos.x++; break; default: // emit junk if (parser->cbs->on_junk && !parser->cbs->on_junk(parser, i, buf[i])) { // return failure return false; } // return failure return false; } } // return success return true; }