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)
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.
33 #include <QApplication>
35 #include <kapplication.h>
36 #include <kcmdlineargs.h>
37 #include <kaboutdata.h>
40 #include <QStringList>
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
);
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
);
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
)
87 static char *find_numbered_param(char *s
, const char*t
, int *i
)
95 strcat(arglist
, "%n");
97 ret
= sscanf(s
, arglist
, i
, &endpos
);
98 if(ret
< 1 || !endpos
) return NULL
;
104 // converts Windows paths to Unix paths if necessary.
105 static QString
convert_path_separators(const char *file
)
111 while ((o
=s
.find('\\',0,TRUE
))>=0)
118 static char* strip(char *str
)
120 int len
= strlen(str
);
123 if( (str
[len
-1] == '\r') || (str
[len
-1] == '\n') )
127 if( (str
[len
-2] == '\r') || (str
[len
-2] == '\n') )
134 Read a line from file and do a clean-up
136 static int read_line(FILE *f
, char *buffer
, int *l
)
139 if(feof(f
)) return EOF
;
140 if (!fgets(buffer
, 256, f
)) return feof(f
)?EOF
:1;
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;
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
159 static int parse_file(FILE *f
,TPRDataStruct
*dest
)
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;
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
;
191 if( !strcmp(buffer
, "[Library Options]") )
193 stype
= SECTION_LIBOPTS
;
197 if( !strcmp(buffer
, "[File Editing]") )
199 stype
= SECTION_FILEEDIT
;
203 if( !strcmp(buffer
, "[Included Files]") )
205 stype
= SECTION_FILES
;
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; \
221 #define tistring_vparam(token,var) \
222 if ( (p=find_param(buffer, token)) ) \
225 dest->var = TiconvTextCodec::instance->toUnicode(p); \
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; \
239 #define ignore_param(token) \
240 if( (p=find_param(buffer, token)) ) \
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
)
280 #undef tistring_vparam
281 #undef tistring_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; \
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")) \
321 #define minams_param(token,setting) \
322 if ( (p=find_param(buffer, "Minimum AMS Version=")) ) \
326 && (sscanf(p,"%1d.%2d",&major,&minor)==2)) \
327 dest->libopts.minams = major * 100 + minor; \
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
)
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
; \
370 // Keywords in the [Included Files] section
371 if(stype
== SECTION_FILES
)
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
;
383 else if( (p
=find_numbered_param(buffer
, "C File %i Folder=", &v
)) )
385 dest
->c_files
.folder
[v
-1]=p
;
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
;
397 else if( (p
=find_numbered_param(buffer
, "GNU Assembler File %i Folder=", &v
)) )
399 dest
->s_files
.folder
[v
-1]=p
;
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
;
411 else if( (p
=find_numbered_param(buffer
, "Header File %i Folder=", &v
)) )
413 dest
->h_files
.folder
[v
-1]=p
;
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
;
425 else if( (p
=find_numbered_param(buffer
, "Assembler File %i Folder=", &v
)) )
427 dest
->asm_files
.folder
[v
-1]=p
;
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
;
439 else if( (p
=find_numbered_param(buffer
, "Object File %i Folder=", &v
)) )
441 dest
->o_files
.folder
[v
-1]=p
;
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
;
453 else if( (p
=find_numbered_param(buffer
, "Archive File %i Folder=", &v
)) )
455 dest
->a_files
.folder
[v
-1]=p
;
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
;
467 else if( (p
=find_numbered_param(buffer
, "Text File %i Folder=", &v
)) )
469 dest
->txt_files
.folder
[v
-1]=p
;
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
;
481 else if( (p
=find_numbered_param(buffer
, "Quill File %i Folder=", &v
)) )
483 dest
->quill_files
.folder
[v
-1]=p
;
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
;
495 else if( (p
=find_numbered_param(buffer
, "Other File %i Folder=", &v
)) )
497 dest
->oth_files
.folder
[v
-1]=p
;
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
)
515 f
= fopen(fileName
, "r");
519 ret
=parse_file(f
,dest
);
524 QString
loadFileText(const char *fileName
)
527 f
=fopen(fileName
,"rb");
529 return QString::null
;
531 size_t flen
=ftell(f
);
533 char *buffer
= new(std::nothrow
) char[flen
+1];
536 return QString::null
;
538 std::memset(buffer
,0,flen
+1);
540 if (fread(buffer
,1,flen
,f
)<flen
) {
546 if (preferences
.useCalcCharset
) {
547 ret
=TiconvTextCodec::instance
->toUnicode(buffer
);
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)*$"));
567 // Returns -1 if the file is empty, -2 on error.
568 int peekFirstChar(const char *fileName
)
571 f
=fopen(fileName
,"rb");
575 if (result
==EOF
) result
=feof(f
)?-1:-2;
580 static QString
convert_path_separators_save(QString s
)
585 while ((o
=s
.find('/',0,TRUE
))>=0)
592 //this is here because QString::ascii() returns "(null)" on a null string.
593 const char *smartAscii(const QString
&s
)
600 static int save_tpr(FILE *f
,TPRDataStruct
*dest
)
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(); \
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
)
650 #undef tistring_vparam
651 #undef tistring_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) \
661 if (fprintf(f,token "None\r\n")<0) return -2; \
664 if (fprintf(f,token "Direct\r\n")<0) return -2; \
667 if (fprintf(f,token "AMS\r\n")<0) return -2; \
670 if (fprintf(f,token "Precomputed\r\n")<0) return -2; \
673 if (fprintf(f,token "Kernel\r\n")<0) return -2; \
675 case RT_COMPRESSED: \
676 if (fprintf(f,token "Compressed\r\n")<0) return -2; \
679 if (fprintf(f,token "MLink\r\n")<0) return -2; \
682 if (fprintf(f,token "F-Line\r\n")<0) return -2; \
686 #define minams_param(token,setting) \
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
)
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(); \
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;
751 void newSettings(tprSettings
*settings
,tprLibOpts
*libopts
)
753 tprSettings newSettings
;
754 tprLibOpts newLibOpts
;
755 *settings
=newSettings
;
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
)
765 f
=fopen(fileName
,"wb");
771 if (fclose(f
)) return -2;
775 void mkdir_multi(const char *fileName
)
777 int l
=strlen(fileName
);
782 ptr
=strchr(fileName
,'\\');
784 ptr
=strchr(fileName
,'/');
789 memcpy(buffer
,fileName
,ptr
-fileName
);
790 buffer
[ptr
-fileName
]=0;
794 ptr
=strchr(ptr
+1,'\\');
796 mkdir(buffer
,S_IRWXU
| S_IRWXG
| S_IRWXO
);
798 ptr
=strchr(ptr
+1,'/');
803 static int writeToFile(FILE *f
, const QString
&text
)
805 if (preferences
.useCalcCharset
) {
806 if (!text
.isEmpty()) {
807 QByteArray s
=TiconvTextCodec::instance
->fromUnicode(text
);
809 if (fwrite(s
.constData(),1,l
,f
)<l
) {
814 const char *s
=smartAscii(text
);
815 size_t l
=std::strlen(s
);
816 if (fwrite(s
,1,l
,f
)<l
) return -2;
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
)
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");
842 mkdir_multi(fileName
);
843 f
=fopen(fileName
,"wb");
847 if (split
&& preferences
.splitSourceFiles
&& !settings
.debug_info
) {
848 unsigned curPos
=0, curLine
=0, curCol
=0, l
=text
.length();
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
++) {
863 QChar c
=text
[curPos
];
871 while (i
&& ((text
[i
]=='\\')||(i
>=2&&!text
.mid(i
-2,3).compare("?""?""/")))) {
873 if (text
[i
]=='\\') --i
; else i
-=3;
878 INSERT_STRING(QString(c
)+"\n");
888 while (i
&& ((text
[i
]=='\\')||(i
>=2&&!text
.mid(i
-2,3).compare("?""?""/")))) {
890 if (text
[i
]=='\\') --i
; else i
-=3;
892 if (b
) curMode
=cmNone
;
896 if ((c
=='/')&&(text
[curPos
-1]=='*')) curMode
=cmNone
;
898 case cmUnchangeableLine
:
899 if (c
=='\n') curMode
=cmNone
;
901 case cmExtUnchangeableLine
:
902 if ((c
=='\n')&&(text
[curPos
-1]!='\\')) curMode
=cmNone
;
903 else if (c
=='\"') curMode
=cmExtUnchangeableLineString
;
905 case cmExtUnchangeableLineString
:
909 while (i
&& ((text
[i
]=='\\')||(i
>=2&&!text
.mid(i
-2,3).compare("?""?""/")))) {
911 if (text
[i
]=='\\') --i
; else i
-=3;
913 if (b
) curMode
=cmExtUnchangeableLine
;
917 if ((c
!='?')&&((curPos
+1>=l
)||(text
[curPos
+1]!='?'))) curMode
=cmNone
;
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
);
930 switch(c
.unicode()) {
933 if (curPos
&& text
[curPos
-1]!=' ' && text
[curPos
-1]!='\t')
941 if (curMode
!=cmNormalText
&& curMode
!=cmNumber
) {
943 if (c
>=QChar('0') && c
<=QChar('9'))
946 curMode
=cmNormalText
;
950 SET_MULTI_CHAR_MODE(cmString
);
953 SET_MULTI_CHAR_MODE(cmChar
);
956 SET_MULTI_CHAR_MODE(cmExtUnchangeableLine
);
959 if (curMode
!=cmNumber
) {
961 &&(text
[curPos
+1]>=QChar('0')
962 &&text
[curPos
+1]<=QChar('9'))) {
965 } else SET_MULTI_CHAR_MODE(cmMultiSymbol
);
970 if ((curMode
!=cmNumber
)||(curPos
<=1)
971 ||!QString("eEpP").contains(text
[curPos
-1]))
972 SET_MULTI_CHAR_MODE(cmMultiSymbol
);
975 if (QString(",;()[]{}").contains(c
)) {
976 if (curMode
!=cmNone
) {
980 if ((curPos
+1<l
)&&text
[curPos
+1]!='\n') {
982 INSERT_STRING(QString(c
)+"\n");
985 } else SET_MULTI_CHAR_MODE(cmMultiSymbol
);
993 switch(c
.unicode()) {
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.
1001 QCoreApplication::processEvents(QEventLoop::AllEvents
,1000);
1005 } else goto de_fault
;
1006 // x-bar and y-bar are special if we use the calculator charset.
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.
1013 QCoreApplication::processEvents(QEventLoop::AllEvents
,1000);
1022 if (c
!='\n') atLineStart
=FALSE
;
1028 // Allow the UI to respond, splitting is a lengthy operation.
1030 QCoreApplication::processEvents(QEventLoop::AllEvents
,1000);
1035 #undef INSERT_STRING
1038 #undef ADD_LINE_NEXT
1040 #undef SET_MULTI_CHAR_MODE
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
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
;
1066 void kurlNewFileName(KUrl
&dir
,const QString
&newFileName
)
1068 if (!newFileName
.isEmpty() && newFileName
[0]=='/')
1069 dir
.setPath(newFileName
);
1071 dir
.setFileName(newFileName
);
1074 static QString
pullOutFileSuffix(const QString
&srcFileName
,QString
&destFileName
)
1078 destFileName
=srcFileName
;
1079 a
=destFileName
.findRev('.');
1080 b
=destFileName
.findRev('/');
1082 return QString::null
;
1084 return QString::null
;
1085 ret
=destFileName
.mid(a
+1);
1086 destFileName
.truncate(a
);
1090 int checkFileName(const QString
&fileName
,const QStringList
&fileNameList
)
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
))
1109 if (!fileNameList
[i
].compare(fileName
))
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
1122 FILE *sf
=fopen(src
,"rb");
1124 FILE *df
=fopen(dest
,"wb");
1125 if (!df
) {fclose(sf
); return -1;}
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
) {
1140 if (fclose(df
)) {fclose(sf
); return -3;}
1141 if (fclose(sf
)) return 3;
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
;
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");
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
) {
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
) {
1190 if (std::fclose(df
)) return -3;
1194 int getPathType(const QString
&thePath
)
1196 struct stat statvar
;
1197 int result
=stat(thePath
,&statvar
);
1199 return errno
==ENOENT
?PATH_NOTFOUND
:PATH_ERROR
;
1200 if (statvar
.st_mode
&S_IFDIR
)
1202 if (statvar
.st_mode
&S_IFREG
)
1208 Build command line arguments (Library Options section)
1210 QStringList
process_libopts(void)
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");
1247 switch (libopts
.reloc_format
) {
1249 args
.append("-DKERNEL_FORMAT_RELOCS");
1252 args
.append("-DCOMPRESSED_FORMAT_RELOCS");
1255 args
.append("-DMLINK_FORMAT_RELOCS");
1258 args
.append("-DUSE_FLINE_JUMPS");
1263 switch (libopts
.rom_call_format
) {
1265 args
.append("-DKERNEL_FORMAT_ROM_CALLS");
1268 args
.append("-DCOMPRESSED_FORMAT_ROM_CALLS");
1271 args
.append("-DMLINK_FORMAT_ROM_CALLS");
1274 args
.append("-DOPTIMIZE_ROM_CALLS");
1277 args
.append("-DUSE_FLINE_ROM_CALLS");
1278 args
.append("-fno-function-cse");
1283 if (libopts
.opt_rom_calls
) {
1284 args
.append("-DOPTIMIZE_ROM_CALLS");
1286 switch (libopts
.bss_ref_format
) {
1288 args
.append("-DMERGE_BSS");
1291 args
.append("-DKERNEL_FORMAT_BSS");
1294 args
.append("-DCOMPRESSED_FORMAT_BSS");
1297 args
.append("-DMLINK_FORMAT_BSS");
1304 switch (libopts
.data_ref_format
) {
1306 args
.append("-DKERNEL_FORMAT_DATA_VAR");
1309 args
.append("-DCOMPRESSED_FORMAT_DATA_VAR");
1312 args
.append("-DMLINK_FORMAT_DATA_VAR");
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");
1344 static QString
urlencode(const QByteArray
&byteArray
)
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('%');
1356 Build linker command line arguments
1358 QStringList
process_settings(const QString
&prjNameUnicode
,
1359 const QString
&projectBaseName
,
1360 QString
&pstarterName
, QByteArray
&packName
)
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('\\');
1373 packNameUnicode
=settings
.pack_name
.mid(slashPos
+1);
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()) {
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");