1/*****************************************************************************/
2/* */
3/* main.c */
4/* */
5/* Main program of 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 <stdio.h>
37#include <stdlib.h>
38#include <string.h>
39#include <errno.h>
40
41/* common */
42#include "abend.h"
43#include "cmdline.h"
44#include "print.h"
45#include "version.h"
46
47/* sp65 */
48#include "attr.h"
49#include "convert.h"
50#include "error.h"
51#include "input.h"
52#include "output.h"
53
54
55
56/*****************************************************************************/
57/* Data */
58/*****************************************************************************/
59
60
61
62/* Bitmap first read */
63static Bitmap* B;
64
65/* Bitmap working copy */
66static Bitmap* C;
67
68/* Output data from convertion */
69static StrBuf* D;
70
71
72
73/*****************************************************************************/
74/* Code */
75/*****************************************************************************/
76
77
78
79static void Usage (void)
80/* Print usage information and exit */
81{
82 printf (
83 "Usage: %s [options] file [options] [file]\n"
84 "Short options:\n"
85 " -V\t\t\t\tPrint the version number and exit\n"
86 " -c fmt[,attrlist]\t\tConvert into target format\n"
87 " -h\t\t\t\tHelp (this text)\n"
88 " -lc\t\t\t\tList all possible conversions\n"
89 " -r file[,attrlist]\t\tRead an input file\n"
90 " -v\t\t\t\tIncrease verbosity\n"
91 " -w file[,attrlist]\t\tWrite the output to a file\n"
92 "\n"
93 "Long options:\n"
94 " --convert-to fmt[,attrlist]\tConvert into target format\n"
95 " --dump-palette\t\tDump palette as table\n"
96 " --help\t\t\tHelp (this text)\n"
97 " --list-conversions\t\tList all possible conversions\n"
98 " --pop\t\t\t\tRestore the original loaded image\n"
99 " --read file[,attrlist]\tRead an input file\n"
100 " --slice x,y,w,h\t\tGenerate a slice from the loaded bitmap\n"
101 " --verbose\t\t\tIncrease verbosity\n"
102 " --version\t\t\tPrint the version number and exit\n"
103 " --write file[,attrlist]\tWrite the output to a file\n",
104 ProgName);
105}
106
107
108
109static void SetWorkBitmap (Bitmap* N)
110/* Delete an old working bitmap and set a new one. The new one may be NULL
111** to clear it.
112*/
113{
114 /* If we have a distinct work bitmap, delete it */
115 if (C != 0 && C != B) {
116 FreeBitmap (C);
117 }
118
119 /* Set the new one */
120 C = N;
121}
122
123
124
125static void SetOutputData (StrBuf* N)
126/* Delete the old output data and replace it by the given one. The new one
127** may be NULL to clear it.
128*/
129{
130 /* Delete the old output data */
131 if (D != 0) {
132 FreeStrBuf (D);
133 }
134
135 /* Set the new one */
136 D = N;
137}
138
139
140
141static void OptConvertTo (const char* Opt attribute ((unused)), const char* Arg)
142/* Convert the bitmap into a target format */
143{
144 static const char* const NameList[] = {
145 "format"
146 };
147
148 /* Parse the argument */
149 Collection* A = ParseAttrList (Arg, NameList, 2);
150
151 /* We must have a bitmap */
152 if (C == 0) {
153 Error ("No bitmap to convert");
154 }
155
156 /* Convert the bitmap */
157 SetOutputData (ConvertTo (C, A));
158
159 /* Delete the attribute list */
160 FreeAttrList (A);
161}
162
163
164
165static void OptDumpPalette (const char* Opt attribute ((unused)),
166 const char* Arg attribute ((unused)))
167/* Dump the palette of the current work bitmap */
168{
169 /* We must have a bitmap ... */
170 if (C == 0) {
171 Error ("No bitmap");
172 }
173
174 /* ... which must be indexed */
175 if (!BitmapIsIndexed (C)) {
176 Error ("Current bitmap is not indexed");
177 }
178
179 /* Dump the palette */
180 DumpPalette (stdout, GetBitmapPalette (C));
181}
182
183
184
185static void OptHelp (const char* Opt attribute ((unused)),
186 const char* Arg attribute ((unused)))
187/* Print usage information and exit */
188{
189 Usage ();
190 exit (EXIT_SUCCESS);
191}
192
193
194
195static void OptListConversions (const char* Opt attribute ((unused)),
196 const char* Arg attribute ((unused)))
197/* Print a list of all conversions */
198{
199 ListConversionTargets (stdout);
200 exit (EXIT_SUCCESS);
201}
202
203
204
205static void OptPop (const char* Opt attribute ((unused)),
206 const char* Arg attribute ((unused)))
207/* Restore the original image */
208{
209 /* C and B must differ and we must have an original */
210 if (B == 0 || C == 0 || C == B) {
211 Error ("Nothing to pop");
212 }
213
214 /* Delete the changed image and restore the original one */
215 SetWorkBitmap (B);
216}
217
218
219
220static void OptRead (const char* Opt attribute ((unused)), const char* Arg)
221/* Read an input file */
222{
223 static const char* const NameList[] = {
224 "name", "format"
225 };
226
227
228 /* Parse the argument */
229 Collection* A = ParseAttrList (Arg, NameList, 2);
230
231 /* Clear the working copy */
232 SetWorkBitmap (0);
233
234 /* Delete the original */
235 FreeBitmap (B);
236
237 /* Read the file and use it as original and as working copy */
238 B = C = ReadInputFile (A);
239
240 /* Delete the attribute list */
241 FreeAttrList (A);
242}
243
244
245
246static void OptSlice (const char* Opt attribute ((unused)), const char* Arg)
247/* Generate a slice of a bitmap */
248{
249 unsigned X, Y, W, H;
250 unsigned char T;
251
252 /* We must have a bitmap otherwise we cannot slice */
253 if (C == 0) {
254 Error ("Nothing to slice");
255 }
256
257 /* The argument is X,Y,W,H */
258 if (sscanf (Arg, "%u,%u,%u,%u,%c", &X, &Y, &W, &H, &T) != 4) {
259 Error ("Invalid argument. Slice must be given as X,Y,W,H");
260 }
261
262 /* Check the coordinates to be within the original bitmap */
263 if (W > BM_MAX_WIDTH || H > BM_MAX_HEIGHT ||
264 X + W > GetBitmapWidth (C) ||
265 Y + H > GetBitmapHeight (C)) {
266 Error ("Invalid slice coordinates and/or size");
267 }
268
269 /* Create the slice */
270 SetWorkBitmap (SliceBitmap (C, X, Y, W, H));
271}
272
273
274
275static void OptVerbose (const char* Opt attribute ((unused)),
276 const char* Arg attribute ((unused)))
277/* Increase verbosity */
278{
279 ++Verbosity;
280}
281
282
283
284static void OptVersion (const char* Opt attribute ((unused)),
285 const char* Arg attribute ((unused)))
286/* Print the assembler version */
287{
288 fprintf (stderr, "%s V%s\n", ProgName, GetVersionAsString ());
289 exit(EXIT_SUCCESS);
290}
291
292
293
294static void OptWrite (const char* Opt attribute ((unused)), const char* Arg)
295/* Write an output file */
296{
297 static const char* const NameList[] = {
298 "name", "format"
299 };
300
301
302 /* Parse the argument */
303 Collection* A = ParseAttrList (Arg, NameList, 2);
304
305 /* We must have output data */
306 if (D == 0) {
307 Error ("No conversion, so there's nothing to write");
308 }
309
310 /* Write the file */
311 WriteOutputFile (D, A, C);
312
313 /* Delete the attribute list */
314 FreeAttrList (A);
315}
316
317
318
319int main (int argc, char* argv [])
320/* sp65 main program */
321{
322 /* Program long options */
323 static const LongOpt OptTab[] = {
324 { "--convert-to", 1, OptConvertTo },
325 { "--dump-palette", 0, OptDumpPalette },
326 { "--help", 0, OptHelp },
327 { "--list-conversions", 0, OptListConversions },
328 { "--pop", 0, OptPop },
329 { "--read", 1, OptRead },
330 { "--slice", 1, OptSlice },
331 { "--verbose", 0, OptVerbose },
332 { "--version", 0, OptVersion },
333 { "--write", 1, OptWrite },
334 };
335
336 unsigned I;
337
338 /* Initialize the cmdline module */
339 InitCmdLine (&argc, &argv, "sp65");
340
341 /* Check the parameters */
342 I = 1;
343 while (I < ArgCount) {
344
345 /* Get the argument */
346 const char* Arg = ArgVec[I];
347
348 /* Check for an option */
349 if (Arg[0] == '-') {
350 switch (Arg[1]) {
351
352 case '-':
353 LongOption (&I, OptTab, sizeof(OptTab)/sizeof(OptTab[0]));
354 break;
355
356 case 'V':
357 OptVersion (Arg, 0);
358 break;
359
360 case 'c':
361 OptConvertTo (Arg, GetArg (&I, 2));
362 break;
363
364 case 'h':
365 OptHelp (Arg, 0);
366 break;
367
368 case 'l':
369 if (Arg[2] == 'c') {
370 OptListConversions (Arg, 0);
371 } else {
372 UnknownOption (Arg);
373 }
374 break;
375
376 case 'r':
377 OptRead (Arg, GetArg (&I, 2));
378 break;
379
380 case 'v':
381 OptVerbose (Arg, 0);
382 break;
383
384 case 'w':
385 OptWrite (Arg, GetArg (&I, 2));
386 break;
387
388 default:
389 UnknownOption (Arg);
390 break;
391
392 }
393 } else {
394 /* We don't accept anything else */
395 AbEnd ("Don't know what to do with '%s'", Arg);
396 }
397
398 /* Next argument */
399 ++I;
400 }
401
402 /* Do we have an input file? */
403 if (I == 1) {
404 Error ("No input file");
405 }
406
407 /* Cleanup data */
408 SetWorkBitmap (C);
409 FreeBitmap (B);
410 FreeStrBuf (D);
411
412 /* Success */
413 return EXIT_SUCCESS;
414}
415