msg2inc.pp 18 KB

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