Subversion Repositories Krakow BASIC

Rev

Rev 8 | Rev 28 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 nishi 1
/* $Id: basic.c 9 2024-09-04 15:25:47Z nishi $ */
2
 
3
/* Krakow BASIC - Multi-platform simple BASIC */
4
 
5
#if defined(PLATFORM_SHIROI)
6
 
7
#include "dri/text.h"
8
#include "dri/video.h"
9
#include "dri/math.h"
10
 
11
#include "mem.h"
12
#include "char.h"
13
#define PLATFORM "Shiroi"
14
#define NEWLINE "\r\n"
15
#define BREAKKEY
16
 
9 nishi 17
#elif defined(PLATFORM_UNIX) || defined(PLATFORM_WINDOWS) || defined(PLATFORM_ARDUINO) || defined(PLATFORM_C64) || defined(PLATFORM_A800XL) || defined(PLATFORM_APPLE2) || defined(PLATFORM_PET)
2 nishi 18
 
19
#if defined(PLATFORM_WINDOWS)
20
#define PLATFORM "Windows"
21
#elif defined(PLATFORM_UNIX)
22
#define PLATFORM "Unix"
23
#elif defined(PLATFORM_ARDUINO)
24
#define PLATFORM "Arduino"
25
#define NEWLINE "\r\n"
26
#define BREAKKEY
4 nishi 27
#elif defined(PLATFORM_C64)
28
#define PLATFORM "Commodore-64"
29
#define NEWLINE "\r\n"
30
#define BREAKKEY
31
#include <conio.h>
9 nishi 32
#elif defined(PLATFORM_PET)
33
#define PLATFORM "Commodore-PET"
34
#define NEWLINE "\r\n"
35
#define BREAKKEY
36
#include <conio.h>
37
#include <peekpoke.h>
6 nishi 38
#elif defined(PLATFORM_A800XL)
39
#define PLATFORM "Atari-800XL"
40
#define NEWLINE "\n"
41
#define BREAKKEY
42
#include <conio.h>
7 nishi 43
#elif defined(PLATFORM_APPLE2)
44
#define PLATFORM "Apple2"
45
#define NEWLINE "\n"
46
#define BREAKKEY
47
#include <conio.h>
2 nishi 48
#endif
49
 
4 nishi 50
#define mull(x, y) ((x) * (y))
51
#define divl(x, y) ((x) / (y))
52
#define killcursor(x)
53
#define cursor(x)
54
#define strnum atoi
55
 
2 nishi 56
#ifndef NEWLINE
57
#define NEWLINE "\n"
58
#endif
59
 
60
#include <stdio.h>
61
#include <stdlib.h>
62
#include <string.h>
63
#include <ctype.h>
64
#include <stdbool.h>
65
 
66
#if defined(__MINGW32__)
67
#include <conio.h>
68
#include <windows.h>
69
#elif defined(PLATFORM_ARDUINO)
70
#define BAUD 9600
71
#include <avr/io.h>
72
#include <util/delay.h>
73
#include <util/setbaud.h>
74
#define BUFFER_SIZE (1024)
75
#define LINE_BUFFER_SIZE (128)
76
#define LINES (32)
77
#undef putchar
78
#define putchar uart_putchar
79
#elif defined(PLATFORM_UNIX)
80
#include <termios.h>
9 nishi 81
#elif defined(PLATFORM_PET)
82
#define BUFFER_SIZE (4 * 1024)
83
#undef killcursor
84
#undef cursor
85
#define killcursor(x) cursor(0)
86
#define cursor(x) cursor(1)
4 nishi 87
#elif defined(PLATFORM_C64)
88
#define BUFFER_SIZE (16 * 1024)
89
#undef killcursor
90
#undef cursor
91
#define killcursor(x) cursor(0)
92
#define cursor(x) cursor(1)
6 nishi 93
#elif defined(PLATFORM_A800XL)
94
#define BUFFER_SIZE (16 * 1024)
95
#undef killcursor
96
#undef cursor
97
#define killcursor(x) cursor(0)
98
#define cursor(x) cursor(1)
7 nishi 99
#elif defined(PLATFORM_APPLE2)
100
#define BUFFER_SIZE (8 * 1024)
101
#undef killcursor
102
#undef cursor
103
#define killcursor(x) cursor(0)
104
#define cursor(x) cursor(1)
2 nishi 105
#endif
106
 
