msg2inc.pp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816
  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:=succ(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. { no +1 anymore because we now have succ(number mod 1000) (JM) }
  256. write(t,msgidxmax[i]);
  257. if i<20 then
  258. write(t,',');
  259. if i=10 then
  260. begin
  261. writeln(t,'');
  262. write(t,' ');
  263. end;
  264. end;
  265. writeln(t,'');
  266. writeln(t,' );');
  267. close(t);
  268. end;
  269. {*****************************************************************************
  270. WriteStringFile
  271. *****************************************************************************}
  272. procedure WriteStringFile(const fn,constname:string);
  273. const
  274. maxslen=240; { to overcome aligning problems }
  275. function l0(l:longint):string;
  276. var
  277. s : string[16];
  278. begin
  279. str(l,s);
  280. while (length(s)<5) do
  281. s:='0'+s;
  282. l0:=s;
  283. end;
  284. var
  285. t : text;
  286. f : file;
  287. slen,
  288. len,i : longint;
  289. p : pchar;
  290. s : string;
  291. start,
  292. quote : boolean;
  293. begin
  294. writeln('Writing stringfile ',fn);
  295. {Open textfile}
  296. assign(t,fn);
  297. rewrite(t);
  298. writeln(t,'{$ifdef Delphi}');
  299. writeln(t,'const '+constname+' : array[0..000000] of string[',maxslen,']=(');
  300. writeln(t,'{$else Delphi}');
  301. writeln(t,'const '+constname+' : array[0..000000,1..',maxslen,'] of char=(');
  302. write(t,'{$endif Delphi}');
  303. {Parse buffer in msgbuf and create indexs}
  304. p:=msgtxt;
  305. slen:=0;
  306. len:=0;
  307. quote:=false;
  308. start:=true;
  309. for i:=1 to msgsize do
  310. begin
  311. if slen>=maxslen then
  312. begin
  313. if quote then
  314. begin
  315. write(t,'''');
  316. quote:=false;
  317. end;
  318. write(t,',');
  319. slen:=0;
  320. inc(len);
  321. end;
  322. if (len>70) or (start) then
  323. begin
  324. if quote then
  325. begin
  326. write(t,'''');
  327. quote:=false;
  328. end;
  329. if slen>0 then
  330. writeln(t,'+')
  331. else
  332. writeln(t);
  333. len:=0;
  334. start:=false;
  335. end;
  336. if (len=0) then
  337. write(t,' ');
  338. if (ord(p^)>=32) and (p^<>#39) then
  339. begin
  340. if not quote then
  341. begin
  342. write(t,'''');
  343. quote:=true;
  344. inc(len);
  345. end;
  346. write(t,p^);
  347. inc(len);
  348. end
  349. else
  350. begin
  351. if quote then
  352. begin
  353. write(t,'''');
  354. inc(len);
  355. quote:=false;
  356. end;
  357. write(t,'#'+chr(ord(p^) div 100+48)+chr((ord(p^) mod 100) div 10+48)+chr(ord(p^) mod 10+48));
  358. inc(len,3);
  359. end;
  360. if p^ in [#0,#10] then
  361. start:=true;
  362. inc(slen);
  363. inc(p);
  364. end;
  365. if quote then
  366. write(t,'''');
  367. writeln(t,'');
  368. writeln(t,');');
  369. close(t);
  370. {update arraysize}
  371. s:=l0(msgsize div maxslen); { we start with 0 }
  372. assign(f,fn);
  373. reset(f,1);
  374. seek(f,34+eollen+length(constname));
  375. blockwrite(f,s[1],5);
  376. seek(f,90+3*eollen+2*length(constname));
  377. blockwrite(f,s[1],5);
  378. close(f);
  379. end;
  380. {*****************************************************************************
  381. WriteCharFile
  382. *****************************************************************************}
  383. procedure WriteCharFile(const fn,constname:string);
  384. function l0(l:longint):string;
  385. var
  386. s : string[16];
  387. begin
  388. str(l,s);
  389. while (length(s)<5) do
  390. s:='0'+s;
  391. l0:=s;
  392. end;
  393. function createconst(b:byte):string;
  394. begin
  395. if (b in [32..127]) and (b<>39) then
  396. createconst:=''''+chr(b)+''''
  397. else
  398. createconst:='#'+chr(b div 100+48)+chr((b mod 100) div 10+48)+chr(b mod 10+48)
  399. end;
  400. var
  401. t : text;
  402. f : file;
  403. cidx,i : longint;
  404. p : pchar;
  405. s : string;
  406. begin
  407. writeln('Writing charfile '+fn);
  408. {Open textfile}
  409. assign(t,fn);
  410. rewrite(t);
  411. writeln(t,'const ',constname,' : array[1..00000] of char=(');
  412. {Parse buffer in msgbuf and create indexs}
  413. p:=msgtxt;
  414. cidx:=0;
  415. for i:=1to msgsize do
  416. begin
  417. if cidx=15 then
  418. begin
  419. if cidx>0 then
  420. writeln(t,',')
  421. else
  422. writeln(t,'');
  423. write(t,' ');
  424. cidx:=0;
  425. end
  426. else
  427. if cidx>0 then
  428. write(t,',')
  429. else
  430. write(t,' ');
  431. write(t,createconst(ord(p^)));
  432. inc(cidx);
  433. inc(p);
  434. end;
  435. writeln(t,');');
  436. close(t);
  437. {update arraysize}
  438. s:=l0(msgsize);
  439. assign(f,fn);
  440. reset(f,1);
  441. seek(f,18+length(constname));
  442. blockwrite(f,s[1],5);
  443. close(f);
  444. end;
  445. {*****************************************************************************
  446. WriteIntelFile
  447. *****************************************************************************}
  448. procedure WriteIntelFile(const fn,constname:string);
  449. var
  450. t : text;
  451. len,i : longint;
  452. p : pchar;
  453. start,
  454. quote : boolean;
  455. begin
  456. writeln('Writing Intelfile ',fn);
  457. {Open textfile}
  458. assign(t,fn);
  459. rewrite(t);
  460. writeln(t,'procedure '+constname+';assembler;');
  461. writeln(t,'asm');
  462. {Parse buffer in msgbuf and create indexs}
  463. p:=msgtxt;
  464. len:=0;
  465. start:=true;
  466. quote:=false;
  467. for i:=1to msgsize do
  468. begin
  469. if len>70 then
  470. begin
  471. if quote then
  472. begin
  473. write(t,'''');
  474. quote:=false;
  475. end;
  476. writeln(t,'');
  477. start:=true;
  478. end;
  479. if start then
  480. begin
  481. write(t,' db ''');
  482. len:=0;
  483. quote:=true;
  484. end;
  485. if (ord(p^)>=32) and (p^<>#39) then
  486. begin
  487. if not quote then
  488. begin
  489. write(t,',''');
  490. quote:=true;
  491. inc(len);
  492. end;
  493. write(t,p^);
  494. inc(len);
  495. end
  496. else
  497. begin
  498. if quote then
  499. begin
  500. write(t,'''');
  501. inc(len);
  502. quote:=false;
  503. end;
  504. write(t,','+chr(ord(p^) div 100+48)+chr((ord(p^) mod 100) div 10+48)+chr(ord(p^) mod 10+48));
  505. inc(len,4);
  506. end;
  507. inc(p);
  508. end;
  509. if quote then
  510. write(t,'''');
  511. writeln(t,'');
  512. writeln(t,'end;');
  513. close(t);
  514. end;
  515. {*****************************************************************************
  516. RenumberFile
  517. *****************************************************************************}
  518. procedure RenumberFile(const fn,name:string);
  519. var
  520. f,t : text;
  521. i : longint;
  522. s,s1 : string;
  523. begin
  524. Writeln('Renumbering ',fn);
  525. {Read the message file}
  526. assign(f,fn);
  527. {$I-}
  528. reset(f);
  529. {$I+}
  530. if ioresult<>0 then
  531. begin
  532. WriteLn('*** message file '+fn+' not found ***');
  533. exit;
  534. end;
  535. assign(t,'msg2inc.$$$');
  536. rewrite(t);
  537. i:=0;
  538. while not eof(f) do
  539. begin
  540. readln(f,s);
  541. if (copy(s,1,length(Name))=Name) and (s[3] in ['0'..'9']) then
  542. begin
  543. inc(i);
  544. str(i,s1);
  545. while length(s1)<3 do
  546. s1:='0'+s1;
  547. writeln(t,Name+s1+Copy(s,6,255));
  548. end
  549. else
  550. writeln(t,s);
  551. end;
  552. close(t);
  553. close(f);
  554. { rename new file }
  555. erase(f);
  556. rename(t,fn);
  557. end;
  558. {*****************************************************************************
  559. WriteTexFile
  560. *****************************************************************************}
  561. Function EscapeString (Const S : String) : String;
  562. Var
  563. I : longint;
  564. hs : string;
  565. begin
  566. hs:='';
  567. for i:=1 to length(s) do
  568. if (S[i]='$') then
  569. begin
  570. if (s[i+1] in ['0'..'9']) then
  571. hs:=hs+'arg'
  572. else
  573. hs:=hs+'\$';
  574. end
  575. else
  576. hs:=hs+s[i];
  577. EscapeString:=hs;
  578. end;
  579. procedure WriteTexFile(const infn,outfn:string);
  580. var
  581. t,f : text;
  582. line,
  583. i,k : longint;
  584. s,s1 : string;
  585. texoutput : boolean;
  586. begin
  587. Writeln('Loading messagefile ',infn);
  588. writeln('Writing TeXfile ',outfn);
  589. { Open infile }
  590. assign(f,infn);
  591. {$I-}
  592. reset(f);
  593. {$I+}
  594. if ioresult<>0 then
  595. begin
  596. WriteLn('*** message file '+infn+' not found ***');
  597. exit;
  598. end;
  599. { Open outfile }
  600. assign(t,outfn);
  601. rewrite(t);
  602. If texheader then
  603. begin
  604. writeln (t,'\documentclass{article}');
  605. writeln (t,'\usepackage{html}');
  606. writeln (t,'\usepackage{fpc}');
  607. writeln (t,'\begin{document}');
  608. end;
  609. { Parse }
  610. line:=0;
  611. TexOutput:=False;
  612. while not eof(f) do
  613. begin
  614. readln(f,s);
  615. inc(line);
  616. If Pos ('# BeginOfTeX',S)=1 then
  617. TexOutPut:=True
  618. else if pos ('# EndOfTeX',S)=1 then
  619. TexOutPut:=False;
  620. if (s<>'') and not(s[1] in ['#',';']) and TeXOutPut then
  621. begin
  622. if s[1]='%' then
  623. begin
  624. Delete(s,1,1);
  625. writeln(t,s);
  626. end
  627. else
  628. begin
  629. i:=pos('=',s);
  630. if i>0 then
  631. begin
  632. inc(i);
  633. while s[i] in ['0'..'9'] do
  634. inc(i);
  635. inc(i);
  636. s1:='';
  637. k:=0;
  638. while (k<5) and (s[i+k]<>'_') do
  639. begin
  640. case s[i+k] of
  641. 'W' : s1:='Warning: ';
  642. 'E' : s1:='Error: ';
  643. 'F' : s1:='Fatal: ';
  644. 'N' : s1:='Note: ';
  645. 'I' : s1:='Info: ';
  646. 'H' : s1:='Hint: ';
  647. end;
  648. inc(k);
  649. end;
  650. if s[i+k]='_' then
  651. inc(i,k+1);
  652. writeln(t,'\item ['+s1+escapestring(Copy(s,i,255))+']');
  653. end
  654. else
  655. writeln('error in line: ',line,' skipping');
  656. end;
  657. end;
  658. end;
  659. If TexHeader then
  660. writeln (t,'\end{document}');
  661. close(t);
  662. close(f);
  663. end;
  664. {*****************************************************************************
  665. Main Program
  666. *****************************************************************************}
  667. procedure getpara;
  668. var
  669. ch : char;
  670. para : string;
  671. files,i : word;
  672. procedure helpscreen;
  673. begin
  674. writeln('usage : msg2inc [Options] <msgfile> <incfile> <constname>');
  675. writeln('<Options> can be : -T Create .doc TeX file');
  676. writeln(' -TS Create .doc TeX file (stand-alone)');
  677. writeln(' -I Intel style asm output');
  678. writeln(' -S array of string');
  679. writeln(' -C array of char');
  680. writeln(' -R renumber section <incfile>');
  681. writeln(' -V Show version');
  682. writeln(' -? or -H This HelpScreen');
  683. halt(1);
  684. end;
  685. begin
  686. Mode:=M_String;
  687. FIles:=0;
  688. for i:=1to paramcount do
  689. begin
  690. para:=paramstr(i);
  691. if (para[1]='-') then
  692. begin
  693. ch:=upcase(para[2]);
  694. delete(para,1,2);
  695. case ch of
  696. 'T' : begin
  697. case upcase(para[1]) of
  698. 'S' : TexHeader:=True;
  699. end;
  700. Mode:=M_Tex;
  701. end;
  702. 'I' : Mode:=M_Intel;
  703. 'S' : Mode:=M_String;
  704. 'C' : Mode:=M_Char;
  705. 'R' : Mode:=M_Renumber;
  706. 'V' : begin
  707. Writeln('Msg2Inc ',version,' for Free Pascal (C) 1998-2000 Peter Vreman');
  708. Writeln;
  709. Halt;
  710. end;
  711. '?','H' : helpscreen;
  712. end;
  713. end
  714. else
  715. begin
  716. inc(Files);
  717. if Files>3 then
  718. HelpScreen;
  719. case Files of
  720. 1 : InFile:=Para;
  721. 2 : OutFile:=Para;
  722. 3 : OutName:=Para;
  723. end;
  724. end;
  725. end;
  726. case Mode of
  727. M_Renumber,
  728. M_Tex : if Files<2 then
  729. Helpscreen;
  730. else
  731. if FIles<3 then
  732. HelpScreen;
  733. end;
  734. end;
  735. begin
  736. GetPara;
  737. case Mode of
  738. M_Renumber : begin
  739. Renumberfile(Infile,OutFile);
  740. end;
  741. M_Tex : begin
  742. if pos('.tex',outfile)=0 then
  743. Outfile:=OutFile+'.tex';
  744. WriteTexFile(InFile,Outfile);
  745. end;
  746. M_Intel : begin
  747. Loadmsgfile(InFile);
  748. WriteEnumFile(OutFile+'idx.inc',OutName+'const');
  749. WriteIntelFile(OutFile+'txt.inc',OutName+'txt');
  750. end;
  751. M_String : begin
  752. Loadmsgfile(InFile);
  753. WriteEnumFile(OutFile+'idx.inc',OutName+'const');
  754. WriteStringFile(OutFile+'txt.inc',OutName+'txt');
  755. end;
  756. M_Char : begin
  757. Loadmsgfile(InFile);
  758. WriteEnumFile(OutFile+'idx.inc',OutName+'const');
  759. WriteCharFile(OutFile+'txt.inc',OutName+'txt');
  760. end;
  761. end;
  762. end.
  763. {
  764. $Log$
  765. Revision 1.4 2000-09-28 11:57:03 jonas
  766. * fixed range errors (merged from fixes branch)
  767. Revision 1.3 2000/09/27 20:59:55 peter
  768. * check for dup numbers
  769. Revision 1.2 2000/07/13 11:32:55 michael
  770. + removed logs
  771. }