fprcp.pp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  1. program FreePasResourcePreprocessor;
  2. {$ifdef win32}
  3. {$APPTYPE CONSOLE}
  4. {$endif}
  5. {$ifndef fpc}{$N+}{$endif}
  6. uses
  7. Comments,PasPrep,Expr,Classes
  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. sValue1, sValue2: String;
  60. size,nextpos:longint;
  61. buf:pchars;
  62. i:longint;
  63. AConstList: TStringList;
  64. function Entry(buf:pchars;Size,fromPos:longint;const sample:str255;casesent:longbool):longbool;
  65. var
  66. i:longint;
  67. c:char;
  68. begin
  69. Entry:=false;
  70. if(fromPos>1)and(buf^[pred(frompos)]>#32)then
  71. exit;
  72. if fromPos+length(sample)-1>=size then
  73. exit;
  74. if buf^[fromPos+length(sample)]>#32 then
  75. exit;
  76. Entry:=true;
  77. for i:=1 to length(sample)do
  78. begin
  79. if pred(fromPos+i)>size then
  80. begin
  81. Entry:=false;
  82. exit;
  83. end;
  84. c:=buf^[pred(fromPos+i)];
  85. if not casesent then
  86. c:=UpCase(c);
  87. if c<>sample[i]then
  88. begin
  89. Entry:=false;
  90. exit;
  91. end;
  92. end;
  93. end;
  94. function GetWord(buf:pchars;Size,fromPos:longint;var EndPos:longint):str255;
  95. var
  96. s:str255;
  97. i:longint;
  98. word_begin:longbool;
  99. begin
  100. s:='';
  101. i:=frompos;
  102. word_begin:=false;
  103. while i<size do
  104. begin
  105. if not word_begin then
  106. word_begin:=(buf^[i]>#32)and(buf^[i]<>';')and(buf^[i]<>'=');
  107. if word_begin then
  108. begin
  109. if not(buf^[i]in[#0..#32,';','='])then
  110. s:=s+buf^[i]
  111. else
  112. begin
  113. EndPos:=i;
  114. break;
  115. end;
  116. end;
  117. inc(i);
  118. end;
  119. GetWord:=s;
  120. end;
  121. procedure excludeComments(buf:pchars;size:longint);
  122. var
  123. comment:longbool;
  124. i:longint;
  125. begin
  126. comment:=false;
  127. for i:=1 to pred(size)do
  128. begin
  129. if(buf^[i]='/')and(buf^[succ(i)]='*')then
  130. comment:=true;
  131. if comment then
  132. begin
  133. if(buf^[i]='*')and(buf^[succ(i)]='/')then
  134. begin
  135. comment:=false;
  136. buf^[succ(i)]:=' ';
  137. end;
  138. buf^[i]:=' ';
  139. end;
  140. end;
  141. comment:=false;
  142. for i:=1 to pred(size)do
  143. begin
  144. if(buf^[i]='/')and(buf^[succ(i)]='/')then
  145. comment:=true;
  146. if comment then
  147. begin
  148. if buf^[i]in[#10,#13]then
  149. comment:=false;
  150. buf^[i]:=' ';
  151. end;
  152. end;
  153. end;
  154. function IsSwitch(const switch:str255):longbool;
  155. var
  156. i:longint;
  157. begin
  158. IsSwitch:=false;
  159. for i:=1 to ParamCount do
  160. if paramstr(i)='-'+switch then
  161. begin
  162. IsSwitch:=true;
  163. exit;
  164. end;
  165. end;
  166. function GetSwitch(const switch:str255):str255;
  167. var
  168. i:longint;
  169. begin
  170. GetSwitch:='';
  171. for i:=1 to paramcount do
  172. if paramstr(i)='-'+switch then
  173. GetSwitch:=paramstr(succ(i));
  174. end;
  175. type
  176. Tlanguage=(L_C,L_Pascal);
  177. function Language(s:str255):tLanguage;
  178. var
  179. s1,Lstr:str255;
  180. i,j:longint;
  181. found:longbool;
  182. type
  183. TLD=record
  184. x:string[3];
  185. l:tLanguage;
  186. end;
  187. const
  188. default:array[1..7]of TLD=(
  189. (x:'PAS';l:L_PASCAL),
  190. (x:'PP';l:L_PASCAL),
  191. (x:'P';l:L_PASCAL),
  192. (x:'DPR';l:L_PASCAL),
  193. (x:'IN?';l:L_PASCAL),
  194. (x:'C';l:L_C),
  195. (x:'H';l:L_C));
  196. begin
  197. Lstr:=GetSwitch('l');
  198. if lstr=''then
  199. Lstr:=GetSwitch('-language');
  200. for i:=1 to length(Lstr)do
  201. Lstr[i]:=UpCase(Lstr[i]);
  202. if Lstr='C'then
  203. begin
  204. Language:=L_C;
  205. exit;
  206. end
  207. else if(Lstr='PASCAL')or(Lstr='DELPHI')then
  208. begin
  209. Language:=L_PASCAL;
  210. exit;
  211. end
  212. else if (Lstr<>'')then
  213. writeln('Warning: unknown language ',Lstr);
  214. s1:='';
  215. for i:=length(s)downto 1 do
  216. begin
  217. if s[i]='.'then
  218. break;
  219. s1:=upcase(s[i])+s1;
  220. end;
  221. for i:=1 to 7 do
  222. begin
  223. found:=true;
  224. for j:=1 to length(s1)do
  225. if s1[j]<>default[i].x[j]then
  226. case default[i].x[j] of
  227. '?':
  228. ;
  229. else
  230. found:=false;
  231. end;
  232. if(found)and(s1<>'')then
  233. begin
  234. Language:=default[i].l;
  235. exit;
  236. end;
  237. end;
  238. Language:=L_PASCAL;
  239. end;
  240. function Up(const s:str255):str255;
  241. var
  242. n:str255;
  243. i:longint;
  244. begin
  245. n:=s;
  246. for i:=1 to length(s)do
  247. n[i]:=upcase(s[i]);
  248. Up:=n;
  249. end;
  250. procedure saveproc(const key,value:str255;CaseSent:longbool);{$ifndef fpc}far;{$endif}
  251. begin
  252. AConstList.Values[Up(key)]:=Up(Value);
  253. end;
  254. procedure do_C(buf:pchars;size:longint;proc:pointer);
  255. type
  256. Tpushfunc=procedure(const key,value:str255;CaseSent:longBool);
  257. var
  258. position:longint;
  259. charconst,stringconst:longbool;
  260. s,s0:str255;
  261. afunc:Tpushfunc absolute proc;
  262. procedure read(var s:str255;toEOL:longbool);
  263. var
  264. i:longint absolute position;
  265. function EndOfWord:longbool;
  266. begin
  267. if toEOL then
  268. EndOfWord:=buf^[i]in[#10,#13]
  269. else
  270. EndOfWord:=buf^[i]<=#32;
  271. end;
  272. begin
  273. s:='';
  274. if i>size then
  275. exit;
  276. while buf^[i]<=#32 do
  277. begin
  278. if i>size then
  279. exit;
  280. inc(i);
  281. end;
  282. repeat
  283. if i>size then
  284. exit;
  285. if not stringConst then
  286. if buf^[i]=''''then
  287. charconst:=not charconst;
  288. if not charConst then
  289. if buf^[i]='"'then
  290. stringconst:=not stringconst;
  291. if(not charconst)and(not stringconst)and EndOfWord then
  292. exit;
  293. if buf^[i]>#32 then
  294. s:=s+buf^[i];
  295. inc(i);
  296. until false;
  297. end;
  298. begin
  299. ExcludeComments(buf,size);
  300. position:=1;
  301. charconst:=false;
  302. stringconst:=false;
  303. repeat
  304. read(s,false);
  305. if Up(s)='#DEFINE' then
  306. begin
  307. read(s,false);
  308. read(s0,true);
  309. Tpushfunc(afunc)(s,s0,true);
  310. end;
  311. until position>=size;
  312. end;
  313. procedure expandname(var s:str255;path:str255);
  314. var
  315. astr:str255;
  316. begin
  317. astr:=fsearch(s,path);
  318. if astr<>''then
  319. s:={$ifndef Win32}FExpand{$endif}(astr);
  320. end;
  321. function do_include(name:str255):longbool;
  322. var
  323. bufinclude:pchars;
  324. finclude:file;
  325. sizeinclude:longint;
  326. s1:str255;
  327. procedure trim;
  328. begin
  329. delete(name,1,1);
  330. dec(name[0]);
  331. end;
  332. begin
  333. if (name[1]='"')and(name[length(name)]='"')then
  334. trim
  335. else if (name[1]='<')and(name[length(name)]='>')then
  336. begin
  337. trim;
  338. s1:=GetSwitch('p');
  339. if s1=''then
  340. s1:=GetSwitch('-path');
  341. expandname(name,s1);
  342. end;
  343. assign(finclude,name);
  344. reset(finclude,1);
  345. sizeinclude:=filesize(finclude);
  346. GetMem(bufinclude,sizeinclude);
  347. blockread(finclude,bufinclude^,sizeinclude);
  348. close(finclude);
  349. case Language(name)of
  350. L_C:
  351. do_C(bufinclude,sizeinclude,@saveProc);
  352. L_PASCAL:
  353. do_pascal(bufinclude,sizeinclude,@saveProc);
  354. end;
  355. FreeMem(bufinclude,sizeinclude);
  356. do_include:=true;
  357. end;
  358. function CheckRight(const s:str255;pos:longint):longbool;
  359. begin
  360. CheckRight:=true;
  361. if pos>length(s)then
  362. CheckRight:=false
  363. else
  364. CheckRight:=not(s[succ(pos)]in['a'..'z','A'..'Z','0'..'9','_']);
  365. end;
  366. function CheckLeft(const s:str255;pos:longint):longbool;
  367. begin
  368. CheckLeft:=true;
  369. if pos>1 then
  370. begin
  371. if pos>length(s)then
  372. CheckLeft:=false
  373. else
  374. CheckLeft:=not(s[pred(pos)]in['a'..'z','A'..'Z','0'..'9','_']);
  375. end;
  376. end;
  377. function Evaluate(Equation:String):String;
  378. var
  379. x:double;
  380. Err:integer;
  381. begin
  382. Eval(Equation,x,Err);
  383. if(Err=0)and(frac(x)=0)then
  384. str(x:1:0,Equation)
  385. else
  386. Equation:='';
  387. Evaluate:=Equation;
  388. end;
  389. type
  390. taccel=array[1..100]of pReplaceRec;
  391. var
  392. accel:^taccel;
  393. c:pReplaceRec;
  394. j,kk:longint;
  395. sss,sst:str255;
  396. bNoMore:Boolean;
  397. begin
  398. if(paramcount=0)or isSwitch('h')or isSwitch('-help')or((paramcount>1)and(GetSwitch('i')=''))then
  399. begin
  400. writeln('FPC CONSTANTS EXTRACTOR for resource scripts preprocessing');
  401. writeln('version 0.01');
  402. writeln('Usage: fprcp <file_name>');
  403. writeln('or:');
  404. writeln('fprcp -i <file_name> [-n] [-C] [-l PASCAL|C] [-p <include_path>]');
  405. writeln(' -C type C header instead preprocessed resource script');
  406. writeln(' -l set programming language for include files');
  407. writeln(' -p set path to include files');
  408. writeln(' -n disable support of pascal comments nesting');
  409. halt;
  410. end;
  411. if ParamCount=1 then
  412. assign(f,paramstr(1))
  413. else
  414. assign(f,GetSwitch('i'));
  415. reset(f,1);
  416. size:=filesize(f);
  417. getmem(buf,size);
  418. blockread(f,buf^,size);
  419. close(f);
  420. if isSwitch('n')then
  421. PasNesting:=false;
  422. if isSwitch('-disable-nested-pascal-comments')then
  423. PasNesting:=false;
  424. excludeComments(buf,size);
  425. AConstList:=TStringList.Create;
  426. //try
  427. AConstList.BeginUpdate;
  428. //try
  429. //include file
  430. for i:=1 to size do
  431. begin
  432. if entry(buf,size,i,'#include',true)then
  433. do_include(GetWord(buf,size,i+length('#include'),nextpos));
  434. end;
  435. //finally
  436. AConstList.EndUpdate; //end;
  437. //replace const-value if needed and evaluate
  438. For i:=0 to (AConstList.Count-1) do begin
  439. sValue1:=AConstList.ValueFromIndex[i];
  440. repeat
  441. sValue2:=AConstList.Values[sValue1];
  442. bNoMore:=Length(sValue2)=0;
  443. if (not bNoMore) then sValue1:=sValue2;
  444. until bNoMore;
  445. sValue2:=Evaluate(sValue1);
  446. if Length(sValue2)>0
  447. then AConstList.ValueFromIndex[i]:=Evaluate(sValue1);
  448. end;
  449. if isSwitch('C')or isSwitch('-Cheader')then begin
  450. for i:=0 to AConstList.Count-1
  451. do writeln('#define ',AConstList.Names[i],' ',AConstList.ValueFromIndex[i]);
  452. end else begin
  453. sss:='';
  454. i:=1;
  455. while i<=size do
  456. begin
  457. if buf^[i]<>#10 then
  458. sss:=sss+buf^[i]
  459. else
  460. begin
  461. while(sss<>'')and(sss[1]<=#32)do
  462. delete(sss,1,1);
  463. sst:=sss;
  464. for j:=1 to length(sst)do sst[j]:=upcase(sst[j]);
  465. if pos('#INCLUDE',sst)=0 then
  466. begin
  467. s:='';
  468. for kk:=1 to length(sss)do
  469. begin
  470. if sss[kk]>#32 then
  471. s:=s+sss[kk]
  472. else if s<>'' then
  473. begin
  474. sValue1:=AConstList.Values[Up(s)];
  475. if Length(sValue1)>0
  476. then write(sValue1,' ')
  477. else write(s,' ');
  478. s:='';
  479. end;
  480. end;
  481. writeln;
  482. sss:='';
  483. end
  484. else
  485. sss:='';
  486. end;
  487. inc(i);
  488. end;
  489. end;
  490. freemem(buf,size);
  491. //finally
  492. AConstList.Free; //end;
  493. end.