107
#if defined(PLATFORM_ARDUINO)
108
int uart_putchar(char c) {
109
	while(!(UCSR0A & _BV(UDRE0)))
110
		;
111
	UDR0 = c;
112
	return 0;
113
}
114
 
115
void uart_init(void) {
116
	UBRR0H = UBRRH_VALUE;
117
	UBRR0L = UBRRL_VALUE;
118
 
119
	UCSR0B |= _BV(TXEN0) | _BV(RXEN0);
120
 
121
	UCSR0C |= _BV(UCSZ00) | _BV(UCSZ01);
122
}
123
#endif
124
 
4 nishi 125
#define agetch(x) oggetch(0)
126
char oggetch(char wait) {
127
	int c;
2 nishi 128
#if defined(PLATFORM_WINDOWS)
129
rescan:
130
	c = _getch();
131
	if(c == '\r') return '\n';
132
	if(c == '\n') goto rescan;
133
#elif defined(PLATFORM_UNIX)
4 nishi 134
	c = getchar();
2 nishi 135
	if(c == EOF) return -1;
136
	if(c == '\r') return '\n';
137
#elif defined(PLATFORM_ARDUINO)
138
rescan:
7 nishi 139
	if(wait) {
4 nishi 140
		if(!(UCSR0A & _BV(RXC0))) return 0;
7 nishi 141
	} else {
142
		while(!(UCSR0A & _BV(RXC0)))
143
			;
4 nishi 144
	}
2 nishi 145
	c = UDR0;
146
	if(c == '\r') return '\n';
147
	if(c == '\n') goto rescan;
148
	if(c == 3) return 1;
9 nishi 149
#elif defined(PLATFORM_C64) || defined(PLATFORM_PET)
7 nishi 150
	if(!wait) {
4 nishi 151
		if(!kbhit()) return 0;
152
	}
153
	c = cgetc();
154
	if(c == EOF) return -1;
155
	if(c == '\r') return '\n';
156
	if(c == 20) return 8;
157
	if(c == 3) return 1;
6 nishi 158
#elif defined(PLATFORM_A800XL)
7 nishi 159
	if(!wait) {
6 nishi 160
		if(!kbhit()) return 0;
161
	}
162
	c = cgetc();
163
	if(c == EOF) return -1;
164
	if(c == '\r') return '\n';
165
	if(c == 126) return 8;
166
	if(c == 3) return 1;
7 nishi 167
#elif defined(PLATFORM_APPLE2)
168
	if(!wait) {
169
		if(!kbhit()) return 0;
170
	}
171
	c = cgetc();
172
	if(c == EOF) return -1;
173
	if(c == '\r') return '\n';
174
	if(c == 3) return 1;
2 nishi 175
#endif
176
	return c;
177
}
178
 
179
bool strcaseequ(const char* a, const char* b) { return strcasecmp(a, b) == 0; }
180
 
181
#if defined(PLATFORM_ARDUINO)
182
void putstr(const char* n) {
183
	int i;
184
	for(i = 0; n[i] != 0; i++) {
185
		uart_putchar(n[i]);
186
	}
187
}
188
 
189
void putnum(int n) {
190
	char buf[64];
191
	int incr = 63;
192
	buf[incr--] = 0;
193
	while(1) {
194
		buf[incr--] = (n % 10) + '0';
195
		n /= 10;
196
		if(n == 0) break;
197
	}
198
	putstr(buf + incr + 1);
199
}
200
#else
201
void putnum(int n) {
202
	printf("%d", n);
203
	fflush(stdout);
204
}
205
 
206
void putstr(const char* n) {
207
	printf("%s", n);
208
	fflush(stdout);
209
}
210
#endif
211
 
