fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
1/*****************************************************************************
2 * pce *
3 *****************************************************************************/
4
5/*****************************************************************************
6 * File name: src/lib/text.c *
7 * Created: 2021-11-30 by Hampa Hug <hampa@hampa.ch> *
8 * Copyright: (C) 2021-2023 Hampa Hug <hampa@hampa.ch> *
9 *****************************************************************************/
10
11/*****************************************************************************
12 * This program is free software. You can redistribute it and / or modify it *
13 * under the terms of the GNU General Public License version 2 as published *
14 * by the Free Software Foundation. *
15 * *
16 * This program is distributed in the hope that it will be useful, but *
17 * WITHOUT ANY WARRANTY, without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General *
19 * Public License for more details. *
20 *****************************************************************************/
21
22
23#include <config.h>
24
25#include <stdlib.h>
26#include <string.h>
27
28#include "text.h"
29
30
31void txt_init (pce_text_t *ctx, FILE *fp)
32{
33 memset (ctx, 0, sizeof (pce_text_t));
34
35 ctx->fp = fp;
36}
37
38void txt_free (pce_text_t *ctx)
39{
40}
41
42int txt_putc (pce_text_t *ctx, int c)
43{
44 return (fputc (c, ctx->fp));
45}
46
47int txt_error (pce_text_t *ctx, const char *str)
48{
49 int c;
50
51 if (str == NULL) {
52 str = "unknown";
53 }
54
55 c = txt_getc (ctx, 0);
56
57 fprintf (stderr, "pce-text:%u: error (%s), next = %02X\n",
58 ctx->line + 1, str, c
59 );
60
61 return (1);
62}
63
64int txt_getc (pce_text_t *ctx, unsigned idx)
65{
66 int c;
67 unsigned i;
68
69 if (idx >= sizeof (ctx->buf)) {
70 return (EOF);
71 }
72
73 for (i = ctx->cnt; i <= idx; i++) {
74 if ((c = fgetc (ctx->fp)) == EOF) {
75 return (EOF);
76 }
77
78 ctx->buf[ctx->cnt++] = c;
79 }
80
81 return (ctx->buf[idx]);
82}
83
84void txt_skip (pce_text_t *ctx, unsigned cnt)
85{
86 unsigned i;
87
88 if (cnt >= ctx->cnt) {
89 cnt -= ctx->cnt;
90 ctx->cnt = 0;
91
92 while (cnt-- > 0) {
93 if (fgetc (ctx->fp) == EOF) {
94 return;
95 }
96 }
97 }
98 else {
99 for (i = cnt; i < ctx->cnt; i++) {
100 ctx->buf[i - cnt] = ctx->buf[i];
101 }
102
103 ctx->cnt -= cnt;
104 }
105}
106
107int txt_match_space (pce_text_t *ctx)
108{
109 int c, cr, ok, line;
110
111 line = 0;
112 ok = 0;
113 cr = 0;
114
115 while (1) {
116 if ((c = txt_getc (ctx, 0)) == EOF) {
117 return (ok);
118 }
119
120 if (c == 0x0d) {
121 line = 0;
122 ctx->line += 1;
123 }
124 else if (c == 0x0a) {
125 line = 0;
126
127 if (cr == 0) {
128 ctx->line += 1;
129 }
130 }
131 else if (line) {
132 ;
133 }
134 else if ((c == '\t') || (c == ' ')) {
135 ;
136 }
137 else if ((c == '#') || (c == ';')) {
138 line = 1;
139 }
140 else {
141 return (ok);
142 }
143
144 cr = (c == 0x0d);
145 ok = 1;
146
147 txt_skip (ctx, 1);
148 }
149}
150
151int txt_match_eol (pce_text_t *ctx)
152{
153 int c, line;
154
155 line = 0;
156
157 while (1) {
158 if ((c = txt_getc (ctx, 0)) == EOF) {
159 return (1);
160 }
161
162 if (c == 0x0d) {
163 ctx->line += 1;
164 txt_skip (ctx, (txt_getc (ctx, 1) == 0x0a) ? 2 : 1);
165
166 return (1);
167 }
168 else if (c == 0x0a) {
169 ctx->line += 1;
170 txt_skip (ctx, 1);
171
172 return (1);
173 }
174 else if (line) {
175 ;
176 }
177 else if ((c == '\t') || (c == ' ')) {
178 ;
179 }
180 else if ((c == '#') || (c == ';')) {
181 line = 1;
182 }
183 else {
184 return (0);
185 }
186
187 txt_skip (ctx, 1);
188 }
189}
190
191int txt_match (pce_text_t *ctx, const char *str, int skip)
192{
193 int c;
194 unsigned i, n;
195
196 txt_match_space (ctx);
197
198 n = 0;
199
200 while (str[n] != 0) {
201 if (n >= ctx->cnt) {
202 if ((c = fgetc (ctx->fp)) == EOF) {
203 return (0);
204 }
205
206 ctx->buf[ctx->cnt++] = c;
207 }
208
209 if (ctx->buf[n] != str[n]) {
210 return (0);
211 }
212
213 n += 1;
214 }
215
216 if (skip) {
217 for (i = n; i < ctx->cnt; i++) {
218 ctx->buf[i - n] = ctx->buf[i];
219 }
220
221 ctx->cnt -= n;
222 }
223
224 return (1);
225}
226
227int txt_match_string (pce_text_t *ctx, char *str, unsigned max)
228{
229 int c, esc, quote;
230 unsigned idx;
231
232 txt_match_space (ctx);
233
234 if ((c = txt_getc (ctx, 0)) != '"') {
235 return (0);
236 }
237
238 quote = '"';
239
240 txt_skip (ctx, 1);
241
242 idx = 0;
243 esc = 0;
244
245 while (idx < max) {
246 if ((c = txt_getc (ctx, 0)) == EOF) {
247 return (0);
248 }
249
250 txt_skip (ctx, 1);
251
252 if (esc) {
253 idx -= 1;
254
255 if (c == 'n') {
256 c = 0x0a;
257 }
258 else if (c == 'r') {
259 c = 0x0d;
260 }
261 else if (c == 't') {
262 c = 0x09;
263 }
264 else if (c == '\\') {
265 c = '\\';
266 }
267 else if (c == '"') {
268 c = '"';
269 }
270 else {
271 idx += 1;
272 }
273
274 esc = 0;
275 }
276 else if (c == '\\') {
277 esc = 1;
278 }
279 else if (c == quote) {
280 break;
281 }
282
283 str[idx++] = c;
284 }
285
286 if (idx >= max) {
287 return (0);
288 }
289
290 str[idx] = 0;
291
292 return (1);
293}
294
295int txt_match_hex_digit (pce_text_t *ctx, unsigned *val)
296{
297 int c;
298
299 c = txt_getc (ctx, 0);
300
301 if ((c >= '0') && (c <= '9')) {
302 *val = c - '0';
303 }
304 else if ((c >= 'A') && (c <= 'F')) {
305 *val = c - 'A' + 10;
306 }
307 else if ((c >= 'a') && (c <= 'f')) {
308 *val = c - 'a' + 10;
309 }
310 else {
311 return (0);
312 }
313
314 txt_skip (ctx, 1);
315
316 return (1);
317}
318
319int txt_match_uint (pce_text_t *ctx, unsigned base, unsigned long *val)
320{
321 unsigned i, dig;
322 int c, s, ok;
323
324 txt_match_space (ctx);
325
326 i = 0;
327 s = 0;
328 ok = 0;
329
330 c = txt_getc (ctx, i);
331
332 if ((c == '-') || (c == '+')) {
333 s = (c == '-');
334
335 c = txt_getc (ctx, ++i);
336 }
337
338 *val = 0;
339
340 while (1) {
341 if ((c >= '0') && (c <= '9')) {
342 dig = c - '0';
343 }
344 else if ((c >= 'a') && (c <= 'z')) {
345 dig = c - 'a' + 10;
346 }
347 else if ((c >= 'A') && (c <= 'Z')) {
348 dig = c - 'A' + 10;
349 }
350 else {
351 break;
352 }
353
354 if (dig >= base) {
355 return (0);
356 }
357
358 *val = base * *val + dig;
359 ok = 1;
360
361 c = txt_getc (ctx, ++i);
362 }
363
364 if (ok == 0) {
365 return (0);
366 }
367
368 if (s) {
369 *val = ~*val + 1;
370 }
371
372 txt_skip (ctx, i);
373
374 return (1);
375}