msg2inc.pp 19 KB

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