212
void change_color(int a) {
4 nishi 213
#if defined(PLATFORM_ARDUINO) || defined(PLATFORM_UNIX)
2 nishi 214
	int fg = (a >> 4) & 0xf;
215
	int bg = (a & 0xf);
4 nishi 216
	char color[2];
2 nishi 217
	if(!(0 <= fg && fg <= 15)) return;
218
	if(!(0 <= bg && bg <= 15)) return;
219
	color[1] = 0;
3 nishi 220
	if(bg < 8) {
2 nishi 221
		color[0] = bg + '0';
222
		putstr("\x1b[4");
3 nishi 223
	} else {
2 nishi 224
		color[0] = (bg - 8) + '0';
225
		putstr("\x1b[10");
226
	}
227
	putstr(color);
228
	putstr("m");
3 nishi 229
	if(fg < 8) {
2 nishi 230
		color[0] = fg + '0';
231
		putstr("\x1b[3");
3 nishi 232
	} else {
2 nishi 233
		color[0] = (fg - 8) + '0';
234
		putstr("\x1b[9");
235
	}
236
	putstr(color);
237
	putstr("m");
238
	putstr("\x1b[2J\x1b[1;1H");
9 nishi 239
#elif defined(PLATFORM_C64) || defined(PLATFORM_A800XL) || defined(PLATFORM_APPLE2) || defined(PLATFORM_PET)
4 nishi 240
	int fg = (a >> 4) & 0xf;
241
	int bg = (a & 0xf);
242
	bgcolor(bg);
243
	textcolor(fg);
244
#endif
2 nishi 245
}
246
 
247
void clear(void) {
248
#if defined(PLATFORM_WINDOWS)
249
	system("cls");
250
#elif defined(PLATFORM_UNIX) || defined(PLATFORM_ARDUINO)
251
	putstr("\x1b[0m\x1b[2J\x1b[1;1H");
9 nishi 252
#elif defined(PLATFORM_C64) || defined(PLATFORM_A800XL) || defined(PLATFORM_APPLE2) || defined(PLATFORM_PET)
4 nishi 253
	clrscr();
2 nishi 254
#endif
255
}
256
 
257
void basic(void);
258
 
259
int main() {
9 nishi 260
#if defined(PLATFORM_PET)
261
	if(PEEK(0x9000) == POKE(0x9000, PEEK(0x9000) + 1)) {
262
		_heapadd((void*)0x9000, 0x2000);
263
	}
264
#endif
2 nishi 265
#if defined(PLATFORM_WINDOWS)
266
	HANDLE winstdout = GetStdHandle(STD_OUTPUT_HANDLE);
267
	DWORD mode = 0;
268
	GetConsoleMode(winstdout, &mode);
269
	const DWORD origmode = mode;
270
	mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
271
	SetConsoleMode(winstdout, mode);
272
#elif defined(PLATFORM_UNIX)
273
	struct termios old, new;
274
	tcgetattr(0, &old);
275
	new = old;
276
	new.c_lflag &= ~(ECHO | ICANON);
277
	tcsetattr(0, TCSANOW, &new);
278
#elif defined(PLATFORM_ARDUINO)
279
	uart_init();
280
	DDRB |= _BV(DDB5);
281
	PORTB |= _BV(PORT5);
282
#endif
9 nishi 283
#if defined(PLATFORM_C64) || defined(PLATFORM_A800XL) || defined(PLATFORM_APPLE2) || defined(PLATFORM_PET)
4 nishi 284
	change_color((1 << 4) | 0);
9 nishi 285
	bordercolor(0);
4 nishi 286
#endif
2 nishi 287
	basic();
288
#if defined(PLATFORM_WINDOWS)
289
	SetConsoleMode(winstdout, origmode);
290
#elif defined(PLATFORM_UNIX)
291
	tcsetattr(0, TCSANOW, &old);
292
#endif
293
}
294
 
295
#else
296
#error "Define PLATFORM_*"
297
#endif
298
 
299
#define VERSION "0.0"
300
 
301
#ifndef LINE_BUFFER_SIZE
302
#define LINE_BUFFER_SIZE (512)
303
#endif
304
 
305
#ifndef BUFFER_SIZE
306
#define BUFFER_SIZE (1024 * 24)
307
#endif
308
 
309
#ifndef LINES
310
#define LINES (1024)
311
#endif
312
 
