msg2inc.pp 18 KB

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