updated on Thu Jan 26 16:09:46 UTC 2012
[aur-mirror.git] / ktigcc-cvs / .obj / ktigcc1.80 / tpr.cpp
blob57017dbe44baa7b1f8a527c66a5d71968f75d45f
1 /*
2 ktigcc - TIGCC IDE for KDE
4 tpr handling routines adapted from tprbuilder
5 Copyright (C) 2002 Romain LiƩvin
6 Copyright (C) 2002-2009 Kevin Kofler
7 Copyright (C) 2006 Joey Adams
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2, or (at your option)
12 any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software Foundation,
21 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include <cstdio>
25 #include <cstdlib>
26 #include <cerrno>
27 #include <cstring>
28 #include <unistd.h>
29 #include <sys/stat.h>
30 #ifndef _WIN32
31 #include <sys/dir.h>
32 #endif
33 #include <QApplication>
34 #include <QEventLoop>
35 #include <kapplication.h>
36 #include <kcmdlineargs.h>
37 #include <kaboutdata.h>
38 #include <kurl.h>
39 #include <QString>
40 #include <QStringList>
41 #include <QByteArray>
42 #include <QRegExp>
43 #include <QTextCodec>
44 #include <QDir>
45 #include <glib.h>
46 #include <ticonv.h>
47 #include "ktigcc.h"
48 #include "tpr.h"
49 #include "preferences.h"
51 TiconvTextCodec *TiconvTextCodec::instance=NULL;
53 QByteArray TiconvTextCodec::convertFromUnicode(const QChar *input, int number,
54 ConverterState *state __attribute__((unused))) const
56 QString inputNullTerminated(input,number);
57 const unsigned short *utf16=inputNullTerminated.utf16();
58 if (!utf16) return QByteArray();
59 char *ti=ticonv_charset_utf16_to_ti(CALC_TI89,utf16);
60 QByteArray result(ti);
61 g_free(ti);
62 return result;
65 QString TiconvTextCodec::convertToUnicode(const char *chars, int len,
66 ConverterState *state __attribute__((unused))) const
68 QByteArray inputNullTerminated(chars,len);
69 const char *ti=inputNullTerminated.constData();
70 if (!ti) return QString();
71 unsigned short *utf16=ticonv_charset_ti_to_utf16(CALC_TI89,ti);
72 QString result=QString::fromUtf16(utf16);
73 g_free(utf16);
74 return result;
77 #define find_param(s_,t_) find_param_ex((s_),(t_),sizeof(t_)-1)
79 static char *find_param_ex(char *s, const char *t, size_t l)
81 if (!strncmp(s,t,l))
82 return s+l;
83 else
84 return NULL;
87 static char *find_numbered_param(char *s, const char*t, int *i)
89 char *p;
90 int endpos = 0;
91 int ret = 0;
92 char arglist[256];
94 strcpy(arglist, t);
95 strcat(arglist, "%n");
97 ret = sscanf(s, arglist, i, &endpos);
98 if(ret < 1 || !endpos) return NULL;
100 p = s + endpos;
101 return p;
104 // converts Windows paths to Unix paths if necessary.
105 static QString convert_path_separators(const char *file)
107 QString s=file;
108 int o;
110 #ifndef _WIN32
111 while ((o=s.find('\\',0,TRUE))>=0)
112 s[o]='/';
113 #endif
115 return s;
118 static char* strip(char *str)
120 int len = strlen(str);
122 if(len > 0)
123 if( (str[len-1] == '\r') || (str[len-1] == '\n') )
124 str[len-1] = '\0';
126 if(len > 1)
127 if( (str[len-2] == '\r') || (str[len-2] == '\n') )
128 str[len-2] = '\0';
130 return str;
134 Read a line from file and do a clean-up
136 static int read_line(FILE *f, char *buffer, int *l)
138 strcpy(buffer, "");
139 if(feof(f)) return EOF;
140 if (!fgets(buffer, 256, f)) return feof(f)?EOF:1;
141 strip(buffer);
142 (*l)++;
143 while( (buffer[0] == '\r') || (buffer[0] == '\n') || (buffer[0] == '\0') )
145 if(feof(f)) return EOF;
146 if (!fgets(buffer, 256, f)) return feof(f)?EOF:1;
147 strip(buffer);
148 (*l)++;
151 return 0;
154 //some items from the TSR might still be ignored or not shown here.
155 //if you need one of them, add an entry to one of the
156 //definition "tables".
157 //If you add an entry here, don't forget to add something to
158 // save_tpr!
159 static int parse_file(FILE *f,TPRDataStruct *dest)
161 char buffer[256];
162 int l = 0;
163 SectionType stype = SECTION_NONE;
165 // Some defaults are different when opening an existing project.
166 dest->settings.cc_switches="";
167 dest->settings.as_switches="";
168 dest->settings.a68k_switches="";
169 dest->libopts.use_ti89=0;
170 dest->libopts.use_ti92p=0;
171 dest->libopts.use_v200=0;
172 dest->libopts.use_minams=0;
173 dest->libopts.save_screen=0;
175 while(!feof(f))
177 char *p;
179 // Get a line from file
180 int result=read_line(f, buffer, &l);
181 if (result == 1) return -1; // error
182 if (result == EOF) break;
184 // Search for sections
185 if( !strcmp(buffer, "[Settings]") )
187 stype = SECTION_SETTINGS;
188 continue;
191 if( !strcmp(buffer, "[Library Options]") )
193 stype = SECTION_LIBOPTS;
194 continue;
197 if( !strcmp(buffer, "[File Editing]") )
199 stype = SECTION_FILEEDIT;
200 continue;
203 if( !strcmp(buffer, "[Included Files]") )
205 stype = SECTION_FILES;
206 continue;
209 // Keywords in the [Settings] section
210 if(stype == SECTION_SETTINGS) {
212 #define boolean_param(token,setting) \
213 if ( (p=find_param(buffer, token)) ) \
215 if(!strcmp(p, "0")) dest->settings.setting = FALSE; \
216 else if(!strcmp(p, "1")) dest->settings.setting = TRUE; \
217 else return l; \
218 continue; \
219 } else
221 #define tistring_vparam(token,var) \
222 if ( (p=find_param(buffer, token)) ) \
224 if (*p) { \
225 dest->var = TiconvTextCodec::instance->toUnicode(p); \
227 continue; \
228 } else
230 #define tistring_param(token,setting) tistring_vparam(token,settings.setting)
232 #define string_param(token,setting) \
233 if ( (p=find_param(buffer, token)) ) \
235 if (*p) dest->settings.setting = p; \
236 continue; \
237 } else
239 #define ignore_param(token) \
240 if( (p=find_param(buffer, token)) ) \
242 continue; \
243 } else
245 boolean_param("Archive=",archive)
246 boolean_param("Pack=",pack)
247 tistring_param("Packed Variable=",pack_name)
248 tistring_vparam("Project Name=",prj_name)
249 string_param("GCC Switches=",cc_switches)
250 string_param("Assembler Switches=",a68k_switches)
251 ignore_param("Linker Switches=") // Obsolete. Ignore.
252 ignore_param("GNU Linker Switches=") // Obsolete. Ignore.
253 string_param("GNU Assembler Switches=",as_switches)
254 ignore_param("BSR Patch=") // Obsolete. Ignore.
255 boolean_param("Debug Info=",debug_info)
256 boolean_param("Standard Library=",std_lib)
257 tistring_param("Command Line=",cmd_line)
258 string_param("Post-Build Process=",post_build)
259 boolean_param("Use Data Variable=",use_data_var)
260 tistring_param("Data Variable=",data_var)
261 boolean_param("Copy Data Variable=",copy_data_var)
262 boolean_param("Copy Data Variable if Archived=",copy_data_var_arc)
263 boolean_param("Optimize NOPs=",optimize_nops)
264 boolean_param("Optimize Returns=",optimize_returns)
265 boolean_param("Optimize Branches=",optimize_branches)
266 boolean_param("Optimize Moves=",optimize_moves)
267 boolean_param("Optimize Tests=",optimize_tests)
268 boolean_param("Optimize Calculations=",optimize_calcs)
269 boolean_param("Remove Unused Sections=",remove_unused)
270 boolean_param("Binary Output=",outputbin)
271 boolean_param("Fargo=",fargo)
272 boolean_param("Flash OS=",flash_os)
273 boolean_param("Cut Unused Ranges=",cut_ranges)
274 boolean_param("Reorder Sections=",reorder_sections)
275 boolean_param("Merge Constants=",merge_constants)
276 boolean_param("Initialize BSS=",initialize_bss)
277 return l;
279 #undef boolean_param
280 #undef tistring_vparam
281 #undef tistring_param
282 #undef string_param
283 #undef ignore_param
286 // Keywords in the [Library Options] section
287 if(stype == SECTION_LIBOPTS) {
288 #define boolean_param(token,setting) \
289 if ( (p=find_param(buffer, token)) ) \
291 if(!strcmp(p, "0")) dest->libopts.setting = FALSE; \
292 else if(!strcmp(p, "1")) dest->libopts.setting = TRUE; \
293 else return l; \
294 continue; \
295 } else
297 #define reloc_param(token,setting) \
298 if ( (p=find_param(buffer, token)) ) \
300 if (!strcmp(p,"None")) \
301 dest->libopts.setting = RT_NONE; \
302 else if (!strcmp(p,"Direct")) \
303 dest->libopts.setting = RT_DIRECT; \
304 else if (!strcmp(p,"AMS")) \
305 dest->libopts.setting = RT_AMS; \
306 else if (!strcmp(p, "Precomputed")) \
307 dest->libopts.setting = RT_PRECOMP; \
308 else if (!strcmp(p, "Kernel")) \
309 dest->libopts.setting = RT_KERNEL; \
310 else if (!strcmp(p, "Compressed")) \
311 dest->libopts.setting = RT_COMPRESSED; \
312 else if (!strcmp(p, "MLink")) \
313 dest->libopts.setting = RT_MLINK; \
314 else if (!strcmp(p, "F-Line")) \
315 dest->libopts.setting = RT_FLINE; \
316 else if (strcmp(p, "Unknown")) \
317 return l; \
318 continue; \
319 } else
321 #define minams_param(token,setting) \
322 if ( (p=find_param(buffer, "Minimum AMS Version=")) ) \
324 int major, minor; \
325 if ((strlen(p)==4) \
326 && (sscanf(p,"%1d.%2d",&major,&minor)==2)) \
327 dest->libopts.minams = major * 100 + minor; \
328 else \
329 return l; \
330 continue; \
331 } else
333 boolean_param("Use TI-89=",use_ti89)
334 boolean_param("Use TI-92 Plus=",use_ti92p)
335 boolean_param("Use V200=",use_v200)
336 boolean_param("Optimize Calc Consts=",opt_calc_consts)
337 boolean_param("Use Kernel=",use_kernel)
338 boolean_param("Use PreOS=",use_preos)
339 boolean_param("Minimum AMS Version Defined=",use_minams)
340 minams_param("Minimum AMS Version=",minams)
341 boolean_param("Unofficial OS Support=",unofficial_os)
342 reloc_param("Reloc Format=",reloc_format)
343 reloc_param("ROM Call Format=",rom_call_format)
344 reloc_param("BSS Ref Format=",bss_ref_format)
345 reloc_param("Data Ref Format=",data_ref_format)
346 boolean_param("Use F-Line Jumps=",use_fline_jumps)
347 boolean_param("Use 4-Byte F-Line Jumps=",use_4b_fline_jumps)
348 boolean_param("Use Internal F-Line Emulator=",use_internal_fline_emu)
349 boolean_param("Use Return Value=",use_return_value)
350 boolean_param("Enable Error Return=",enable_error_return)
351 boolean_param("Save Screen=",save_screen)
352 boolean_param("Optimize ROM Calls=",opt_rom_calls)
353 return l;
355 #undef boolean_param
356 #undef reloc_param
357 #undef minams_param
360 // Keywords in the [File Editing] section
361 if(stype == SECTION_FILEEDIT)
363 if ( (p=find_param(buffer, "Open File=")) ) \
365 if (*p) dest->open_file = p; \
366 continue; \
367 } else return l;
370 // Keywords in the [Included Files] section
371 if(stype == SECTION_FILES)
373 int v;
375 if( (p=find_numbered_param(buffer, "C File %i=", &v)) )
377 QString s = convert_path_separators(p);
378 dest->c_files.path << s;
379 dest->c_files.folder << QString::null;
381 continue;
383 else if( (p=find_numbered_param(buffer, "C File %i Folder=", &v)) )
385 dest->c_files.folder[v-1]=p;
386 continue;
389 else if( (p=find_numbered_param(buffer, "GNU Assembler File %i=", &v)) )
391 QString s = convert_path_separators(p);
392 dest->s_files.path << s;
393 dest->s_files.folder << QString::null;
395 continue;
397 else if( (p=find_numbered_param(buffer, "GNU Assembler File %i Folder=", &v)) )
399 dest->s_files.folder[v-1]=p;
400 continue;
403 else if( (p=find_numbered_param(buffer, "Header File %i=", &v)) )
405 QString s = convert_path_separators(p);
406 dest->h_files.path << s;
407 dest->h_files.folder << QString::null;
409 continue;
411 else if( (p=find_numbered_param(buffer, "Header File %i Folder=", &v)) )
413 dest->h_files.folder[v-1]=p;
414 continue;
417 else if( (p=find_numbered_param(buffer, "Assembler File %i=", &v)) )
419 QString s = convert_path_separators(p);
420 dest->asm_files.path << s;
421 dest->asm_files.folder << QString::null;
423 continue;
425 else if( (p=find_numbered_param(buffer, "Assembler File %i Folder=", &v)) )
427 dest->asm_files.folder[v-1]=p;
428 continue;
431 else if( (p=find_numbered_param(buffer, "Object File %i=", &v)) )
433 QString s = convert_path_separators(p);
434 dest->o_files.path << s;
435 dest->o_files.folder << QString::null;
437 continue;
439 else if( (p=find_numbered_param(buffer, "Object File %i Folder=", &v)) )
441 dest->o_files.folder[v-1]=p;
442 continue;
445 else if( (p=find_numbered_param(buffer, "Archive File %i=", &v)) )
447 QString s = convert_path_separators(p);
448 dest->a_files.path << s;
449 dest->a_files.folder << QString::null;
451 continue;
453 else if( (p=find_numbered_param(buffer, "Archive File %i Folder=", &v)) )
455 dest->a_files.folder[v-1]=p;
456 continue;
459 else if( (p=find_numbered_param(buffer, "Text File %i=", &v)) )
461 QString s = convert_path_separators(p);
462 dest->txt_files.path << s;
463 dest->txt_files.folder << QString::null;
465 continue;
467 else if( (p=find_numbered_param(buffer, "Text File %i Folder=", &v)) )
469 dest->txt_files.folder[v-1]=p;
470 continue;
473 else if( (p=find_numbered_param(buffer, "Quill File %i=", &v)) )
475 QString s = convert_path_separators(p);
476 dest->quill_files.path << s;
477 dest->quill_files.folder << QString::null;
479 continue;
481 else if( (p=find_numbered_param(buffer, "Quill File %i Folder=", &v)) )
483 dest->quill_files.folder[v-1]=p;
484 continue;
487 else if( (p=find_numbered_param(buffer, "Other File %i=", &v)) )
489 QString s = convert_path_separators(p);
490 dest->oth_files.path << s;
491 dest->oth_files.folder << QString::null;
493 continue;
495 else if( (p=find_numbered_param(buffer, "Other File %i Folder=", &v)) )
497 dest->oth_files.folder[v-1]=p;
498 continue;
501 else return l;
506 return 0;
509 // returns 0 on success, -1 if it can't open the TPR and a (positive) line
510 // number if there is an error in the TPR
511 int loadTPR(const QString &fileName,TPRDataStruct *dest)
513 FILE *f;
514 int ret;
515 f = fopen(fileName, "r");
516 if(f == NULL) {
517 return -1;
519 ret=parse_file(f,dest);
520 fclose(f);
521 return ret;
524 QString loadFileText(const char *fileName)
526 FILE *f;
527 f=fopen(fileName,"rb");
528 if (!f)
529 return QString::null;
530 fseek(f,0,SEEK_END);
531 size_t flen=ftell(f);
532 fseek(f,0,SEEK_SET);
533 char *buffer = new(std::nothrow) char[flen+1];
534 if (!buffer) {
535 fclose(f);
536 return QString::null;
538 std::memset(buffer,0,flen+1);
539 QString ret;
540 if (fread(buffer,1,flen,f)<flen) {
541 fclose(f);
542 delete[] buffer;
543 ret=QString::null;
544 } else {
545 fclose(f);
546 if (preferences.useCalcCharset) {
547 ret=TiconvTextCodec::instance->toUnicode(buffer);
548 } else {
549 ret=buffer;
551 delete[] buffer;
553 if (!ret.isNull()) {
554 // convert Windows line endings
555 ret=ret.replace("\r\n","\n");
556 // interpret remaining \r characters as Mac line endings
557 ret=ret.replace('\r','\n');
558 // remove trailing spaces if requested
559 if (preferences.removeTrailingSpaces) {
560 ret=ret.replace(QRegExp("((?!\n)\\s)*\n"),"\n");
561 ret=ret.remove(QRegExp("((?!\n)\\s)*$"));
564 return ret;
567 // Returns -1 if the file is empty, -2 on error.
568 int peekFirstChar(const char *fileName)
570 FILE *f;
571 f=fopen(fileName,"rb");
572 if (!f)
573 return -2;
574 int result=getc(f);
575 if (result==EOF) result=feof(f)?-1:-2;
576 fclose(f);
577 return result;
580 static QString convert_path_separators_save(QString s)
582 int o;
584 #ifndef _WIN32
585 while ((o=s.find('/',0,TRUE))>=0)
586 s[o]='\\';
587 #endif
589 return s;
592 //this is here because QString::ascii() returns "(null)" on a null string.
593 const char *smartAscii(const QString &s)
595 if (s.isNull())
596 return "";
597 return s.ascii();
600 static int save_tpr(FILE *f,TPRDataStruct *dest)
602 unsigned i=0,e;
603 QString tmp;
605 #define boolean_param(token,setting) if (fprintf(f,token "%d\r\n",!!dest->settings.setting)<0) return -2;
606 #define tistring_vparam(token,var) { \
607 const char *ti=TiconvTextCodec::instance->fromUnicode(dest->var).constData(); \
608 if (!ti) ti=""; \
609 if (fprintf(f,token "%s\r\n",ti)<0) return -2; \
611 #define tistring_param(token,setting) tistring_vparam(token,settings.setting)
612 #define string_param(token,setting) if (fprintf(f,token "%s\r\n",smartAscii(dest->settings.setting))<0) return -2;
613 #define ignore_param(token) /**/
615 if (fputs("[Settings]\r\n",f)<0) return -2;
616 boolean_param("Archive=",archive)
617 boolean_param("Pack=",pack)
618 tistring_param("Packed Variable=",pack_name)
619 tistring_vparam("Project Name=",prj_name)
620 string_param("GCC Switches=",cc_switches)
621 string_param("Assembler Switches=",a68k_switches)
622 ignore_param("Linker Switches=") // Obsolete. Ignore.
623 ignore_param("GNU Linker Switches=") // Obsolete. Ignore.
624 string_param("GNU Assembler Switches=",as_switches)
625 ignore_param("BSR Patch=") // Obsolete. Ignore.
626 boolean_param("Debug Info=",debug_info)
627 boolean_param("Standard Library=",std_lib)
628 tistring_param("Command Line=",cmd_line)
629 string_param("Post-Build Process=",post_build)
630 boolean_param("Use Data Variable=",use_data_var)
631 tistring_param("Data Variable=",data_var)
632 boolean_param("Copy Data Variable=",copy_data_var)
633 boolean_param("Copy Data Variable if Archived=",copy_data_var_arc)
634 boolean_param("Optimize NOPs=",optimize_nops)
635 boolean_param("Optimize Returns=",optimize_returns)
636 boolean_param("Optimize Branches=",optimize_branches)
637 boolean_param("Optimize Moves=",optimize_moves)
638 boolean_param("Optimize Tests=",optimize_tests)
639 boolean_param("Optimize Calculations=",optimize_calcs)
640 boolean_param("Remove Unused Sections=",remove_unused)
641 boolean_param("Binary Output=",outputbin)
642 boolean_param("Fargo=",fargo)
643 boolean_param("Flash OS=",flash_os)
644 boolean_param("Cut Unused Ranges=",cut_ranges)
645 boolean_param("Reorder Sections=",reorder_sections)
646 boolean_param("Merge Constants=",merge_constants)
647 boolean_param("Initialize BSS=",initialize_bss)
649 #undef boolean_param
650 #undef tistring_vparam
651 #undef tistring_param
652 #undef string_param
653 #undef ignore_param
655 #define boolean_param(token,setting) if (fprintf(f,token "%d\r\n",!!dest->libopts.setting)<0) return -2;
657 #define reloc_param(token,setting) \
658 switch(dest->libopts.setting) \
660 case RT_NONE: \
661 if (fprintf(f,token "None\r\n")<0) return -2; \
662 break; \
663 case RT_DIRECT: \
664 if (fprintf(f,token "Direct\r\n")<0) return -2; \
665 break; \
666 case RT_AMS: \
667 if (fprintf(f,token "AMS\r\n")<0) return -2; \
668 break; \
669 case RT_PRECOMP: \
670 if (fprintf(f,token "Precomputed\r\n")<0) return -2; \
671 break; \
672 case RT_KERNEL: \
673 if (fprintf(f,token "Kernel\r\n")<0) return -2; \
674 break; \
675 case RT_COMPRESSED: \
676 if (fprintf(f,token "Compressed\r\n")<0) return -2; \
677 break; \
678 case RT_MLINK: \
679 if (fprintf(f,token "MLink\r\n")<0) return -2; \
680 break; \
681 case RT_FLINE: \
682 if (fprintf(f,token "F-Line\r\n")<0) return -2; \
683 break; \
686 #define minams_param(token,setting) \
688 int major,minor; \
689 major=dest->libopts.setting/100; \
690 minor=dest->libopts.setting%100; \
691 if (fprintf(f,token "%d.%02d\r\n",major,minor)<0) return -2; \
694 if (fputs("\r\n[Library Options]\r\n",f)<0) return -2;
695 boolean_param("Use TI-89=",use_ti89)
696 boolean_param("Use TI-92 Plus=",use_ti92p)
697 boolean_param("Use V200=",use_v200)
698 boolean_param("Optimize Calc Consts=",opt_calc_consts)
699 boolean_param("Use Kernel=",use_kernel)
700 boolean_param("Use PreOS=",use_preos)
701 boolean_param("Minimum AMS Version Defined=",use_minams)
702 minams_param("Minimum AMS Version=",minams)
703 boolean_param("Unofficial OS Support=",unofficial_os)
704 reloc_param("Reloc Format=",reloc_format)
705 reloc_param("ROM Call Format=",rom_call_format)
706 reloc_param("BSS Ref Format=",bss_ref_format)
707 reloc_param("Data Ref Format=",data_ref_format)
708 boolean_param("Use F-Line Jumps=",use_fline_jumps)
709 boolean_param("Use 4-Byte F-Line Jumps=",use_4b_fline_jumps)
710 boolean_param("Use Internal F-Line Emulator=",use_internal_fline_emu)
711 boolean_param("Use Return Value=",use_return_value)
712 boolean_param("Enable Error Return=",enable_error_return)
713 boolean_param("Save Screen=",save_screen)
714 boolean_param("Optimize ROM Calls=",opt_rom_calls)
716 #undef boolean_param
717 #undef reloc_param
718 #undef minams_param
720 if (fprintf(f,"\r\n[File Editing]\r\nOpen File=%s\r\n\r\n[Included Files]\r\n",smartAscii(dest->open_file))<0) return -2;
722 #define filepath_param(token,filetype) \
723 e=dest->filetype.path.count(); \
724 for(i=0;i<e;i++) \
726 tmp=convert_path_separators_save(smartAscii(dest->filetype.path[i])); \
727 if (fprintf(f,token " %u=%s\r\n",i+1,smartAscii(tmp))<0) return -2; \
728 if (!dest->filetype.folder[i].isEmpty()) \
730 if (fprintf(f,token " %u Folder=%s\r\n",i+1,smartAscii(dest->filetype.folder[i]))<0) return -2; \
734 filepath_param("C File",c_files)
735 filepath_param("GNU Assembler File",s_files)
736 filepath_param("Header File",h_files)
737 filepath_param("Assembler File",asm_files)
738 filepath_param("Object File",o_files)
739 filepath_param("Archive File",a_files)
740 filepath_param("Text File",txt_files)
741 filepath_param("Quill File",quill_files)
742 filepath_param("Other File",oth_files)
744 #undef filepath_param
746 if (fputs("\r\n",f)<0) return -2;
748 return 0;
751 void newSettings(tprSettings *settings,tprLibOpts *libopts)
753 tprSettings newSettings;
754 tprLibOpts newLibOpts;
755 *settings=newSettings;
756 *libopts=newLibOpts;
759 //returns 0 on success, -1 if the file couldn't be created or -2 if fprintf,
760 //fputs or fclose failed
761 int saveTPR(const QString &fileName,TPRDataStruct *src)
763 FILE *f;
764 int ret;
765 f=fopen(fileName,"wb");
766 if (!f)
768 return -1;
770 ret=save_tpr(f,src);
771 if (fclose(f)) return -2;
772 return ret;
775 void mkdir_multi(const char *fileName)
777 int l=strlen(fileName);
778 char buffer[l+2];
779 const char *ptr;
781 #ifdef _WIN32
782 ptr=strchr(fileName,'\\');
783 #else
784 ptr=strchr(fileName,'/');
785 #endif
787 while (ptr)
789 memcpy(buffer,fileName,ptr-fileName);
790 buffer[ptr-fileName]=0;
791 #ifdef _WIN32
792 mkdir(buffer);
794 ptr=strchr(ptr+1,'\\');
795 #else
796 mkdir(buffer,S_IRWXU | S_IRWXG | S_IRWXO);
798 ptr=strchr(ptr+1,'/');
799 #endif
803 static int writeToFile(FILE *f, const QString &text)
805 if (preferences.useCalcCharset) {
806 if (!text.isEmpty()) {
807 QByteArray s=TiconvTextCodec::instance->fromUnicode(text);
808 size_t l=s.length();
809 if (fwrite(s.constData(),1,l,f)<l) {
810 return -2;
813 } else {
814 const char *s=smartAscii(text);
815 size_t l=std::strlen(s);
816 if (fwrite(s,1,l,f)<l) return -2;
818 return 0;
821 enum CharModes {cmNone, cmNormalText, cmNumber, cmMultiSymbol, cmString, cmChar,
822 cmComment, cmUnchangeableLine, cmExtUnchangeableLine,
823 cmExtUnchangeableLineString, cmTrigraph};
825 int saveAndSplitFileText(const char *fileName, const QString &fileText,
826 bool split, bool addCLineDirective,
827 bool addASMLineDirective, const QString &origFileName,
828 LineStartList *pLineStartList)
830 FILE *f;
831 LineStartList lineStartList;
832 // remove trailing spaces if requested
833 QString text=fileText;
834 if (preferences.removeTrailingSpaces && !text.isNull()) {
835 text=text.replace(QRegExp("((?!\n)\\s)*\n"),"\n");
836 text=text.remove(QRegExp("((?!\n)\\s)*$"));
839 f=fopen(fileName,"wb");
840 if (!f)
842 mkdir_multi(fileName);
843 f=fopen(fileName,"wb");
844 if (!f)
845 return -1;
847 if (split && preferences.splitSourceFiles && !settings.debug_info) {
848 unsigned curPos=0, curLine=0, curCol=0, l=text.length();
849 bool atLineStart;
850 CharModes curMode=cmNone;
852 #define INSERT_CHAR(ch) do {if (writeToFile(f,QString((ch)))) {fclose(f); return -2;}} while(0)
853 #define INSERT_STRING(str) do {if (writeToFile(f,(str))) {fclose(f); return -2;}} while(0)
854 #define ADD_LINE() do {lineStartList.append(qMakePair(curLine,curCol)); atLineStart=TRUE;} while(0)
855 #define IS_NEWLINE() (text[curPos]=='\n')
856 #define ADD_LINE_NEXT() do {lineStartList.append(qMakePair(curLine+(unsigned)(IS_NEWLINE()),(IS_NEWLINE())?0u:(curCol+1u))); atLineStart=TRUE;} while(0)
857 #define NEW_LINE() do {if((!(atLineStart||IS_NEWLINE())) || (text[curPos]=='#')) {INSERT_CHAR(QChar('\n')); ADD_LINE();} curMode=cmNone;} while(0)
858 #define SET_MULTI_CHAR_MODE(mode) do {if (curMode!=(mode)) {NEW_LINE(); curMode=(mode);}} while(0)
860 ADD_LINE(); // Line 0
861 for (; curPos<l; curPos++) {
862 bool noInsert=FALSE;
863 QChar c=text[curPos];
864 if (c=='\n')
865 ADD_LINE_NEXT();
866 switch (curMode) {
867 case cmString:
868 if (c=='\"') {
869 bool b=TRUE;
870 unsigned i=curPos-1;
871 while (i && ((text[i]=='\\')||(i>=2&&!text.mid(i-2,3).compare("?""?""/")))) {
872 b=!b;
873 if (text[i]=='\\') --i; else i-=3;
875 if (b) {
876 curMode=cmNone;
877 noInsert=TRUE;
878 INSERT_STRING(QString(c)+"\n");
879 atLineStart=TRUE;
880 ADD_LINE_NEXT();
883 break;
884 case cmChar:
885 if (c=='\'') {
886 bool b=TRUE;
887 unsigned i=curPos-1;
888 while (i && ((text[i]=='\\')||(i>=2&&!text.mid(i-2,3).compare("?""?""/")))) {
889 b=!b;
890 if (text[i]=='\\') --i; else i-=3;
892 if (b) curMode=cmNone;
894 break;
895 case cmComment:
896 if ((c=='/')&&(text[curPos-1]=='*')) curMode=cmNone;
897 break;
898 case cmUnchangeableLine:
899 if (c=='\n') curMode=cmNone;
900 break;
901 case cmExtUnchangeableLine:
902 if ((c=='\n')&&(text[curPos-1]!='\\')) curMode=cmNone;
903 else if (c=='\"') curMode=cmExtUnchangeableLineString;
904 break;
905 case cmExtUnchangeableLineString:
906 if (c=='\"') {
907 bool b=TRUE;
908 unsigned i=curPos-1;
909 while (i && ((text[i]=='\\')||(i>=2&&!text.mid(i-2,3).compare("?""?""/")))) {
910 b=!b;
911 if (text[i]=='\\') --i; else i-=3;
913 if (b) curMode=cmExtUnchangeableLine;
915 break;
916 case cmTrigraph:
917 if ((c!='?')&&((curPos+1>=l)||(text[curPos+1]!='?'))) curMode=cmNone;
918 break;
919 default:
920 if (!text.mid(curPos,2).compare("//"))
921 SET_MULTI_CHAR_MODE(cmUnchangeableLine);
922 else if (!text.mid(curPos,2).compare("/*"))
923 SET_MULTI_CHAR_MODE(cmComment);
924 else if (!text.mid(curPos,3).compare("?""?""="))
925 SET_MULTI_CHAR_MODE(cmExtUnchangeableLine);
926 else if (!text.mid(curPos,2).compare("?""?")&&(curPos+2<l)
927 &&QString("()/\'<>!-").contains(text[curPos+2]))
928 SET_MULTI_CHAR_MODE(cmTrigraph);
929 else {
930 switch(c.unicode()) {
931 case ' ':
932 case '\t':
933 if (curPos && text[curPos-1]!=' ' && text[curPos-1]!='\t')
934 NEW_LINE();
935 break;
936 case 'A' ... 'Z':
937 case 'a' ... 'z':
938 case '0' ... '9':
939 case '_':
940 case '$':
941 if (curMode!=cmNormalText && curMode!=cmNumber) {
942 NEW_LINE();
943 if (c>=QChar('0') && c<=QChar('9'))
944 curMode=cmNumber;
945 else
946 curMode=cmNormalText;
948 break;
949 case '\"':
950 SET_MULTI_CHAR_MODE(cmString);
951 break;
952 case '\'':
953 SET_MULTI_CHAR_MODE(cmChar);
954 break;
955 case '#':
956 SET_MULTI_CHAR_MODE(cmExtUnchangeableLine);
957 break;
958 case '.':
959 if (curMode!=cmNumber) {
960 if ((curPos+1<l)
961 &&(text[curPos+1]>=QChar('0')
962 &&text[curPos+1]<=QChar('9'))) {
963 NEW_LINE();
964 curMode=cmNumber;
965 } else SET_MULTI_CHAR_MODE(cmMultiSymbol);
967 break;
968 case '+':
969 case '-':
970 if ((curMode!=cmNumber)||(curPos<=1)
971 ||!QString("eEpP").contains(text[curPos-1]))
972 SET_MULTI_CHAR_MODE(cmMultiSymbol);
973 break;
974 default:
975 if (QString(",;()[]{}").contains(c)) {
976 if (curMode!=cmNone) {
977 NEW_LINE();
978 curMode=cmNone;
980 if ((curPos+1<l)&&text[curPos+1]!='\n') {
981 noInsert=TRUE;
982 INSERT_STRING(QString(c)+"\n");
983 ADD_LINE_NEXT();
985 } else SET_MULTI_CHAR_MODE(cmMultiSymbol);
986 break;
989 break;
991 if (!noInsert) {
992 // Special cases:
993 switch(c.unicode()) {
994 // Surrogate pairs.
995 case 0xd800 ... 0xdbff:
996 if (curPos<l && text[curPos+1].unicode()>=0xdc00
997 && text[curPos+1].unicode()<=0xdfff) {
998 INSERT_STRING(QString(c)+text[curPos+1]);
999 // Allow the UI to respond, splitting is a lengthy operation.
1000 if ((curPos++)&127)
1001 QCoreApplication::processEvents(QEventLoop::AllEvents,1000);
1002 curPos++;
1003 curCol++;
1004 break;
1005 } else goto de_fault;
1006 // x-bar and y-bar are special if we use the calculator charset.
1007 case 0x305:
1008 if (preferences.useCalcCharset && curPos<l
1009 && (text[curPos+1]=='x' || text[curPos+1]=='y')) {
1010 INSERT_STRING(QString(c)+text[curPos+1]);
1011 // Allow the UI to respond, splitting is a lengthy operation.
1012 if ((curPos++)&127)
1013 QCoreApplication::processEvents(QEventLoop::AllEvents,1000);
1014 curCol++;
1015 break;
1017 default:
1018 de_fault:
1019 INSERT_CHAR(c);
1020 break;
1022 if (c!='\n') atLineStart=FALSE;
1024 if (c=='\n') {
1025 curLine++;
1026 curCol=0;
1027 } else curCol++;
1028 // Allow the UI to respond, splitting is a lengthy operation.
1029 if (curPos&127)
1030 QCoreApplication::processEvents(QEventLoop::AllEvents,1000);
1032 NEW_LINE();
1034 #undef INSERT_CHAR
1035 #undef INSERT_STRING
1036 #undef ADD_LINE
1037 #undef IS_NEWLINE
1038 #undef ADD_LINE_NEXT
1039 #undef NEW_LINE
1040 #undef SET_MULTI_CHAR_MODE
1041 } else {
1042 if ((addCLineDirective || addASMLineDirective) && settings.debug_info) {
1043 QString escapedFileName=origFileName, lineDirective;
1044 escapedFileName.replace("\\","\\\\");
1045 escapedFileName.replace("\"","\\\"");
1046 // These have no business to be in a file name, but someone somewhere may
1047 // have that very bad idea...
1048 escapedFileName.replace("\r","\\r");
1049 escapedFileName.replace("\n","\\n");
1050 lineDirective=QString(addCLineDirective
1051 ?"#line 1 \"%1\"\n"
1052 :".appfile \"%1\"; .appline 1\n").arg(escapedFileName);
1053 // Don't use calc charset for this, it's a host file name.
1054 const char *s=smartAscii(lineDirective);
1055 size_t l=std::strlen(s);
1056 if (fwrite(s,1,l,f)<l) return -2;
1058 if (writeToFile(f,text)) {fclose(f); return -2;}
1059 if (fwrite("\n",1,1,f)<1) {fclose(f); return -2;}
1061 if (fclose(f)) return -2;
1062 if (pLineStartList) *pLineStartList=lineStartList;
1063 return 0;
1066 void kurlNewFileName(KUrl &dir,const QString &newFileName)
1068 if (!newFileName.isEmpty() && newFileName[0]=='/')
1069 dir.setPath(newFileName);
1070 else
1071 dir.setFileName(newFileName);
1074 static QString pullOutFileSuffix(const QString &srcFileName,QString &destFileName)
1076 int a,b;
1077 QString ret;
1078 destFileName=srcFileName;
1079 a=destFileName.findRev('.');
1080 b=destFileName.findRev('/');
1081 if (a<0)
1082 return QString::null;
1083 if (a<b)
1084 return QString::null;
1085 ret=destFileName.mid(a+1);
1086 destFileName.truncate(a);
1087 return ret;
1090 int checkFileName(const QString &fileName,const QStringList &fileNameList)
1092 int i;
1093 QString fileName_name,fileName_suffix;
1094 QString name,suffix;
1095 fileName_suffix=pullOutFileSuffix(fileName,fileName_name);
1096 for (i=fileNameList.count()-1;i>=0;i--)
1098 suffix=pullOutFileSuffix(fileNameList[i],name);
1099 if (!suffix.compare("c")||!suffix.compare("s")||!suffix.compare("asm")||!suffix.compare("o")||!suffix.compare("qll"))
1101 if (!fileName_suffix.compare("c")||!fileName_suffix.compare("s")||!fileName_suffix.compare("asm")||!fileName_suffix.compare("o")||!fileName_suffix.compare("qll"))
1103 if (!name.compare(fileName_name))
1104 return 0;
1107 else
1109 if (!fileNameList[i].compare(fileName))
1110 return 0;
1113 return 1;
1116 // returns 0 on success, >0 on read failure, <0 on write failure
1117 int copyFile(const char *src, const char *dest)
1119 // This doesn't load everything at once onto the stack because it may be
1120 // used for huge binary files, which don't fit on the stack. So we copy 1KB
1121 // at a time.
1122 FILE *sf=fopen(src,"rb");
1123 if (!sf) return 1;
1124 FILE *df=fopen(dest,"wb");
1125 if (!df) {fclose(sf); return -1;}
1126 char buffer[1024];
1127 while (!ferror(sf) && !feof(sf)) {
1128 size_t bytes_read=fread(buffer,1,1024,sf);
1129 if (fwrite(buffer,1,bytes_read,df)<bytes_read) {
1130 fclose(df);
1131 fclose(sf);
1132 return -2;
1135 if (ferror(sf)) {
1136 fclose(df);
1137 fclose(sf);
1138 return 2;
1140 if (fclose(df)) {fclose(sf); return -3;}
1141 if (fclose(sf)) return 3;
1142 return 0;
1145 // Returns TRUE on success, FALSE on failure.
1146 bool moveFile(const QString &src, const QString &dest)
1148 // Trap the obvious case before even bothering.
1149 if (src==dest) return TRUE;
1150 QDir qdir;
1151 // First try a simple rename.
1152 if (qdir.rename(src,dest)) return TRUE;
1153 // That didn't work, probably because the files are not on the same file
1154 // system. So do a copy&delete operation.
1155 if (copyFile(src,dest)) return FALSE;
1156 return qdir.remove(src);
1159 // Replaces the first occurrence of "tempprog" in a pstarter with name.
1160 // returns 0 on success, >0 on read failure, <0 on write failure
1161 int insertName(const char *src, const char *dest, const char *name)
1163 FILE *sf=std::fopen(src,"rb");
1164 if (!sf) return 1;
1165 std::fseek(sf,0,SEEK_END);
1166 std::size_t flen=std::ftell(sf);
1167 std::fseek(sf,0,SEEK_SET);
1168 char *buffer = new(std::nothrow) char[flen];
1169 if (!buffer) {std::fclose(sf); return 4;}
1170 if (std::fread(buffer,1,flen,sf)<flen) {
1171 delete[] buffer;
1172 std::fclose(sf);
1173 return 2;
1175 if (fclose(sf)) {delete[] buffer; return 3;}
1176 for (std::size_t i=0; i<=flen-8; i++) {
1177 if (!std::memcmp(buffer+i,"tempprog",8)) {
1178 std::strncpy(buffer+i,name,8);
1179 break; // do only one replacement
1182 FILE *df=std::fopen(dest,"wb");
1183 if (!df) {delete[] buffer; return -1;}
1184 if (std::fwrite(buffer,1,flen,df)<flen) {
1185 delete[] buffer;
1186 std::fclose(df);
1187 return -2;
1189 delete[] buffer;
1190 if (std::fclose(df)) return -3;
1191 return 0;
1194 int getPathType(const QString &thePath)
1196 struct stat statvar;
1197 int result=stat(thePath,&statvar);
1198 if (result)
1199 return errno==ENOENT?PATH_NOTFOUND:PATH_ERROR;
1200 if (statvar.st_mode&S_IFDIR)
1201 return PATH_FOLDER;
1202 if (statvar.st_mode&S_IFREG)
1203 return PATH_FILE;
1204 return PATH_ERROR;
1208 Build command line arguments (Library Options section)
1210 QStringList process_libopts(void)
1212 QStringList args;
1214 if (libopts.use_ti89) {
1215 args.append("-DUSE_TI89");
1217 if (libopts.use_ti92p) {
1218 args.append("-DUSE_TI92PLUS");
1220 if (libopts.use_v200) {
1221 args.append("-DUSE_V200");
1224 if (libopts.opt_calc_consts) {
1225 args.append("-DOPTIMIZE_CALC_CONSTS");
1228 if (libopts.use_kernel || libopts.use_preos) {
1229 args.append("-DUSE_KERNEL");
1231 if (libopts.use_preos) {
1232 args.append("-DUSE_PREOS_COMPRESSED_TABLES");
1235 if (libopts.use_minams) {
1236 args.append(QString("-DMIN_AMS=%1").arg(libopts.minams));
1239 if (libopts.unofficial_os) {
1240 args.append("-DUNOFFICIAL_OS_SUPPORT");
1243 if (libopts.use_preos) {
1244 if (libopts.bss_ref_format == RT_NONE)
1245 args.append("-DMERGE_BSS");
1246 } else {
1247 switch (libopts.reloc_format) {
1248 case RT_KERNEL:
1249 args.append("-DKERNEL_FORMAT_RELOCS");
1250 break;
1251 case RT_COMPRESSED:
1252 args.append("-DCOMPRESSED_FORMAT_RELOCS");
1253 break;
1254 case RT_MLINK:
1255 args.append("-DMLINK_FORMAT_RELOCS");
1256 break;
1257 case RT_FLINE:
1258 args.append("-DUSE_FLINE_JUMPS");
1259 break;
1260 default:
1261 break;
1263 switch (libopts.rom_call_format) {
1264 case RT_KERNEL:
1265 args.append("-DKERNEL_FORMAT_ROM_CALLS");
1266 break;
1267 case RT_COMPRESSED:
1268 args.append("-DCOMPRESSED_FORMAT_ROM_CALLS");
1269 break;
1270 case RT_MLINK:
1271 args.append("-DMLINK_FORMAT_ROM_CALLS");
1272 break;
1273 case RT_PRECOMP:
1274 args.append("-DOPTIMIZE_ROM_CALLS");
1275 break;
1276 case RT_FLINE:
1277 args.append("-DUSE_FLINE_ROM_CALLS");
1278 args.append("-fno-function-cse");
1279 break;
1280 default:
1281 break;
1283 if (libopts.opt_rom_calls) {
1284 args.append("-DOPTIMIZE_ROM_CALLS");
1286 switch (libopts.bss_ref_format) {
1287 case RT_NONE:
1288 args.append("-DMERGE_BSS");
1289 break;
1290 case RT_KERNEL:
1291 args.append("-DKERNEL_FORMAT_BSS");
1292 break;
1293 case RT_COMPRESSED:
1294 args.append("-DCOMPRESSED_FORMAT_BSS");
1295 break;
1296 case RT_MLINK:
1297 args.append("-DMLINK_FORMAT_BSS");
1298 break;
1299 default:
1300 break;
1304 switch (libopts.data_ref_format) {
1305 case RT_KERNEL:
1306 args.append("-DKERNEL_FORMAT_DATA_VAR");
1307 break;
1308 case RT_COMPRESSED:
1309 args.append("-DCOMPRESSED_FORMAT_DATA_VAR");
1310 break;
1311 case RT_MLINK:
1312 args.append("-DMLINK_FORMAT_DATA_VAR");
1313 break;
1314 default:
1315 break;
1318 if (libopts.use_fline_jumps) {
1319 args.append("-DUSE_FLINE_JUMPS");
1320 if (libopts.use_4b_fline_jumps) {
1321 args.append("-DUSE_4BYTE_FLINE_JUMPS");
1325 if (libopts.use_internal_fline_emu) {
1326 args.append("-DUSE_INTERNAL_FLINE_EMULATOR");
1329 if (libopts.use_return_value) {
1330 args.append("-DRETURN_VALUE");
1333 if (libopts.enable_error_return) {
1334 args.append("-DENABLE_ERROR_RETURN");
1337 if (libopts.save_screen) {
1338 args.append("-DSAVE_SCREEN");
1341 return args;
1344 static QString urlencode(const QByteArray &byteArray)
1346 QString result;
1347 int len=byteArray.size();
1348 for (int i=0; i<len; i++) {
1349 unsigned char c=byteArray.at(i);
1350 if (c<128) result+=c; else result+=QString::number(c,16).prepend('%');
1352 return result;
1356 Build linker command line arguments
1358 QStringList process_settings(const QString &prjNameUnicode,
1359 const QString &projectBaseName,
1360 QString &pstarterName, QByteArray &packName)
1362 QStringList args;
1363 args<<"-o"<<projectBaseName<<"-n";
1365 // Convert the project name to the calculator charset.
1366 QByteArray projectName=TiconvTextCodec::instance->fromUnicode(prjNameUnicode);
1368 if (settings.pack && !settings.pack_name.isEmpty()) {
1369 // Split the PPG name into folder and file.
1370 QString packNameUnicode;
1371 int slashPos=settings.pack_name.find('\\');
1372 if (slashPos>=0) {
1373 packNameUnicode=settings.pack_name.mid(slashPos+1);
1374 } else {
1375 packNameUnicode=settings.pack_name;
1378 // Convert the PPG file name to the calculator charset.
1379 packName=TiconvTextCodec::instance->fromUnicode(packNameUnicode);
1380 args<<urlencode(TiconvTextCodec::instance->fromUnicode(settings.pack_name));
1381 pstarterName=urlencode(projectName);
1382 } else args<<urlencode(projectName);
1384 if (settings.use_data_var && !settings.data_var.isEmpty()) {
1385 args<<"-d"
1386 <<urlencode(TiconvTextCodec::instance->fromUnicode(settings.data_var))
1387 <<"--output-data-var"<<projectBaseName+"-data";
1388 if (!settings.copy_data_var) {
1389 args.append("--data-var-copy=never");
1390 } else if (!settings.copy_data_var_arc) {
1391 args.append("--data-var-copy=always");
1395 if (settings.optimize_nops) {
1396 args.append("--optimize-nops");
1398 if (settings.optimize_returns) {
1399 args.append("--optimize-returns");
1401 if (settings.optimize_branches) {
1402 args.append("--optimize-branches");
1404 if (settings.optimize_moves) {
1405 args.append("--optimize-moves");
1407 if (settings.optimize_tests) {
1408 args.append("--optimize-tests");
1410 if (settings.optimize_calcs) {
1411 args.append("--optimize-calcs");
1414 if (settings.remove_unused) {
1415 args.append("--remove-unused");
1418 if (settings.cut_ranges) {
1419 args.append("--cut-ranges");
1422 if (settings.reorder_sections) {
1423 args.append("--reorder-sections");
1426 if (settings.merge_constants) {
1427 args.append("--merge-constants");
1430 if (settings.pack) {
1431 args.append("--pack");
1434 if (settings.outputbin) {
1435 args.append("--outputbin");
1438 if (!settings.initialize_bss) {
1439 args.append("--omit-bss-init");
1442 if (settings.fargo) {
1443 args.append("--fargo");
1446 if (settings.flash_os) {
1447 args.append("--flash-os");
1450 return args;