/[projet1]/public/pc/tools/osdk/main/bas2tap/sources/bas2tap.cpp
Defence Force logotype

Contents of /public/pc/tools/osdk/main/bas2tap/sources/bas2tap.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1481 - (show annotations)
Sat Jun 30 14:20:20 2018 UTC (22 months, 3 weeks ago) by dbug
File size: 11159 byte(s)
Bas2Tap 1.3
- Added a -optimize option (used to disable things like comments)
- Modified the parser code so future modifications are easier to do

1
2 #include "infos.h"
3
4 #include "common.h"
5
6 #include <stdlib.h>
7 #include <stdio.h>
8 #ifdef _WIN32
9 #include <conio.h>
10 #else
11 #define memicmp strncasecmp
12 #endif
13 #include <string.h>
14
15 //
16 // Things to do:
17 // - Handle auto-numeration and labels
18 // - Option to optimize the programs (truncate variables to two characters, remove comments)
19 //
20
21 const char *keywords[]=
22 {
23 // 128-246: BASIC keywords
24 "END","EDIT","STORE","RECALL","TRON","TROFF","POP","PLOT",
25 "PULL","LORES","DOKE","REPEAT","UNTIL","FOR","LLIST","LPRINT","NEXT","DATA",
26 "INPUT","DIM","CLS","READ","LET","GOTO","RUN","IF","RESTORE","GOSUB","RETURN",
27 "REM","HIMEM","GRAB","RELEASE","TEXT","HIRES","SHOOT","EXPLODE","ZAP","PING",
28 "SOUND","MUSIC","PLAY","CURSET","CURMOV","DRAW","CIRCLE","PATTERN","FILL",
29 "CHAR","PAPER","INK","STOP","ON","WAIT","CLOAD","CSAVE","DEF","POKE","PRINT",
30 "CONT","LIST","CLEAR","GET","CALL","!","NEW","TAB(","TO","FN","SPC(","@",
31 "AUTO","ELSE","THEN","NOT","STEP","+","-","*","/","^","AND","OR",">","=","<",
32 "SGN","INT","ABS","USR","FRE","POS","HEX$","&","SQR","RND","LN","EXP","COS",
33 "SIN","TAN","ATN","PEEK","DEEK","LOG","LEN","STR$","VAL","ASC","CHR$","PI",
34 "TRUE","FALSE","KEY$","SCRN","POINT","LEFT$","RIGHT$","MID$"
35 // 247- : Error messages
36 };
37
38 unsigned char head[14]={ 0x16,0x16,0x16,0x24,0,0,0,0,0,0,5,1,0,0 };
39
40
41
42
43 void Tap2Bas(unsigned char *ptr_buffer,size_t file_size,const char *destFile)
44 {
45 unsigned int i, car;
46
47 FILE *out = stdout;
48 if (destFile && (strlen(destFile) != 0))
49 {
50 out = fopen(destFile, "wb");
51 }
52 if (out == NULL)
53 {
54 printf("Can't open file for writing\n");
55 exit(1);
56 }
57
58
59 if (ptr_buffer[0]!=0x16 || ptr_buffer[3]!=0x24)
60 {
61 ShowError("Not an Oric file");
62 }
63 if (ptr_buffer[6])
64 {
65 ShowError("Not a BASIC file");
66 }
67 i=13;
68 while (ptr_buffer[i++]);
69 while (ptr_buffer[i] || ptr_buffer[i+1])
70 {
71 i+=2;
72 fprintf(out," %u ",ptr_buffer[i]+(ptr_buffer[i+1]<<8));
73 i+=2;
74 while ((car=ptr_buffer[i++]))
75 {
76 if (car<128)
77 fputc(car,out);
78 else
79 if (car < 247)
80 {
81 fprintf(out,"%s", keywords[car - 128]);
82 }
83 else
84 {
85 // Probably corrupted listing
86 // 247 : NEXT WITHOUT FOR
87 fprintf(out,"CORRUPTED_ERROR_CODE_%u", car);
88 }
89 }
90 fputc('\r',out);
91 fputc('\n', out);
92 }
93
94 fclose(out);
95 }
96
97
98
99 // tap2bas
100 int search_keyword(const char *str)
101 {
102 for (unsigned int i=0;i<sizeof(keywords)/sizeof(char *);i++)
103 {
104 if (strncmp(keywords[i],str,strlen(keywords[i]))==0)
105 {
106 return i;
107 }
108 }
109 return -1;
110 }
111
112
113
114 void Bas2Tap(const char *sourceFile,const char *destFile,bool autoRun,bool useColor,bool optimize)
115 {
116 unsigned char buf[48192];
117 unsigned int end, lastptr, adr;
118 int j,ptr,keyw,string,rem,data;
119
120 // Mike: Need to improve the parsing of this with a global function to split
121 // a text file in separate lines.
122 std::vector<std::string> textData;
123 if (!LoadText(sourceFile,textData))
124 {
125 ShowError("Unable to load source file");
126 }
127
128 std::string currentFile=sourceFile;
129 int currentLineNumber=0;
130 unsigned char* bufPtr = buf;
131 std::vector<std::string>::const_iterator lineIt=textData.begin();
132 while (lineIt!=textData.end())
133 {
134 const std::string& currentLine=StringTrim(*lineIt);
135 ++lineIt;
136 ++currentLineNumber;
137
138 if (!currentLine.empty())
139 {
140 const char* ligne=currentLine.c_str();
141 if (ligne[0]=='#')
142 {
143 // Preprocessor directive
144 if (memicmp(ligne,"#file",5)==0)
145 {
146 //"#file font.BAS""
147 // Very approximative "get the name of the file and reset the line counter" code.
148 // Will clean up that when I will have some more time.
149 ligne+=5;
150 currentFile=ligne;
151 currentLineNumber=0;
152 }
153 else
154 {
155 ShowError("Unknown preprocessor directive in file %s line number line %d",currentFile.c_str(),currentLineNumber);
156 }
157 }
158 else
159 {
160 int number=get_value(ligne,-1);
161 if (number<0)
162 {
163 char car = *ligne++;
164 if (car != 0)
165 {
166 char car2 = *ligne++;
167 if ((car == '\'') || (car == ';') || ( (car == '/') && (car2 == '/')) )
168 {
169 // We accept the usual C, Assembler and BASIC comments are actual comments that do not count as normal lines
170 // Technically we could have used a decent pre-processor, or even a full file filter, but I'm aiming at "more bangs for the bucks" approach.
171 // If necessary we can refactor later
172 continue;
173 }
174 }
175
176 // Mike: Need to add better diagnostic here
177 ShowError("Missing line number in file %s line %d",currentFile.c_str(),currentLineNumber);
178 break;
179 }
180
181 // Standard line
182 *bufPtr++ = 0;
183 *bufPtr++ = 0;
184
185 *bufPtr++ =number&0xFF;
186 *bufPtr++ =number>>8;
187
188 ptr=0;
189 rem=0;
190 bool color=useColor;
191 string=0;
192 data=0;
193 if (ligne[ptr]==' ') ptr++;
194
195 while (ligne[ptr])
196 {
197 if (rem)
198 {
199 char value = ligne[ptr++];
200 if (!optimize)
201 {
202 if (color)
203 {
204 color=false;
205 *bufPtr++ =27; // ESCAPE
206 *bufPtr++ ='B'; // GREEN labels
207 }
208 *bufPtr++ =value;
209 }
210 }
211 else
212 if (string)
213 {
214 if (ligne[ptr]=='"') string=0;
215 *bufPtr++ =ligne[ptr++];
216 }
217 else
218 if (data)
219 {
220 if (ligne[ptr]==':') data=0;
221 *bufPtr++ =ligne[ptr++];
222 }
223 else
224 {
225 const char* pLine=(ligne+ptr);
226 keyw=search_keyword(pLine);
227 if (keyw==29 || ligne[ptr]=='\'') rem=1;
228 if (keyw==17) data=1;
229 if (ligne[ptr]=='"') string=1;
230 if (keyw>=0)
231 {
232 *bufPtr++ =keyw+128;
233 ptr+=strlen(keywords[keyw]);
234 }
235 else
236 {
237 *bufPtr++ =ligne[ptr++];
238 }
239 }
240 }
241 *bufPtr++ = 0;
242 }
243 }
244 }
245 *bufPtr++ = 0;
246 *bufPtr++ = 0;
247
248 //following line modified by Wilfrid AVRILLON (Waskol) 06/20/2009
249 //It should follow this rule of computation : End_Address=Start_Address+File_Size-1
250 //Let's assume a 1 byte program, it starts at address #501 and ends at address #501 (Address=Address+1-1) !
251 //It was a blocking issue for various utilities (tap2wav for instance)
252 //end=0x501+i-1; //end=0x501+i;
253 int i = bufPtr - buf;
254 end=0x501+i;
255
256 if (autoRun) head[7]=0x80; // Autorun for basic :)
257 else head[7]=0;
258
259 head[8]=end>>8;
260 head[9]=end&0xFF;
261
262 for(j=4,lastptr=0;j<i;j++)
263 {
264 if (buf[j]==0)
265 {
266 adr=0x501+j+1;
267 buf[lastptr]=adr&0xFF;
268 buf[lastptr+1]=adr>>8;
269 lastptr=j+1;
270 j+=4;
271 }
272 }
273
274 //
275 // Save file
276 //
277 FILE *out=fopen(destFile,"wb");
278 if (out==NULL)
279 {
280 printf("Can't open file for writing\n");
281 exit(1);
282 }
283 fwrite(head,1,13,out);
284 // write the name
285 if (currentFile.length() > 0)
286 {
287 char *currentFileDup = strdup(currentFile.c_str());
288 char *fileName = currentFileDup;
289 // only take the file name from the path
290 // try to find '\\'
291 char *lastsep = strrchr(fileName, '\\');
292 if (lastsep != NULL)
293 {
294 // if there is something after the separator
295 if (lastsep + 1 != 0)
296 fileName = lastsep + 1;
297 }
298 else
299 {
300 // try to find /
301 lastsep = strrchr(fileName, '/');
302 if (lastsep != NULL)
303 {
304 // if there is something after the separator
305 if (lastsep + 1 != 0)
306 fileName = lastsep + 1;
307 }
308 }
309 // remove the extension if there is one
310 char *lastdot = strrchr(fileName, '.');
311 if (lastdot != NULL)
312 *lastdot = 0;
313 fwrite(fileName, 1, strlen(fileName), out);
314 free(currentFileDup);
315 }
316 fwrite("\x00", 1, 1, out);
317 fwrite(buf,1,i+1,out);
318 // oricutron bug work around
319 //fwrite("\x00", 1, 1, out);
320 fclose(out);
321 }
322
323
324
325
326 #define NB_ARG 2
327
328 int main(int argc, char **argv)
329 {
330 //
331 // Some initialization for the common library
332 //
333 SetApplicationParameters(
334 "Bas2Tap",
335 TOOL_VERSION_MAJOR,
336 TOOL_VERSION_MINOR,
337 "{ApplicationName} - Version {ApplicationVersion} - This program is a part of the OSDK\r\n"
338 "\r\n"
339 "Author:\r\n"
340 " Fabrice Frances \r\n"
341 "\r\n"
342 "Purpose:\r\n"
343 " Converting a text file containing a BASIC source code to a binary\r\n"
344 " encoded TAPE file that can be loaded using the CLOAD command.\r\n"
345 " (and the opposite operation as well).\r\n"
346 "\r\n"
347 "Parameters:\r\n"
348 " <options> <sourcefile> <destinationfile>\r\n"
349 "\r\n"
350 "Options:\r\n"
351 " -b2t[0|1] for converting to tape format with autorun (1) or not (0)\r\n"
352 " -t2b for converting from tape format text\r\n"
353 " -color[0|1] for enabling colored comments"
354 " -optimize[0|1] for allowing for optimizations (disabling comments, etc...)"
355 "\r\n"
356 "Example:\r\n"
357 " {ApplicationName} -b2t1 final.txt osdk.tap\r\n"
358 " {ApplicationName} -t2b osdk.tap program.txt\r\n"
359 );
360
361 bool basicToTape=true;
362 bool autoRun=true;
363 bool useColor=false;
364 bool optimize = false;
365
366 ArgumentParser argumentParser(argc,argv);
367
368 while (argumentParser.ProcessNextArgument())
369 {
370 if (argumentParser.IsSwitch("-t2b"))
371 {
372 // Tape to BASIC source code
373 basicToTape=false;
374 }
375 else
376 if (argumentParser.IsSwitch("-b2t"))
377 {
378 // BASIC source code to tape
379 basicToTape=true;
380 autoRun=argumentParser.GetBooleanValue(true);
381 }
382 else
383 if (argumentParser.IsSwitch("-color"))
384 {
385 // Handling of color codes
386 useColor=argumentParser.GetBooleanValue(false);
387 }
388 else
389 if (argumentParser.IsSwitch("-optimize"))
390 {
391 // Handling of optimization (disables color if enabled)
392 optimize =argumentParser.GetBooleanValue(false);
393 }
394 }
395
396 if (argumentParser.GetParameterCount()!=NB_ARG)
397 {
398 ShowError(0);
399 }
400
401
402 std::string nameSrc(argumentParser.GetParameter(0));
403 std::string nameDst(argumentParser.GetParameter(1));
404
405 if (basicToTape)
406 {
407 Bas2Tap(nameSrc.c_str(),nameDst.c_str(),autoRun,useColor, optimize);
408 }
409 else
410 {
411 // Load the source file
412 void* ptr_buffer_void;
413 size_t file_size;
414 if (!LoadFile(nameSrc.c_str(),ptr_buffer_void,file_size))
415 {
416 ShowError("Unable to load the source file");
417 }
418 unsigned char *ptr_buffer=(unsigned char*)ptr_buffer_void;
419
420 Tap2Bas(ptr_buffer,file_size,nameDst.c_str());
421 }
422
423 exit(0);
424 }

  ViewVC Help
Powered by ViewVC 1.1.26