#include #include #include "adventure.h" struct param params[MAX_PARAMS]; static const char * skip_spaces(const char *src) { while (isspace(*src)) src++; return src; } static const char * match_spaces(const char *src) { return *src == '\0' || isspace(*src) ? skip_spaces(src) : NULL; } static const char * match_terminal(const char *src, char terminal) { return terminal == ' ' ? match_spaces(src) : tolower(*src) == tolower(terminal) ? src + 1 : NULL; } static const char * match_tag(const char *src, const char *tag) { while (src != NULL && *tag != '\0') src = match_terminal(src, *tag++); return src; } static int compare_with_param(const char *tag, enum distance dist, struct param *par) { int diff = strlen(tag) - strlen(par->tag); if (diff == 0) diff = par->distance - dist; if (diff == 0) par->count++; return diff; } static const char * match_param(const char *src, struct param *par, int loose) { struct object *obj; const char *rest_of_src = loose ? src + strlen(src) : NULL; par->tag = src; par->distance = *src == '\0' ? dist_no_obj_specified : dist_unknown_obj; foreach_obj (obj) { const char **tag; enum distance dist = distance_to(obj); for (tag = obj->tags; *tag != NULL; ++tag) { const char *behind_match = match_tag(src, *tag); if (behind_match != NULL && compare_with_param(*tag, dist, par) > 0 && (!loose || *skip_spaces(behind_match) == '\0')) { par->tag = *tag; par->object = obj; par->distance = dist; par->count = 1; rest_of_src = behind_match; } } } return rest_of_src; } int match_command(const char *src, const char *pattern) { struct param *par; /* clean params */ for (par = params; par < params + MAX_PARAMS; ++par) { par->object = NULL; par->distance = dist_no_obj_specified; par->count = 0; } /* actual parsing */ for (src = skip_spaces(src); src != NULL && *pattern != '\0'; ++pattern) { src = isupper(*pattern) ? match_param(src, param_by_letter(*pattern), pattern[1] == '?') : *pattern == '?' ? src : match_terminal(src, *pattern); } return src != NULL && *skip_spaces(src) == '\0'; }