xplshn
·
2025-08-13
uxn.b
B
1/* Standard Library for the Uxn target */
2
3fputc(c, fd) {
4 extrn uxn_deo;
5 uxn_deo(fd + 0x18, c); /* 0x18 - Console/write,
6 0x19 - Console/error */
7}
8
9putchar(c) {
10 fputc(c, 0);
11}
12
13exit(code) {
14 extrn uxn_deo;
15 uxn_deo(0x0f, code | 0x80); /* System/state */
16}
17
18abort() {
19 extrn printf;
20 printf("Aborted\n");
21 exit(1);
22}
23
24_udiv(a, b) {
25 extrn uxn_div2;
26 return (uxn_div2(a, b));
27}
28
29// TODO: `b` has to be <32768, because of `*`
30_urem(a, b) {
31 return (a - _udiv(a, b) * b);
32}
33
34/* loosely based on the original code by Ken Thompson */
35
36_fprintn(n, b, fd) {
37 auto a, c;
38
39 if(a=_udiv(n,b)) /* assignment, not test for equality */
40 _fprintn(a, b, fd); /* recursive */
41 c = _urem(n,b) + '0';
42 if (c > '9') c += 7;
43 fputc(c, fd);
44}
45
46printn(n, b) _fprintn(n, b, 0);
47
48/* doesn't support fancy features like padding, but neither did the original in B */
49
50/* TODO: Consider adding support for negative numbers to Uxn's printf. */
51/* TODO: Consider adding support for %ul to Uxn's printf. */
52fprintf(fd, string, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12) {
53 extrn char;
54 auto i, j, c, arg;
55 i = 0;
56 j = 0;
57 c = char(string, i);
58 arg = &x1;
59 while (c != 0) {
60 if (c == '%') {
61 i += 1;
62 c = char(string, i);
63 if (c == 0) {
64 return;
65 } else if (c == 'x') {
66 _fprintn(*arg, 16, fd);
67 } else if (c == 'd') {
68 if (*arg < 0) {
69 fputc('-', fd);
70 *arg = -*arg;
71 }
72 _fprintn(*arg, 10, fd);
73 } else if (c == 'u') {
74 _fprintn(*arg, 10, fd);
75 } else if (c == 'o') {
76 _fprintn(*arg, 8, fd);
77 } else if (c == 'c') {
78 fputc(*arg, fd);
79 } else if (c == 's') { /* clobbers `c`, the last one */
80 while (c = char(*arg, j++)) {
81 fputc(c, fd);
82 }
83 } else if (c == 'l' | c == 'z') {
84 c = '%';
85 goto continue;
86 } else {
87 fputc('%', fd);
88 arg += 2; /* word size */
89 }
90 arg -= 2; /* word size */
91 } else {
92 fputc(c, fd);
93 }
94 i += 1;
95 c = char(string, i);
96 continue:;
97 }
98}
99
100printf(string, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12) {
101 fprintf(0, string, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12);
102}
103
104// TODO: doesn't skip whitespace, doesn't handle negative numbers
105atoi(s) {
106 extrn char;
107 auto i, result, c;
108 i = 0;
109 while (1) {
110 c = char(s, i++);
111 if (c < '0' | c > '9') {
112 goto out;
113 }
114 result = result * 10 + (c - '0');
115 }
116out:
117 return (result);
118}
119
120/* simple bump allocator */
121
122__alloc_ptr;
123
124malloc(size) {
125 auto ret;
126 if (__alloc_ptr == 0) {
127 __alloc_ptr = 0x8000; /* provide __heap_base by the compiler? */
128 }
129 ret = __alloc_ptr;
130 __alloc_ptr += size;
131 return (ret);
132}
133
134memset(addr, val, size) {
135 extrn lchar;
136 auto i;
137 i = 0;
138 while (i < size) {
139 lchar(addr, i, val);
140 i += 1;
141 }
142}
143
144stdout; stderr;
145
146_args_count;
147_args_items;
148_prog_name;
149
150_start_with_arguments() {
151 extrn uxn_dei, uxn_deo2, lchar, main;
152 auto type, c;
153 type = uxn_dei(0x17); /* Console/type */
154 c = uxn_dei(0x12);
155 if (type == 2) { /* argument */
156 lchar(__alloc_ptr++, 0, c);
157 } else if (type == 3) { /* argument spacer */
158 lchar(__alloc_ptr++, 0, 0);
159 *(_args_items + (_args_count++)*2) = __alloc_ptr;
160 } else if (type == 4) { /* arguments end */
161 lchar(__alloc_ptr++, 0, 0);
162 uxn_deo2(0x10, 0);
163 exit(main(_args_count, _args_items));
164 }
165}
166
167_start() {
168 extrn main, uxn_dei, uxn_deo2;
169 __alloc_ptr = 0x8000;
170 _args_items = 0x7f00; /* 128 arguments ought to be enough for everyone */
171 stdout = 0;
172 stderr = 1;
173 _prog_name = "-"; /* we don't have access to it */
174 *_args_items = _prog_name;
175 _args_count = 1;
176 if (uxn_dei(0x17) != 0) {
177 *(_args_items + (_args_count++)*2) = __alloc_ptr;
178 uxn_deo2(0x10, &_start_with_arguments);
179 } else {
180 exit(main(_args_count, _args_items));
181 }
182}
183
184strlen(s) {
185 auto n;
186 n = 0;
187 while (*s++) n++;
188 return (n);
189}
190
191toupper(c) {
192 if ('a' <= c & c <= 'z') return (c - 'a' + 'A');
193 return (c);
194}