313
unsigned char basicbuffer[BUFFER_SIZE];
314
char linebuf[LINE_BUFFER_SIZE];
315
 
8 nishi 316
int hexnum(char c) {
317
	if('0' <= c && c <= '9') {
318
		return c - '0';
319
	} else if('A' <= c && c <= 'F') {
320
		return c - 'A' + 10;
321
	} else if('a' <= c && c <= 'f') {
322
		return c - 'a' + 10;
323
	}
324
	return 0;
325
}
326
 
2 nishi 327
int pexpr(char* expr, char* buffer, int* number) {
328
	char ownbuf[128];
329
	int i;
330
	int start = 0;
331
	int br = 0;
332
	int result = 0;
333
	int stack[32];
334
	int sp = 0;
335
	char put = 0;
8 nishi 336
	char hex = 0;
4 nishi 337
	for(i = 0; expr[i] != 0; i++) ownbuf[i] = expr[i];
338
	ownbuf[i] = 0;
2 nishi 339
	for(i = 0; i < 32; i++) stack[i] = 0;
340
	for(i = 0;; i++) {
341
		if(ownbuf[i] == 0) {
342
			break;
8 nishi 343
		} else if(ownbuf[i] == '&' && put == 0) {
2 nishi 344
			put = 1;
8 nishi 345
			hex = 1;
346
		} else if(('0' <= ownbuf[i] && ownbuf[i] <= '9') || (hex ? ('A' <= ownbuf[i] && ownbuf[i] <= 'F') : 0) || (hex ? ('a' <= ownbuf[i] && ownbuf[i] <= 'f') : 0)) {
347
			stack[sp] *= hex ? 16 : 10;
348
			if(hex == 1) {
349
				stack[sp] += hexnum(ownbuf[i]);
350
			} else {
351
				stack[sp] += ownbuf[i] - '0';
352
			}
353
			put = 1;
354
		} else if(ownbuf[i] == 'R') {
355
			put = 0;
356
			hex = 0;
357
			if(sp < 1) {
358
				return -1;
359
			} else {
360
				int top = stack[--sp];
361
				stack[sp++] = (int)*(unsigned char*)top;
362
			}
363
			stack[sp] = 0;
2 nishi 364
		} else if(ownbuf[i] == '+' || ownbuf[i] == '-' || ownbuf[i] == '*' || ownbuf[i] == '/') {
365
			put = 0;
8 nishi 366
			hex = 0;
2 nishi 367
			if(sp < 2) {
368
				return -1;
369
			} else {
370
				int top = stack[--sp];
371
				int bottom = stack[--sp];
372
				int value = 0;
373
				if(ownbuf[i] == '+') {
374
					value = top + bottom;
375
				} else if(ownbuf[i] == '-') {
376
					value = bottom + top;
377
				} else if(ownbuf[i] == '*') {
378
					value = mull(top, bottom);
379
				} else if(ownbuf[i] == '/') {
380
					value = divl(bottom, top);
381
				}
382
				stack[sp++] = value;
383
			}
384
			stack[sp] = 0;
385
		} else if(ownbuf[i] == ' ' && put == 1) {
386
			stack[++sp] = 0;
387
		}
388
	}
389
	result = stack[0];
390
	*number = result;
391
	return 1;
392
}
393
 
394
/* arr gets sorted, arr2 index gets replaced */
395
void sort(int* arr, int* arr2, int size) {
396
	int i;
397
redo:
398
	for(i = 1; i < size; i++) {
399
		if(arr[i - 1] > arr[i]) {
400
			int tmp = arr[i];
401
			arr[i] = arr[i - 1];
402
			arr[i - 1] = tmp;
403
			tmp = arr2[i];
404
			arr2[i] = arr2[i - 1];
405
			arr2[i - 1] = tmp;
406
		}
407
	}
408
	for(i = 1; i < size; i++) {
409
		if(arr[i - 1] > arr[i]) {
410
			goto redo;
411
		}
412
	}
413
}
414
 
