paramparser.pas 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458
  1. {
  2. FPCRes - Free Pascal Resource Converter
  3. Part of the Free Pascal distribution
  4. Copyright (C) 2008 by Giulio Bernardi
  5. Handles the parsing of parameters
  6. See the file COPYING, 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. unit paramparser;
  13. {$MODE OBJFPC} {$H+}
  14. interface
  15. uses
  16. Classes, SysUtils, target;
  17. type
  18. EParametersException = class(Exception);
  19. EOutputFileAlreadySetException = class(EParametersException);
  20. EUnknownParameterException = class(EParametersException);
  21. EArgumentMissingException = class(EParametersException);
  22. EUnknownObjFormatException = class(EParametersException);
  23. EUnknownMachineException = class(EParametersException);
  24. EUnknownSubMachineException = class(EParametersException);
  25. ECannotReadConfFile = class(EParametersException);
  26. type
  27. { TParameters }
  28. TParameters = class
  29. private
  30. fHelp : boolean;
  31. fVersion : boolean;
  32. fVerbose : boolean;
  33. fInputFiles : TStringList;
  34. fOutputFile : string;
  35. fTarget : TResTarget;
  36. fRCIncludeDirs: TStringList;
  37. fRCDefines: TStringList;
  38. procedure ParseInputFiles(aList : TStringList; var index : integer; const parname : string);
  39. procedure ParseRCInclude(aList: TStringList; var index: integer; const parname: string);
  40. procedure ParseRCUnDefine(aList: TStringList; var index: integer; const parname: string);
  41. procedure ParseOutputFile(aList : TStringList; var index : integer; const parname : string);
  42. procedure ParseOutputFormat(aList : TStringList; var index : integer; const parname : string);virtual;
  43. procedure ParseArchitecture(aList : TStringList; var index : integer; const parname : string);virtual;
  44. procedure ParseSubArchitecture(aList : TStringList; var index : integer; const parname : string);virtual;
  45. procedure ParseConfigFile(aList : TStringList; var index : integer; const parname : string);
  46. function DoOptionalArgument(aList : TStringList; const i : integer) : string;
  47. function DoMandatoryArgument(aList : TStringList; const i : integer) : string;
  48. function IsParameter(const s : string) : boolean;
  49. function ParamsToStrList : TStringList;
  50. protected
  51. public
  52. constructor Create;
  53. destructor Destroy; override;
  54. procedure Parse;
  55. property Help : boolean read fHelp;
  56. property Version : boolean read fVersion;
  57. property Verbose : boolean read fVerbose;
  58. property InputFiles : TStringList read fInputFiles;
  59. property RCIncludeDirs: TStringList read fRCIncludeDirs;
  60. property RCDefines: TStringList read fRCDefines;
  61. property OutputFile : string read fOutputFile write fOutputFile;
  62. property Target : TResTarget read fTarget;
  63. end;
  64. implementation
  65. uses
  66. msghandler;
  67. type
  68. { TConfFileParser }
  69. TConfFileParser = class
  70. private
  71. fConfFile : TStringList;
  72. fParList : TStringList;
  73. fInsPos : integer;
  74. procedure ParseLine(idx : integer);
  75. function GetParameter(pc : pchar; var i : integer) : string;
  76. function GetString(pc : pchar; var i : integer) : string;
  77. protected
  78. public
  79. constructor Create(aFileName : string; aParList : TStringList; aInsPos : integer);
  80. procedure Parse;
  81. destructor Destroy; override;
  82. end;
  83. { TConfFileParser }
  84. procedure TConfFileParser.ParseLine(idx: integer);
  85. var pc : pchar;
  86. tmp : string;
  87. i : integer;
  88. begin
  89. pc:=pchar(fConfFile[idx]);
  90. i:=0;
  91. while pc[i]<>#0 do
  92. begin
  93. case pc[i] of
  94. ' ',#9,#13,#10 : inc(i);
  95. '#' : break
  96. else
  97. begin
  98. tmp:=GetParameter(pc,i);
  99. if tmp<>'' then
  100. begin
  101. fParList.Insert(fInsPos,tmp);
  102. inc(fInsPos);
  103. end;
  104. end;
  105. end;
  106. end;
  107. end;
  108. function TConfFileParser.GetParameter(pc : pchar; var i : integer): string;
  109. begin
  110. Result:='';
  111. while pc[i]<>#0 do
  112. begin
  113. case pc[i] of
  114. ' ',#9,#13,#10 : exit;
  115. '#' : exit;
  116. '"' : Result:=Result+GetString(pc,i);
  117. else
  118. Result:=Result+pc[i];
  119. end;
  120. inc(i);
  121. end;
  122. end;
  123. function TConfFileParser.GetString(pc: pchar; var i: integer): string;
  124. begin
  125. Result:='';
  126. inc(i);
  127. while pc[i]<>#0 do
  128. begin
  129. if pc[i] = '"' then
  130. exit
  131. else
  132. Result:=Result+pc[i];
  133. inc(i);
  134. end;
  135. dec(i);
  136. end;
  137. constructor TConfFileParser.Create(aFileName: string; aParList: TStringList; aInsPos : integer);
  138. begin
  139. fInsPos:=aInsPos+1;
  140. fConfFile:=TStringList.Create;
  141. fParList:=aParList;
  142. try
  143. fConfFile.LoadFromFile(aFileName);
  144. except
  145. raise ECannotReadConfFile.Create(aFileName);
  146. end;
  147. end;
  148. procedure TConfFileParser.Parse;
  149. var i : integer;
  150. begin
  151. for i:=0 to fConfFile.Count-1 do
  152. ParseLine(i);
  153. end;
  154. destructor TConfFileParser.Destroy;
  155. begin
  156. fConfFile.Free;
  157. end;
  158. { TParameters }
  159. //for compatibility allow -i <inputfiles>
  160. procedure TParameters.ParseInputFiles(aList: TStringList; var index: integer;
  161. const parname : string);
  162. var tmp : string;
  163. begin
  164. tmp:=DoMandatoryArgument(aList,index+1);
  165. if tmp='' then
  166. raise EArgumentMissingException.Create(parname);
  167. while tmp<>'' do
  168. begin
  169. inc(index);
  170. fInputFiles.Add(tmp);
  171. tmp:=DoOptionalArgument(aList,index+1);
  172. end;
  173. end;
  174. procedure TParameters.ParseRCInclude(aList: TStringList; var index: integer;
  175. const parname : string);
  176. var
  177. tmp: String;
  178. begin
  179. inc(index);
  180. tmp:=DoMandatoryArgument(aList,index);
  181. if tmp='' then
  182. raise EArgumentMissingException.Create(parname);
  183. fRCIncludeDirs.Add(tmp);
  184. end;
  185. procedure TParameters.ParseRCUnDefine(aList: TStringList; var index: integer;
  186. const parname : string);
  187. var
  188. tmp: String;
  189. i: integer;
  190. begin
  191. inc(index);
  192. tmp:=DoMandatoryArgument(aList,index);
  193. if tmp='' then
  194. raise EArgumentMissingException.Create(parname);
  195. if (parname='-D') or (parname='--define') then begin
  196. i:= pos('=', tmp);
  197. if i<1 then
  198. fRCDefines.Values[tmp]:= ''
  199. else
  200. fRCDefines.Values[Copy(tmp, 1, i-1)]:= Copy(tmp, i+1);
  201. end else begin
  202. i:= fRCDefines.IndexOfName(tmp);
  203. if i >= 0 then
  204. fRCDefines.Delete(i);
  205. end;
  206. fRCIncludeDirs.Add(tmp);
  207. end;
  208. procedure TParameters.ParseOutputFile(aList: TStringList; var index: integer;
  209. const parname : string);
  210. begin
  211. if fOutputFile<>'' then
  212. raise EOutputFileAlreadySetException.Create('');
  213. inc(index);
  214. fOutputFile:=DoMandatoryArgument(aList,index);
  215. if fOutputFile='' then
  216. raise EArgumentMissingException.Create(parname);
  217. end;
  218. procedure TParameters.ParseOutputFormat(aList: TStringList; var index: integer;
  219. const parname: string);
  220. var tmp : string;
  221. aFormat : TObjFormat;
  222. begin
  223. inc(index);
  224. tmp:=DoMandatoryArgument(aList,index);
  225. if tmp='' then
  226. raise EArgumentMissingException.Create(parname);
  227. for aFormat:=low(TObjFormat) to high(TObjFormat) do
  228. begin
  229. if ObjFormats[aFormat].name=tmp then
  230. begin
  231. fTarget.objformat:=aFormat;
  232. exit;
  233. end;
  234. end;
  235. raise EUnknownObjFormatException.Create(tmp);
  236. end;
  237. procedure TParameters.ParseArchitecture(aList: TStringList; var index: integer;
  238. const parname: string);
  239. var tmp : string;
  240. aMachine : TMachineType;
  241. begin
  242. inc(index);
  243. tmp:=DoMandatoryArgument(aList,index);
  244. if tmp='' then
  245. raise EArgumentMissingException.Create(parname);
  246. for aMachine:=low(TMachineType) to high(TMachineType) do
  247. begin
  248. if (Machines[aMachine].name=tmp) or (Machines[aMachine].alias = tmp) then
  249. begin
  250. fTarget.machine:=aMachine;
  251. fTarget.submachine:=GetDefaultSubMachineForMachine(fTarget.machine);
  252. exit;
  253. end;
  254. end;
  255. raise EUnknownMachineException.Create(tmp);
  256. end;
  257. procedure TParameters.ParseSubArchitecture(aList: TStringList; var index: integer; const parname: string);
  258. var tmp : string;
  259. aSubMachineArm : TSubMachineTypeArm;
  260. aSubMachineGeneric : TSubMachineTypeGeneric;
  261. begin
  262. inc(index);
  263. tmp:=DoMandatoryArgument(aList,index);
  264. if tmp='' then
  265. raise EArgumentMissingException.Create(parname);
  266. case fTarget.machine of
  267. mtarm,mtarmeb:
  268. for aSubMachineArm:=low(TSubMachineTypeArm) to high(TSubMachineTypeArm) do
  269. if SubMachinesArm[aSubMachineArm]=tmp then
  270. begin
  271. ftarget.submachine.subarm:=aSubMachineArm;
  272. exit;
  273. end;
  274. else
  275. for aSubMachineGeneric:=low(TSubMachineTypeGeneric) to high(TSubMachineTypeGeneric) do
  276. if SubMachinesGen[aSubMachineGeneric]=tmp then
  277. begin
  278. ftarget.submachine.subgen:=aSubMachineGeneric;
  279. exit;
  280. end;
  281. end;
  282. raise EUnknownSubMachineException.Create(tmp);
  283. end;
  284. procedure TParameters.ParseConfigFile(aList: TStringList; var index: integer;
  285. const parname : string);
  286. var tmp : string;
  287. cp : TConfFileParser;
  288. begin
  289. tmp:=copy(parname,2,length(parname)-1);
  290. if tmp='' then
  291. raise EArgumentMissingException.Create(parname);
  292. cp:=TConfFileParser.Create(tmp,aList,index);
  293. try
  294. cp.Parse;
  295. finally
  296. cp.Free;
  297. end;
  298. end;
  299. function TParameters.DoOptionalArgument(aList: TStringList; const i: integer
  300. ): string;
  301. begin
  302. Result:='';
  303. if aList.Count>i then
  304. begin
  305. if not IsParameter(aList[i]) then
  306. Result:=aList[i];
  307. end;
  308. end;
  309. function TParameters.DoMandatoryArgument(aList: TStringList; const i: integer
  310. ): string;
  311. begin
  312. Result:='';
  313. if aList.count>i then
  314. Result:=aList[i];
  315. end;
  316. function TParameters.IsParameter(const s: string): boolean;
  317. begin
  318. Result:=false;
  319. if length(s)<=1 then exit;
  320. if copy(s,1,1)='-' then Result:=true;
  321. end;
  322. function TParameters.ParamsToStrList: TStringList;
  323. var i : integer;
  324. begin
  325. Result:=TStringList.Create;
  326. try
  327. for i:=1 to ParamCount do
  328. Result.Add(ParamStr(i));
  329. except
  330. Result.Free;
  331. raise;
  332. end;
  333. end;
  334. procedure TParameters.Parse;
  335. var fList : TStringList;
  336. tmp : string;
  337. i : integer;
  338. begin
  339. fList:=ParamsToStrList;
  340. try
  341. i:=0;
  342. while i<fList.Count do
  343. begin
  344. tmp:=fList[i];
  345. Messages.DoVerbose(Format('parsing parameter ''%s''',[tmp]));
  346. if IsParameter(tmp) then
  347. begin
  348. if ((tmp='--help') or (tmp='-h') or (tmp='-?')) then
  349. fHelp:=true
  350. else if ((tmp='--version') or (tmp='-V')) then
  351. fVersion:=true
  352. else if ((tmp='--verbose') or (tmp='-v')) then
  353. fVerbose:=true
  354. else if ((tmp='-i') or (tmp='--input')) then
  355. ParseInputFiles(fList,i,tmp)
  356. else if ((tmp='-I') or (tmp='--include')) then
  357. ParseRCInclude(fList,i,tmp)
  358. else if ((tmp='-D') or (tmp='--define'))
  359. or ((tmp='-U') or (tmp='--undefine')) then
  360. ParseRCUnDefine(fList,i,tmp)
  361. else if ((tmp='-o') or (tmp='--output')) then
  362. ParseOutputFile(fList,i,tmp)
  363. else if (tmp='-of') then
  364. ParseOutputFormat(fList,i,tmp)
  365. else if ((tmp='-a') or (tmp='--arch')) then
  366. ParseArchitecture(fList,i,tmp)
  367. else if ((tmp='-s') or (tmp='--subarch')) then
  368. ParseSubArchitecture(fList,i,tmp)
  369. else
  370. raise EUnknownParameterException.Create(tmp);
  371. end
  372. else
  373. if copy(tmp,1,1)='@' then
  374. ParseConfigFile(fList,i,tmp)
  375. else
  376. fInputFiles.Add(tmp); //assume it is an input file
  377. inc(i);
  378. end;
  379. finally
  380. fList.Free;
  381. end;
  382. end;
  383. constructor TParameters.Create;
  384. begin
  385. inherited Create;
  386. fHelp:=false;
  387. fVersion:=false;
  388. fVerbose:=false;
  389. fInputFiles:=TStringList.Create;
  390. fRCIncludeDirs:= TStringList.Create;
  391. fRCIncludeDirs.Duplicates:= dupIgnore;
  392. fRCDefines:= TStringList.Create;
  393. fOutputFile:='';
  394. fTarget.machine:=mtnone;
  395. GetDefaultSubMachineForMachine(fTarget.machine);
  396. fTarget.objformat:=ofnone;
  397. end;
  398. destructor TParameters.Destroy;
  399. begin
  400. fRCDefines.Free;
  401. fRCIncludeDirs.Free;
  402. fInputFiles.Free;
  403. inherited;
  404. end;
  405. end.