Subversion Repositories Krakow BASIC

Rev

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