tprbuilder.c 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273
  1. /*
  2. tprbuilder - tprbuilder is a MAKE program for TIGCC projects (.tpr files)
  3. Copyright (C) 2002 Romain Liévin
  4. Copyright (C) 2002-2007 Kevin Kofler
  5. Copyright (C) 2005, 2009 Lionel Debroux
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2, or (at your option)
  9. any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program; if not, write to the Free Software Foundation,
  16. Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17. */
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <sys/types.h>
  22. #ifndef __WIN32__
  23. #include <sys/wait.h>
  24. #endif
  25. #include "tprbuilder.h"
  26. #define EXIT_FAILURE 1
  27. /* The name the program was run with, stripped of any leading path. */
  28. char *program_name;
  29. /* global arrays */
  30. char **c_files = NULL;
  31. char **s_files = NULL;
  32. char **h_files = NULL;
  33. char **o_files = NULL;
  34. char **a_files = NULL;
  35. char **asm_files = NULL;
  36. /* global vars */
  37. char *tigcc_base = NULL;
  38. int c_file_count=0, s_file_count=0, m_file_count=0, h_file_count=0,
  39. asm_file_count=0, a_file_count=0, o_file_count=0;
  40. Settings settings = {0,0,0,0,1,0,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0};
  41. LibOpts libopts = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,RT_NONE,RT_NONE,RT_KERNEL,RT_KERNEL};
  42. int clean = 0;
  43. int verbose = 0;
  44. int quiet = 0;
  45. /*
  46. An implementation of system() for Win32 which doesn't use the crippled
  47. command.com to execute commands.
  48. Note that this implementation hardcodes the name of the program to launch. A
  49. complete implementation would have to read it from the command line.
  50. */
  51. #ifdef __WIN32__
  52. #define WIN32_LEAN_AND_MEAN
  53. #include <windows.h>
  54. static inline int win32_system(const char *cmdline)
  55. {
  56. char execname[MAX_PATH], *p;
  57. long exitcode;
  58. STARTUPINFO startupinfo={.cb=sizeof(startupinfo)};
  59. PROCESS_INFORMATION processinfo;
  60. _searchenv("tigcc.exe","PATH",execname);
  61. if (!*execname) return 1;
  62. while ((p=strchr(execname,'/'))) *p='\\';
  63. if (!CreateProcess(execname,(char *)cmdline,NULL,NULL,FALSE,0,NULL,NULL,
  64. &startupinfo,&processinfo)) return 1;
  65. if (WaitForSingleObject(processinfo.hProcess,INFINITE)==WAIT_FAILED) return 1;
  66. if (!GetExitCodeProcess(processinfo.hProcess,&exitcode)) return 1;
  67. CloseHandle(processinfo.hProcess);
  68. CloseHandle(processinfo.hThread);
  69. return exitcode;
  70. }
  71. #undef system
  72. #define system win32_system
  73. #endif
  74. /*
  75. Our main function
  76. */
  77. int main(int argc, char **argv)
  78. {
  79. int i;
  80. /* GNU stuffs */
  81. program_name = argv[0];
  82. i = decode_switches (argc, argv);
  83. /* Do some checkings */
  84. if (argc < 2) {
  85. fprintf(stderr, "tprbuilder: no input files\n");
  86. exit(0);
  87. }
  88. /* Register exit callback */
  89. if (atexit(safe_exit) != 0) {
  90. fprintf(stderr, "Fatal error: unable to register safe exit callback\n");
  91. exit(-1);
  92. }
  93. /* Parse for files */
  94. if (i < argc)
  95. {
  96. size_t l=strlen(argv[i])-3;
  97. char outfile[l];
  98. if(!strcmp(file_extension(argv[i]),".tpr")) {
  99. parse_file(argv[i]);
  100. }
  101. else {
  102. usage(EXIT_FAILURE);
  103. }
  104. strncpy(outfile,argv[i],l-1);
  105. outfile[l-1]=0;
  106. /* Build files */
  107. if(!clean) {
  108. build_files(outfile);
  109. }
  110. /* Clean-up (if enabled) */
  111. if(clean) {
  112. clean_files(outfile);
  113. }
  114. } else usage(0);
  115. return 0;
  116. }
  117. /*
  118. Determine the size of a file array
  119. */
  120. int dyn_file_array_size(char **array, int *size)
  121. {
  122. char **p;
  123. *size = 0;
  124. if(array != NULL) {
  125. for(p=array; *p != NULL; p++, (*size)++);
  126. }
  127. return *size;
  128. }
  129. /*
  130. Add a filename to a filename array while maintaing a file count
  131. */
  132. int dyn_file_array_add(char *file, char ***array, int *file_count)
  133. {
  134. int len = strlen(file) + 1;
  135. int nfiles = 0;
  136. char **files = *array;
  137. // Determine size of array
  138. dyn_file_array_size(files, &nfiles);
  139. // Resize array
  140. files = (char **) realloc(files, (nfiles + 2) * sizeof(char *));
  141. if (files == NULL) outofmem();
  142. // Allocate and copy string
  143. if ((files[nfiles] = (char *)calloc(len, sizeof(char))) == NULL) outofmem();
  144. // Maintain array consistency
  145. strcpy(files[nfiles], file);
  146. files[++nfiles] = NULL;
  147. *file_count = nfiles;
  148. *array = files;
  149. return TRUE;
  150. }
  151. /*
  152. Free a file array and the associated strings
  153. */
  154. void dyn_file_array_free(char **files)
  155. {
  156. int i, count;
  157. if(files == NULL) return;
  158. dyn_file_array_size(files, &count);
  159. for(i=0; i<count; i++) {
  160. free(files[i]);
  161. }
  162. free(files);
  163. }
  164. /*
  165. Encapsulate long filenames with "".
  166. The returned string must be freed when no longer used
  167. */
  168. char* encapsulate_long_filename(const char *file)
  169. {
  170. char *s;
  171. if ((s = calloc(strlen(file)+1+2, sizeof(char))) == NULL) outofmem();
  172. if(!strchr(file, ' '))
  173. strcpy(s, file);
  174. else {
  175. strcpy(s, "\"");
  176. strcat(s, file);
  177. strcat(s, "\"");
  178. }
  179. #ifndef __WIN32__
  180. {
  181. char *p;
  182. while ((p=strchr(s,'\\')))
  183. *p='/';
  184. }
  185. #endif
  186. return s;
  187. }
  188. /*
  189. Remove beginning & ending '"' from files.
  190. The string is modified in place !
  191. */
  192. char* tail_long_filename(char *file)
  193. {
  194. char *p = file;
  195. if( (file[0] != '\"') && (file[strlen(file)] != '\"') )
  196. return file;
  197. p++;
  198. memmove(file, p, strlen(p)+1); /* remove first quote */
  199. p[strlen(p)-1] = '\0'; /* remove last quote */
  200. return file;
  201. }
  202. /* Return the filename extension or NULL */
  203. static const char *file_extension(const char *filename)
  204. {
  205. int i;
  206. const char *p;
  207. for(i=strlen(filename); i > 0; i--)
  208. {
  209. if(filename[i] == '.') break;
  210. }
  211. p=filename+i;
  212. return p;
  213. }
  214. /*
  215. Change filename extension and keep long filenames.
  216. If the filename has no extension, then the extension is append
  217. Dynamic allocation to do ...
  218. */
  219. char *change_extension(char *file, const char *newext)
  220. {
  221. char *start = (char *)strrchr(file, '.');
  222. if(start == NULL) {
  223. start = file; //return file;
  224. } else {
  225. sprintf(start, "%s", newext);
  226. }
  227. if(file[0] == '\"') strcat(start, "\"");
  228. return file;
  229. }
  230. /*
  231. Set all the option flags according to the switches specified.
  232. Return the index of the first non-option argument.
  233. */
  234. static int decode_switches (int argc, char **argv)
  235. {
  236. int c;
  237. char * cmdline_cc_switches=malloc(5);
  238. if (!cmdline_cc_switches) outofmem();
  239. cmdline_cc_switches[0] = 0;
  240. for (c=1;c<argc;c++) {
  241. if (!strcmp(argv[c],"-V")||!strcmp(argv[c],"--version")) {
  242. printf ("tprbuilder 1.0.19\n");
  243. exit(0);
  244. } else if (!strcmp(argv[c],"-h")||!strcmp(argv[c],"--help")) {
  245. usage(0);
  246. } else if (!strcmp(argv[c],"-c")||!strcmp(argv[c],"--clean")) {
  247. clean = 1;
  248. } else if (!strcmp(argv[c],"-q")||!strcmp(argv[c],"--quiet")) {
  249. quiet = 1;
  250. } else if (!strcmp(argv[c],"-v")||!strcmp(argv[c],"--verbose")) {
  251. verbose = 1;
  252. } else if (!strncmp(argv[c],"-D",2)) {
  253. cmdline_cc_switches = dynstrcat(cmdline_cc_switches,argv[c]);
  254. cmdline_cc_switches = dynstrcat(cmdline_cc_switches," ");
  255. } else break;
  256. }
  257. if (c>=argc) usage(EXIT_FAILURE);
  258. settings.cmdline_cc_switches = cmdline_cc_switches;
  259. return c;
  260. }
  261. /*
  262. Display usage options
  263. */
  264. __attribute__((noreturn)) static void usage (int status)
  265. {
  266. printf ("%s - \
  267. tprbuilder is a MAKE program for TIGCC projects (.tpr files)\n", program_name);
  268. printf ("Usage: %s [OPTION]... [FILE]...\n", program_name);
  269. printf ("\
  270. Options:\n\
  271. -h, --help display this help and exit\n\
  272. -V, --version output version information and exit\n\
  273. -v, --verbose enable verbose mode (make tigcc verbose)\n\
  274. -q, --quiet enable quiet mode (display nothing)\n\
  275. -D[DEFINE] pass -D[DEFINE] to compiler\n\
  276. --clean do a cleanup of files\n\
  277. ");
  278. exit (status);
  279. }
  280. /*
  281. Destroy allocated resources (exit callback)
  282. */
  283. void safe_exit(void)
  284. {
  285. free(settings.pack_name);
  286. free(settings.prj_name);
  287. free(settings.cc_switches);
  288. if (settings.cmdline_cc_switches) free(settings.cmdline_cc_switches);
  289. free(settings.as_switches);
  290. free(settings.a68k_switches);
  291. free(settings.post_build);
  292. free(settings.data_var);
  293. dyn_file_array_free(c_files);
  294. dyn_file_array_free(s_files);
  295. dyn_file_array_free(h_files);
  296. dyn_file_array_free(asm_files);
  297. dyn_file_array_free(a_files);
  298. }
  299. /*
  300. Remove/unlink a file
  301. */
  302. int delete(char *filename)
  303. {
  304. if (!quiet) {
  305. fprintf(stderr, "tprbuilder: removing %s\n", filename);
  306. }
  307. tail_long_filename(filename);
  308. remove(filename);
  309. return 0;
  310. }
  311. /*
  312. Execute a program by calling the shell
  313. */
  314. int execute(char *cmdline)
  315. {
  316. int exitcode;
  317. if (!quiet) {
  318. fprintf(stderr, "tprbuilder: %s\n", cmdline);
  319. }
  320. exitcode = system(cmdline);
  321. #ifdef __WIN32__
  322. if (exitcode != 0) {
  323. exit(exitcode);
  324. }
  325. #else
  326. if (WEXITSTATUS(exitcode) != 0) {
  327. exit(WEXITSTATUS(exitcode));
  328. }
  329. #endif
  330. return 0;
  331. }
  332. /*
  333. Execute tigcc
  334. */
  335. void execute_tigcc(char *filename, char *args)
  336. {
  337. char *cmdline; const char *quill_flag = "";
  338. /* We need to do this here because Win32 tigcc.exe only understands -quill
  339. at the beginning of the command line. */
  340. if(settings.quill == TRUE) quill_flag = "-quill ";
  341. cmdline = calloc(strlen(filename) + strlen(args) + 25, sizeof(char));
  342. if (!cmdline) outofmem();
  343. sprintf(cmdline, "tigcc %s%s %s", quill_flag, filename, args);
  344. if(verbose)
  345. strcat(cmdline, " --verbose");
  346. execute(cmdline);
  347. free(cmdline);
  348. }
  349. /*
  350. Strip CR and/or LF terminators
  351. */
  352. char* strip(char *str)
  353. {
  354. int len = strlen(str);
  355. if(len > 0)
  356. if( (str[len-1] == '\r') || (str[len-1] == '\n') )
  357. str[len-1] = '\0';
  358. if(len > 1)
  359. if( (str[len-2] == '\r') || (str[len-2] == '\n') )
  360. str[len-2] = '\0';
  361. return str;
  362. }
  363. /*
  364. Print an error msg
  365. */
  366. void stop (int line)
  367. {
  368. fprintf(stderr, "Configuration file error at line %i.\n", line);
  369. }
  370. /*
  371. Read a line from file and do a clean-up
  372. */
  373. int read_line(FILE *f, char *buffer, int *l)
  374. {
  375. strcpy(buffer, "");
  376. if(feof(f)) return EOF;
  377. fgets(buffer, 256, f);
  378. strip(buffer);
  379. (*l)++;
  380. while( (buffer[0] == '\r') || (buffer[0] == '\n') || (buffer[0] == '\0') )
  381. {
  382. if(feof(f)) return EOF;
  383. fgets(buffer, 256, f);
  384. strip(buffer);
  385. (*l)++;
  386. }
  387. return 0;
  388. }
  389. /*
  390. Find a token in a string and return the subsequent string
  391. */
  392. char *find_param_ex(char *s, const char *t, size_t l)
  393. {
  394. if (!strncmp(s,t,l))
  395. return s+l;
  396. else
  397. return NULL;
  398. }
  399. /*
  400. Same as above but this one can extract a number such as scanf
  401. */
  402. char *find_numbered_param(char *s, const char*t, int *i)
  403. {
  404. char *p;
  405. int endpos = 0;
  406. int ret = 0;
  407. char arglist[256];
  408. strcpy(arglist, t);
  409. strcat(arglist, "%n");
  410. ret = sscanf(s, arglist, i, &endpos);
  411. if(ret < 1 || !endpos) return NULL;
  412. p = s + endpos;
  413. return p;
  414. }
  415. /*
  416. Parse a TPR file, fill the Setting structure and the filename arrays
  417. */
  418. int parse_file(const char *filename)
  419. {
  420. FILE *f;
  421. char buffer[256];
  422. int l = 0;
  423. SectionType stype = SECTION_NONE;
  424. f = fopen(filename, "rt");
  425. if(f == NULL) {
  426. fprintf(stderr, "Unable to open this file: <%s>\n", filename);
  427. exit(-1);
  428. }
  429. while(!feof(f))
  430. {
  431. char *p;
  432. // Get a line from file
  433. if(read_line(f, buffer, &l) == EOF) break;
  434. // Search for sections
  435. if( !strcmp(buffer, "[Settings]") )
  436. {
  437. stype = SECTION_SETTINGS;
  438. continue;
  439. }
  440. if( !strcmp(buffer, "[Library Options]") )
  441. {
  442. stype = SECTION_LIBOPTS;
  443. continue;
  444. }
  445. if( !strcmp(buffer, "[File Editing]") )
  446. {
  447. stype = SECTION_FILEEDIT;
  448. continue;
  449. }
  450. if( !strcmp(buffer, "[Included Files]") )
  451. {
  452. stype = SECTION_FILES;
  453. continue;
  454. }
  455. // Keywords in the [Settings] section
  456. if(stype == SECTION_SETTINGS) {
  457. #define boolean_param(token,setting) \
  458. if ( (p=find_param(buffer, token)) ) \
  459. { \
  460. if(!strcmp(p, "0")) settings.setting = FALSE; \
  461. else if(!strcmp(p, "1")) settings.setting = TRUE; \
  462. else stop(l); \
  463. continue; \
  464. } else
  465. #define string_param(token,setting) \
  466. if ( (p=find_param(buffer, token)) ) \
  467. { \
  468. if (*p) settings.setting = strdup(p); \
  469. continue; \
  470. } else
  471. #define ignore_param(token) \
  472. if( (p=find_param(buffer, token)) ) \
  473. { \
  474. continue; \
  475. } else
  476. boolean_param("Archive=",archive)
  477. boolean_param("Pack=",pack)
  478. string_param("Packed Variable=",pack_name)
  479. string_param("Project Name=",prj_name)
  480. string_param("GCC Switches=",cc_switches)
  481. string_param("Assembler Switches=",a68k_switches)
  482. ignore_param("Linker Switches=") // Obsolete. Ignore.
  483. ignore_param("GNU Linker Switches=") // Obsolete. Ignore.
  484. string_param("GNU Assembler Switches=",as_switches)
  485. ignore_param("BSR Patch=") // Obsolete. Ignore.
  486. boolean_param("Debug Info=",debug_info)
  487. boolean_param("Standard Library=",std_lib)
  488. ignore_param("Command Line=") // Used only for transferring. Ignore.
  489. string_param("Post-Build Process=",post_build)
  490. boolean_param("Use Data Variable=",use_data_var)
  491. string_param("Data Variable=",data_var)
  492. boolean_param("Copy Data Variable=",copy_data_var)
  493. boolean_param("Copy Data Variable if Archived=",copy_data_var_arc)
  494. boolean_param("Optimize NOPs=",optimize_nops)
  495. boolean_param("Optimize Returns=",optimize_returns)
  496. boolean_param("Optimize Branches=",optimize_branches)
  497. boolean_param("Optimize Moves=",optimize_moves)
  498. boolean_param("Optimize Tests=",optimize_tests)
  499. boolean_param("Optimize Calculations=",optimize_calcs)
  500. boolean_param("Remove Unused Sections=",remove_unused)
  501. boolean_param("Binary Output=",outputbin)
  502. boolean_param("Fargo=",fargo)
  503. boolean_param("Flash OS=",flash_os)
  504. boolean_param("Cut Unused Ranges=",cut_ranges)
  505. boolean_param("Reorder Sections=",reorder_sections)
  506. boolean_param("Merge Constants=",merge_constants)
  507. boolean_param("Initialize BSS=",initialize_bss)
  508. stop(l);
  509. #undef boolean_param
  510. #undef string_param
  511. #undef ignore_param
  512. }
  513. // Keywords in the [Library Options] section
  514. if(stype == SECTION_LIBOPTS) {
  515. #define boolean_param(token,setting) \
  516. if ( (p=find_param(buffer, token)) ) \
  517. { \
  518. if(!strcmp(p, "0")) libopts.setting = FALSE; \
  519. else if(!strcmp(p, "1")) libopts.setting = TRUE; \
  520. else stop(l); \
  521. continue; \
  522. } else
  523. #define reloc_param(token,setting) \
  524. if ( (p=find_param(buffer, token)) ) \
  525. { \
  526. if (!strcmp(p,"None") || !strcmp(p,"AMS") \
  527. || !strcmp(p,"Direct")) \
  528. libopts.setting = RT_NONE; \
  529. else if (!strcmp(p, "Precomputed")) \
  530. libopts.setting = RT_PRECOMP; \
  531. else if (!strcmp(p, "Kernel")) \
  532. libopts.setting = RT_KERNEL; \
  533. else if (!strcmp(p, "Compressed")) \
  534. libopts.setting = RT_COMPRESSED; \
  535. else if (!strcmp(p, "MLink")) \
  536. libopts.setting = RT_MLINK; \
  537. else if (!strcmp(p, "F-Line")) \
  538. libopts.setting = RT_FLINE; \
  539. else if (strcmp(p, "Unknown")) \
  540. stop(l); \
  541. continue; \
  542. } else
  543. boolean_param("Use TI-89=",use_ti89)
  544. boolean_param("Use TI-92 Plus=",use_ti92p)
  545. boolean_param("Use V200=",use_v200)
  546. boolean_param("Optimize Calc Consts=",opt_calc_consts)
  547. boolean_param("Use Kernel=",use_kernel)
  548. boolean_param("Use PreOS=",use_preos)
  549. boolean_param("Minimum AMS Version Defined=",use_minams)
  550. if ( (p=find_param(buffer, "Minimum AMS Version=")) )
  551. {
  552. int major, minor;
  553. if ((strlen(p)==4) && (sscanf(p,"%1d.%2d",&major,&minor)==2))
  554. libopts.minams = major * 100 + minor;
  555. else
  556. stop(l);
  557. continue;
  558. } else
  559. boolean_param("Unofficial OS Support=",unofficial_os)
  560. reloc_param("Reloc Format=",reloc_format)
  561. reloc_param("ROM Call Format=",rom_call_format)
  562. reloc_param("BSS Ref Format=",bss_ref_format)
  563. reloc_param("Data Ref Format=",data_ref_format)
  564. boolean_param("Use F-Line Jumps=",use_fline_jumps)
  565. boolean_param("Use 4-Byte F-Line Jumps=",use_4b_fline_jumps)
  566. boolean_param("Use Internal F-Line Emulator=",use_internal_fline_emu)
  567. boolean_param("Use Return Value=",use_return_value)
  568. boolean_param("Enable Error Return=",enable_error_return)
  569. boolean_param("Save Screen=",save_screen)
  570. boolean_param("Optimize ROM Calls=",opt_rom_calls)
  571. stop(l);
  572. #undef boolean_param
  573. #undef reloc_param
  574. }
  575. // Ignore [File Editing] section, it is used only for editing.
  576. // Keywords in the [Included Files] section
  577. if(stype == SECTION_FILES)
  578. {
  579. int v;
  580. if( (p=find_numbered_param(buffer, "C File %i=", &v)) )
  581. {
  582. char *s = encapsulate_long_filename(p);
  583. dyn_file_array_add(s, &c_files, &c_file_count);
  584. free(s);
  585. continue;
  586. }
  587. else if( (p=find_numbered_param(buffer, "C File %i Folder=", &v)) )
  588. { // ignore folder specification for now
  589. continue;
  590. }
  591. else if( (p=find_numbered_param(buffer, "GNU Assembler File %i=", &v)) )
  592. {
  593. char *s = encapsulate_long_filename(p);
  594. dyn_file_array_add(s, &s_files, &s_file_count);
  595. free(s);
  596. continue;
  597. }
  598. else if( (p=find_numbered_param(buffer, "GNU Assembler File %i Folder=", &v)) )
  599. { // ignore folder specification for now
  600. continue;
  601. }
  602. else if( (p=find_numbered_param(buffer, "Header File %i=", &v)) )
  603. {
  604. char *s = encapsulate_long_filename(p);
  605. dyn_file_array_add(s, &h_files, &h_file_count);
  606. free(s);
  607. continue;
  608. }
  609. else if( (p=find_numbered_param(buffer, "Header File %i Folder=", &v)) )
  610. { // ignore folder specification for now
  611. continue;
  612. }
  613. else if( (p=find_numbered_param(buffer, "Assembler File %i=", &v)) )
  614. {
  615. char *s = encapsulate_long_filename(p);
  616. dyn_file_array_add(s, &asm_files, &asm_file_count);
  617. free(s);
  618. continue;
  619. }
  620. else if( (p=find_numbered_param(buffer, "Assembler File %i Folder=", &v)) )
  621. { // ignore folder specification for now
  622. continue;
  623. }
  624. else if( (p=find_numbered_param(buffer, "Object File %i=", &v)) )
  625. {
  626. char *s = encapsulate_long_filename(p);
  627. dyn_file_array_add(s, &o_files, &o_file_count);
  628. free(s);
  629. continue;
  630. }
  631. else if( (p=find_numbered_param(buffer, "Object File %i Folder=", &v)) )
  632. { // ignore folder specification for now
  633. continue;
  634. }
  635. else if( (p=find_numbered_param(buffer, "Archive File %i=", &v)) )
  636. {
  637. char *s = encapsulate_long_filename(p);
  638. dyn_file_array_add(s, &a_files, &a_file_count);
  639. free(s);
  640. continue;
  641. }
  642. else if( (p=find_numbered_param(buffer, "Archive File %i Folder=", &v)) )
  643. { // ignore folder specification for now
  644. continue;
  645. }
  646. else if( (p=find_numbered_param(buffer, "Text File %i=", &v)) )
  647. { // text file: do nothing
  648. continue;
  649. }
  650. else if( (p=find_numbered_param(buffer, "Text File %i Folder=", &v)) )
  651. { // ignore folder specification for now
  652. continue;
  653. }
  654. else if( (p=find_numbered_param(buffer, "Quill File %i=", &v)) )
  655. { // Quill file: treat like C file and add -quill flag
  656. char *s = encapsulate_long_filename(p);
  657. dyn_file_array_add(s, &c_files, &c_file_count);
  658. free(s);
  659. settings.quill = TRUE; // -quill flag needed
  660. continue;
  661. }
  662. else if( (p=find_numbered_param(buffer, "Quill File %i Folder=", &v)) )
  663. { // ignore folder specification for now
  664. continue;
  665. }
  666. else if( (p=find_numbered_param(buffer, "Other File %i=", &v)) )
  667. { // other file: do nothing
  668. continue;
  669. }
  670. else if( (p=find_numbered_param(buffer, "Other File %i Folder=", &v)) )
  671. { // ignore folder specification for now
  672. continue;
  673. }
  674. else stop(l);
  675. }
  676. }
  677. fclose(f);
  678. return 0;
  679. }
  680. /*
  681. Build command line arguments (Settings and Library Options sections)
  682. */
  683. int process_settings(char *outfile, char **pargs)
  684. {
  685. #define args (*pargs)
  686. args=malloc(5);
  687. if (!args) outofmem();
  688. strcpy(args, "-o \"");
  689. args = dynstrcat(args, outfile);
  690. args = dynstrcat(args, "\"");
  691. // Process settings
  692. if (settings.archive) {
  693. args = dynstrcat(args, " -ar");
  694. }
  695. if (settings.pack) {
  696. args = dynstrcat(args, " -pack ");
  697. args = dynstrcat(args, settings.pack_name);
  698. }
  699. if (settings.debug_info) {
  700. args = dynstrcat(args, " -g");
  701. }
  702. if (!settings.std_lib) {
  703. args = dynstrcat(args, " -standalone");
  704. }
  705. if (settings.prj_name) {
  706. args = dynstrcat(args, " -n ");
  707. args = dynstrcat(args, settings.prj_name);
  708. }
  709. if (settings.cc_switches) {
  710. args = dynstrcat(args, " ");
  711. args = dynstrcat(args, settings.cc_switches);
  712. }
  713. if (settings.cmdline_cc_switches) {
  714. args = dynstrcat(args, " ");
  715. args = dynstrcat(args, settings.cmdline_cc_switches);
  716. }
  717. if (settings.as_switches) {
  718. size_t i;
  719. args = dynstrcat(args, " -Wa,");
  720. for (i=0;i<strlen(settings.as_switches);i++) if (settings.as_switches[i]==' ') settings.as_switches[i]=',';
  721. args = dynstrcat(args, settings.as_switches);
  722. }
  723. if (settings.a68k_switches) {
  724. size_t i;
  725. args = dynstrcat(args, " -WA,");
  726. for (i=0;i<strlen(settings.a68k_switches);i++) {
  727. char *p=settings.a68k_switches+i;
  728. if (*p==',') *p=';'; else if (*p==' ') *p=',';
  729. }
  730. args = dynstrcat(args, settings.a68k_switches);
  731. }
  732. if (!settings.archive) {
  733. if (settings.use_data_var && settings.data_var) {
  734. args = dynstrcat(args, " -d ");
  735. args = dynstrcat(args, settings.data_var);
  736. if (!settings.copy_data_var) {
  737. args = dynstrcat(args, " --data-var-copy=never");
  738. } else if (!settings.copy_data_var_arc) {
  739. args = dynstrcat(args, " --data-var-copy=always");
  740. }
  741. }
  742. if (settings.optimize_nops) {
  743. args = dynstrcat(args, " --optimize-nops");
  744. }
  745. if (settings.optimize_returns) {
  746. args = dynstrcat(args, " --optimize-returns");
  747. }
  748. if (settings.optimize_branches) {
  749. args = dynstrcat(args, " --optimize-branches");
  750. }
  751. if (settings.optimize_moves) {
  752. args = dynstrcat(args, " --optimize-moves");
  753. }
  754. if (settings.optimize_tests) {
  755. args = dynstrcat(args, " --optimize-tests");
  756. }
  757. if (settings.optimize_calcs) {
  758. args = dynstrcat(args, " --optimize-calcs");
  759. }
  760. if (settings.remove_unused) {
  761. args = dynstrcat(args, " --remove-unused");
  762. }
  763. if (settings.cut_ranges) {
  764. args = dynstrcat(args, " --cut-ranges");
  765. }
  766. if (settings.reorder_sections) {
  767. args = dynstrcat(args, " --reorder-sections");
  768. }
  769. if (settings.merge_constants) {
  770. args = dynstrcat(args, " --merge-constants");
  771. }
  772. if (settings.outputbin) {
  773. args = dynstrcat(args, " --outputbin");
  774. }
  775. if (!settings.initialize_bss) {
  776. args = dynstrcat(args, " --omit-bss-init");
  777. }
  778. }
  779. if (settings.fargo) {
  780. args = dynstrcat(args, " --fargo");
  781. }
  782. if (settings.flash_os) {
  783. args = dynstrcat(args, " --flash-os");
  784. }
  785. // Process library options
  786. if (libopts.use_ti89) {
  787. args = dynstrcat(args, " -DUSE_TI89");
  788. }
  789. if (libopts.use_ti92p) {
  790. args = dynstrcat(args, " -DUSE_TI92PLUS");
  791. }
  792. if (libopts.use_v200) {
  793. args = dynstrcat(args, " -DUSE_V200");
  794. }
  795. if (libopts.opt_calc_consts) {
  796. args = dynstrcat(args, " -DOPTIMIZE_CALC_CONSTS");
  797. }
  798. if (libopts.use_kernel || libopts.use_preos) {
  799. args = dynstrcat(args, " -DUSE_KERNEL");
  800. }
  801. if (libopts.use_preos) {
  802. args = dynstrcat(args, " -DUSE_PREOS_COMPRESSED_TABLES");
  803. }
  804. if (libopts.use_minams) {
  805. char buffer[23];
  806. sprintf(buffer, " -DMIN_AMS=%d", libopts.minams);
  807. args = dynstrcat(args, buffer);
  808. }
  809. if (libopts.unofficial_os) {
  810. args = dynstrcat(args, " -DUNOFFICIAL_OS_SUPPORT");
  811. }
  812. if (libopts.use_preos) {
  813. if (libopts.bss_ref_format == RT_NONE)
  814. args = dynstrcat(args, " -DMERGE_BSS");
  815. } else {
  816. switch (libopts.reloc_format) {
  817. case RT_KERNEL:
  818. args = dynstrcat(args, " -DKERNEL_FORMAT_RELOCS");
  819. break;
  820. case RT_COMPRESSED:
  821. args = dynstrcat(args, " -DCOMPRESSED_FORMAT_RELOCS");
  822. break;
  823. case RT_MLINK:
  824. args = dynstrcat(args, " -DMLINK_FORMAT_RELOCS");
  825. break;
  826. case RT_FLINE:
  827. args = dynstrcat(args, " -DUSE_FLINE_JUMPS");
  828. break;
  829. default:
  830. break;
  831. }
  832. switch (libopts.rom_call_format) {
  833. case RT_KERNEL:
  834. args = dynstrcat(args, " -DKERNEL_FORMAT_ROM_CALLS");
  835. break;
  836. case RT_COMPRESSED:
  837. args = dynstrcat(args, " -DCOMPRESSED_FORMAT_ROM_CALLS");
  838. break;
  839. case RT_MLINK:
  840. args = dynstrcat(args, " -DMLINK_FORMAT_ROM_CALLS");
  841. break;
  842. case RT_PRECOMP:
  843. args = dynstrcat(args, " -DOPTIMIZE_ROM_CALLS");
  844. break;
  845. case RT_FLINE:
  846. args = dynstrcat(args, " -DUSE_FLINE_ROM_CALLS -fno-function-cse");
  847. break;
  848. default:
  849. break;
  850. }
  851. if (libopts.opt_rom_calls) {
  852. args = dynstrcat(args, " -DOPTIMIZE_ROM_CALLS");
  853. }
  854. switch (libopts.bss_ref_format) {
  855. case RT_NONE:
  856. args = dynstrcat(args, " -DMERGE_BSS");
  857. break;
  858. case RT_KERNEL:
  859. args = dynstrcat(args, " -DKERNEL_FORMAT_BSS");
  860. break;
  861. case RT_COMPRESSED:
  862. args = dynstrcat(args, " -DCOMPRESSED_FORMAT_BSS");
  863. break;
  864. case RT_MLINK:
  865. args = dynstrcat(args, " -DMLINK_FORMAT_BSS");
  866. break;
  867. default:
  868. break;
  869. }
  870. }
  871. switch (libopts.data_ref_format) {
  872. case RT_KERNEL:
  873. args = dynstrcat(args, " -DKERNEL_FORMAT_DATA_VAR");
  874. break;
  875. case RT_COMPRESSED:
  876. args = dynstrcat(args, " -DCOMPRESSED_FORMAT_DATA_VAR");
  877. break;
  878. case RT_MLINK:
  879. args = dynstrcat(args, " -DMLINK_FORMAT_DATA_VAR");
  880. break;
  881. default:
  882. break;
  883. }
  884. if (libopts.use_fline_jumps) {
  885. args = dynstrcat(args, " -DUSE_FLINE_JUMPS");
  886. if (libopts.use_4b_fline_jumps) {
  887. args = dynstrcat(args, " -DUSE_4BYTE_FLINE_JUMPS");
  888. }
  889. }
  890. if (libopts.use_internal_fline_emu) {
  891. args = dynstrcat(args, " -DUSE_INTERNAL_FLINE_EMULATOR");
  892. }
  893. if (libopts.use_return_value) {
  894. args = dynstrcat(args, " -DRETURN_VALUE");
  895. }
  896. if (libopts.enable_error_return) {
  897. args = dynstrcat(args, " -DENABLE_ERROR_RETURN");
  898. }
  899. if (libopts.save_screen) {
  900. args = dynstrcat(args, " -DSAVE_SCREEN");
  901. }
  902. return 0;
  903. #undef args
  904. }
  905. /*
  906. Build command line files (Included Files section)
  907. */
  908. int process_files(char **pfiles)
  909. {
  910. #define files (*pfiles)
  911. int i, count;
  912. files=malloc(1);
  913. if (!files) outofmem();
  914. *files=0;
  915. /* Process .c files */
  916. dyn_file_array_size(c_files, &count);
  917. for(i=0; i<count; i++) {
  918. files = dynstrcat(files, c_files[i]);
  919. files = dynstrcat(files, " ");
  920. }
  921. /* Process .s files */
  922. dyn_file_array_size(s_files, &count);
  923. for(i=0; i<count; i++) {
  924. files = dynstrcat(files, s_files[i]);
  925. files = dynstrcat(files, " ");
  926. }
  927. /* Process .asm files */
  928. dyn_file_array_size(asm_files, &count);
  929. for(i=0; i<count; i++) {
  930. files = dynstrcat(files, asm_files[i]);
  931. files = dynstrcat(files, " ");
  932. }
  933. /* Process .o files */
  934. dyn_file_array_size(o_files, &count);
  935. for(i=0; i<count; i++) {
  936. files = dynstrcat(files, o_files[i]);
  937. files = dynstrcat(files, " ");
  938. }
  939. /* Process .a files */
  940. dyn_file_array_size(a_files, &count);
  941. for(i=0; i<count; i++) {
  942. files = dynstrcat(files, a_files[i]);
  943. files = dynstrcat(files, " ");
  944. }
  945. return 0;
  946. #undef files
  947. }
  948. /*
  949. Call tigcc for making files
  950. */
  951. void build_files(char *outfile)
  952. {
  953. char *options = NULL;
  954. char *files = NULL;
  955. process_settings(outfile, &options);
  956. process_files(&files);
  957. execute_tigcc(files, options);
  958. free(options);
  959. free(files);
  960. }
  961. /*
  962. Remove files generated by tigcc
  963. */
  964. void clean_files(char *outfile)
  965. {
  966. char executable[strlen(outfile)+14];
  967. int i, count;
  968. /* Process .c files */
  969. dyn_file_array_size(c_files, &count);
  970. for(i=0; i<count; i++) {
  971. char tmpfile[strlen(c_files[i])+3];
  972. strcpy(tmpfile, c_files[i]);
  973. change_extension(tmpfile, ".s");
  974. delete(tmpfile);
  975. strcpy(tmpfile, c_files[i]);
  976. change_extension(tmpfile, ".o");
  977. delete(tmpfile);
  978. }
  979. /* Process .s files */
  980. dyn_file_array_size(s_files, &count);
  981. for(i=0; i<count; i++) {
  982. char tmpfile[strlen(s_files[i])+3];
  983. strcpy(tmpfile, s_files[i]);
  984. change_extension(tmpfile, ".o");
  985. delete(tmpfile);
  986. }
  987. /* Process .asm files */
  988. dyn_file_array_size(asm_files, &count);
  989. for(i=0; i<count; i++) {
  990. char tmpfile[strlen(asm_files[i])+3];
  991. strcpy(tmpfile, asm_files[i]);
  992. change_extension(tmpfile, ".o");
  993. delete(tmpfile);
  994. }
  995. /* Remove executables */
  996. if (settings.archive) {
  997. strcpy(executable, outfile);
  998. strcat(executable, ".a");
  999. delete(executable);
  1000. } else if (settings.fargo) {
  1001. strcpy(executable, outfile);
  1002. strcat(executable, settings.outputbin?".p92":".92p");
  1003. delete(executable);
  1004. } else if (settings.flash_os) {
  1005. if (settings.outputbin) {
  1006. strcpy(executable, outfile);
  1007. strcat(executable, "-89.tib");
  1008. delete(executable);
  1009. strcpy(executable, outfile);
  1010. strcat(executable, "-89ti.tib");
  1011. delete(executable);
  1012. strcpy(executable, outfile);
  1013. strcat(executable, "-9x.tib");
  1014. delete(executable);
  1015. strcpy(executable, outfile);
  1016. strcat(executable, "-v2.tib");
  1017. delete(executable);
  1018. } else {
  1019. strcpy(executable, outfile);
  1020. strcat(executable, ".89u");
  1021. delete(executable);
  1022. strcpy(executable, outfile);
  1023. strcat(executable, ".9xu");
  1024. delete(executable);
  1025. strcpy(executable, outfile);
  1026. strcat(executable, ".v2u");
  1027. delete(executable);
  1028. }
  1029. } else {
  1030. if (settings.outputbin) {
  1031. strcpy(executable, outfile);
  1032. strcat(executable, ".z89");
  1033. delete(executable);
  1034. strcpy(executable, outfile);
  1035. strcat(executable, ".z9x");
  1036. delete(executable);
  1037. strcpy(executable, outfile);
  1038. strcat(executable, ".zv2");
  1039. delete(executable);
  1040. } else {
  1041. strcpy(executable, outfile);
  1042. strcat(executable, ".89z");
  1043. delete(executable);
  1044. strcpy(executable, outfile);
  1045. strcat(executable, ".9xz");
  1046. delete(executable);
  1047. strcpy(executable, outfile);
  1048. strcat(executable, ".v2z");
  1049. delete(executable);
  1050. strcpy(executable, outfile);
  1051. strcat(executable, ".89y");
  1052. delete(executable);
  1053. strcpy(executable, outfile);
  1054. strcat(executable, ".9xy");
  1055. delete(executable);
  1056. strcpy(executable, outfile);
  1057. strcat(executable, ".v2y");
  1058. delete(executable);
  1059. if (settings.pack) {
  1060. strcpy(executable, outfile);
  1061. strcat(executable, "-titanium.89z");
  1062. delete(executable);
  1063. strcpy(executable, outfile);
  1064. strcat(executable, "-Titanium.89z");
  1065. delete(executable);
  1066. }
  1067. }
  1068. }
  1069. }
  1070. __attribute__((noreturn)) static void outofmem(void)
  1071. {
  1072. fprintf(stderr,"Fatal error: not enough free memory\n");
  1073. exit(-1);
  1074. }
  1075. static char *dynstrcat(char *s, const char *t)
  1076. {
  1077. char *p;
  1078. size_t l = strlen(s) + strlen(t) + 1;
  1079. p = realloc(s,l);
  1080. if (p) {
  1081. strcat(p,t);
  1082. return p;
  1083. } else {
  1084. free(s);
  1085. outofmem();
  1086. }
  1087. }