fprcp.pp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572
  1. program FreePasResourcePreprocessor;
  2. {$ifdef win32}
  3. {$APPTYPE CONSOLE}
  4. {$endif}
  5. {$N+}
  6. uses
  7. Comments,PasPrep,Expr
  8. {$ifndef win32}
  9. ,DOS;
  10. type
  11. str255=string[255];
  12. {$else}
  13. ;
  14. type
  15. str255=string[255];
  16. function SearchPath(path,name,ext:pchar;size:longint;buf:pchar;var x:pointer):longint;stdcall;
  17. external 'kernel32.dll' name 'SearchPathA';
  18. function FSearch(s,path:str255):Str255;
  19. var
  20. l:longint;
  21. procedure zeroterm(var s:str255);
  22. begin
  23. l:=length(s);
  24. move(s[1],s[0],l);
  25. s[l]:=#0;
  26. end;
  27. var
  28. buf:str255;
  29. aPtr:pointer;
  30. i:longint;
  31. begin
  32. zeroterm(path);
  33. zeroterm(s);
  34. i:=SearchPath(pchar(@path),pchar(@s),nil,255,pchar(@buf[1]),aPtr);
  35. if i<=255 then
  36. byte(buf[0]):=i
  37. else
  38. buf[0]:=#0;
  39. FSearch:=buf;
  40. end;
  41. {$endif}
  42. type
  43. pstring=^str255;
  44. PReplaceRec=^TReplaceRec;
  45. TReplaceRec=record
  46. next:PReplaceRec;
  47. CaseSentitive:longbool;
  48. oldvalue,newvalue:pstring;
  49. end;
  50. chars=array[1..2]of char;
  51. pchars=^chars;
  52. const
  53. Chain:PReplaceRec=nil;
  54. ChainHdr:PReplaceRec=nil;
  55. Chainlen:longint=0;
  56. var
  57. f:file;
  58. s:str255;
  59. size,nextpos:longint;
  60. buf:pchars;
  61. i:longint;
  62. function Entry(buf:pchars;Size,fromPos:longint;const sample:str255;casesent:longbool):longbool;
  63. var
  64. i:longint;
  65. c:char;
  66. begin
  67. Entry:=false;
  68. if(fromPos>1)and(buf^[pred(frompos)]>#32)then
  69. exit;
  70. if fromPos+length(sample)-1>=size then
  71. exit;
  72. if buf^[fromPos+length(sample)]>#32 then
  73. exit;
  74. Entry:=true;
  75. for i:=1 to length(sample)do
  76. begin
  77. if pred(fromPos+i)>size then
  78. begin
  79. Entry:=false;
  80. exit;
  81. end;
  82. c:=buf^[pred(fromPos+i)];
  83. if not casesent then
  84. c:=UpCase(c);
  85. if c<>sample[i]then
  86. begin
  87. Entry:=false;
  88. exit;
  89. end;
  90. end;
  91. end;
  92. function GetWord(buf:pchars;Size,fromPos:longint;var EndPos:longint):str255;
  93. var
  94. s:str255;
  95. i:longint;
  96. word_begin:longbool;
  97. begin
  98. s:='';
  99. i:=frompos;
  100. word_begin:=false;
  101. while i<size do
  102. begin
  103. if not word_begin then
  104. word_begin:=(buf^[i]>#32)and(buf^[i]<>';')and(buf^[i]<>'=');
  105. if word_begin then
  106. begin
  107. if not(buf^[i]in[#0..#32,';','='])then
  108. s:=s+buf^[i]
  109. else
  110. begin
  111. EndPos:=i;
  112. break;
  113. end;
  114. end;
  115. inc(i);
  116. end;
  117. GetWord:=s;
  118. end;
  119. procedure excludeComments(buf:pchars;size:longint);
  120. var
  121. comment:longbool;
  122. i:longint;
  123. begin
  124. comment:=false;
  125. for i:=1 to pred(size)do
  126. begin
  127. if(buf^[i]='/')and(buf^[succ(i)]='*')then
  128. comment:=true;
  129. if comment then
  130. begin
  131. if(buf^[i]='*')and(buf^[succ(i)]='/')then
  132. begin
  133. comment:=false;
  134. buf^[succ(i)]:=' ';
  135. end;
  136. buf^[i]:=' ';
  137. end;
  138. end;
  139. comment:=false;
  140. for i:=1 to pred(size)do
  141. begin
  142. if(buf^[i]='/')and(buf^[succ(i)]='/')then
  143. comment:=true;
  144. if comment then
  145. begin
  146. if buf^[i]in[#10,#13]then
  147. comment:=false;
  148. buf^[i]:=' ';
  149. end;
  150. end;
  151. end;
  152. function IsSwitch(const switch:str255):longbool;
  153. var
  154. i:longint;
  155. begin
  156. IsSwitch:=false;
  157. for i:=1 to ParamCount do
  158. if paramstr(i)='-'+switch then
  159. begin
  160. IsSwitch:=true;
  161. exit;
  162. end;
  163. end;
  164. function GetSwitch(const switch:str255):str255;
  165. var
  166. i:longint;
  167. begin
  168. GetSwitch:='';
  169. for i:=1 to paramcount do
  170. if paramstr(i)='-'+switch then
  171. GetSwitch:=paramstr(succ(i));
  172. end;
  173. procedure saveproc(const key,value:str255;CaseSent:longbool);far;
  174. var
  175. c:pReplaceRec;
  176. begin
  177. new(c);
  178. c^.next:=nil;
  179. c^.CaseSentitive:=CaseSent;
  180. getmem(c^.oldvalue,succ(length(key)));
  181. c^.oldvalue^:=key;
  182. getmem(c^.newvalue,succ(length(value)));
  183. c^.newvalue^:=value;
  184. if chainhdr=nil then
  185. begin
  186. chain:=c;
  187. chainhdr:=chain;
  188. ChainLen:=1;
  189. end
  190. else
  191. begin
  192. chain^.next:=c;
  193. chain:=c;
  194. inc(ChainLen);
  195. end;
  196. end;
  197. type
  198. Tlanguage=(L_C,L_Pascal);
  199. function Language(s:str255):tLanguage;
  200. var
  201. s1,Lstr:str255;
  202. i,j:longint;
  203. found:longbool;
  204. type
  205. TLD=record
  206. x:string[3];
  207. l:tLanguage;
  208. end;
  209. const
  210. default:array[1..7]of TLD=(
  211. (x:'PAS';l:L_PASCAL),
  212. (x:'PP';l:L_PASCAL),
  213. (x:'P';l:L_PASCAL),
  214. (x:'DPR';l:L_PASCAL),
  215. (x:'IN?';l:L_PASCAL),
  216. (x:'C';l:L_C),
  217. (x:'H';l:L_C));
  218. begin
  219. Lstr:=GetSwitch('l');
  220. if lstr=''then
  221. Lstr:=GetSwitch('-language');
  222. for i:=1 to length(Lstr)do
  223. Lstr[i]:=UpCase(Lstr[i]);
  224. if Lstr='C'then
  225. begin
  226. Language:=L_C;
  227. exit;
  228. end
  229. else if(Lstr='PASCAL')or(Lstr='DELPHI')then
  230. begin
  231. Language:=L_PASCAL;
  232. exit;
  233. end
  234. else if (Lstr<>'')then
  235. writeln('Warning: unknown language ',Lstr);
  236. s1:='';
  237. for i:=length(s)downto 1 do
  238. begin
  239. if s[i]='.'then
  240. break;
  241. s1:=upcase(s[i])+s1;
  242. end;
  243. for i:=1 to 7 do
  244. begin
  245. found:=true;
  246. for j:=1 to length(s1)do
  247. if s1[j]<>default[i].x[j]then
  248. case default[i].x[j] of
  249. '?':
  250. ;
  251. else
  252. found:=false;
  253. end;
  254. if(found)and(s1<>'')then
  255. begin
  256. Language:=default[i].l;
  257. exit;
  258. end;
  259. end;
  260. Language:=L_PASCAL;
  261. end;
  262. function Up(const s:str255):str255;
  263. var
  264. n:str255;
  265. i:longint;
  266. begin
  267. n:=s;
  268. for i:=1 to length(s)do
  269. n[i]:=upcase(s[i]);
  270. Up:=n;
  271. end;
  272. procedure do_C(buf:pchars;size:longint;proc:pointer);
  273. type
  274. Tpushfunc=procedure(const key,value:str255;CaseSent:longBool);
  275. var
  276. position:longint;
  277. charconst,stringconst:longbool;
  278. s,s0:str255;
  279. afunc:Tpushfunc absolute proc;
  280. procedure read(var s:str255;toEOL:longbool);
  281. var
  282. i:longint absolute position;
  283. function EndOfWord:longbool;
  284. begin
  285. if toEOL then
  286. EndOfWord:=buf^[i]in[#10,#13]
  287. else
  288. EndOfWord:=buf^[i]<=#32;
  289. end;
  290. begin
  291. s:='';
  292. if i>size then
  293. exit;
  294. while buf^[i]<=#32 do
  295. begin
  296. if i>size then
  297. exit;
  298. inc(i);
  299. end;
  300. repeat
  301. if i>size then
  302. exit;
  303. if not stringConst then
  304. if buf^[i]=''''then
  305. charconst:=not charconst;
  306. if not charConst then
  307. if buf^[i]='"'then
  308. stringconst:=not stringconst;
  309. if(not charconst)and(not stringconst)and EndOfWord then
  310. exit;
  311. if buf^[i]>#32 then
  312. s:=s+buf^[i];
  313. inc(i);
  314. until false;
  315. end;
  316. begin
  317. ExcludeComments(buf,size);
  318. position:=1;
  319. charconst:=false;
  320. stringconst:=false;
  321. repeat
  322. read(s,false);
  323. if Up(s)='#DEFINE' then
  324. begin
  325. read(s,false);
  326. read(s0,true);
  327. Tpushfunc(afunc)(s,s0,true);
  328. end;
  329. until position>=size;
  330. end;
  331. procedure expandname(var s:str255;path:str255);
  332. var
  333. astr:str255;
  334. begin
  335. astr:=fsearch(s,path);
  336. if astr<>''then
  337. s:={$ifndef Win32}FExpand{$endif}(astr);
  338. end;
  339. function do_include(name:str255):longbool;
  340. var
  341. buf:pchars;
  342. f:file;
  343. i,size,nextpos:longint;
  344. s1,s2:str255;
  345. done:longbool;
  346. procedure trim;
  347. begin
  348. delete(name,1,1);
  349. dec(name[0]);
  350. end;
  351. begin
  352. if (name[1]='"')and(name[length(name)]='"')then
  353. trim
  354. else if (name[1]='<')and(name[length(name)]='>')then
  355. begin
  356. trim;
  357. s1:=GetSwitch('p');
  358. if s1=''then
  359. s1:=GetSwitch('-path');
  360. expandname(name,s1);
  361. end;
  362. assign(f,name);
  363. reset(f,1);
  364. size:=filesize(f);
  365. GetMem(buf,size);
  366. blockread(f,buf^,size);
  367. close(f);
  368. case Language(name)of
  369. L_C:
  370. do_C(buf,size,@saveProc);
  371. L_PASCAL:
  372. do_pascal(buf,size,@saveProc);
  373. end;
  374. FreeMem(buf,size);
  375. end;
  376. function CheckRight(const s:str255;pos:longint):longbool;
  377. begin
  378. CheckRight:=true;
  379. if pos>length(s)then
  380. CheckRight:=false
  381. else
  382. CheckRight:=not(s[succ(pos)]in['a'..'z','A'..'Z','0'..'9','_']);
  383. end;
  384. function CheckLeft(const s:str255;pos:longint):longbool;
  385. begin
  386. CheckLeft:=true;
  387. if pos>1 then
  388. begin
  389. if pos>length(s)then
  390. CheckLeft:=false
  391. else
  392. CheckLeft:=not(s[pred(pos)]in['a'..'z','A'..'Z','0'..'9','_']);
  393. end;
  394. end;
  395. function Evaluate(Equation:Str255):Str255;
  396. var
  397. x:double;
  398. Err:integer;
  399. begin
  400. Eval(Equation,x,Err);
  401. if(Err=0)and(frac(x)=0)then
  402. str(x:1:0,Equation)
  403. else
  404. Equation:='';
  405. Evaluate:=Equation;
  406. end;
  407. type
  408. taccel=array[1..100]of pReplaceRec;
  409. var
  410. accel:^taccel;
  411. c:pReplaceRec;
  412. j,kk:longint;
  413. sss,sst:str255;
  414. MustBeReplaced,includeStatement,beginline:longbool;
  415. begin
  416. if(paramcount=0)or isSwitch('h')or isSwitch('-help')or((paramcount>1)and(GetSwitch('i')=''))then
  417. begin
  418. writeln('FPC CONSTANTS EXTRACTOR for resource scripts preprocessing');
  419. writeln('version 0.01');
  420. writeln('Usage: fprcp <file_name>');
  421. writeln('or:');
  422. writeln('fprcp -i <file_name> [-n] [-C] [-l PASCAL|C] [-p <include_path>]');
  423. writeln(' -C type C header instead preprocessed resource script');
  424. writeln(' -l set programming language for include files');
  425. writeln(' -p set path to include files');
  426. writeln(' -n disable support of pascal comments nesting');
  427. halt;
  428. end;
  429. if ParamCount=1 then
  430. assign(f,paramstr(1))
  431. else
  432. assign(f,GetSwitch('i'));
  433. reset(f,1);
  434. size:=filesize(f);
  435. getmem(buf,size);
  436. blockread(f,buf^,size);
  437. close(f);
  438. if isSwitch('n')then
  439. PasNesting:=false;
  440. if isSwitch('-disable-nested-pascal-comments')then
  441. PasNesting:=false;
  442. excludeComments(buf,size);
  443. for i:=1 to size do
  444. begin
  445. if entry(buf,size,i,'#include',true)then
  446. do_include(GetWord(buf,size,i+length('#include'),nextpos));
  447. end;
  448. getmem(Accel,sizeof(pReplaceRec)*ChainLen);
  449. c:=ChainHdr;
  450. i:=0;
  451. while c<>nil do
  452. begin
  453. inc(i);
  454. Accel^[i]:=c;
  455. c:=c^.next;
  456. end;
  457. for i:=1 to pred(Chainlen)do
  458. for j:=succ(i)to Chainlen do
  459. if length(Accel^[j]^.newvalue^)>=length(Accel^[i]^.oldvalue^)then
  460. repeat
  461. MustBeReplaced:=false;
  462. for kk:=1 to length(Accel^[j]^.newvalue^)do
  463. begin
  464. sss:=copy(Accel^[j]^.newvalue^,kk,length(Accel^[i]^.oldvalue^));
  465. if length(sss)<>length(Accel^[i]^.oldvalue^)then
  466. break
  467. else if sss=Accel^[i]^.oldvalue^ then
  468. begin
  469. MustBeReplaced:=(CheckLeft(Accel^[j]^.newvalue^,kk)and CheckRight(Accel^[j]^.newvalue^,kk-1+
  470. length(Accel^[i]^.oldvalue^)));
  471. if MustBeReplaced then
  472. break;
  473. end;
  474. end;
  475. if MustBeReplaced then
  476. begin
  477. sss:=Accel^[j]^.newvalue^;
  478. delete(sss,kk,length(Accel^[i]^.oldvalue^));
  479. insert(Accel^[i]^.newvalue^,sss,kk);
  480. freemem(Accel^[j]^.newvalue,length(Accel^[j]^.newvalue^));
  481. getmem(Accel^[j]^.newvalue,length(sss));
  482. Accel^[j]^.newvalue^:=sss;
  483. end;
  484. until not MustBeReplaced;
  485. for j:=1 to Chainlen do
  486. begin
  487. sss:=Evaluate(Accel^[j]^.newvalue^);
  488. freemem(Accel^[j]^.newvalue,length(Accel^[j]^.newvalue^));
  489. getmem(Accel^[j]^.newvalue,length(sss));
  490. Accel^[j]^.newvalue^:=sss;
  491. end;
  492. if isSwitch('C')or isSwitch('-Cheader')then
  493. for i:=1 to Chainlen do
  494. begin
  495. if Accel^[i]^.newvalue^<>''then
  496. writeln('#define ',Accel^[i]^.oldvalue^,' ',Accel^[i]^.newvalue^)
  497. end
  498. else
  499. begin
  500. sss:='';
  501. includeStatement:=false;
  502. beginline:=true;
  503. i:=1;
  504. sss:='';
  505. while i<=size do
  506. begin
  507. if buf^[i]<>#10 then
  508. sss:=sss+buf^[i]
  509. else
  510. begin
  511. while(sss<>'')and(sss[1]<=#32)do
  512. delete(sss,1,1);
  513. sst:=sss;
  514. for j:=1 to length(sst)do
  515. sst[j]:=upcase(sst[j]);
  516. if pos('#INCLUDE',sst)=0 then
  517. begin
  518. s:='';
  519. for kk:=1 to length(sss)do
  520. begin
  521. if sss[kk]>#32 then
  522. s:=s+sss[kk]
  523. else if s<>'' then
  524. begin
  525. for j:=1 to ChainLen do
  526. begin
  527. if accel^[j]^.casesentitive then
  528. begin
  529. if(accel^[j]^.oldvalue^=s)and(accel^[j]^.newvalue^<>'')then
  530. begin
  531. s:=accel^[j]^.newvalue^;
  532. break;
  533. end;
  534. end
  535. else
  536. begin
  537. if(accel^[j]^.oldvalue^=Up(s))and(accel^[j]^.newvalue^<>'')then
  538. begin
  539. s:=accel^[j]^.newvalue^;
  540. break;
  541. end;
  542. end;
  543. end;
  544. write(s,' ');
  545. s:='';
  546. end;
  547. end;
  548. writeln;
  549. sss:='';
  550. end
  551. else
  552. sss:='';
  553. end;
  554. inc(i);
  555. end;
  556. end;
  557. freemem(Accel,sizeof(pReplaceRec)*ChainLen);
  558. Chain:=ChainHdr;
  559. while Chain<>nil do
  560. begin
  561. c:=Chain;
  562. Chain:=Chain^.next;
  563. if c^.oldvalue<>nil then
  564. freemem(c^.oldvalue,succ(length(c^.oldvalue^)));
  565. if c^.newvalue<>nil then
  566. freemem(c^.newvalue,succ(length(c^.newvalue^)));
  567. dispose(c);
  568. end;
  569. freemem(buf,size);
  570. end.