1// i got to eventually clean up this file a bit i feel like its very janky but i
2// suppose i can worry about that later
3
4#include "interpreter.h"
5#include "cottonwindow.h"
6#include "eiki.h"
7#include <SDL2/SDL.h>
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11#include <unistd.h>
12
13// maximum length of a .cot file line
14#define MAX_LINE 256
15
16// da string AND variable stuff
17
18static void
19strip_newline(char *s)
20{
21 s[strcspn(s, "\r\n")] = 0;
22}
23
24static char
25*get_arg (char *line)
26{
27 char *space = strchr(line, ' ');
28
29 if (space != NULL) {
30 return space + 1;
31 }
32
33 else {
34 return NULL;
35 }
36}
37
38static char
39*strip_quotes(char *s)
40{
41 if (s[0] == '"') {
42 char *end = strrchr(s, '"');
43
44 if (end == NULL) {
45 fprintf(stderr, "cot syntax error : looks like you forgot a quote at the end xP\n");
46 return s;
47 }
48
49 *end = '\0';
50 return s + 1;
51 }
52
53 return s;
54}
55
56static const char *get_var_value
57(Cotton *cotton, const char *name)
58{
59 for (int i = 0; i < cotton->var_count; i++) {
60 if (strcmp(cotton->vars[i].name, name) == 0) {
61 return cotton->vars[i].value;
62 }
63 }
64 return NULL;
65}
66
67// da graphics stuff
68
69static void draw_pixel
70(Cotton *cotton, int x, int y)
71{
72 cotton->video[y * VIDEO_WIDTH + x] = cotton->c_cottolette;
73}
74
75static void draw_char
76(Cotton *cotton, char c, int x, int y)
77{
78 for (int row = 0; row < FONT_HEIGHT; row++) {
79 uint8_t bits = EIKI_FONT[(uint8_t)c][row];
80
81 for (int col = 0; col < FONT_WIDTH; col++) {
82
83 if (bits & (1 << col)) {
84 draw_pixel(cotton, x + col, y + row);
85 }
86 }
87 }
88}
89
90// da commands
91
92static void
93cmd_print(Cotton *cotton, CottonWindow *cw, char *arg)
94{
95 if (!arg)
96 return;
97
98 char *text = strip_quotes(arg);
99
100 const char *value = get_var_value(cotton, text);
101 if (value != NULL) {
102 text = (char *)value;
103 }
104
105 printf("%s\n", text);
106
107 for (int i = 0; text[i] != '\0'; i++) {
108 if (text[i] == '\n') {
109 cotton->cursor_x = 0;
110 cotton->cursor_y += FONT_HEIGHT + 4;
111 continue;
112 }
113
114 draw_char(cotton, text[i], cotton->cursor_x, cotton->cursor_y);
115 cotton->cursor_x += FONT_WIDTH + 2;
116
117 if (cotton->cursor_x + FONT_WIDTH + 2 >= VIDEO_WIDTH) {
118 cotton->cursor_x = 0;
119 cotton->cursor_y += FONT_HEIGHT + 4;
120 }
121 }
122
123 cotton->cursor_x = 0;
124 cotton->cursor_y += FONT_HEIGHT + 4;
125
126 cottonwindow_update(cw, cotton->video, sizeof(cotton->video[0]) * VIDEO_WIDTH);
127}
128
129static void
130cmd_var(Cotton *cotton, char *arg)
131{
132 if (!arg)
133 return;
134
135 char *space = strchr(arg, ' ');
136 if (!space) {
137 fprintf(stderr, "cot syntax error: you forgor to put a value for your variable xP\n");
138 return;
139 }
140
141 *space = '\0';
142 char *name = arg;
143 char *value = space + 1;
144
145 cotton_store_var(cotton, name, value);
146}
147
148static void
149cmd_clear(Cotton *cotton, CottonWindow *cw)
150{
151 for (int i = 0; i < VIDEO_WIDTH * VIDEO_HEIGHT; i++) {
152 cotton->video[i] = 0;
153 }
154
155 cotton->cursor_x = 0;
156 cotton->cursor_y = 0;
157
158 cottonwindow_update(cw, cotton->video,
159 sizeof(cotton->video[0]) * VIDEO_WIDTH);
160}
161
162static void
163cmd_color(Cotton *cotton, char *arg)
164{
165 if (!arg)
166 return;
167
168 if (strcmp(arg, "black") == 0)
169 cotton->c_cottolette = COTTOLETTE[0];
170
171 else if (strcmp(arg, "white") == 0)
172 cotton->c_cottolette = COTTOLETTE[1];
173
174 else if (strcmp(arg, "rey") == 0)
175 cotton->c_cottolette = COTTOLETTE[2];
176
177 else if (strcmp(arg, "wist") == 0)
178 cotton->c_cottolette = COTTOLETTE[3];
179
180 else if (strcmp(arg, "wink") == 0)
181 cotton->c_cottolette = COTTOLETTE[4];
182
183 else if (strcmp(arg, "laven") == 0)
184 cotton->c_cottolette = COTTOLETTE[5];
185
186 else if (strcmp(arg, "geen") == 0)
187 cotton->c_cottolette = COTTOLETTE[6];
188
189 else
190 fprintf(stderr,
191 "cot syntax error: cotton doesn't know the color \"%s\" "
192 "sorry,, :(\n",
193 arg);
194}
195
196static void
197cmd_wait(Cotton *cotton, char *arg)
198{
199 if (!arg)
200 return;
201
202 int seconds = atoi(arg);
203
204 cotton->ticktock = SDL_GetTicks() + (seconds * 1000);
205}
206
207static void
208cmd_input(Cotton *cotton, char *arg)
209{
210 if (!arg) {
211 fprintf(stderr,
212 "cotton syntax error: input needs a variable name xP\n");
213 return;
214 }
215
216 char buffer[VAR_VAL_LEN];
217
218 // kind of a quick and dirty way of implementing input, i know, but, i cant be arsed to get myself into a potential rabbit hole with SDL so for now i will leave this to be this way,, sorry,,
219 if (fgets(buffer, sizeof(buffer), stdin) != NULL) {
220 buffer[strcspn(buffer, "\r\n")] = '\0';
221
222 cotton_store_var(cotton, arg, buffer);
223 }
224}
225
226static void
227cmd_kill(void)
228{
229 printf("[cotton stopped]\n");
230 exit(0);
231}
232
233static void
234cmd_math(Cotton *cotton, char *arg, char op)
235{
236 char var_name[64];
237 char value[64];
238
239 if (!arg || sscanf(arg, "%63s %63s", var_name, value) != 2) {
240 fprintf(stderr, "cot syntax error: usage is '<add, sub, mult, div> <variable> <number OR another variable>'\n");
241 return;
242 }
243
244 int current = 0;
245 int amount = 0;
246
247 // thank you clang for coming in clutch and telling me to make this const i forgor (skull emoji)
248 const char *var = get_var_value(cotton, var_name);
249 if (var) {
250 current = atoi(var);
251 }
252
253 // and this too, i love clang, clang is the best compiler evah !!!
254 const char *other = get_var_value(cotton, value);
255 if (other) {
256 amount = atoi(other);
257 } else {
258 amount = atoi(value);
259 }
260
261 switch (op) {
262 case '+':
263 current += amount;
264 break;
265
266 case '-':
267 current -= amount;
268 break;
269
270 case '*':
271 current *= amount;
272 break;
273
274 case '/':
275 current /= amount;
276 break;
277
278 default:
279 fprintf(stderr, "cot syntax error: cot doesn't know what operator this is :( \n");
280 return;
281 }
282
283 char buffer[32];
284 sprintf(buffer, "%d", current);
285
286 cotton_store_var(cotton, var_name, buffer);
287}
288
289static void
290cmd_unknown(const char *cmd)
291{
292 fprintf(stderr,
293 "cot syntax error: cotton doesn't know what \"%s\" means, care to "
294 "type that out again? :<\n",
295 cmd);
296}
297
298// da interpreter loop
299
300void
301cotton_interpret(Cotton *cotton, CottonWindow *cw, FILE *file)
302{
303 char line[MAX_LINE];
304
305 // this reads the file one line at a time until we get to da end of da file
306 if (!fgets(line, sizeof(line), file))
307 return;
308
309 strip_newline(line);
310
311 // cot shall use # comments like C because C is cool and i love C so bwaaa
312 if (line[0] == '\0' || line[0] == '#')
313 return;
314
315 char line_copy[MAX_LINE];
316
317 strncpy(line_copy, line, MAX_LINE - 1);
318 line_copy[MAX_LINE - 1] = '\0';
319
320 char *cmd = strtok(line_copy, " ");
321
322 if (!cmd)
323 return;
324
325 // RELEASE THE KRAKE- I MEAN, RELEASE THE GREAT WALL OF COMMANDS !!!
326 // could i format this better? maybe,, but but i'd say this is readable and
327 // i think readability is gud so i will keep it nice and green,,, green!! :D
328 char *arg = get_arg(line);
329
330 if (strcmp(cmd, "print") == 0) {
331 cmd_print(cotton, cw, arg);
332 }
333
334 else if (strcmp(cmd, "var") == 0) {
335 cmd_var(cotton, arg);
336 }
337
338 else if (strcmp(cmd, "clear") == 0) {
339 cmd_clear(cotton, cw);
340 }
341
342 else if (strcmp(cmd, "color") == 0) {
343 cmd_color(cotton, arg);
344 }
345
346 else if (strcmp(cmd, "wait") == 0) {
347 cmd_wait(cotton, arg);
348 }
349
350 else if (strcmp(cmd, "input") == 0) {
351 cmd_input(cotton, arg);
352 }
353
354 else if (strcmp(cmd, "kill") == 0) {
355 cmd_kill();
356 }
357
358 else if (strcmp(cmd, "add") == 0) {
359 cmd_math(cotton, arg, '+');
360 }
361
362 else if (strcmp(cmd, "sub") == 0) {
363 cmd_math(cotton, arg, '-');
364 }
365
366 else if (strcmp(cmd, "mult") == 0) {
367 cmd_math(cotton, arg, '*');
368 }
369
370 else if (strcmp(cmd, "div") == 0) {
371 cmd_math(cotton, arg, '/');
372 }
373
374 else {
375 cmd_unknown(cmd);
376 }
377}