]>
Commit | Line | Data |
---|---|---|
14c7c974 A |
1 | /* |
2 | * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
f083c6c3 A |
6 | * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. |
7 | * | |
8 | * This file contains Original Code and/or Modifications of Original Code | |
9 | * as defined in and that are subject to the Apple Public Source License | |
10 | * Version 2.0 (the 'License'). You may not use this file except in | |
11 | * compliance with the License. Please obtain a copy of the License at | |
12 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
13 | * file. | |
14c7c974 A |
14 | * |
15 | * The Original Code and all software distributed under the License are | |
f083c6c3 | 16 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER |
14c7c974 A |
17 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
18 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
f083c6c3 A |
19 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. |
20 | * Please see the License for the specific language governing rights and | |
21 | * limitations under the License. | |
14c7c974 A |
22 | * |
23 | * @APPLE_LICENSE_HEADER_END@ | |
24 | */ | |
25 | /* nasmlib.c library routines for the Netwide Assembler | |
26 | * | |
27 | * The Netwide Assembler is copyright (C) 1996 Simon Tatham and | |
28 | * Julian Hall. All rights reserved. The software is | |
29 | * redistributable under the licence given in the file "Licence" | |
30 | * distributed in the NASM archive. | |
31 | */ | |
32 | ||
33 | #include <stdio.h> | |
34 | #include <stdlib.h> | |
35 | #include <string.h> | |
36 | #include <ctype.h> | |
37 | ||
38 | #include "nasm.h" | |
39 | #include "nasmlib.h" | |
40 | ||
41 | static efunc nasm_malloc_error; | |
42 | ||
43 | #ifdef LOGALLOC | |
44 | static FILE *logfp; | |
45 | #endif | |
46 | ||
47 | void nasm_set_malloc_error (efunc error) { | |
48 | nasm_malloc_error = error; | |
49 | #ifdef LOGALLOC | |
50 | logfp = fopen ("malloc.log", "w"); | |
51 | setvbuf (logfp, NULL, _IOLBF, BUFSIZ); | |
52 | fprintf (logfp, "null pointer is %p\n", NULL); | |
53 | #endif | |
54 | } | |
55 | ||
56 | #ifdef LOGALLOC | |
57 | void *nasm_malloc_log (char *file, int line, size_t size) | |
58 | #else | |
59 | void *nasm_malloc (size_t size) | |
60 | #endif | |
61 | { | |
62 | void *p = malloc(size); | |
63 | if (!p) | |
64 | nasm_malloc_error (ERR_FATAL | ERR_NOFILE, "out of memory"); | |
65 | #ifdef LOGALLOC | |
66 | else | |
67 | fprintf(logfp, "%s %d malloc(%ld) returns %p\n", | |
68 | file, line, (long)size, p); | |
69 | #endif | |
70 | return p; | |
71 | } | |
72 | ||
73 | #ifdef LOGALLOC | |
74 | void *nasm_realloc_log (char *file, int line, void *q, size_t size) | |
75 | #else | |
76 | void *nasm_realloc (void *q, size_t size) | |
77 | #endif | |
78 | { | |
79 | void *p = q ? realloc(q, size) : malloc(size); | |
80 | if (!p) | |
81 | nasm_malloc_error (ERR_FATAL | ERR_NOFILE, "out of memory"); | |
82 | #ifdef LOGALLOC | |
83 | else if (q) | |
84 | fprintf(logfp, "%s %d realloc(%p,%ld) returns %p\n", | |
85 | file, line, q, (long)size, p); | |
86 | else | |
87 | fprintf(logfp, "%s %d malloc(%ld) returns %p\n", | |
88 | file, line, (long)size, p); | |
89 | #endif | |
90 | return p; | |
91 | } | |
92 | ||
93 | #ifdef LOGALLOC | |
94 | void nasm_free_log (char *file, int line, void *q) | |
95 | #else | |
96 | void nasm_free (void *q) | |
97 | #endif | |
98 | { | |
99 | if (q) { | |
100 | free (q); | |
101 | #ifdef LOGALLOC | |
102 | fprintf(logfp, "%s %d free(%p)\n", | |
103 | file, line, q); | |
104 | #endif | |
105 | } | |
106 | } | |
107 | ||
108 | #ifdef LOGALLOC | |
109 | char *nasm_strdup_log (char *file, int line, char *s) | |
110 | #else | |
111 | char *nasm_strdup (char *s) | |
112 | #endif | |
113 | { | |
114 | char *p; | |
115 | int size = strlen(s)+1; | |
116 | ||
117 | p = malloc(size); | |
118 | if (!p) | |
119 | nasm_malloc_error (ERR_FATAL | ERR_NOFILE, "out of memory"); | |
120 | #ifdef LOGALLOC | |
121 | else | |
122 | fprintf(logfp, "%s %d strdup(%ld) returns %p\n", | |
123 | file, line, (long)size, p); | |
124 | #endif | |
125 | strcpy (p, s); | |
126 | return p; | |
127 | } | |
128 | ||
129 | #ifdef LOGALLOC | |
130 | char *nasm_strndup_log (char *file, int line, char *s, size_t len) | |
131 | #else | |
132 | char *nasm_strndup (char *s, size_t len) | |
133 | #endif | |
134 | { | |
135 | char *p; | |
136 | int size = len+1; | |
137 | ||
138 | p = malloc(size); | |
139 | if (!p) | |
140 | nasm_malloc_error (ERR_FATAL | ERR_NOFILE, "out of memory"); | |
141 | #ifdef LOGALLOC | |
142 | else | |
143 | fprintf(logfp, "%s %d strndup(%ld) returns %p\n", | |
144 | file, line, (long)size, p); | |
145 | #endif | |
146 | strncpy (p, s, len); | |
147 | p[len] = '\0'; | |
148 | return p; | |
149 | } | |
150 | ||
151 | int nasm_stricmp (char *s1, char *s2) { | |
152 | while (*s1 && toupper(*s1) == toupper(*s2)) | |
153 | s1++, s2++; | |
154 | if (!*s1 && !*s2) | |
155 | return 0; | |
156 | else if (toupper(*s1) < toupper(*s2)) | |
157 | return -1; | |
158 | else | |
159 | return 1; | |
160 | } | |
161 | ||
162 | int nasm_strnicmp (char *s1, char *s2, int n) { | |
163 | while (n > 0 && *s1 && toupper(*s1) == toupper(*s2)) | |
164 | s1++, s2++, n--; | |
165 | if ((!*s1 && !*s2) || n==0) | |
166 | return 0; | |
167 | else if (toupper(*s1) < toupper(*s2)) | |
168 | return -1; | |
169 | else | |
170 | return 1; | |
171 | } | |
172 | ||
173 | #define lib_isnumchar(c) ( isalnum(c) || (c) == '$') | |
174 | #define numvalue(c) ((c)>='a' ? (c)-'a'+10 : (c)>='A' ? (c)-'A'+10 : (c)-'0') | |
175 | ||
176 | long readnum (char *str, int *error) { | |
177 | char *r = str, *q; | |
178 | long radix; | |
179 | unsigned long result, checklimit; | |
180 | int warn = FALSE; | |
181 | ||
182 | *error = FALSE; | |
183 | ||
184 | while (isspace(*r)) r++; /* find start of number */ | |
185 | q = r; | |
186 | ||
187 | while (lib_isnumchar(*q)) q++; /* find end of number */ | |
188 | ||
189 | /* | |
190 | * If it begins 0x, 0X or $, or ends in H, it's in hex. if it | |
191 | * ends in Q, it's octal. if it ends in B, it's binary. | |
192 | * Otherwise, it's ordinary decimal. | |
193 | */ | |
194 | if (*r=='0' && (r[1]=='x' || r[1]=='X')) | |
195 | radix = 16, r += 2; | |
196 | else if (*r=='$') | |
197 | radix = 16, r++; | |
198 | else if (q[-1]=='H' || q[-1]=='h') | |
199 | radix = 16 , q--; | |
200 | else if (q[-1]=='Q' || q[-1]=='q') | |
201 | radix = 8 , q--; | |
202 | else if (q[-1]=='B' || q[-1]=='b') | |
203 | radix = 2 , q--; | |
204 | else | |
205 | radix = 10; | |
206 | ||
207 | /* | |
208 | * If this number has been found for us by something other than | |
209 | * the ordinary scanners, then it might be malformed by having | |
210 | * nothing between the prefix and the suffix. Check this case | |
211 | * now. | |
212 | */ | |
213 | if (r >= q) { | |
214 | *error = TRUE; | |
215 | return 0; | |
216 | } | |
217 | ||
218 | /* | |
219 | * `checklimit' must be 2**32 / radix. We can't do that in | |
220 | * 32-bit arithmetic, which we're (probably) using, so we | |
221 | * cheat: since we know that all radices we use are even, we | |
222 | * can divide 2**31 by radix/2 instead. | |
223 | */ | |
224 | checklimit = 0x80000000UL / (radix>>1); | |
225 | ||
226 | result = 0; | |
227 | while (*r && r < q) { | |
228 | if (*r<'0' || (*r>'9' && *r<'A') || numvalue(*r)>=radix) { | |
229 | *error = TRUE; | |
230 | return 0; | |
231 | } | |
232 | if (result >= checklimit) | |
233 | warn = TRUE; | |
234 | result = radix * result + numvalue(*r); | |
235 | r++; | |
236 | } | |
237 | ||
238 | if (warn) | |
239 | nasm_malloc_error (ERR_WARNING | ERR_PASS1 | ERR_WARN_NOV, | |
240 | "numeric constant %s does not fit in 32 bits", | |
241 | str); | |
242 | ||
243 | return result; | |
244 | } | |
245 | ||
246 | static long next_seg; | |
247 | ||
248 | void seg_init(void) { | |
249 | next_seg = 0; | |
250 | } | |
251 | ||
252 | long seg_alloc(void) { | |
253 | return (next_seg += 2) - 2; | |
254 | } | |
255 | ||
256 | void fwriteshort (int data, FILE *fp) { | |
257 | fputc ((int) (data & 255), fp); | |
258 | fputc ((int) ((data >> 8) & 255), fp); | |
259 | } | |
260 | ||
261 | void fwritelong (long data, FILE *fp) { | |
262 | fputc ((int) (data & 255), fp); | |
263 | fputc ((int) ((data >> 8) & 255), fp); | |
264 | fputc ((int) ((data >> 16) & 255), fp); | |
265 | fputc ((int) ((data >> 24) & 255), fp); | |
266 | } | |
267 | ||
268 | void standard_extension (char *inname, char *outname, char *extension, | |
269 | efunc error) { | |
270 | char *p, *q; | |
271 | ||
272 | if (*outname) /* file name already exists, */ | |
273 | return; /* so do nothing */ | |
274 | q = inname; | |
275 | p = outname; | |
276 | while (*q) *p++ = *q++; /* copy, and find end of string */ | |
277 | *p = '\0'; /* terminate it */ | |
278 | while (p > outname && *--p != '.');/* find final period (or whatever) */ | |
279 | if (*p != '.') while (*p) p++; /* go back to end if none found */ | |
280 | if (!strcmp(p, extension)) { /* is the extension already there? */ | |
281 | if (*extension) | |
282 | error(ERR_WARNING | ERR_NOFILE, | |
283 | "file name already ends in `%s': " | |
284 | "output will be in `nasm.out'", | |
285 | extension); | |
286 | else | |
287 | error(ERR_WARNING | ERR_NOFILE, | |
288 | "file name already has no extension: " | |
289 | "output will be in `nasm.out'"); | |
290 | strcpy(outname, "nasm.out"); | |
291 | } else | |
292 | strcpy(p, extension); | |
293 | } | |
294 | ||
295 | #define RAA_BLKSIZE 4096 /* this many longs allocated at once */ | |
296 | #define RAA_LAYERSIZE 1024 /* this many _pointers_ allocated */ | |
297 | ||
298 | typedef struct RAA RAA; | |
299 | typedef union RAA_UNION RAA_UNION; | |
300 | typedef struct RAA_LEAF RAA_LEAF; | |
301 | typedef struct RAA_BRANCH RAA_BRANCH; | |
302 | ||
303 | struct RAA { | |
304 | /* | |
305 | * Number of layers below this one to get to the real data. 0 | |
306 | * means this structure is a leaf, holding RAA_BLKSIZE real | |
307 | * data items; 1 and above mean it's a branch, holding | |
308 | * RAA_LAYERSIZE pointers to the next level branch or leaf | |
309 | * structures. | |
310 | */ | |
311 | int layers; | |
312 | /* | |
313 | * Number of real data items spanned by one position in the | |
314 | * `data' array at this level. This number is 1, trivially, for | |
315 | * a leaf (level 0): for a level 1 branch it should be | |
316 | * RAA_BLKSIZE, and for a level 2 branch it's | |
317 | * RAA_LAYERSIZE*RAA_BLKSIZE. | |
318 | */ | |
319 | long stepsize; | |
320 | union RAA_UNION { | |
321 | struct RAA_LEAF { | |
322 | long data[RAA_BLKSIZE]; | |
323 | } l; | |
324 | struct RAA_BRANCH { | |
325 | struct RAA *data[RAA_LAYERSIZE]; | |
326 | } b; | |
327 | } u; | |
328 | }; | |
329 | ||
330 | #define LEAFSIZ (sizeof(RAA)-sizeof(RAA_UNION)+sizeof(RAA_LEAF)) | |
331 | #define BRANCHSIZ (sizeof(RAA)-sizeof(RAA_UNION)+sizeof(RAA_BRANCH)) | |
332 | ||
333 | #define LAYERSIZ(r) ( (r)->layers==0 ? RAA_BLKSIZE : RAA_LAYERSIZE ) | |
334 | ||
335 | static struct RAA *real_raa_init (int layers) { | |
336 | struct RAA *r; | |
337 | ||
338 | if (layers == 0) { | |
339 | r = nasm_malloc (LEAFSIZ); | |
340 | memset (r->u.l.data, 0, sizeof(r->u.l.data)); | |
341 | r->layers = 0; | |
342 | r->stepsize = 1L; | |
343 | } else { | |
344 | r = nasm_malloc (BRANCHSIZ); | |
345 | memset (r->u.b.data, 0, sizeof(r->u.b.data)); | |
346 | r->layers = layers; | |
347 | r->stepsize = RAA_BLKSIZE; | |
348 | while (--layers) | |
349 | r->stepsize *= RAA_LAYERSIZE; | |
350 | } | |
351 | return r; | |
352 | } | |
353 | ||
354 | struct RAA *raa_init (void) { | |
355 | return real_raa_init (0); | |
356 | } | |
357 | ||
358 | void raa_free (struct RAA *r) { | |
359 | if (r->layers == 0) | |
360 | nasm_free (r); | |
361 | else { | |
362 | struct RAA **p; | |
363 | for (p = r->u.b.data; p - r->u.b.data < RAA_LAYERSIZE; p++) | |
364 | if (*p) | |
365 | raa_free (*p); | |
366 | } | |
367 | } | |
368 | ||
369 | long raa_read (struct RAA *r, long posn) { | |
370 | if (posn > r->stepsize * LAYERSIZ(r)) | |
371 | return 0L; | |
372 | while (r->layers > 0) { | |
373 | ldiv_t l; | |
374 | l = ldiv (posn, r->stepsize); | |
375 | r = r->u.b.data[l.quot]; | |
376 | posn = l.rem; | |
377 | if (!r) /* better check this */ | |
378 | return 0L; | |
379 | } | |
380 | return r->u.l.data[posn]; | |
381 | } | |
382 | ||
383 | struct RAA *raa_write (struct RAA *r, long posn, long value) { | |
384 | struct RAA *result; | |
385 | ||
386 | if (posn < 0) | |
387 | nasm_malloc_error (ERR_PANIC, "negative position in raa_write"); | |
388 | ||
389 | while (r->stepsize * LAYERSIZ(r) < posn) { | |
390 | /* | |
391 | * Must go up a layer. | |
392 | */ | |
393 | struct RAA *s; | |
394 | ||
395 | s = nasm_malloc (BRANCHSIZ); | |
396 | memset (s->u.b.data, 0, sizeof(r->u.b.data)); | |
397 | s->layers = r->layers + 1; | |
398 | s->stepsize = RAA_LAYERSIZE * r->stepsize; | |
399 | s->u.b.data[0] = r; | |
400 | r = s; | |
401 | } | |
402 | ||
403 | result = r; | |
404 | ||
405 | while (r->layers > 0) { | |
406 | ldiv_t l; | |
407 | struct RAA **s; | |
408 | l = ldiv (posn, r->stepsize); | |
409 | s = &r->u.b.data[l.quot]; | |
410 | if (!*s) | |
411 | *s = real_raa_init (r->layers - 1); | |
412 | r = *s; | |
413 | posn = l.rem; | |
414 | } | |
415 | ||
416 | r->u.l.data[posn] = value; | |
417 | ||
418 | return result; | |
419 | } | |
420 | ||
421 | #define SAA_MAXLEN 8192 | |
422 | ||
423 | struct SAA { | |
424 | /* | |
425 | * members `end' and `elem_len' are only valid in first link in | |
426 | * list; `rptr' and `rpos' are used for reading | |
427 | */ | |
428 | struct SAA *next, *end, *rptr; | |
429 | long elem_len, length, posn, start, rpos; | |
430 | char *data; | |
431 | }; | |
432 | ||
433 | struct SAA *saa_init (long elem_len) { | |
434 | struct SAA *s; | |
435 | ||
436 | if (elem_len > SAA_MAXLEN) | |
437 | nasm_malloc_error (ERR_PANIC | ERR_NOFILE, "SAA with huge elements"); | |
438 | ||
439 | s = nasm_malloc (sizeof(struct SAA)); | |
440 | s->posn = s->start = 0L; | |
441 | s->elem_len = elem_len; | |
442 | s->length = SAA_MAXLEN - (SAA_MAXLEN % elem_len); | |
443 | s->data = nasm_malloc (s->length); | |
444 | s->next = NULL; | |
445 | s->end = s; | |
446 | ||
447 | return s; | |
448 | } | |
449 | ||
450 | void saa_free (struct SAA *s) { | |
451 | struct SAA *t; | |
452 | ||
453 | while (s) { | |
454 | t = s->next; | |
455 | nasm_free (s->data); | |
456 | nasm_free (s); | |
457 | s = t; | |
458 | } | |
459 | } | |
460 | ||
461 | void *saa_wstruct (struct SAA *s) { | |
462 | void *p; | |
463 | ||
464 | if (s->end->length - s->end->posn < s->elem_len) { | |
465 | s->end->next = nasm_malloc (sizeof(struct SAA)); | |
466 | s->end->next->start = s->end->start + s->end->posn; | |
467 | s->end = s->end->next; | |
468 | s->end->length = s->length; | |
469 | s->end->next = NULL; | |
470 | s->end->posn = 0L; | |
471 | s->end->data = nasm_malloc (s->length); | |
472 | } | |
473 | ||
474 | p = s->end->data + s->end->posn; | |
475 | s->end->posn += s->elem_len; | |
476 | return p; | |
477 | } | |
478 | ||
479 | void saa_wbytes (struct SAA *s, void *data, long len) { | |
480 | char *d = data; | |
481 | ||
482 | while (len > 0) { | |
483 | long l = s->end->length - s->end->posn; | |
484 | if (l > len) | |
485 | l = len; | |
486 | if (l > 0) { | |
487 | if (d) { | |
488 | memcpy (s->end->data + s->end->posn, d, l); | |
489 | d += l; | |
490 | } else | |
491 | memset (s->end->data + s->end->posn, 0, l); | |
492 | s->end->posn += l; | |
493 | len -= l; | |
494 | } | |
495 | if (len > 0) { | |
496 | s->end->next = nasm_malloc (sizeof(struct SAA)); | |
497 | s->end->next->start = s->end->start + s->end->posn; | |
498 | s->end = s->end->next; | |
499 | s->end->length = s->length; | |
500 | s->end->next = NULL; | |
501 | s->end->posn = 0L; | |
502 | s->end->data = nasm_malloc (s->length); | |
503 | } | |
504 | } | |
505 | } | |
506 | ||
507 | void saa_rewind (struct SAA *s) { | |
508 | s->rptr = s; | |
509 | s->rpos = 0L; | |
510 | } | |
511 | ||
512 | void *saa_rstruct (struct SAA *s) { | |
513 | void *p; | |
514 | ||
515 | if (!s->rptr) | |
516 | return NULL; | |
517 | ||
518 | if (s->rptr->posn - s->rpos < s->elem_len) { | |
519 | s->rptr = s->rptr->next; | |
520 | if (!s->rptr) | |
521 | return NULL; /* end of array */ | |
522 | s->rpos = 0L; | |
523 | } | |
524 | ||
525 | p = s->rptr->data + s->rpos; | |
526 | s->rpos += s->elem_len; | |
527 | return p; | |
528 | } | |
529 | ||
530 | void *saa_rbytes (struct SAA *s, long *len) { | |
531 | void *p; | |
532 | ||
533 | if (!s->rptr) | |
534 | return NULL; | |
535 | ||
536 | p = s->rptr->data + s->rpos; | |
537 | *len = s->rptr->posn - s->rpos; | |
538 | s->rptr = s->rptr->next; | |
539 | s->rpos = 0L; | |
540 | return p; | |
541 | } | |
542 | ||
543 | void saa_rnbytes (struct SAA *s, void *data, long len) { | |
544 | char *d = data; | |
545 | ||
546 | while (len > 0) { | |
547 | long l; | |
548 | ||
549 | if (!s->rptr) | |
550 | return; | |
551 | ||
552 | l = s->rptr->posn - s->rpos; | |
553 | if (l > len) | |
554 | l = len; | |
555 | if (l > 0) { | |
556 | memcpy (d, s->rptr->data + s->rpos, l); | |
557 | d += l; | |
558 | s->rpos += l; | |
559 | len -= l; | |
560 | } | |
561 | if (len > 0) { | |
562 | s->rptr = s->rptr->next; | |
563 | s->rpos = 0L; | |
564 | } | |
565 | } | |
566 | } | |
567 | ||
568 | void saa_fread (struct SAA *s, long posn, void *data, long len) { | |
569 | struct SAA *p; | |
570 | long pos; | |
571 | char *cdata = data; | |
572 | ||
573 | if (!s->rptr || posn > s->rptr->start + s->rpos) | |
574 | saa_rewind (s); | |
575 | while (posn >= s->rptr->start + s->rptr->posn) { | |
576 | s->rptr = s->rptr->next; | |
577 | if (!s->rptr) | |
578 | return; /* what else can we do?! */ | |
579 | } | |
580 | ||
581 | p = s->rptr; | |
582 | pos = posn - s->rptr->start; | |
583 | while (len) { | |
584 | long l = s->rptr->posn - pos; | |
585 | if (l > len) | |
586 | l = len; | |
587 | memcpy (cdata, s->rptr->data+pos, l); | |
588 | len -= l; | |
589 | cdata += l; | |
590 | p = p->next; | |
591 | if (!p) | |
592 | return; | |
593 | pos = 0L; | |
594 | } | |
595 | } | |
596 | ||
597 | void saa_fwrite (struct SAA *s, long posn, void *data, long len) { | |
598 | struct SAA *p; | |
599 | long pos; | |
600 | char *cdata = data; | |
601 | ||
602 | if (!s->rptr || posn > s->rptr->start + s->rpos) | |
603 | saa_rewind (s); | |
604 | while (posn >= s->rptr->start + s->rptr->posn) { | |
605 | s->rptr = s->rptr->next; | |
606 | if (!s->rptr) | |
607 | return; /* what else can we do?! */ | |
608 | } | |
609 | ||
610 | p = s->rptr; | |
611 | pos = posn - s->rptr->start; | |
612 | while (len) { | |
613 | long l = s->rptr->posn - pos; | |
614 | if (l > len) | |
615 | l = len; | |
616 | memcpy (s->rptr->data+pos, cdata, l); | |
617 | len -= l; | |
618 | cdata += l; | |
619 | p = p->next; | |
620 | if (!p) | |
621 | return; | |
622 | pos = 0L; | |
623 | } | |
624 | } | |
625 | ||
626 | void saa_fpwrite (struct SAA *s, FILE *fp) { | |
627 | char *data; | |
628 | long len; | |
629 | ||
630 | saa_rewind (s); | |
631 | while ( (data = saa_rbytes (s, &len)) ) | |
632 | fwrite (data, 1, len, fp); | |
633 | } | |
634 | ||
635 | /* | |
636 | * Register, instruction, condition-code and prefix keywords used | |
637 | * by the scanner. | |
638 | */ | |
639 | #include "names.c" | |
640 | static char *special_names[] = { | |
641 | "byte", "dword", "far", "long", "near", "nosplit", "qword", | |
642 | "short", "to", "tword", "word" | |
643 | }; | |
644 | static char *prefix_names[] = { | |
645 | "a16", "a32", "lock", "o16", "o32", "rep", "repe", "repne", | |
646 | "repnz", "repz", "times" | |
647 | }; | |
648 | ||
649 | ||
650 | /* | |
651 | * Standard scanner routine used by parser.c and some output | |
652 | * formats. It keeps a succession of temporary-storage strings in | |
653 | * stdscan_tempstorage, which can be cleared using stdscan_reset. | |
654 | */ | |
655 | static char **stdscan_tempstorage = NULL; | |
656 | static int stdscan_tempsize = 0, stdscan_templen = 0; | |
657 | #define STDSCAN_TEMP_DELTA 256 | |
658 | ||
659 | static void stdscan_pop(void) { | |
660 | nasm_free (stdscan_tempstorage[--stdscan_templen]); | |
661 | } | |
662 | ||
663 | void stdscan_reset(void) { | |
664 | while (stdscan_templen > 0) | |
665 | stdscan_pop(); | |
666 | } | |
667 | ||
668 | static char *stdscan_copy(char *p, int len) { | |
669 | char *text; | |
670 | ||
671 | text = nasm_malloc(len+1); | |
672 | strncpy (text, p, len); | |
673 | text[len] = '\0'; | |
674 | ||
675 | if (stdscan_templen >= stdscan_tempsize) { | |
676 | stdscan_tempsize += STDSCAN_TEMP_DELTA; | |
677 | stdscan_tempstorage = nasm_realloc(stdscan_tempstorage, | |
678 | stdscan_tempsize*sizeof(char *)); | |
679 | } | |
680 | stdscan_tempstorage[stdscan_templen++] = text; | |
681 | ||
682 | return text; | |
683 | } | |
684 | ||
685 | char *stdscan_bufptr = NULL; | |
686 | int stdscan (void *private_data, struct tokenval *tv) { | |
687 | char ourcopy[256], *r, *s; | |
688 | ||
689 | while (isspace(*stdscan_bufptr)) stdscan_bufptr++; | |
690 | if (!*stdscan_bufptr) | |
691 | return tv->t_type = 0; | |
692 | ||
693 | /* we have a token; either an id, a number or a char */ | |
694 | if (isidstart(*stdscan_bufptr) || | |
695 | (*stdscan_bufptr == '$' && isidstart(stdscan_bufptr[1]))) { | |
696 | /* now we've got an identifier */ | |
697 | int i; | |
698 | int is_sym = FALSE; | |
699 | ||
700 | if (*stdscan_bufptr == '$') { | |
701 | is_sym = TRUE; | |
702 | stdscan_bufptr++; | |
703 | } | |
704 | ||
705 | r = stdscan_bufptr++; | |
706 | while (isidchar(*stdscan_bufptr)) stdscan_bufptr++; | |
707 | tv->t_charptr = stdscan_copy(r, stdscan_bufptr - r); | |
708 | ||
709 | for (s=tv->t_charptr, r=ourcopy; *s; s++) | |
710 | *r++ = tolower (*s); | |
711 | *r = '\0'; | |
712 | if (is_sym) | |
713 | return tv->t_type = TOKEN_ID;/* bypass all other checks */ | |
714 | /* right, so we have an identifier sitting in temp storage. now, | |
715 | * is it actually a register or instruction name, or what? */ | |
716 | if ((tv->t_integer=bsi(ourcopy, reg_names, | |
717 | elements(reg_names)))>=0) { | |
718 | tv->t_integer += EXPR_REG_START; | |
719 | return tv->t_type = TOKEN_REG; | |
720 | } else if ((tv->t_integer=bsi(ourcopy, insn_names, | |
721 | elements(insn_names)))>=0) { | |
722 | return tv->t_type = TOKEN_INSN; | |
723 | } | |
f083c6c3 | 724 | for (i=0; i<(int)elements(icn); i++) |
14c7c974 A |
725 | if (!strncmp(ourcopy, icn[i], strlen(icn[i]))) { |
726 | char *p = ourcopy + strlen(icn[i]); | |
727 | tv->t_integer = ico[i]; | |
728 | if ((tv->t_inttwo=bsi(p, conditions, | |
729 | elements(conditions)))>=0) | |
730 | return tv->t_type = TOKEN_INSN; | |
731 | } | |
732 | if ((tv->t_integer=bsi(ourcopy, prefix_names, | |
733 | elements(prefix_names)))>=0) { | |
734 | tv->t_integer += PREFIX_ENUM_START; | |
735 | return tv->t_type = TOKEN_PREFIX; | |
736 | } | |
737 | if ((tv->t_integer=bsi(ourcopy, special_names, | |
738 | elements(special_names)))>=0) | |
739 | return tv->t_type = TOKEN_SPECIAL; | |
740 | if (!strcmp(ourcopy, "seg")) | |
741 | return tv->t_type = TOKEN_SEG; | |
742 | if (!strcmp(ourcopy, "wrt")) | |
743 | return tv->t_type = TOKEN_WRT; | |
744 | return tv->t_type = TOKEN_ID; | |
745 | } else if (*stdscan_bufptr == '$' && !isnumchar(stdscan_bufptr[1])) { | |
746 | /* | |
747 | * It's a $ sign with no following hex number; this must | |
748 | * mean it's a Here token ($), evaluating to the current | |
749 | * assembly location, or a Base token ($$), evaluating to | |
750 | * the base of the current segment. | |
751 | */ | |
752 | stdscan_bufptr++; | |
753 | if (*stdscan_bufptr == '$') { | |
754 | stdscan_bufptr++; | |
755 | return tv->t_type = TOKEN_BASE; | |
756 | } | |
757 | return tv->t_type = TOKEN_HERE; | |
758 | } else if (isnumstart(*stdscan_bufptr)) { /* now we've got a number */ | |
759 | int rn_error; | |
760 | ||
761 | r = stdscan_bufptr++; | |
762 | while (isnumchar(*stdscan_bufptr)) | |
763 | stdscan_bufptr++; | |
764 | ||
765 | if (*stdscan_bufptr == '.') { | |
766 | /* | |
767 | * a floating point constant | |
768 | */ | |
769 | stdscan_bufptr++; | |
770 | while (isnumchar(*stdscan_bufptr)) { | |
771 | stdscan_bufptr++; | |
772 | } | |
773 | tv->t_charptr = stdscan_copy(r, stdscan_bufptr - r); | |
774 | return tv->t_type = TOKEN_FLOAT; | |
775 | } | |
776 | r = stdscan_copy(r, stdscan_bufptr - r); | |
777 | tv->t_integer = readnum(r, &rn_error); | |
778 | stdscan_pop(); | |
779 | if (rn_error) | |
780 | return tv->t_type = TOKEN_ERRNUM;/* some malformation occurred */ | |
781 | tv->t_charptr = NULL; | |
782 | return tv->t_type = TOKEN_NUM; | |
783 | } else if (*stdscan_bufptr == '\'' || | |
784 | *stdscan_bufptr == '"') {/* a char constant */ | |
785 | char quote = *stdscan_bufptr++, *r; | |
786 | r = tv->t_charptr = stdscan_bufptr; | |
787 | while (*stdscan_bufptr && *stdscan_bufptr != quote) stdscan_bufptr++; | |
788 | tv->t_inttwo = stdscan_bufptr - r; /* store full version */ | |
789 | if (!*stdscan_bufptr) | |
790 | return tv->t_type = TOKEN_ERRNUM; /* unmatched quotes */ | |
791 | tv->t_integer = 0; | |
792 | r = stdscan_bufptr++; /* skip over final quote */ | |
793 | while (quote != *--r) { | |
794 | tv->t_integer = (tv->t_integer<<8) + (unsigned char) *r; | |
795 | } | |
796 | return tv->t_type = TOKEN_NUM; | |
797 | } else if (*stdscan_bufptr == ';') { /* a comment has happened - stay */ | |
798 | return tv->t_type = 0; | |
799 | } else if (stdscan_bufptr[0] == '>' && stdscan_bufptr[1] == '>') { | |
800 | stdscan_bufptr += 2; | |
801 | return tv->t_type = TOKEN_SHR; | |
802 | } else if (stdscan_bufptr[0] == '<' && stdscan_bufptr[1] == '<') { | |
803 | stdscan_bufptr += 2; | |
804 | return tv->t_type = TOKEN_SHL; | |
805 | } else if (stdscan_bufptr[0] == '/' && stdscan_bufptr[1] == '/') { | |
806 | stdscan_bufptr += 2; | |
807 | return tv->t_type = TOKEN_SDIV; | |
808 | } else if (stdscan_bufptr[0] == '%' && stdscan_bufptr[1] == '%') { | |
809 | stdscan_bufptr += 2; | |
810 | return tv->t_type = TOKEN_SMOD; | |
811 | } else if (stdscan_bufptr[0] == '=' && stdscan_bufptr[1] == '=') { | |
812 | stdscan_bufptr += 2; | |
813 | return tv->t_type = TOKEN_EQ; | |
814 | } else if (stdscan_bufptr[0] == '<' && stdscan_bufptr[1] == '>') { | |
815 | stdscan_bufptr += 2; | |
816 | return tv->t_type = TOKEN_NE; | |
817 | } else if (stdscan_bufptr[0] == '!' && stdscan_bufptr[1] == '=') { | |
818 | stdscan_bufptr += 2; | |
819 | return tv->t_type = TOKEN_NE; | |
820 | } else if (stdscan_bufptr[0] == '<' && stdscan_bufptr[1] == '=') { | |
821 | stdscan_bufptr += 2; | |
822 | return tv->t_type = TOKEN_LE; | |
823 | } else if (stdscan_bufptr[0] == '>' && stdscan_bufptr[1] == '=') { | |
824 | stdscan_bufptr += 2; | |
825 | return tv->t_type = TOKEN_GE; | |
826 | } else if (stdscan_bufptr[0] == '&' && stdscan_bufptr[1] == '&') { | |
827 | stdscan_bufptr += 2; | |
828 | return tv->t_type = TOKEN_DBL_AND; | |
829 | } else if (stdscan_bufptr[0] == '^' && stdscan_bufptr[1] == '^') { | |
830 | stdscan_bufptr += 2; | |
831 | return tv->t_type = TOKEN_DBL_XOR; | |
832 | } else if (stdscan_bufptr[0] == '|' && stdscan_bufptr[1] == '|') { | |
833 | stdscan_bufptr += 2; | |
834 | return tv->t_type = TOKEN_DBL_OR; | |
835 | } else /* just an ordinary char */ | |
836 | return tv->t_type = (unsigned char) (*stdscan_bufptr++); | |
837 | } | |
838 | ||
839 | /* | |
840 | * Return TRUE if the argument is a simple scalar. (Or a far- | |
841 | * absolute, which counts.) | |
842 | */ | |
843 | int is_simple (expr *vect) { | |
844 | while (vect->type && !vect->value) | |
845 | vect++; | |
846 | if (!vect->type) | |
847 | return 1; | |
848 | if (vect->type != EXPR_SIMPLE) | |
849 | return 0; | |
850 | do { | |
851 | vect++; | |
852 | } while (vect->type && !vect->value); | |
853 | if (vect->type && vect->type < EXPR_SEGBASE+SEG_ABS) return 0; | |
854 | return 1; | |
855 | } | |
856 | ||
857 | /* | |
858 | * Return TRUE if the argument is a simple scalar, _NOT_ a far- | |
859 | * absolute. | |
860 | */ | |
861 | int is_really_simple (expr *vect) { | |
862 | while (vect->type && !vect->value) | |
863 | vect++; | |
864 | if (!vect->type) | |
865 | return 1; | |
866 | if (vect->type != EXPR_SIMPLE) | |
867 | return 0; | |
868 | do { | |
869 | vect++; | |
870 | } while (vect->type && !vect->value); | |
871 | if (vect->type) return 0; | |
872 | return 1; | |
873 | } | |
874 | ||
875 | /* | |
876 | * Return TRUE if the argument is relocatable (i.e. a simple | |
877 | * scalar, plus at most one segment-base, plus possibly a WRT). | |
878 | */ | |
879 | int is_reloc (expr *vect) { | |
880 | while (vect->type && !vect->value) /* skip initial value-0 terms */ | |
881 | vect++; | |
882 | if (!vect->type) /* trivially return TRUE if nothing */ | |
883 | return 1; /* is present apart from value-0s */ | |
884 | if (vect->type < EXPR_SIMPLE) /* FALSE if a register is present */ | |
885 | return 0; | |
886 | if (vect->type == EXPR_SIMPLE) { /* skip over a pure number term... */ | |
887 | do { | |
888 | vect++; | |
889 | } while (vect->type && !vect->value); | |
890 | if (!vect->type) /* ...returning TRUE if that's all */ | |
891 | return 1; | |
892 | } | |
893 | if (vect->type == EXPR_WRT) { /* skip over a WRT term... */ | |
894 | do { | |
895 | vect++; | |
896 | } while (vect->type && !vect->value); | |
897 | if (!vect->type) /* ...returning TRUE if that's all */ | |
898 | return 1; | |
899 | } | |
900 | if (vect->value != 0 && vect->value != 1) | |
901 | return 0; /* segment base multiplier non-unity */ | |
902 | do { /* skip over _one_ seg-base term... */ | |
903 | vect++; | |
904 | } while (vect->type && !vect->value); | |
905 | if (!vect->type) /* ...returning TRUE if that's all */ | |
906 | return 1; | |
907 | return 0; /* And return FALSE if there's more */ | |
908 | } | |
909 | ||
910 | /* | |
911 | * Return TRUE if the argument contains an `unknown' part. | |
912 | */ | |
913 | int is_unknown(expr *vect) { | |
914 | while (vect->type && vect->type < EXPR_UNKNOWN) | |
915 | vect++; | |
916 | return (vect->type == EXPR_UNKNOWN); | |
917 | } | |
918 | ||
919 | /* | |
920 | * Return TRUE if the argument contains nothing but an `unknown' | |
921 | * part. | |
922 | */ | |
923 | int is_just_unknown(expr *vect) { | |
924 | while (vect->type && !vect->value) | |
925 | vect++; | |
926 | return (vect->type == EXPR_UNKNOWN); | |
927 | } | |
928 | ||
929 | /* | |
930 | * Return the scalar part of a relocatable vector. (Including | |
931 | * simple scalar vectors - those qualify as relocatable.) | |
932 | */ | |
933 | long reloc_value (expr *vect) { | |
934 | while (vect->type && !vect->value) | |
935 | vect++; | |
936 | if (!vect->type) return 0; | |
937 | if (vect->type == EXPR_SIMPLE) | |
938 | return vect->value; | |
939 | else | |
940 | return 0; | |
941 | } | |
942 | ||
943 | /* | |
944 | * Return the segment number of a relocatable vector, or NO_SEG for | |
945 | * simple scalars. | |
946 | */ | |
947 | long reloc_seg (expr *vect) { | |
948 | while (vect->type && (vect->type == EXPR_WRT || !vect->value)) | |
949 | vect++; | |
950 | if (vect->type == EXPR_SIMPLE) { | |
951 | do { | |
952 | vect++; | |
953 | } while (vect->type && (vect->type == EXPR_WRT || !vect->value)); | |
954 | } | |
955 | if (!vect->type) | |
956 | return NO_SEG; | |
957 | else | |
958 | return vect->type - EXPR_SEGBASE; | |
959 | } | |
960 | ||
961 | /* | |
962 | * Return the WRT segment number of a relocatable vector, or NO_SEG | |
963 | * if no WRT part is present. | |
964 | */ | |
965 | long reloc_wrt (expr *vect) { | |
966 | while (vect->type && vect->type < EXPR_WRT) | |
967 | vect++; | |
968 | if (vect->type == EXPR_WRT) { | |
969 | return vect->value; | |
970 | } else | |
971 | return NO_SEG; | |
972 | } | |
973 | ||
974 | /* | |
975 | * Binary search. | |
976 | */ | |
977 | int bsi (char *string, char **array, int size) { | |
978 | int i = -1, j = size; /* always, i < index < j */ | |
979 | while (j-i >= 2) { | |
980 | int k = (i+j)/2; | |
981 | int l = strcmp(string, array[k]); | |
982 | if (l<0) /* it's in the first half */ | |
983 | j = k; | |
984 | else if (l>0) /* it's in the second half */ | |
985 | i = k; | |
986 | else /* we've got it :) */ | |
987 | return k; | |
988 | } | |
989 | return -1; /* we haven't got it :( */ | |
990 | } |