415
int run(char* cmd, int linenum, char num, int* lgoto) {
4 nishi 416
	char line[LINE_BUFFER_SIZE];
417
	char rcmd[32];
418
	int i;
419
	char* arg;
420
	int incr = 0;
2 nishi 421
#ifdef BREAKKEY
422
	if(agetch() == 1) return -1;
423
#endif
424
	if(lgoto != 0) *lgoto = 0;
425
	for(i = 0; cmd[i] != 0; i++) line[i] = cmd[i];
426
	line[i] = 0;
427
	rcmd[0] = 0;
428
	for(i = 0;; i++) {
429
		if(line[i] == ' ' || line[i] == '\t' || line[i] == 0 || line[i] == '"') {
430
			break;
431
		} else {
432
			rcmd[incr++] = line[i];
433
			if(incr == 32) {
434
				putstr("! Command too long");
435
				if(linenum != -1) {
436
					putstr(" in line ");
437
					putnum(linenum);
438
				}
439
				putstr(NEWLINE);
440
				return 1;
441
			}
442
			rcmd[incr] = 0;
443
		}
444
	}
4 nishi 445
	arg = line + 1 + strlen(rcmd);
2 nishi 446
	if(strcaseequ(rcmd, "COLOR")) {
447
		int argc = 0;
448
		char* farg = 0;
449
		char* sarg = 0;
4 nishi 450
		int fgcolor, bgcolor, ret0, ret1;
2 nishi 451
		if(arg[0] != 0) argc++;
452
		for(i = 0; arg[i] != 0; i++) {
453
			if(arg[i] == ',') {
454
				arg[i] = 0;
455
				farg = arg;
456
				sarg = arg + i + 1;
457
				for(; *sarg != 0 && (*sarg == '\t' || *sarg == ' '); sarg++)
458
					;
459
				argc++;
460
			}
461
		}
462
		if(argc != 2) {
463
			putstr("! Invalid argument");
464
			if(linenum != -1) {
465
				putstr(" in line ");
466
				putnum(linenum);
467
			}
468
			putstr(NEWLINE);
469
			return 1;
470
		}
4 nishi 471
		bgcolor = 0;
472
		fgcolor = 0;
473
		ret0 = pexpr(farg, 0, &bgcolor);
474
		ret1 = pexpr(sarg, 0, &fgcolor);
2 nishi 475
		if(ret0 == 0) {
476
			putstr("! Invalid argument");
477
			if(linenum != -1) {
478
				putstr(" in line ");
479
				putnum(linenum);
480
			}
481
			putstr(NEWLINE);
482
			return 1;
483
		} else if(ret0 == -1) {
484
			putstr("! Syntax error");
485
			if(linenum != -1) {
486
				putstr(" in line ");
487
				putnum(linenum);
488
			}
489
			putstr(NEWLINE);
490
			return 1;
491
		}
492
		if(ret1 == 1) {
493
			change_color((fgcolor << 4) | bgcolor);
494
		} else if(ret1 == 0) {
495
			putstr("! Invalid argument");
496
			if(linenum != -1) {
497
				putstr(" in line ");
498
				putnum(linenum);
499
			}
500
			putstr(NEWLINE);
501
			return 1;
502
		} else if(ret1 == -1) {
503
			putstr("! Syntax error");
504
			if(linenum != -1) {
505
				putstr(" in line ");
506
				putnum(linenum);
507
			}
508
			putstr(NEWLINE);
509
			return 1;
510
		}
8 nishi 511
	} else if(strcaseequ(rcmd, "POKE")) {
512
		int argc = 0;
513
		char* farg = 0;
514
		char* sarg = 0;
515
		int addr, data, ret0, ret1;
516
		if(arg[0] != 0) argc++;
517
		for(i = 0; arg[i] != 0; i++) {
518
			if(arg[i] == ',') {
519
				arg[i] = 0;
520
				farg = arg;
521
				sarg = arg + i + 1;
522
				for(; *sarg != 0 && (*sarg == '\t' || *sarg == ' '); sarg++)
523
					;
524
				argc++;
525
			}
526
		}
527
		if(argc != 2) {
528
			putstr("! Invalid argument");
529
			if(linenum != -1) {
530
				putstr(" in line ");
531
				putnum(linenum);
532
			}
533
			putstr(NEWLINE);
534
			return 1;
535
		}
536
		addr = 0;
537
		data = 0;
538
		ret0 = pexpr(farg, 0, &addr);
539
		ret1 = pexpr(sarg, 0, &data);
540
		if(ret0 == 0) {
541
			putstr("! Invalid argument");
542
			if(linenum != -1) {
543
				putstr(" in line ");
544
				putnum(linenum);
545
			}
546
			putstr(NEWLINE);
547
			return 1;
548
		} else if(ret0 == -1) {
549
			putstr("! Syntax error");
550
			if(linenum != -1) {
551
				putstr(" in line ");
552
				putnum(linenum);
553
			}
554
			putstr(NEWLINE);
555
			return 1;
556
		}
557
		if(ret1 == 1) {
558
			unsigned char* a = (unsigned char*)addr;
559
			*a = data;
560
		} else if(ret1 == 0) {
561
			putstr("! Invalid argument");
562
			if(linenum != -1) {
563
				putstr(" in line ");
564
				putnum(linenum);
565
			}
566
			putstr(NEWLINE);
567
			return 1;
568
		} else if(ret1 == -1) {
569
			putstr("! Syntax error");
570
			if(linenum != -1) {
571
				putstr(" in line ");
572
				putnum(linenum);
573
			}
574
			putstr(NEWLINE);
575
			return 1;
576
		}
2 nishi 577
	} else if(num == 0 && strcaseequ(rcmd, "LIST")) {
578
		int addr = BUFFER_SIZE - 1;
579
		int saddr = 0;
580
		int lbuf[LINES];
581
		int shift[LINES];
582
		int cnt = 0;
4 nishi 583
		int i;
2 nishi 584
		while(1) {
585
			unsigned long ln = 0;
586
			for(i = 0; i < 4; i++) {
587
				ln >>= 8;
588
				ln |= (unsigned long)basicbuffer[addr--] << 24;
589
			}
590
			if(ln == 0) break;
591
			lbuf[cnt] = ln;
592
			shift[cnt++] = saddr;
593
			saddr += strlen(basicbuffer + saddr) + 1;
594
		}
595
		sort(lbuf, shift, cnt);
596
		for(i = 0; i < cnt; i++) {
597
			putnum(lbuf[i]);
598
			putstr(" ");
599
			putstr(basicbuffer + shift[i]);
600
			putstr(NEWLINE);
601
		}
602
	} else if(num == 1 && strcaseequ(rcmd, "GOTO")) {
603
		int ret = pexpr(arg, 0, lgoto);
604
		if(ret == 0) {
605
			putstr("! Invalid argument");
606
			if(linenum != -1) {
607
				putstr(" in line ");
608
				putnum(linenum);
609
			}
610
			putstr(NEWLINE);
611
			return 1;
612
		} else if(ret == -1) {
613
			putstr("! Syntax error");
614
			if(linenum != -1) {
615
				putstr(" in line ");
616
				putnum(linenum);
617
			}
618
			putstr(NEWLINE);
619
			return 1;
620
		}
621
	} else if(num == 0 && strcaseequ(rcmd, "RUN")) {
622
		int addr = BUFFER_SIZE - 1;
623
		int saddr = 0;
624
		int lbuf[LINES];
625
		int shift[LINES];
626
		int cnt = 0;
4 nishi 627
		int gt, i;
2 nishi 628
		while(1) {
629
			unsigned long ln = 0;
630
			for(i = 0; i < 4; i++) {
631
				ln >>= 8;
632
				ln |= (unsigned long)basicbuffer[addr--] << 24;
633
			}
634
			if(ln == 0) break;
635
			lbuf[cnt] = ln;
636
			shift[cnt++] = saddr;
637
			saddr += strlen(basicbuffer + saddr) + 1;
638
		}
639
		sort(lbuf, shift, cnt);
640
		for(i = 0; i < cnt; i++) {
641
			int ret = run(basicbuffer + shift[i], lbuf[i], 1, &gt);
642
			if(ret != 0) return ret;
643
			if(gt != 0) {
4 nishi 644
				char found;
2 nishi 645
				for(i = 0; i < cnt; i++) {
646
					if(lbuf[i] == gt) {
647
						found = 1;
648
						break;
649
					}
650
				}
651
				if(found) {
652
					i--;
653
				} else {
654
					putstr("! GOTO no such line");
655
					if(linenum != -1) {
656
						putstr(" in line ");
657
						putnum(linenum);
658
					}
659
					putstr(NEWLINE);
660
					return 1;
661
				}
662
			}
663
		}
664
	} else {
665
		putstr("! Unknown command");
666
		if(linenum != -1) {
667
			putstr(" in line ");
668
			putnum(linenum);
669
		}
670
		putstr(NEWLINE);
671
		return 1;
672
	}
673
	return 0;
674
}
675
 
