2
0

msg2inc.pp 18 KB

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