2
0

msg2inc.pp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817
  1. {
  2. This program is part of the Free Pascal run time library.
  3. Copyright (c) 1998-2002 by Peter Vreman
  4. Convert a .msg file to an .inc file with a const array of char
  5. And for the lazy docwriters it can also generate some TeX output
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. program msg2inc;
  13. uses
  14. strings;
  15. {$ifdef unix}
  16. {$define EOL_ONE_CHAR}
  17. {$endif unix}
  18. {$ifdef amiga}
  19. {$define EOL_ONE_CHAR}
  20. {$endif amiga}
  21. {$ifdef morphos}
  22. {$define EOL_ONE_CHAR}
  23. {$endif}
  24. {$ifdef macos}
  25. {$define EOL_ONE_CHAR}
  26. {$endif}
  27. const
  28. version='1.00';
  29. {$ifdef EOL_ONE_CHAR}
  30. eollen=1;
  31. {$else}
  32. eollen=2;
  33. {$endif}
  34. msgparts = 20;
  35. type
  36. TMode=(M_Char,M_Tex,M_Intel,M_String,M_Renumber);
  37. var
  38. InFile,
  39. OutFile,
  40. OutName : string;
  41. Mode : TMode;
  42. TexHeader : boolean;
  43. MsgTxt : pchar;
  44. EnumTxt : pchar;
  45. enumsize,
  46. msgsize : longint;
  47. msgidxmax : array[1..msgparts] of longint;
  48. msgs : array[0..msgparts,0..999] of boolean;
  49. procedure LoadMsgFile(const fn:string);
  50. var
  51. f : text;
  52. error,
  53. multiline : boolean;
  54. code : word;
  55. numpart,numidx,
  56. line,i,j,num : longint;
  57. ptxt,
  58. penum : pchar;
  59. number,
  60. s,s1 : string;
  61. procedure err(const msgstr:string);
  62. begin
  63. writeln('error in line ',line,': ',msgstr);
  64. error:=true;
  65. end;
  66. begin
  67. Writeln('Loading messagefile ',fn);
  68. {Read the message file}
  69. assign(f,fn);
  70. {$I-}
  71. reset(f);
  72. {$I+}
  73. if ioresult<>0 then
  74. begin
  75. WriteLn('fatal error: '+fn+' not found');
  76. halt(1);
  77. end;
  78. { First parse the file and count bytes needed }
  79. fillchar(msgidxmax,sizeof(msgidxmax),0);
  80. fillchar(msgs,sizeof(msgs),0);
  81. error:=false;
  82. line:=0;
  83. multiline:=false;
  84. msgsize:=0;
  85. while not eof(f) do
  86. begin
  87. readln(f,s);
  88. inc(line);
  89. if multiline then
  90. begin
  91. if s=']' then
  92. multiline:=false
  93. else
  94. inc(msgsize,length(s)+1); { +1 for linebreak }
  95. end
  96. else
  97. begin
  98. if (s<>'') and not(s[1] in ['#',';','%']) then
  99. begin
  100. i:=pos('=',s);
  101. if i>0 then
  102. begin
  103. j:=i+1;
  104. if not(s[j] in ['0'..'9']) then
  105. err('no number found')
  106. else
  107. begin
  108. while (s[j] in ['0'..'9']) do
  109. inc(j);
  110. end;
  111. if j-i-1<>5 then
  112. err('number length is not 5');
  113. number:=Copy(s,i+1,j-i-1);
  114. { update the max index }
  115. val(number,num,code);
  116. numpart:=num div 1000;
  117. if numpart=0 then
  118. err('number should be > 1000');
  119. numidx:=num mod 1000;
  120. { duplicate ? }
  121. if msgs[numpart,numidx] then
  122. err('duplicate number found');
  123. msgs[numpart,numidx]:=true;
  124. { check range }
  125. if numpart > msgparts then
  126. err('number is to large')
  127. else
  128. if numidx > msgidxmax[numpart] then
  129. msgidxmax[numpart]:=numidx;
  130. if s[j+1]='[' then
  131. begin
  132. inc(msgsize,j-i);
  133. multiline:=true
  134. end
  135. else
  136. inc(msgsize,length(s)-i+1);
  137. inc(enumsize,j);
  138. end
  139. else
  140. err('no = found');
  141. end;
  142. end;
  143. end;
  144. if multiline then
  145. err('still in multiline mode');
  146. if error then
  147. begin
  148. close(f);
  149. writeln('aborting');
  150. halt(1);
  151. end;
  152. { alloc memory }
  153. getmem(msgtxt,msgsize);
  154. { no linebreak after last entry }
  155. dec(msgsize);
  156. ptxt:=msgtxt;
  157. getmem(enumtxt,enumsize);
  158. penum:=enumtxt;
  159. { now read the buffer in mem }
  160. reset(f);
  161. while not eof(f) do
  162. begin
  163. readln(f,s);
  164. if multiline then
  165. begin
  166. if s=']' then
  167. begin
  168. multiline:=false;
  169. { overwrite last eol }
  170. dec(ptxt);
  171. ptxt^:=#0;
  172. inc(ptxt);
  173. end
  174. else
  175. begin
  176. move(s[1],ptxt^,length(s));
  177. inc(ptxt,length(s));
  178. ptxt^:=#10;
  179. inc(ptxt);
  180. end;
  181. end
  182. else
  183. begin
  184. if (s<>'') and not(s[1] in ['#',';','%']) then
  185. begin
  186. i:=pos('=',s);
  187. if i>0 then
  188. begin
  189. j:=i+1;
  190. while (s[j] in ['0'..'9']) do
  191. inc(j);
  192. {enum}
  193. move(s[1],penum^,i-1);
  194. inc(penum,i-1);
  195. penum^:='=';
  196. inc(penum);
  197. number:=Copy(s,i+1,j-i-1);
  198. move(number[1],penum^,length(number));
  199. inc(penum,length(number));
  200. penum^:=#0;
  201. inc(penum);
  202. { multiline start then no txt }
  203. if s[j+1]='[' then
  204. begin
  205. s1:=Copy(s,i+1,j-i);
  206. move(s1[1],ptxt^,length(s1));
  207. inc(ptxt,length(s1));
  208. multiline:=true;
  209. end
  210. else
  211. begin
  212. { txt including number }
  213. s1:=Copy(s,i+1,255);
  214. move(s1[1],ptxt^,length(s1));
  215. inc(ptxt,length(s1));
  216. ptxt^:=#0;
  217. inc(ptxt);
  218. end;
  219. end;
  220. end;
  221. end;
  222. end;
  223. close(f);
  224. end;
  225. {*****************************************************************************
  226. WriteEnumFile
  227. *****************************************************************************}
  228. procedure WriteEnumFile(const fn,typename:string);
  229. var
  230. t : text;
  231. i : longint;
  232. p : pchar;
  233. start : boolean;
  234. begin
  235. writeln('Writing enumfile '+fn);
  236. {Open textfile}
  237. assign(t,fn);
  238. rewrite(t);
  239. writeln(t,'const');
  240. {Parse buffer in msgbuf and create indexs}
  241. p:=enumtxt;
  242. start:=true;
  243. for i:=1 to enumsize do
  244. begin
  245. if start then
  246. begin
  247. write(t,' ');
  248. start:=false;
  249. end;
  250. if p^=#0 then
  251. begin
  252. writeln(t,';');
  253. start:=true;
  254. end
  255. else
  256. begin
  257. write(t,p^);
  258. end;
  259. inc(p);
  260. end;
  261. writeln(t,'');
  262. { msgtxt size }
  263. writeln(t,' MsgTxtSize = ',msgsize,';');
  264. writeln(t,'');
  265. { max msg idx table }
  266. writeln(t,' MsgIdxMax : array[1..20] of longint=(');
  267. write(t,' ');
  268. for i:=1 to 20 do
  269. begin
  270. write(t,msgidxmax[i]+1);
  271. if i<20 then
  272. write(t,',');
  273. if i=10 then
  274. begin
  275. writeln(t,'');
  276. write(t,' ');
  277. end;
  278. end;
  279. writeln(t,'');
  280. writeln(t,' );');
  281. close(t);
  282. end;
  283. {*****************************************************************************
  284. WriteStringFile
  285. *****************************************************************************}
  286. procedure WriteStringFile(const fn,constname:string);
  287. const
  288. maxslen=240; { to overcome aligning problems }
  289. function l0(l:longint):string;
  290. var
  291. s : string[16];
  292. begin
  293. str(l,s);
  294. while (length(s)<5) do
  295. s:='0'+s;
  296. l0:=s;
  297. end;
  298. var
  299. t : text;
  300. f : file;
  301. slen,
  302. len,i : longint;
  303. p : pchar;
  304. s : string;
  305. start,
  306. quote : boolean;
  307. begin
  308. writeln('Writing stringfile ',fn);
  309. {Open textfile}
  310. assign(t,fn);
  311. rewrite(t);
  312. writeln(t,'{$ifdef Delphi}');
  313. writeln(t,'const '+constname+' : array[0..000000] of string[',maxslen,']=(');
  314. writeln(t,'{$else Delphi}');
  315. writeln(t,'const '+constname+' : array[0..000000,1..',maxslen,'] of char=(');
  316. write(t,'{$endif Delphi}');
  317. {Parse buffer in msgbuf and create indexs}
  318. p:=msgtxt;
  319. slen:=0;
  320. len:=0;
  321. quote:=false;
  322. start:=true;
  323. for i:=1 to msgsize do
  324. begin
  325. if slen>=maxslen then
  326. begin
  327. if quote then
  328. begin
  329. write(t,'''');
  330. quote:=false;
  331. end;
  332. write(t,',');
  333. slen:=0;
  334. inc(len);
  335. end;
  336. if (len>70) or (start) then
  337. begin
  338. if quote then
  339. begin
  340. write(t,'''');
  341. quote:=false;
  342. end;
  343. if slen>0 then
  344. writeln(t,'+')
  345. else
  346. writeln(t);
  347. len:=0;
  348. start:=false;
  349. end;
  350. if (len=0) then
  351. write(t,' ');
  352. if (ord(p^)>=32) and (p^<>#39) then
  353. begin
  354. if not quote then
  355. begin
  356. write(t,'''');
  357. quote:=true;
  358. inc(len);
  359. end;
  360. write(t,p^);
  361. inc(len);
  362. end
  363. else
  364. begin
  365. if quote then
  366. begin
  367. write(t,'''');
  368. inc(len);
  369. quote:=false;
  370. end;
  371. write(t,'#'+chr(ord(p^) div 100+48)+chr((ord(p^) mod 100) div 10+48)+chr(ord(p^) mod 10+48));
  372. inc(len,3);
  373. end;
  374. if p^ in [#0,#10] then
  375. start:=true;
  376. inc(slen);
  377. inc(p);
  378. end;
  379. if quote then
  380. write(t,'''');
  381. writeln(t,'');
  382. writeln(t,');');
  383. close(t);
  384. {update arraysize}
  385. s:=l0(msgsize div maxslen); { we start with 0 }
  386. assign(f,fn);
  387. reset(f,1);
  388. seek(f,34+eollen+length(constname));
  389. blockwrite(f,s[1],5);
  390. seek(f,90+3*eollen+2*length(constname));
  391. blockwrite(f,s[1],5);
  392. close(f);
  393. end;
  394. {*****************************************************************************
  395. WriteCharFile
  396. *****************************************************************************}
  397. procedure WriteCharFile(const fn,constname:string);
  398. function l0(l:longint):string;
  399. var
  400. s : string[16];
  401. begin
  402. str(l,s);
  403. while (length(s)<5) do
  404. s:='0'+s;
  405. l0:=s;
  406. end;
  407. function createconst(b:byte):string;
  408. begin
  409. if (b in [32..127]) and (b<>39) then
  410. createconst:=''''+chr(b)+''''
  411. else
  412. createconst:='#'+chr(b div 100+48)+chr((b mod 100) div 10+48)+chr(b mod 10+48)
  413. end;
  414. var
  415. t : text;
  416. f : file;
  417. cidx,i : longint;
  418. p : pchar;
  419. s : string;
  420. begin
  421. writeln('Writing charfile '+fn);
  422. {Open textfile}
  423. assign(t,fn);
  424. rewrite(t);
  425. writeln(t,'const ',constname,' : array[1..00000] of char=(');
  426. {Parse buffer in msgbuf and create indexs}
  427. p:=msgtxt;
  428. cidx:=0;
  429. for i:=1to msgsize do
  430. begin
  431. if cidx=15 then
  432. begin
  433. if cidx>0 then
  434. writeln(t,',')
  435. else
  436. writeln(t,'');
  437. write(t,' ');
  438. cidx:=0;
  439. end
  440. else
  441. if cidx>0 then
  442. write(t,',')
  443. else
  444. write(t,' ');
  445. write(t,createconst(ord(p^)));
  446. inc(cidx);
  447. inc(p);
  448. end;
  449. writeln(t,');');
  450. close(t);
  451. {update arraysize}
  452. s:=l0(msgsize);
  453. assign(f,fn);
  454. reset(f,1);
  455. seek(f,18+length(constname));
  456. blockwrite(f,s[1],5);
  457. close(f);
  458. end;
  459. {*****************************************************************************
  460. WriteIntelFile
  461. *****************************************************************************}
  462. procedure WriteIntelFile(const fn,constname:string);
  463. var
  464. t : text;
  465. len,i : longint;
  466. p : pchar;
  467. start,
  468. quote : boolean;
  469. begin
  470. writeln('Writing Intelfile ',fn);
  471. {Open textfile}
  472. assign(t,fn);
  473. rewrite(t);
  474. writeln(t,'procedure '+constname+';assembler;');
  475. writeln(t,'asm');
  476. {Parse buffer in msgbuf and create indexs}
  477. p:=msgtxt;
  478. len:=0;
  479. start:=true;
  480. quote:=false;
  481. for i:=1to msgsize do
  482. begin
  483. if len>70 then
  484. begin
  485. if quote then
  486. begin
  487. write(t,'''');
  488. quote:=false;
  489. end;
  490. writeln(t,'');
  491. start:=true;
  492. end;
  493. if start then
  494. begin
  495. write(t,' db ''');
  496. len:=0;
  497. quote:=true;
  498. end;
  499. if (ord(p^)>=32) and (p^<>#39) then
  500. begin
  501. if not quote then
  502. begin
  503. write(t,',''');
  504. quote:=true;
  505. inc(len);
  506. end;
  507. write(t,p^);
  508. inc(len);
  509. end
  510. else
  511. begin
  512. if quote then
  513. begin
  514. write(t,'''');
  515. inc(len);
  516. quote:=false;
  517. end;
  518. write(t,','+chr(ord(p^) div 100+48)+chr((ord(p^) mod 100) div 10+48)+chr(ord(p^) mod 10+48));
  519. inc(len,4);
  520. end;
  521. inc(p);
  522. end;
  523. if quote then
  524. write(t,'''');
  525. writeln(t,'');
  526. writeln(t,'end;');
  527. close(t);
  528. end;
  529. {*****************************************************************************
  530. RenumberFile
  531. *****************************************************************************}
  532. procedure RenumberFile(const fn,name:string);
  533. var
  534. f,t : text;
  535. i : longint;
  536. s,s1 : string;
  537. begin
  538. Writeln('Renumbering ',fn);
  539. {Read the message file}
  540. assign(f,fn);
  541. {$I-}
  542. reset(f);
  543. {$I+}
  544. if ioresult<>0 then
  545. begin
  546. WriteLn('*** message file '+fn+' not found ***');
  547. exit;
  548. end;
  549. assign(t,'msg2inc.$$$');
  550. rewrite(t);
  551. i:=0;
  552. while not eof(f) do
  553. begin
  554. readln(f,s);
  555. if (copy(s,1,length(Name))=Name) and (s[3] in ['0'..'9']) then
  556. begin
  557. inc(i);
  558. str(i,s1);
  559. while length(s1)<3 do
  560. s1:='0'+s1;
  561. writeln(t,Name+s1+Copy(s,6,255));
  562. end
  563. else
  564. writeln(t,s);
  565. end;
  566. close(t);
  567. close(f);
  568. { rename new file }
  569. erase(f);
  570. rename(t,fn);
  571. end;
  572. {*****************************************************************************
  573. WriteTexFile
  574. *****************************************************************************}
  575. Function EscapeString (Const S : String) : String;
  576. Var
  577. I : longint;
  578. hs : string;
  579. begin
  580. hs:='';
  581. for i:=1 to length(s) do
  582. if (S[i]='$') then
  583. begin
  584. if (s[i+1] in ['0'..'9']) then
  585. hs:=hs+'arg'
  586. else
  587. hs:=hs+'\$';
  588. end
  589. else
  590. hs:=hs+s[i];
  591. EscapeString:=hs;
  592. end;
  593. procedure WriteTexFile(const infn,outfn:string);
  594. var
  595. t,f : text;
  596. line,
  597. i,k : longint;
  598. s,s1 : string;
  599. texoutput : boolean;
  600. begin
  601. Writeln('Loading messagefile ',infn);
  602. writeln('Writing TeXfile ',outfn);
  603. { Open infile }
  604. assign(f,infn);
  605. {$I-}
  606. reset(f);
  607. {$I+}
  608. if ioresult<>0 then
  609. begin
  610. WriteLn('*** message file '+infn+' not found ***');
  611. exit;
  612. end;
  613. { Open outfile }
  614. assign(t,outfn);
  615. rewrite(t);
  616. If texheader then
  617. begin
  618. writeln (t,'\documentclass{article}');
  619. writeln (t,'\usepackage{html}');
  620. writeln (t,'\usepackage{fpc}');
  621. writeln (t,'\begin{document}');
  622. end;
  623. { Parse }
  624. line:=0;
  625. TexOutput:=False;
  626. while not eof(f) do
  627. begin
  628. readln(f,s);
  629. inc(line);
  630. If Pos ('# BeginOfTeX',S)=1 then
  631. TexOutPut:=True
  632. else if pos ('# EndOfTeX',S)=1 then
  633. TexOutPut:=False;
  634. if (s<>'') and not(s[1] in ['#',';']) and TeXOutPut then
  635. begin
  636. if s[1]='%' then
  637. begin
  638. Delete(s,1,1);
  639. writeln(t,s);
  640. end
  641. else
  642. begin
  643. i:=pos('=',s);
  644. if i>0 then
  645. begin
  646. inc(i);
  647. while s[i] in ['0'..'9'] do
  648. inc(i);
  649. inc(i);
  650. s1:='';
  651. k:=0;
  652. while (k<5) and (s[i+k]<>'_') do
  653. begin
  654. case s[i+k] of
  655. 'W' : s1:='Warning: ';
  656. 'E' : s1:='Error: ';
  657. 'F' : s1:='Fatal: ';
  658. 'N' : s1:='Note: ';
  659. 'I' : s1:='Info: ';
  660. 'H' : s1:='Hint: ';
  661. end;
  662. inc(k);
  663. end;
  664. if s[i+k]='_' then
  665. inc(i,k+1);
  666. writeln(t,'\item ['+s1+escapestring(Copy(s,i,255))+']');
  667. end
  668. else
  669. writeln('error in line: ',line,' skipping');
  670. end;
  671. end;
  672. end;
  673. If TexHeader then
  674. writeln (t,'\end{document}');
  675. close(t);
  676. close(f);
  677. end;
  678. {*****************************************************************************
  679. Main Program
  680. *****************************************************************************}
  681. procedure getpara;
  682. var
  683. ch : char;
  684. para : string;
  685. files,i : word;
  686. procedure helpscreen;
  687. begin
  688. writeln('usage : msg2inc [Options] <msgfile> <incfile> <constname>');
  689. writeln('<Options> can be : -T Create .doc TeX file');
  690. writeln(' -TS Create .doc TeX file (stand-alone)');
  691. writeln(' -I Intel style asm output');
  692. writeln(' -S array of string');
  693. writeln(' -C array of char');
  694. writeln(' -R renumber section <incfile>');
  695. writeln(' -V Show version');
  696. writeln(' -? or -H This HelpScreen');
  697. halt(1);
  698. end;
  699. begin
  700. Mode:=M_String;
  701. FIles:=0;
  702. for i:=1to paramcount do
  703. begin
  704. para:=paramstr(i);
  705. if (para[1]='-') then
  706. begin
  707. ch:=upcase(para[2]);
  708. delete(para,1,2);
  709. case ch of
  710. 'T' : begin
  711. case upcase(para[1]) of
  712. 'S' : TexHeader:=True;
  713. end;
  714. Mode:=M_Tex;
  715. end;
  716. 'I' : Mode:=M_Intel;
  717. 'S' : Mode:=M_String;
  718. 'C' : Mode:=M_Char;
  719. 'R' : Mode:=M_Renumber;
  720. 'V' : begin
  721. Writeln('Msg2Inc ',version,' for Free Pascal (C) 1998-2002 Peter Vreman');
  722. Writeln;
  723. Halt;
  724. end;
  725. '?','H' : helpscreen;
  726. end;
  727. end
  728. else
  729. begin
  730. inc(Files);
  731. if Files>3 then
  732. HelpScreen;
  733. case Files of
  734. 1 : InFile:=Para;
  735. 2 : OutFile:=Para;
  736. 3 : OutName:=Para;
  737. end;
  738. end;
  739. end;
  740. case Mode of
  741. M_Renumber,
  742. M_Tex : if Files<2 then
  743. Helpscreen;
  744. else
  745. if FIles<3 then
  746. HelpScreen;
  747. end;
  748. end;
  749. begin
  750. GetPara;
  751. case Mode of
  752. M_Renumber : begin
  753. Renumberfile(Infile,OutFile);
  754. end;
  755. M_Tex : begin
  756. WriteTexFile(InFile,Outfile);
  757. end;
  758. M_Intel : begin
  759. Loadmsgfile(InFile);
  760. WriteEnumFile(OutFile+'idx.inc',OutName+'const');
  761. WriteIntelFile(OutFile+'txt.inc',OutName+'txt');
  762. end;
  763. M_String : begin
  764. Loadmsgfile(InFile);
  765. WriteEnumFile(OutFile+'idx.inc',OutName+'const');
  766. WriteStringFile(OutFile+'txt.inc',OutName+'txt');
  767. end;
  768. M_Char : begin
  769. Loadmsgfile(InFile);
  770. WriteEnumFile(OutFile+'idx.inc',OutName+'const');
  771. WriteCharFile(OutFile+'txt.inc',OutName+'txt');
  772. end;
  773. end;
  774. end.