676
int execute(int linenum, char* cmd, char num) {
677
	int i;
678
	char line[LINE_BUFFER_SIZE];
679
	int incr = 0;
680
	char dq = 0;
681
	for(i = 0; cmd[i] != 0; i++) {
682
		if(cmd[i] == ' ' || cmd[i] == '\t') {
683
			if(!dq) {
684
				for(; cmd[i] != 0 && (cmd[i] == ' ' || cmd[i] == '\t'); i++)
685
					;
686
				i--;
687
			}
688
			line[incr++] = cmd[i];
689
		} else if(cmd[i] == '"') {
690
			line[incr++] = '"';
691
			dq = dq == 0 ? 1 : 0;
692
		} else {
693
			line[incr++] = dq == 0 ? toupper(cmd[i]) : cmd[i];
694
		}
695
	}
696
	line[incr] = 0;
697
	if(num == 0) {
698
		int ret = run(line, -1, 0, 0);
6 nishi 699
		putstr("Ready");
700
		putstr(NEWLINE);
2 nishi 701
		return ret;
702
	} else {
703
		int addr = BUFFER_SIZE - 1;
704
		int i;
705
		int shf = 0;
706
		int cnt = 0;
4 nishi 707
		int len;
2 nishi 708
		while(1) {
709
			unsigned long ln = 0;
710
			for(i = 0; i < 4; i++) {
711
				ln >>= 8;
712
				ln |= (unsigned long)basicbuffer[addr--] << 24;
713
			}
714
			cnt++;
715
			if(ln == linenum) shf = cnt;
716
			if(shf != 0) {
717
				addr += 4;
718
				for(i = 0; i < 4; i++) {
719
					basicbuffer[addr] = basicbuffer[addr - 4 * shf];
720
					addr--;
721
				}
722
				addr += 4;
723
				ln = 0;
724
				for(i = 0; i < 4; i++) {
725
					ln >>= 8;
726
					ln |= (unsigned long)basicbuffer[addr--] << 24;
727
				}
728
			}
729
			if(ln == 0) break;
730
		}
731
		if(line[0] != 0) {
732
			addr += 4;
733
			for(i = 0; i < 4; i++) {
734
				basicbuffer[addr--] = linenum & 0xff;
735
				linenum >>= 8;
736
			}
737
		}
4 nishi 738
		len = 0;
2 nishi 739
		cnt = 0;
740
		while(1) {
741
			int slen = strlen(basicbuffer + len);
742
			if(slen == 0) break;
743
			len += slen + 1;
744
			cnt++;
745
		}
746
		if(line[0] != 0) {
747
			for(i = 0; line[i] != 0; i++) {
748
				basicbuffer[len + i] = line[i];
749
			}
750
			basicbuffer[len + i] = 0;
751
			basicbuffer[len + i + 1] = 0;
752
		}
753
		if(shf != 0) {
754
			cnt = 0;
755
			len = 0;
756
			while(1) {
757
				int slen = strlen(basicbuffer + len);
758
				if(slen == 0) break;
759
 
760
				len += slen + 1;
761
				cnt++;
762
 
763
				if(cnt == shf) {
764
					int i;
765
					int nc = 0;
4 nishi 766
					len -= slen + 1;
2 nishi 767
					for(i = len;; i++) {
768
						basicbuffer[i] = basicbuffer[i + slen + 1];
769
						if(basicbuffer[i] == 0) {
770
							nc++;
771
							if(nc == 2) break;
772
						} else {
773
							nc = 0;
774
						}
775
					}
776
					break;
777
				}
778
			}
779
		}
780
		return 0;
781
	}
782
}
783
 
