]> git.sur5r.net Git - cc65/blob - src/c1p65/main.c
Merge https://github.com/cc65/cc65 into c1p
[cc65] / src / c1p65 / main.c
1 /* Object file conversion utility for Challenger 1P
2
3    by Stephan Muehlstrasser
4 */
5
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <stdarg.h>
10 #include <string.h>
11 #include <errno.h>
12 #include <time.h>
13
14 /* common stuff */
15 #include "abend.h"
16 #include "cmdline.h"
17 #include "fname.h"
18 #include "chartype.h"
19 #include "target.h"
20 #include "version.h"
21 #include "xmalloc.h"
22
23 static void Usage (void)
24 {
25     printf (
26         "Usage: %s [options] file\n"
27         "Short options:\n"
28         "  -V\t\t\tPrint the version number\n"
29         "  -h\t\t\tHelp (this text)\n"
30                 "  -o name\t\tName the C1P output file (default: <input.c1p>)\n"
31                 "  -S addr\t\tLoad address (default 0x400)\n"
32         "\n"
33         "Long options:\n"
34         "  --help\t\tHelp (this text)\n"
35         "  --version\t\tPrint the version number\n",
36         ProgName);
37 }
38
39 static void OptHelp (const char* Opt attribute ((unused)),
40                      const char* Arg attribute ((unused)))
41 /* Print usage information and exit */
42 {
43     Usage ();
44     exit (EXIT_SUCCESS);
45 }
46
47
48 static void OptVersion (const char* Opt attribute ((unused)),
49                         const char* Arg attribute ((unused)))
50 /* Print the program version */
51 {
52     fprintf (stderr, "grc65 V%s\n", GetVersionAsString ());
53 }
54
55
56 static unsigned long CvtNumber (const char* Arg, const char* Number)
57 /* Convert a number from a string. Allow '$' and '0x' prefixes for hex
58  * numbers. Duplicated from ld65's main.c.
59  */
60 {
61     unsigned long Val;
62     int           Converted;
63
64     /* Convert */
65     if (*Number == '$') {
66         ++Number;
67         Converted = sscanf (Number, "%lx", &Val);
68     } else {
69         Converted = sscanf (Number, "%li", (long*)&Val);
70     }
71
72     /* Check if we do really have a number */
73     if (Converted != 1) {
74         AbEnd ("Invalid number given in argument: %s\n", Arg);
75     }
76
77     /* Return the result */
78     return Val;
79 }
80
81 /* Commands of C1P PROM monitor */
82 #define ADDRESS_MODE_CMD     '.'
83 #define DATA_MODE_CMD        '/'
84 #define EXECUTE_CMD          'G'
85
86 /* Transform the cc65 executable binary into a series of
87    commands that make the C1P PROM monitor load the bytes
88    into memory.
89 */
90 static void Transform (unsigned long StartAddress, FILE *In, FILE *Out)
91 {
92         int c;
93         unsigned long CurrentAddress;
94
95         /* Loop over all input bytes, position to current address,
96            switch to data mod, output input byte
97         */
98         for (CurrentAddress = StartAddress, c = getc(In);
99                                 c != EOF;
100                                 c = getc(In), CurrentAddress += 1) {
101                 fprintf (Out, "%c%04.4X%c%02.2X",
102                         ADDRESS_MODE_CMD, (unsigned int) CurrentAddress & 0xFFFF,
103                         DATA_MODE_CMD, (unsigned int) c & 0xFF);
104         }
105
106         /* And execute
107         fprintf (Out, "%c%04.4x%c",
108                         ADDRESS_MODE_CMD, (unsigned int) StartAddress & 0xFFFF,
109                         EXECUTE_CMD);
110                          */
111
112
113 /* Default suffix for C1P object file */
114 #define C1P_SUFFIX ".c1p"
115
116 int main (int argc, char *argv[])
117 {
118     /* Program long options */
119     static const LongOpt OptTab[] = {
120         { "--help",    0, OptHelp},
121         { "--version", 0, OptVersion},
122     };
123
124         /* Initialize input and output file name */
125     const char* InputFile = 0;
126     const char* OutputFile = 0;
127         char *GeneratedOutputFile = 0;
128
129         /* Initialize file pointers */
130         FILE *InputFileFp = 0;
131         FILE *OutputFileFp = 0;
132
133         /* Initialize with default start address defined in c1p.cfg */
134         unsigned long StartAddr = 0x400;
135
136     unsigned int I;
137
138     /* Initialize the cmdline module */
139     InitCmdLine (&argc, &argv, "c1p65");
140
141     /* Check the parameters */
142     I = 1;
143     while (I < ArgCount) {
144
145         /* Get the argument */
146         const char* Arg = ArgVec [I];
147
148         /* Check for an option */
149         if (Arg[0] == '-') {
150             switch (Arg[1]) {
151
152                 case '-':
153                     LongOption (&I, OptTab, sizeof(OptTab)/sizeof(OptTab[0]));
154                     break;
155
156                 case 'o':
157                     OutputFile = GetArg (&I, 2);
158                     break;
159
160                 case 'S':
161                     StartAddr = CvtNumber (Arg, GetArg (&I, 2));
162                     break;
163
164                 case 'h':
165                 case '?':
166                     OptHelp (Arg, 0);
167                     break;
168
169                 case 'V':
170                     OptVersion (Arg, 0);
171                     break;
172
173                 default:
174                     UnknownOption (Arg);
175             }
176
177         } else {
178             if (InputFile) {
179                 fprintf (stderr, "additional file specs ignored\n");
180             } else {
181                 InputFile = Arg;
182             }
183         }
184
185         /* Next argument */
186         ++I;
187     }
188
189     if (!InputFile) AbEnd ("No input file");
190
191         if (!OutputFile) {
192                 const size_t len = strlen(InputFile) + sizeof(C1P_SUFFIX);
193                 
194                 GeneratedOutputFile = (char *) xmalloc(len);
195                 sprintf(GeneratedOutputFile, "%s%s", InputFile, C1P_SUFFIX);
196                 OutputFile = GeneratedOutputFile;
197         }
198
199         /* Open input and output files */
200         InputFileFp = fopen(InputFile, "rb");
201         if (!InputFileFp) AbEnd ("Unable to open input file");
202
203         OutputFileFp = fopen(OutputFile, "wb");
204         if (!OutputFileFp) AbEnd ("Unable to open output file");
205
206         /* Generate object file */
207         Transform (StartAddr, InputFileFp, OutputFileFp);
208
209         /* Cleanup */
210         if (fclose(InputFileFp) == EOF) AbEnd ("Error closing input file");
211
212         if (fclose(OutputFileFp) == EOF) AbEnd ("Error closing output file");
213
214         if (GeneratedOutputFile) {
215                 xfree(GeneratedOutputFile);
216         }
217
218     return EXIT_SUCCESS;
219 }