1/*****************************************************************************/
2/* */
3/* asminc.c */
4/* */
5/* Read an assembler include file containing symbols */
6/* */
7/* */
8/* */
9/* (C) 2005-2008 Ullrich von Bassewitz */
10/* Roemerstrasse 52 */
11/* D-70794 Filderstadt */
12/* EMail: uz@cc65.org */
13/* */
14/* */
15/* This software is provided 'as-is', without any expressed or implied */
16/* warranty. In no event will the authors be held liable for any damages */
17/* arising from the use of this software. */
18/* */
19/* Permission is granted to anyone to use this software for any purpose, */
20/* including commercial applications, and to alter it and redistribute it */
21/* freely, subject to the following restrictions: */
22/* */
23/* 1. The origin of this software must not be misrepresented; you must not */
24/* claim that you wrote the original software. If you use this software */
25/* in a product, an acknowledgment in the product documentation would be */
26/* appreciated but is not required. */
27/* 2. Altered source versions must be plainly marked as such, and must not */
28/* be misrepresented as being the original software. */
29/* 3. This notice may not be removed or altered from any source */
30/* distribution. */
31/* */
32/*****************************************************************************/
33
34
35
36#include <stdio.h>
37#include <errno.h>
38
39/* common */
40#include "chartype.h"
41#include "strbuf.h"
42
43/* da65 */
44#include "asminc.h"
45#include "comments.h"
46#include "error.h"
47#include "labels.h"
48
49
50
51/*****************************************************************************/
52/* Code */
53/*****************************************************************************/
54
55
56
57static char* SkipWhitespace (char* L)
58/* Ignore white space in L */
59{
60 while (IsBlank (*L)) {
61 ++L;
62 }
63 return L;
64}
65
66
67
68unsigned DigitVal (unsigned char C)
69/* Return the value of the given digit */
70{
71 if (IsDigit (C)) {
72 return C - '0';
73 } else {
74 return tolower (C) - 'a' + 10;
75 }
76}
77
78
79
80void AsmInc (const char* Filename, char CommentStart, int IgnoreUnknown)
81/* Read an assembler include file */
82{
83 char Buf[1024];
84 char* L;
85 const char* Comment;
86 unsigned Line;
87 unsigned Len;
88 long Val;
89 unsigned DVal;
90 int Sign;
91 unsigned Base;
92 unsigned Digits;
93 StrBuf Ident = STATIC_STRBUF_INITIALIZER;
94
95 /* Try to open the file for reading */
96 FILE* F = fopen (Filename, "r");
97 if (F == 0) {
98 Error ("Cannot open asm include file \"%s\": %s",
99 Filename, strerror (errno));
100 }
101
102 /* Read line by line, check for NAME = VALUE lines */
103 Line = 0;
104 while ((L = fgets (Buf, sizeof (Buf), F)) != 0) {
105
106 /* One more line read */
107 ++Line;
108
109 /* Ignore leading white space */
110 while (IsBlank (*L)) {
111 ++L;
112 }
113
114 /* Remove trailing whitespace */
115 Len = strlen (L);
116 while (Len > 0 && IsSpace (L[Len-1])) {
117 --Len;
118 }
119 L[Len] = '\0';
120
121 /* If the line is empty or starts with a comment char, ignore it */
122 if (*L == '\0' || *L == CommentStart) {
123 continue;
124 }
125
126 /* Read an identifier */
127 SB_Clear (&Ident);
128 if (IsAlpha (*L) || *L == '_') {
129 SB_AppendChar (&Ident, *L++);
130 while (IsAlNum (*L) || *L == '_') {
131 SB_AppendChar (&Ident, *L++);
132 }
133 SB_Terminate (&Ident);
134 } else {
135 if (!IgnoreUnknown) {
136 Error ("%s(%u): Syntax error", Filename, Line);
137 }
138 continue;
139 }
140
141 /* Ignore white space */
142 L = SkipWhitespace (L);
143
144 /* Check for := or = */
145 if (*L == '=') {
146 ++L;
147 } else if (*L == ':' && *++L == '=') {
148 ++L;
149 } else {
150 if (!IgnoreUnknown) {
151 Error ("%s(%u): Missing '='", Filename, Line);
152 }
153 continue;
154 }
155
156 /* Allow white space once again */
157 L = SkipWhitespace (L);
158
159 /* A number follows. Read the sign. */
160 if (*L == '-') {
161 Sign = -1;
162 ++L;
163 } else {
164 Sign = 1;
165 if (*L == '+') {
166 ++L;
167 }
168 }
169
170 /* Determine the base of the number. Allow $ and % as prefixes for
171 ** hex and binary numbers respectively.
172 */
173 if (*L == '$') {
174 Base = 16;
175 ++L;
176 } else if (*L == '%') {
177 Base = 2;
178 ++L;
179 } else {
180 Base = 10;
181 }
182
183 /* Decode the number */
184 Digits = 0;
185 Val = 0;
186 while (IsXDigit (*L) && (DVal = DigitVal (*L)) < Base) {
187 Val = (Val * Base) + DVal;
188 ++Digits;
189 ++L;
190 }
191
192 /* Must have at least one digit */
193 if (Digits == 0) {
194 if (!IgnoreUnknown) {
195 Error ("%s(%u): Error in number format", Filename, Line);
196 }
197 continue;
198 }
199
200 /* Skip whitespace again */
201 L = SkipWhitespace (L);
202
203 /* Check for a comment */
204 if (*L == CommentStart) {
205 Comment = SkipWhitespace (L+1);
206 if (*Comment == '\0') {
207 Comment = 0;
208 }
209 } else {
210 Comment = 0;
211 }
212
213 /* Check for a comment character or end of line */
214 if (*L != CommentStart && *L != '\0') {
215 if (!IgnoreUnknown) {
216 Error ("%s(%u): Trailing garbage", Filename, Line);
217 }
218 continue;
219 }
220
221 /* Apply the sign */
222 Val *= Sign;
223
224 /* Define the symbol and the comment */
225 AddExtLabel (Val, SB_GetConstBuf (&Ident));
226 SetComment (Val, Comment);
227
228 }
229
230 /* Delete the string buffer contents */
231 SB_Done (&Ident);
232
233 /* Close the include file ignoring errors (we were just reading). */
234 (void) fclose (F);
235}
236