msg2inc.pp 18 KB

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