msg2inc.pp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803
  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. begin
  563. if (s[i+1] in ['0'..'9']) then
  564. hs:=hs+'arg'
  565. else
  566. hs:=hs+'\$';
  567. end
  568. else
  569. hs:=hs+s[i];
  570. EscapeString:=hs;
  571. end;
  572. procedure WriteTexFile(const infn,outfn:string);
  573. var
  574. t,f : text;
  575. line,
  576. i,k : longint;
  577. s,s1 : string;
  578. texoutput : boolean;
  579. begin
  580. Writeln('Loading messagefile ',infn);
  581. writeln('Writing TeXfile ',outfn);
  582. { Open infile }
  583. assign(f,infn);
  584. {$I-}
  585. reset(f);
  586. {$I+}
  587. if ioresult<>0 then
  588. begin
  589. WriteLn('*** message file '+infn+' not found ***');
  590. exit;
  591. end;
  592. { Open outfile }
  593. assign(t,outfn);
  594. rewrite(t);
  595. If texheader then
  596. begin
  597. writeln (t,'\documentclass{article}');
  598. writeln (t,'\usepackage{html}');
  599. writeln (t,'\usepackage{fpc}');
  600. writeln (t,'\begin{document}');
  601. end;
  602. { Parse }
  603. line:=0;
  604. TexOutput:=False;
  605. while not eof(f) do
  606. begin
  607. readln(f,s);
  608. inc(line);
  609. If Pos ('# BeginOfTeX',S)=1 then
  610. TexOutPut:=True
  611. else if pos ('# EndOfTeX',S)=1 then
  612. TexOutPut:=False;
  613. if (s<>'') and not(s[1] in ['#',';']) and TeXOutPut then
  614. begin
  615. if s[1]='%' then
  616. begin
  617. Delete(s,1,1);
  618. writeln(t,s);
  619. end
  620. else
  621. begin
  622. i:=pos('=',s);
  623. if i>0 then
  624. begin
  625. inc(i);
  626. while s[i] in ['0'..'9'] do
  627. inc(i);
  628. inc(i);
  629. s1:='';
  630. k:=0;
  631. while (k<5) and (s[i+k]<>'_') do
  632. begin
  633. case s[i+k] of
  634. 'W' : s1:='Warning: ';
  635. 'E' : s1:='Error: ';
  636. 'F' : s1:='Fatal: ';
  637. 'N' : s1:='Note: ';
  638. 'I' : s1:='Info: ';
  639. 'H' : s1:='Hint: ';
  640. end;
  641. inc(k);
  642. end;
  643. if s[i+k]='_' then
  644. inc(i,k+1);
  645. writeln(t,'\item ['+s1+escapestring(Copy(s,i,255))+']');
  646. end
  647. else
  648. writeln('error in line: ',line,' skipping');
  649. end;
  650. end;
  651. end;
  652. If TexHeader then
  653. writeln (t,'\end{document}');
  654. close(t);
  655. close(f);
  656. end;
  657. {*****************************************************************************
  658. Main Program
  659. *****************************************************************************}
  660. procedure getpara;
  661. var
  662. ch : char;
  663. para : string;
  664. files,i : word;
  665. procedure helpscreen;
  666. begin
  667. writeln('usage : msg2inc [Options] <msgfile> <incfile> <constname>');
  668. writeln('<Options> can be : -T Create .doc TeX file');
  669. writeln(' -TS Create .doc TeX file (stand-alone)');
  670. writeln(' -I Intel style asm output');
  671. writeln(' -S array of string');
  672. writeln(' -C array of char');
  673. writeln(' -R renumber section <incfile>');
  674. writeln(' -V Show version');
  675. writeln(' -? or -H This HelpScreen');
  676. halt(1);
  677. end;
  678. begin
  679. Mode:=M_String;
  680. FIles:=0;
  681. for i:=1to paramcount do
  682. begin
  683. para:=paramstr(i);
  684. if (para[1]='-') then
  685. begin
  686. ch:=upcase(para[2]);
  687. delete(para,1,2);
  688. case ch of
  689. 'T' : begin
  690. case upcase(para[1]) of
  691. 'S' : TexHeader:=True;
  692. end;
  693. Mode:=M_Tex;
  694. end;
  695. 'I' : Mode:=M_Intel;
  696. 'S' : Mode:=M_String;
  697. 'C' : Mode:=M_Char;
  698. 'R' : Mode:=M_Renumber;
  699. 'V' : begin
  700. Writeln('Msg2Inc ',version,' for Free Pascal (C) 1998-2000 Peter Vreman');
  701. Writeln;
  702. Halt;
  703. end;
  704. '?','H' : helpscreen;
  705. end;
  706. end
  707. else
  708. begin
  709. inc(Files);
  710. if Files>3 then
  711. HelpScreen;
  712. case Files of
  713. 1 : InFile:=Para;
  714. 2 : OutFile:=Para;
  715. 3 : OutName:=Para;
  716. end;
  717. end;
  718. end;
  719. case Mode of
  720. M_Renumber,
  721. M_Tex : if Files<2 then
  722. Helpscreen;
  723. else
  724. if FIles<3 then
  725. HelpScreen;
  726. end;
  727. end;
  728. begin
  729. GetPara;
  730. case Mode of
  731. M_Renumber : begin
  732. Renumberfile(Infile,OutFile);
  733. end;
  734. M_Tex : begin
  735. if pos('.tex',outfile)=0 then
  736. Outfile:=OutFile+'.tex';
  737. WriteTexFile(InFile,Outfile);
  738. end;
  739. M_Intel : begin
  740. Loadmsgfile(InFile);
  741. WriteEnumFile(OutFile+'idx.inc',OutName+'const');
  742. WriteIntelFile(OutFile+'txt.inc',OutName+'txt');
  743. end;
  744. M_String : begin
  745. Loadmsgfile(InFile);
  746. WriteEnumFile(OutFile+'idx.inc',OutName+'const');
  747. WriteStringFile(OutFile+'txt.inc',OutName+'txt');
  748. end;
  749. M_Char : begin
  750. Loadmsgfile(InFile);
  751. WriteEnumFile(OutFile+'idx.inc',OutName+'const');
  752. WriteCharFile(OutFile+'txt.inc',OutName+'txt');
  753. end;
  754. end;
  755. end.
  756. {
  757. $Log$
  758. Revision 1.2 2000-07-13 11:32:55 michael
  759. + removed logs
  760. }