784
void basic(void) {
785
	int i;
4 nishi 786
	int lineind;
2 nishi 787
	clear();
788
 
789
#ifdef SMALL
790
	putstr("Krakow BASIC  Ver. ");
791
	putstr(VERSION);
792
	putstr(NEWLINE);
793
	putstr(NEWLINE);
794
#else
795
	putstr(PLATFORM);
796
	putstr("   Krakow BASIC V");
797
	putstr(VERSION);
6 nishi 798
	putstr(NEWLINE);
799
	putstr("Copyright 2024 by: Nishi.");
800
	putstr(NEWLINE);
2 nishi 801
	putstr("                   penguin2233.");
802
	putstr(NEWLINE);
803
	putstr(NEWLINE);
804
	putstr(" Max ");
805
	putnum(LINE_BUFFER_SIZE);
806
	putstr(" characters per line");
807
	putstr(NEWLINE);
808
	putstr(" Max ");
809
	putnum(LINES);
810
	putstr(" lines");
811
	putstr(NEWLINE);
812
	putstr(" ");
813
#endif
814
	putnum(BUFFER_SIZE);
815
	putstr(" bytes free");
816
	putstr(NEWLINE);
817
	putstr(NEWLINE);
818
 
819
	for(i = 0; i < BUFFER_SIZE; i++) {
820
		basicbuffer[i] = 0;
821
	}
822
	putstr("Ready");
823
	putstr(NEWLINE);
824
 
825
	cursor();
826
	linebuf[0] = 0;
4 nishi 827
	lineind = 0;
2 nishi 828
	while(1) {
4 nishi 829
		char c;
9 nishi 830
#if defined(PLATFORM_C64) || defined(PLATFORM_A800XL) || defined(PLATFORM_APPLE2) || defined(PLATFORM_PET)
4 nishi 831
		c = oggetch(1);
832
#else
833
		c = agetch();
834
#endif
8 nishi 835
		if(c != 0) {
836
			killcursor();
837
		}
2 nishi 838
		if(c == 1) {
839
			putstr("Break");
840
			putstr(NEWLINE);
841
			lineind = 0;
842
		} else if(c == '\n') {
4 nishi 843
			int i;
844
			char num = 1;
845
			char* cmd = linebuf;
846
 
2 nishi 847
			linebuf[lineind] = 0;
848
			putstr(NEWLINE);
849
			if(lineind == 0) goto skip;
850
 
851
			for(i = 0; linebuf[i] != 0; i++) {
852
				if(linebuf[i] == ' ') {
853
					linebuf[i] = 0;
854
					cmd = linebuf + i + 1;
855
					break;
856
				} else if(!('0' <= linebuf[i] && linebuf[i] <= '9')) {
857
					num = 0;
858
					break;
859
				}
860
			}
861
 
862
			if(num == 1 && strnum(linebuf) == 0) {
863
				putstr("! Line number 0 is illegal");
864
				putstr(NEWLINE);
865
			} else {
866
				int ret = execute(num == 1 ? strnum(linebuf) : -1, (num == 1 && cmd == linebuf) ? "" : cmd, num);
867
				if(ret == -1) {
868
					putstr("! Break");
869
					putstr(NEWLINE);
870
				}
871
			}
872
 
873
		skip:
874
			lineind = 0;
875
		} else if(c == 0x8 || c == 0x7f) {
876
			if(lineind > 0) {
6 nishi 877
#if defined(PLATFORM_A800XL)
878
				putstr("\x7e \x7e");
879
#else
2 nishi 880
				putstr("\x08 \x08");
6 nishi 881
#endif
2 nishi 882
				linebuf[--lineind] = 0;
883
			}
884
		} else if(c == -1) {
885
			break;
886
		} else if(c != 0) {
887
			putchar(c);
888
			linebuf[lineind++] = c;
889
		}
890
		cursor();
891
	}
892
}