]> git.sur5r.net Git - cc65/blob - src/sp65/asm.c
Removed the flags and optimized the Attr structure.
[cc65] / src / sp65 / asm.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                   asm.c                                   */
4 /*                                                                           */
5 /*          Assembler output for the sp65 sprite and bitmap utility          */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2012,      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 <errno.h>
37 #include <stdio.h>
38 #include <string.h>
39
40 /* common */
41 #include "chartype.h"
42 #include "check.h"
43 #include "cmdline.h"
44 #include "version.h"
45
46 /* sp65 */
47 #include "attr.h"
48 #include "bin.h"
49 #include "error.h"
50
51
52
53 /*****************************************************************************/
54 /*                                   Code                                    */
55 /*****************************************************************************/
56
57
58
59 static int ValidAsmLabel (const char* L)
60 /* Check an assembler label for validity */
61 {
62     /* Must begin with underscore or alphabetic character */
63     if (*L != '_' && !IsAlpha (*L)) {
64         return 0;
65     }
66     ++L;
67
68     /* Remainder must be as above plus digits */
69     while (*L) {
70         if (*L != '_' && !IsAlNum (*L)) {
71             return 0;
72         }
73         ++L;
74     }
75
76     /* Ok */
77     return 1;
78 }
79
80
81
82 static unsigned GetBytesPerLine (const Collection* A)
83 /* Return the number of bytes per line from the attribute collection A */
84 {
85     char        C;
86     unsigned    BytesPerLine = 16;
87
88     /* Check for a bytesperline attribute */
89     const char* V = GetAttrVal (A, "bytesperline");
90     if ((V && sscanf (V, "%u%c", &BytesPerLine, &C) != 1) ||
91         (BytesPerLine < 1 || BytesPerLine > 64)) {
92         Error ("Invalid value for attribute `bytesperline'");
93     }
94     return BytesPerLine;
95 }
96
97
98
99 static unsigned GetBase (const Collection* A)
100 /* Return the number base from the attribute collection A */
101 {
102     char        C;
103     unsigned    Base = 16;
104
105     /* Check for a base attribute */
106     const char* V = GetAttrVal (A, "base");
107     if ((V && sscanf (V, "%u%c", &Base, &C) != 1) ||
108         (Base != 2 && Base != 10 && Base != 16)) {
109         Error ("Invalid value for attribute `base'");
110     }
111     return Base;
112 }
113
114
115
116 static const char* GetLabel (const Collection* A)
117 /* Return the assembler label from the attribute collection A */
118 {
119     /* Check for a label attribute */
120     const char* Label = GetAttrVal (A, "label");
121     if (Label && !ValidAsmLabel (Label)) {
122         Error ("Invalid value for attribute `label'");
123     }
124     return Label;
125 }
126
127
128
129 static const char* GetSegment (const Collection* A)
130 /* Return the segment name from the attribute collection A */
131 {
132     /* Check for a label attribute */
133     const char* Seg = GetAttrVal (A, "segment");
134     if (Seg && !ValidAsmLabel (Seg)) {
135         Error ("Invalid value for attribute `segment'");
136     }
137     return Seg;
138 }
139
140
141
142 void WriteAsmFile (const StrBuf* Data, const Collection* A)
143 /* Write the contents of Data to the given file in assembler (ca65) format */
144 {
145     FILE*       F;
146     const char* D;
147     unsigned    Size;
148
149
150     /* Get the file name */
151     const char* Name = NeedAttrVal (A, "name", "write");
152
153     /* Check the number of bytes per line */
154     unsigned BytesPerLine = GetBytesPerLine (A);
155
156     /* Get the number base */
157     unsigned Base = GetBase (A);
158
159     /* Get the assembler label */
160     const char* Label = GetLabel (A);
161
162     /* Get the segment */
163     const char* Segment = GetSegment (A);
164
165     /* Open the output file */
166     F = fopen (Name, "w");
167     if (F == 0) {
168         Error ("Cannot open output file `%s': %s", Name, strerror (errno));
169     }
170
171     /* Write a readable header */
172     fprintf (F,
173              ";\n"
174              "; This file was generated by %s %s\n"
175              ";\n"
176              "\n",
177              ProgName,
178              GetVersionAsString ());
179
180
181     /* If we have a segment defined, output a segment directive */
182     if (Segment) {
183         fprintf (F, ".segment        \"%s\"\n\n", Segment);
184     }
185
186     /* If we have an assembler label, output that */
187     if (Label) {
188         fprintf (F, "%s:\n", Label);
189     }
190
191     /* Write the data */
192     D    = SB_GetConstBuf (Data);
193     Size = SB_GetLen (Data);
194     while (Size) {
195
196         unsigned I;
197
198         /* Output one line */
199         unsigned Chunk = Size;
200         if (Chunk > BytesPerLine) {
201             Chunk = BytesPerLine;
202         }
203         fputs ("        .byte   ", F);
204         for (I = 0; I < Chunk; ++I) {
205             unsigned char V = *D++;
206             if (I > 0) {
207                 fputc (',', F);
208             }
209             switch (Base) {
210                 case 2:
211                     fprintf (F, "%%%u%u%u%u%u%u%u%u",
212                              (V >> 7) & 0x01, (V >> 6) & 0x01,
213                              (V >> 5) & 0x01, (V >> 4) & 0x01,
214                              (V >> 3) & 0x01, (V >> 2) & 0x01,
215                              (V >> 1) & 0x01, (V >> 0) & 0x01);
216                     break;
217
218                 case 10:
219                     fprintf (F, "%u", V);
220                     break;
221
222                 case 16:
223                     fprintf (F, "$%02X", V);
224                     break;
225
226             }
227         }
228         fputc ('\n', F);
229
230         /* Bump the counters */
231         Size -= Chunk;
232     }
233
234     /* Add an empty line at the end */
235     fputc ('\n', F);
236
237     /* Close the file */
238     if (fclose (F) != 0) {
239         Error ("Error closing output file `%s': %s", Name, strerror (errno));
240     }
241 }
242
243
244