msg2inc.pp 17 KB

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