Skip to content

Commit 0a692ed

Browse files
committed
useful script
1 parent 947d6eb commit 0a692ed

File tree

4 files changed

+87
-6
lines changed

4 files changed

+87
-6
lines changed

basic.c

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -848,7 +848,8 @@ enum func_code {
848848
FN_ARG = 26,
849849
FN_INSTR = 27,
850850
FN_DEC = 28,
851-
FN_HEX = 29
851+
FN_HEX = 29,
852+
FN_STRINGFN = 30
852853
};
853854

854855
/* Report an error and halt further execution.
@@ -1520,6 +1521,9 @@ static int function_lookup(const char *name, int len)
15201521
if ((len == 3 && name[0] == 'S' && name[1] == 'T' && name[2] == 'R') ||
15211522
(len == 4 && name[0] == 'S' && name[1] == 'T' && name[2] == 'R' && name[3] == '$')) return FN_STR;
15221523
if (len == 3 && name[0] == 'S' && name[1] == 'P' && name[2] == 'C') return FN_SPC;
1524+
if ((len == 6 && name[0] == 'S' && name[1] == 'T' && name[2] == 'R' && name[3] == 'I' && name[4] == 'N' && name[5] == 'G') ||
1525+
(len == 7 && name[0] == 'S' && name[1] == 'T' && name[2] == 'R' && name[3] == 'I' && name[4] == 'N' && name[5] == 'G' && name[6] == '$'))
1526+
return FN_STRINGFN;
15231527
if (len == 6 && name[0] == 'S' && name[1] == 'Y' && name[2] == 'S' && name[3] == 'T' && name[4] == 'E' && name[5] == 'M') return FN_SYSTEM;
15241528
return FN_NONE;
15251529
case 'C':
@@ -1868,7 +1872,7 @@ static struct value eval_function(const char *name, char **p)
18681872
* the closing ')'. For all other intrinsics we expect exactly one
18691873
* argument and consume ')' here so the caller resumes after it.
18701874
*/
1871-
if (code != FN_MID && code != FN_LEFT && code != FN_RIGHT && code != FN_INSTR) {
1875+
if (code != FN_MID && code != FN_LEFT && code != FN_RIGHT && code != FN_INSTR && code != FN_STRINGFN) {
18721876
if (**p == ')') {
18731877
(*p)++;
18741878
} else {
@@ -2321,6 +2325,58 @@ static struct value eval_function(const char *name, char **p)
23212325
sprintf(outbuf, "%lX", v);
23222326
return make_str(outbuf);
23232327
}
2328+
case FN_STRINGFN: {
2329+
/* STRING$(n, char$) or STRING$(n, code) */
2330+
struct value v_count = arg;
2331+
struct value v_ch;
2332+
int count;
2333+
char ch;
2334+
2335+
ensure_num(&v_count);
2336+
skip_spaces(p);
2337+
if (**p != ',') {
2338+
runtime_error("STRING$ requires 2 arguments");
2339+
return make_str("");
2340+
}
2341+
(*p)++;
2342+
v_ch = eval_expr(p);
2343+
skip_spaces(p);
2344+
if (**p == ')') {
2345+
(*p)++;
2346+
} else {
2347+
runtime_error("Missing ')'");
2348+
return make_str("");
2349+
}
2350+
2351+
count = (int)v_count.num;
2352+
if (count <= 0) {
2353+
return make_str("");
2354+
}
2355+
if (count >= MAX_STR_LEN) {
2356+
count = MAX_STR_LEN - 1;
2357+
}
2358+
2359+
if (v_ch.type == VAL_STR) {
2360+
if (v_ch.str[0] == '\0') {
2361+
ch = ' ';
2362+
} else {
2363+
ch = v_ch.str[0];
2364+
}
2365+
} else {
2366+
/* Treat numeric second arg as character code. */
2367+
ch = (char)((int)v_ch.num & 0xff);
2368+
}
2369+
2370+
{
2371+
char out[MAX_STR_LEN];
2372+
int i;
2373+
for (i = 0; i < count; i++) {
2374+
out[i] = ch;
2375+
}
2376+
out[count] = '\0';
2377+
return make_str(out);
2378+
}
2379+
}
23242380
case FN_UCASE: {
23252381
char out[MAX_STR_LEN];
23262382
size_t i, n;
@@ -2626,7 +2682,7 @@ static struct value eval_factor(char **p)
26262682
starts_with_kw(*p, "RND") || starts_with_kw(*p, "LEN") || starts_with_kw(*p, "VAL") ||
26272683
starts_with_kw(*p, "STR") || starts_with_kw(*p, "CHR") || starts_with_kw(*p, "ASC") ||
26282684
starts_with_kw(*p, "TAB") || starts_with_kw(*p, "SPC") || starts_with_kw(*p, "MID") ||
2629-
starts_with_kw(*p, "LEFT") || starts_with_kw(*p, "RIGHT") ||
2685+
starts_with_kw(*p, "LEFT") || starts_with_kw(*p, "RIGHT") || starts_with_kw(*p, "STRING") ||
26302686
starts_with_kw(*p, "UCASE") || starts_with_kw(*p, "LCASE") ||
26312687
starts_with_kw(*p, "INSTR") || starts_with_kw(*p, "DEC") || starts_with_kw(*p, "HEX") ||
26322688
starts_with_kw(*p, "ARGC") || starts_with_kw(*p, "ARG") ||

examples/delete-tag.bas

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
5 REM Delete a git tag vX.Y.Z locally and on origin
2+
10 IF ARGC() <> 1 THEN GOTO 40
3+
4+
20 VER$ = ARG$(1)
5+
30 GOTO 70
6+
7+
40 PRINT "Usage: delete-tag.bas <version>"
8+
50 PRINT "Example: delete-tag.bas 1.1.3"
9+
60 END
10+
11+
70 TAG$ = "v" + VER$
12+
80 PRINT "Deleting local tag "; TAG$
13+
90 CMD$ = "git tag -d " + TAG$
14+
100 RC = SYSTEM(CMD$)
15+
110 PRINT "SYSTEM returned "; RC
16+
17+
120 PRINT "Deleting remote tag "; TAG$
18+
130 CMD$ = "git push origin --delete " + TAG$
19+
140 RC = SYSTEM(CMD$)
20+
150 PRINT "SYSTEM returned "; RC
21+
22+
160 END

tests/trek_strings.bas

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
5 REM Regression tests for string slicing patterns used in trek.bas
2-
3-
REM Basic LEFT$/RIGHT$ behaviour
2+
6 REM Basic LEFT$/RIGHT$ behaviour
43
10 A$="ABCDEFG"
54
20 PRINT RIGHT$(A$,5) : REM Expect CDEFG
65
30 PRINT LEFT$(A$,5) : REM Expect ABCDE
76

8-
REM Quadrant insertion-style splice like trek.bas line 5440
7+
35 REM Quadrant insertion-style splice like trek.bas line 5440
98
40 Q$=STRING$(190,".") : REM 190 dots
109
50 A$="XYZ"
1110
60 S8=10

to-do.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@
4141
* Allow splitting larger programs into multiple source files / libraries while preserving line-numbered semantics
4242
* Consider search paths and guarding against recursive includes
4343

44+
* Shebang-aware loader
45+
* Teach `load_program` to ignore an initial `#!...` shebang line before deciding numbered vs numberless mode
46+
* Allow Unix-style executable BASIC scripts with a shebang (`#!/usr/bin/env ./basic`) without triggering the "mixed numbered and numberless" error
47+
4448
---
4549

4650
**Completed (removed from list):**

0 commit comments

Comments
 (0)