39 */ |
39 */ |
40 |
40 |
41 #define __COMMANDS_CXX__ |
41 #define __COMMANDS_CXX__ |
42 #include <stdlib.h> |
42 #include <stdlib.h> |
43 #include <stdio.h> |
43 #include <stdio.h> |
|
44 #include <string.h> |
44 #include "common.h" |
45 #include "common.h" |
45 #include "scriptreader.h" |
46 #include "scriptreader.h" |
46 #include "str.h" |
47 #include "str.h" |
47 #include "commands.h" |
48 #include "commands.h" |
48 |
49 |
49 CommandDef* g_CommDef; |
50 CommandDef* g_CommDef; |
50 |
51 |
51 void ReadCommands () { |
52 void ReadCommands () { |
52 ScriptReader* r = new ScriptReader ((char*)"commands.def"); |
53 ScriptReader* r = new ScriptReader ((char*)"commands.def"); |
|
54 r->extdelimeters = true; |
53 g_CommDef = NULL; |
55 g_CommDef = NULL; |
54 CommandDef* curdef = g_CommDef; |
56 CommandDef* curdef = g_CommDef; |
55 unsigned int numCommDefs = 0; |
57 unsigned int numCommDefs = 0; |
56 |
58 |
57 while (r->Next()) { |
59 while (r->PeekNext().compare ("") != 0) { |
58 CommandDef* comm = new CommandDef; |
60 CommandDef* comm = new CommandDef; |
|
61 comm->next = NULL; |
59 |
62 |
60 // Any more than 4 is a warning, any less is an error. |
63 // Number |
61 unsigned int c = r->token.count (const_cast<char*> (":")); |
64 r->MustNumber (); |
62 if (c < 4) |
65 comm->number = r->token; |
63 r->ParserError ("not enough parameters: got %d, expected 4", c); |
|
64 |
66 |
65 int n = 0; |
67 r->MustNext (":"); |
66 str t = ""; |
68 |
67 for (unsigned int u = 0; u < r->token.len(); u++) { |
69 // Name |
68 // If we're at the last character of the string, we need |
70 r->MustNext (); |
69 // to both add the character to t and check it. Thus, |
71 comm->name = r->token; |
70 // we do the addition, exceptionally, here. |
72 |
71 if (u == r->token.len() - 1 && r->token[u] != ':') |
73 r->MustNext (":"); |
72 t += r->token[u]; |
74 |
|
75 // Return value |
|
76 r->MustNext (); |
|
77 comm->returnvalue = GetReturnTypeByString (r->token); |
|
78 if (comm->returnvalue == -1) |
|
79 r->ParserError ("bad return value type `%s`", r->token.chars()); |
|
80 |
|
81 r->MustNext (":"); |
|
82 |
|
83 // Num args |
|
84 r->MustNumber (); |
|
85 comm->numargs = r->token; |
|
86 |
|
87 r->MustNext (":"); |
|
88 |
|
89 // Max args |
|
90 r->MustNumber (); |
|
91 comm->maxargs = r->token; |
|
92 |
|
93 if (comm->maxargs > MAX_MAXARGS) |
|
94 r->ParserError ("maxargs (%d) greater than %d!", comm->maxargs, MAX_MAXARGS); |
|
95 |
|
96 // Argument types |
|
97 int curarg = 0; |
|
98 while (curarg < comm->maxargs) { |
|
99 r->MustNext (":"); |
|
100 r->MustNext (); |
73 |
101 |
74 if (r->token[u] == ':' || u == r->token.len() - 1) { |
102 int type = GetReturnTypeByString (r->token); |
75 int i = atoi (t.chars()); |
103 if (type == -1) |
76 switch (n) { |
104 r->ParserError ("bad argument %d type `%s`", curarg, r->token.chars()); |
77 case 0: |
105 if (type == RETURNVAL_VOID) |
78 // Number |
106 r->ParserError ("void is not a valid argument type!"); |
79 comm->number = i; |
107 comm->argtypes[curarg] = type; |
80 break; |
108 |
81 case 1: |
109 r->MustNext ("("); |
82 // Name |
110 r->MustNext (); |
83 comm->name = t; |
111 |
84 break; |
112 // - 1 because of terminating null character |
85 case 2: |
113 if (r->token.len() > MAX_ARGNAMELEN - 1) |
86 // Return value |
114 r->ParserWarning ("argument name is too long (%d, max is %d)", |
87 t.tolower(); |
115 r->token.len(), MAX_ARGNAMELEN-1); |
88 if (!t.compare ("int")) |
116 |
89 comm->returnvalue = RETURNVAL_INT; |
117 strncpy (comm->argnames[curarg], r->token.chars(), MAX_ARGNAMELEN); |
90 else if (!t.compare ("str")) |
118 comm->argnames[curarg][MAX_ARGNAMELEN-1] = 0; |
91 comm->returnvalue = RETURNVAL_STRING; |
119 |
92 else if (!t.compare ("void")) |
120 // If this is an optional parameter, we need the default value. |
93 comm->returnvalue = RETURNVAL_VOID; |
121 if (curarg >= comm->numargs) { |
94 else if (!t.compare ("bool")) |
122 r->MustNext ("="); |
95 comm->returnvalue = RETURNVAL_BOOLEAN; |
123 switch (type) { |
96 else |
124 case RETURNVAL_INT: r->MustNumber(); break; |
97 r->ParserError ("bad return value type `%s`", t.chars()); |
125 case RETURNVAL_STRING: r->token = r->MustGetString(); break; |
98 break; |
126 case RETURNVAL_BOOLEAN: r->MustBool(); break; |
99 case 3: |
|
100 // Num args |
|
101 comm->numargs = i; |
|
102 break; |
|
103 case 4: |
|
104 // Max args |
|
105 comm->maxargs = i; |
|
106 break; |
|
107 default: |
|
108 r->ParserWarning ("too many parameters"); |
|
109 break; |
|
110 } |
127 } |
111 |
128 |
112 n++; |
129 comm->defvals[curarg] = r->token; |
113 t = ""; |
|
114 } else { |
|
115 t += r->token[u]; |
|
116 } |
130 } |
|
131 |
|
132 r->MustNext (")"); |
|
133 curarg++; |
117 } |
134 } |
118 |
|
119 comm->next = NULL; |
|
120 |
135 |
121 if (!g_CommDef) |
136 if (!g_CommDef) |
122 g_CommDef = comm; |
137 g_CommDef = comm; |
123 |
138 |
124 if (!curdef) { |
139 if (!curdef) { |
140 |
155 |
141 delete r; |
156 delete r; |
142 printf ("%d command definitions read.\n", numCommDefs); |
157 printf ("%d command definitions read.\n", numCommDefs); |
143 } |
158 } |
144 |
159 |
|
160 // urgh long name |
|
161 int GetReturnTypeByString (str t) { |
|
162 // "float" is for now just int. |
|
163 // TODO: find out how BotScript floats work |
|
164 // (are they real floats or fixed? how are they |
|
165 // stored?) and add proper floating point support. |
|
166 // NOTE: Also, shouldn't use RETURNVAL for data types.. |
|
167 t.tolower(); |
|
168 return !t.compare ("int") ? RETURNVAL_INT : |
|
169 !t.compare ("float") ? RETURNVAL_INT : |
|
170 !t.compare ("str") ? RETURNVAL_STRING : |
|
171 !t.compare ("void") ? RETURNVAL_VOID : |
|
172 !t.compare ("bool") ? RETURNVAL_BOOLEAN : -1; |
|
173 } |
|
174 |
|
175 // Inverse operation |
|
176 str GetReturnTypeName (int r) { |
|
177 switch (r) { |
|
178 case RETURNVAL_INT: return "int"; break; |
|
179 case RETURNVAL_STRING: return "str"; break; |
|
180 case RETURNVAL_VOID: return "void"; break; |
|
181 case RETURNVAL_BOOLEAN: return "bool"; break; |
|
182 } |
|
183 |
|
184 return ""; |
|
185 } |
|
186 |
145 CommandDef* GetCommandByName (str a) { |
187 CommandDef* GetCommandByName (str a) { |
146 a.tolower (); |
188 a.tolower (); |
147 CommandDef* c; |
189 CommandDef* c; |
148 ITERATE_COMMANDS (c) { |
190 ITERATE_COMMANDS (c) { |
149 str b = c->name; |
191 str b = c->name; |