Blob


1 #include <ctype.h>
2 #include <string.h>
4 #include "adventure.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) ? src + 1 : NULL;
28 }
30 static const char *
31 match_tag(const char *src, const char *tag)
32 {
33 while (src != NULL && *tag != '\0')
34 src = match_terminal(src, *tag++);
35 return src;
36 }
38 static int
39 compare_with_param(const char *tag, enum distance dist, struct param *par)
40 {
41 int diff = strlen(tag) - strlen(par->tag);
42 if (diff == 0)
43 diff = par->distance - dist;
44 if (diff == 0)
45 par->count++;
46 return diff;
47 }
49 static const char *
50 match_param(const char *src, struct param *par, int loose)
51 {
52 struct object *obj;
53 const char *rest_of_src = loose ? src + strlen(src) : NULL;
55 par->tag = src;
56 par->distance
57 = *src == '\0' ? dist_no_obj_specified : dist_unknown_obj;
59 foreach_obj(obj)
60 {
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
68 || *skip_spaces(behind_match)
69 == '\0')) {
70 par->tag = *tag;
71 par->object = obj;
72 par->distance = dist;
73 par->count = 1;
74 rest_of_src = behind_match;
75 }
76 }
77 }
79 return rest_of_src;
80 }
82 int
83 match_command(const char *src, const char *pattern)
84 {
85 struct param *par;
87 /* clean params */
88 for (par = params; par < params + MAX_PARAMS; ++par) {
89 par->object = NULL;
90 par->distance = dist_no_obj_specified;
91 par->count = 0;
92 }
94 /* actual parsing */
95 for (src = skip_spaces(src); src != NULL && *pattern != '\0';
96 ++pattern) {
97 src = isupper(*pattern)
98 ? match_param(src, param_by_letter(*pattern),
99 pattern[1] == '?')
100 : *pattern == '?' ? src
101 : match_terminal(src, *pattern);
104 return src != NULL && *skip_spaces(src) == '\0';