Blob


1 #include "adventure.h"
3 #include <ctype.h>
4 #include <string.h>
6 struct param params[MAX_PARAMS];
8 static const char *
9 skip_spaces(const char *src)
10 {
11 while (isspace(*src))
12 src++;
13 return src;
14 }
16 static const char *
17 match_spaces(const char *src)
18 {
19 return *src == '\0' || isspace(*src) ? skip_spaces(src) : NULL;
20 }
22 static const char *
23 match_terminal(const char *src, char terminal)
24 {
25 return terminal == ' '
26 ? match_spaces(src)
27 : tolower(*src) == tolower(terminal)
28 ? src + 1
29 : NULL;
30 }
32 static const char *
33 match_tag(const char *src, const char *tag)
34 {
35 while (src != NULL && *tag != '\0')
36 src = match_terminal(src, *tag++);
37 return src;
38 }
40 static int
41 compare_with_param(const char *tag, enum distance dist, struct param *par)
42 {
43 int diff = strlen(tag) - strlen(par->tag);
44 if (diff == 0)
45 diff = par->distance - dist;
46 if (diff == 0)
47 par->count++;
48 return diff;
49 }
51 static const char *
52 match_param(const char *src, struct param *par, int loose)
53 {
54 struct object *obj;
55 const char *rest_of_src = loose ? src + strlen(src) : NULL;
57 par->tag = src;
58 par->distance = *src == '\0' ? dist_no_obj_specified : dist_unknown_obj;
60 foreach_obj (obj) {
61 const char **tag;
62 enum distance dist = distance_to(obj);
63 for (tag = obj->tags; *tag != NULL; ++tag) {
64 const char *behind_match = match_tag(src, *tag);
65 if (behind_match != NULL &&
66 compare_with_param(*tag, dist, par) > 0 &&
67 (!loose || *skip_spaces(behind_match) == '\0')) {
68 par->tag = *tag;
69 par->object = obj;
70 par->distance = dist;
71 par->count = 1;
72 rest_of_src = behind_match;
73 }
74 }
75 }
77 return rest_of_src;
78 }
80 int
81 match_command(const char *src, const char *pattern)
82 {
83 struct param *par;
85 /* clean params */
86 for (par = params; par < params + MAX_PARAMS; ++par) {
87 par->object = NULL;
88 par->distance = dist_no_obj_specified;
89 par->count = 0;
90 }
92 /* actual parsing */
93 for (src = skip_spaces(src); src != NULL && *pattern != '\0'; ++pattern) {
94 src = isupper(*pattern)
95 ? match_param(src, param_by_letter(*pattern),
96 pattern[1] == '?')
97 : *pattern == '?'
98 ? src
99 : match_terminal(src, *pattern);
102 return src != NULL && *skip_spaces(src) == '\0';