ttdos2ebk.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581
  1. /******************************************************************************
  2. *
  3. * project name: TI-68k Developer Utilities
  4. * file name: ttdos2ebk.c
  5. * initial date: 20/08/2000
  6. * author: thomas.nussbaumer@gmx.net
  7. * description: prepares a text file for ebook
  8. *
  9. ******************************************************************************/
  10. /*
  11. This file is part of TI-68k Developer Utilities.
  12. This file is free software; you can redistribute it and/or
  13. modify it under the terms of the GNU Lesser General Public
  14. License as published by the Free Software Foundation; either
  15. version 2.1 of the License, or (at your option) any later version.
  16. As a special exception, UNMODIFIED copies of ttdos2ebk may also be
  17. redistributed or sold without source code, for any purpose. (The Lesser
  18. General Public License restrictions do apply in other respects; for example,
  19. they cover modification of the program.) This exception notice must be
  20. removed on modified copies of this file.
  21. This program is distributed in the hope that it will be useful,
  22. but WITHOUT ANY WARRANTY; without even the implied warranty of
  23. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  24. Lesser General Public License for more details.
  25. You should have received a copy of the GNU Lesser General Public
  26. License along with this library; if not, write to the Free Software
  27. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  28. */
  29. // if EMBEDDED_USE is defined, than we use this sourcefile from within another
  30. // sourcefile
  31. #ifndef EMBEDDED_USE
  32. #include <stdio.h>
  33. #include <stdlib.h>
  34. #include <string.h>
  35. #include "ttversion.h"
  36. #include "revtools.h"
  37. #include "ttebkmeta.h"
  38. #ifdef FILE_REVISION
  39. #undef FILE_REVISION
  40. #endif
  41. #define FILE_REVISION "1.9"
  42. //=============================================================================
  43. // print the usage
  44. //=============================================================================
  45. void PrintUsage() {
  46. fprintf(USAGE_OUT, "Usage: ttdos2ebk [-v] <infile> <outfile>\n\n"\
  47. " -v ... print verbose messages\n\n"\
  48. " converts a plain dos text to an ebook conform text\n"\
  49. " by discarding all 0x0D and by handling the following\n"\
  50. " inlined metatags:\n\n"\
  51. " <mt ff> ... inserts a form feed\n"\
  52. " <mt hr> ... inserts a horizontal ruler\n"\
  53. " <mt left> ... text alignment left\n"\
  54. " <mt right> ... text alignment right\n"\
  55. " <mt center> ... text alignment right\n\n"\
  56. " and the following preprocessing metatags:\n\n"\
  57. " <mt r=on> ... replace single 0x0A by space ON\n"\
  58. " <mt r=off> ... replace single 0x0A by space OFF\n"\
  59. " <mt c=on> ... collapse spaces ON\n"\
  60. " <mt c=off> ... collapse spaces OFF\n"\
  61. " <mt t=on> ... metatag translation ON\n"\
  62. " <mt t=off> ... metatag translation OFF\n");
  63. }
  64. #endif
  65. #define DEFAULT_COLLAPSE 1
  66. #define DEFAULT_REPLACE 1
  67. #define DEFAULT_TRANSLATE 1
  68. #define DEFAULT_DBLSPACE 0
  69. typedef struct {
  70. char* metatag;
  71. unsigned char sbcc;
  72. } ConvEntry;
  73. //#define CONV_ENTRIES 13
  74. #define IDX_TRANS_OFF 10
  75. #define IDX_TRANS_ON 9
  76. //-----------------------------------------------------------------------------
  77. // mapping table for meta tags
  78. //-----------------------------------------------------------------------------
  79. ConvEntry ctable[] = {
  80. {"<mt ff>", SBCC_FF },
  81. {"<mt hr>", SBCC_HR },
  82. {"<mt left>", SBCC_LEFT },
  83. {"<mt right>", SBCC_RIGHT },
  84. {"<mt center>", SBCC_CENTER },
  85. {"<mt r=on>", SBCC_REPLACE_ON },
  86. {"<mt r=off>", SBCC_REPLACE_OFF },
  87. {"<mt c=on>", SBCC_COLLAPSE_ON },
  88. {"<mt c=off>", SBCC_COLLAPSE_OFF },
  89. {"<mt t=on>", SBCC_TRANS_ON },
  90. {"<mt t=off>", SBCC_TRANS_OFF },
  91. {"<mt ds=on>", SBCC_DOUBLESPACE_ON },
  92. {"<mt ds=off>", SBCC_DOUBLESPACE_OFF },
  93. {0,0}};
  94. //=============================================================================
  95. // reads 1 line from src into dest and appends a zero
  96. //=============================================================================
  97. long ReadLine(char* src, char* dest, char* end) {
  98. long icount = 0;
  99. while (*src != 0x0A && src < end && icount < 4094) *dest++ = *src++,icount++;
  100. *dest=0;
  101. return icount;
  102. }
  103. int state_translate = DEFAULT_TRANSLATE;
  104. //=============================================================================
  105. // handles metatag replacement for one line
  106. //=============================================================================
  107. void TranslateLine(char* src,char* dest) {
  108. int i=0;
  109. char* tmp;
  110. strcpy(dest,src);
  111. while (ctable[i].metatag) {
  112. if (state_translate || i==IDX_TRANS_ON || i==IDX_TRANS_OFF) {
  113. char* location = strstr(dest,ctable[i].metatag);
  114. if (location) {
  115. if (i == IDX_TRANS_OFF || i == IDX_TRANS_ON) {
  116. if (i==IDX_TRANS_OFF) state_translate = 0;
  117. else if (i==IDX_TRANS_ON) state_translate = 1;
  118. tmp = location + strlen(ctable[i].metatag);
  119. }
  120. else {
  121. *location = CCI;
  122. *(location+1) = ctable[i].sbcc;
  123. tmp = location + strlen(ctable[i].metatag);
  124. location+=2;
  125. }
  126. while (*tmp) *location++ = *tmp++;
  127. *location = 0;
  128. i--;
  129. }
  130. }
  131. i++;
  132. }
  133. }
  134. //=============================================================================
  135. // replaces all meta tags of within a buffer
  136. //=============================================================================
  137. long Translate(char* src,char* dest,long ilength) {
  138. char b[4096];
  139. char b2[4096];
  140. long len,clen,ilen = 0;
  141. char* end = src + ilength;
  142. while (src < end) {
  143. len = ReadLine(src,b,end);
  144. TranslateLine(b,b2);
  145. clen = strlen(b2);
  146. memcpy(dest,b2,clen);
  147. dest += clen;
  148. *dest++ = 0x0A;
  149. ilen += clen + 1;
  150. src += len + 1;
  151. //printf("%s\n",b2);
  152. }
  153. return ilen;
  154. }
  155. //=============================================================================
  156. // copies a maximum of length bytes from src to dest, but skipping 0x0D bytes
  157. //
  158. // returns number of bytes copied
  159. //=============================================================================
  160. long RemoveAll0D(char* src, char* dest,long length) {
  161. long i;
  162. long cnt = 0;
  163. for (i=0;i<length;i++) {
  164. unsigned char c = *src++;
  165. if (c != 0x0D) {
  166. *dest++ = c;
  167. cnt++;
  168. }
  169. }
  170. return cnt;
  171. }
  172. //=============================================================================
  173. // handles complete preprocessing including space collapsing and break
  174. // replacement
  175. //=============================================================================
  176. long Preprocess(char* src,char* dest,long length,int verbose) {
  177. long i;
  178. long space_count = 0;
  179. long break_count = 0;
  180. long collapse_count = 0;
  181. long replace_count = 0;
  182. int state_replace = DEFAULT_REPLACE;
  183. int state_collapse = DEFAULT_COLLAPSE;
  184. int state_dblspace = DEFAULT_DBLSPACE;
  185. int removed_codes = 0;
  186. char* orig_dest = dest;
  187. for (i=0;i<length;i++) {
  188. unsigned char c = *src++;
  189. if (c == 0x0A) {
  190. break_count++;
  191. if (space_count) {
  192. if (state_collapse) {
  193. *dest++ = ' ';
  194. collapse_count += space_count - 1;
  195. }
  196. else {
  197. while (space_count--) *dest++ = ' ';
  198. }
  199. space_count = 0;
  200. }
  201. continue;
  202. }
  203. if (c == ' ') {
  204. space_count++;
  205. if (state_dblspace) space_count++; // NEW
  206. if (break_count) {
  207. if (state_replace) {
  208. if (break_count == 1) {
  209. space_count++;
  210. if (state_dblspace) space_count++; // NEW
  211. replace_count++;
  212. }
  213. else {
  214. while (break_count--) *dest++ = 0x0A;
  215. }
  216. }
  217. else {
  218. while (break_count--) *dest++ = 0x0A;
  219. }
  220. break_count = 0;
  221. }
  222. continue;
  223. }
  224. if (c == CCI) {
  225. c = *src++;
  226. i++;
  227. switch(c) {
  228. case SBCC_DOUBLESPACE_ON:
  229. removed_codes++;
  230. state_dblspace = 1;
  231. break;
  232. case SBCC_DOUBLESPACE_OFF:
  233. removed_codes++;
  234. state_dblspace = 0;
  235. break;
  236. case SBCC_COLLAPSE_ON:
  237. removed_codes++;
  238. if (space_count) {
  239. if (state_collapse) {
  240. *dest++ = ' ';
  241. collapse_count += space_count - 1;
  242. }
  243. else {
  244. while (space_count--) *dest++ = ' ';
  245. }
  246. space_count = 0;
  247. }
  248. state_collapse = 1;
  249. break;
  250. case SBCC_COLLAPSE_OFF:
  251. removed_codes++;
  252. if (space_count) {
  253. if (state_collapse) {
  254. *dest++ = ' ';
  255. collapse_count += space_count - 1;
  256. }
  257. else {
  258. while (space_count--) *dest++ = ' ';
  259. }
  260. space_count = 0;
  261. }
  262. state_collapse = 0;
  263. break;
  264. case SBCC_REPLACE_ON:
  265. removed_codes++;
  266. if (break_count) {
  267. if (state_replace) {
  268. if (break_count == 1) {
  269. space_count++;
  270. if (state_dblspace) space_count++; // NEW
  271. replace_count++;
  272. }
  273. else {
  274. while (break_count--) *dest++ = 0x0A;
  275. }
  276. }
  277. else {
  278. while (break_count--) *dest++ = 0x0A;
  279. }
  280. break_count = 0;
  281. }
  282. state_replace = 1;
  283. break;
  284. case SBCC_REPLACE_OFF:
  285. removed_codes++;
  286. if (break_count) {
  287. if (state_replace) {
  288. if (break_count == 1) {
  289. space_count++;
  290. if (state_dblspace) space_count++; // NEW
  291. replace_count++;
  292. }
  293. else {
  294. while (break_count--) *dest++ = 0x0A;
  295. }
  296. }
  297. else {
  298. while (break_count--) *dest++ = 0x0A;
  299. }
  300. break_count = 0;
  301. }
  302. state_replace = 0;
  303. break;
  304. default:
  305. *dest++ = CCI;
  306. *dest++ = c;
  307. break;
  308. }
  309. continue;
  310. }
  311. //------------------------------------------------------
  312. // If we'll come here we have to flush spaces and breaks
  313. //------------------------------------------------------
  314. if (break_count) {
  315. if (state_replace) {
  316. if (break_count == 1) {
  317. space_count++;
  318. if (state_dblspace) space_count++; // NEW
  319. replace_count++;
  320. }
  321. else {
  322. while (break_count--) *dest++ = 0x0A;
  323. }
  324. }
  325. else {
  326. while (break_count--) *dest++ = 0x0A;
  327. }
  328. break_count = 0;
  329. }
  330. if (space_count) {
  331. if (state_collapse) {
  332. *dest++ = ' ';
  333. collapse_count += space_count - 1;
  334. }
  335. else {
  336. while (space_count--) *dest++ = ' ';
  337. }
  338. space_count = 0;
  339. }
  340. *dest++ = c;
  341. }
  342. //-----------------------------------------------
  343. // once more a little bit flushing
  344. //-----------------------------------------------
  345. if (break_count) {
  346. if (state_replace) {
  347. if (break_count == 1) {
  348. space_count++;
  349. if (state_dblspace) space_count++; // NEW
  350. replace_count++;
  351. }
  352. else {
  353. while (break_count--) *dest++ = 0x0A;
  354. }
  355. }
  356. else {
  357. while (break_count--) *dest++ = 0x0A;
  358. }
  359. break_count = 0;
  360. }
  361. if (space_count) {
  362. if (state_collapse) {
  363. *dest++ = ' ';
  364. collapse_count += space_count - 1;
  365. }
  366. else {
  367. while (space_count--) *dest++ = ' ';
  368. }
  369. space_count = 0;
  370. }
  371. if (verbose) fprintf(stderr,"replace_count=%ld collapse_count=%ld removed_codes=%d\n",replace_count,collapse_count,removed_codes);
  372. //return length-collapse_count-removed_codes*2;
  373. return dest - orig_dest;
  374. }
  375. //=============================================================================
  376. // nomen omen est
  377. //=============================================================================
  378. #ifndef EMBEDDED_USE
  379. int main(int argc, char* argv[]) {
  380. #else
  381. int TTDos2Ebk(int argc,char* argv[]) {
  382. #endif
  383. FILE* fp = NULL;
  384. long size;
  385. char* buf1 = NULL;
  386. char* buf2 = NULL;
  387. char* infile = 0;
  388. char* outfile = 0;
  389. //int replace = 1;
  390. int verbose = 0;
  391. int i;
  392. #ifndef EMBEDDED_USE
  393. PRINT_ID("TTDos2EBK");
  394. #endif
  395. if (argc < 3) {
  396. #ifndef EMBEDDED_USE
  397. PrintUsage();
  398. #endif
  399. return 1;
  400. }
  401. // parse arguments
  402. for (i=1; i<argc; i++) {
  403. if (!strcmp(argv[i], "-v")) verbose = 1;
  404. else if (!infile) infile = argv[i];
  405. else if (!outfile) outfile = argv[i];
  406. else {
  407. #ifndef EMBEDDED_USE
  408. PrintUsage();
  409. #endif
  410. return 1;
  411. }
  412. }
  413. if (!infile || !outfile) {
  414. #ifndef EMBEDDED_USE
  415. PrintUsage();
  416. #endif
  417. return 1;
  418. }
  419. if (!(fp = fopen(infile,"rb"))) {
  420. fprintf(stderr,"ERROR: cannot open inputfile %s\n",infile);
  421. return 1;
  422. }
  423. fseek(fp,0,SEEK_END);
  424. size = ftell(fp);
  425. rewind(fp);
  426. if (verbose) fprintf(stderr,"inputsize is %ld bytes\n",size);
  427. if (!(buf1 = malloc(size*2))) { // size*2 necessary for double-space
  428. fprintf(stderr,"ERROR: cannot allocate %ld bytes\n",size);
  429. fclose(fp);
  430. free(buf2);
  431. free(buf1);
  432. return 1;
  433. }
  434. if (!(buf2 = malloc(size*2))) { // size*2 necessary for double-space
  435. fprintf(stderr,"ERROR: cannot allocate %ld bytes\n",size);
  436. fclose(fp);
  437. free(buf2);
  438. free(buf1);
  439. return 1;
  440. }
  441. if (fread(buf1,size,1,fp) != 1) {
  442. fprintf(stderr,"ERROR: cannot read content of inputfile %s\n",infile);
  443. fclose(fp);
  444. free(buf2);
  445. free(buf1);
  446. return 1;
  447. }
  448. fclose(fp);
  449. if (!(fp = fopen(outfile,"wb"))) {
  450. fprintf(stderr,"ERROR: cannot open outputfile %s\n",outfile);
  451. free(buf2);
  452. free(buf1);
  453. return 1;
  454. }
  455. size = Translate(buf1,buf2,size);
  456. if (verbose) fprintf(stderr,"size after translation = %ld\n",size);
  457. size = RemoveAll0D(buf2,buf1,size);
  458. if (verbose) fprintf(stderr,"after removing all 0x0D is size %ld bytes\n",size);
  459. size = Preprocess(buf1,buf2,size,verbose);
  460. if (fwrite(buf2,size,1,fp) != 1) {
  461. fprintf(stderr,"ERROR: cannot write %ld bytes to outputfile %s\n",size,outfile);
  462. }
  463. else {
  464. if (verbose) fprintf(stderr,"%ld bytes written to file %s\n",size,outfile);
  465. }
  466. fclose(fp);
  467. free(buf2);
  468. free(buf1);
  469. return 0;
  470. }
  471. //#############################################################################
  472. //###################### NO MORE FAKES BEYOND THIS LINE #######################
  473. //#############################################################################
  474. //
  475. //=============================================================================
  476. // Revision History
  477. //=============================================================================
  478. //
  479. // Revision 1.9 2009/01/25 Lionel Debroux
  480. // Changes by Romain Liévin and/or me for 64-bit compatibility.
  481. // Adapt to new version display (revtools.h).
  482. //
  483. // Revision 1.8 2002/03/06 16:08:52 tnussb
  484. // typo in PrintUsage() fixed
  485. //
  486. // Revision 1.7 2002/03/04 14:32:41 tnussb
  487. // now tool can be used as embedded version from within other tools
  488. // by defining EMBEDDED_VERSION before including the sourcefile
  489. //
  490. // Revision 1.6 2002/02/07 09:49:37 tnussb
  491. // all local includes changed, because header files are now located in pctools folder
  492. //
  493. // Revision 1.5 2000/11/28 00:06:33 Thomas Nussbaumer
  494. // using now USAGE_OUT stream for usage info
  495. //
  496. // Revision 1.4 2000/10/01 15:06:54 Thomas Nussbaumer
  497. // support for more tags and some bugs fixed
  498. //
  499. // Revision 1.3 2000/08/27 23:54:55 Thomas Nussbaumer
  500. // metatag handling support added
  501. //
  502. // Revision 1.2 2000/08/23 19:51:38 Thomas Nussbaumer
  503. // adapted to automatic version display (revtools.h)
  504. //
  505. // Revision 1.1 2000/08/20 15:45:02 Thomas Nussbaumer
  506. // initial version
  507. //
  508. //
  509. //