paramparser.pas 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  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. procedure ParseInputFiles(aList : TStringList; var index : integer; const parname : string);
  37. procedure ParseOutputFile(aList : TStringList; var index : integer; const parname : string);
  38. procedure ParseOutputFormat(aList : TStringList; var index : integer; const parname : string);virtual;
  39. procedure ParseArchitecture(aList : TStringList; var index : integer; const parname : string);virtual;
  40. procedure ParseSubArchitecture(aList : TStringList; var index : integer; const parname : string);virtual;
  41. procedure ParseConfigFile(aList : TStringList; var index : integer; const parname : string);
  42. function DoOptionalArgument(aList : TStringList; const i : integer) : string;
  43. function DoMandatoryArgument(aList : TStringList; const i : integer) : string;
  44. function IsParameter(const s : string) : boolean;
  45. function ParamsToStrList : TStringList;
  46. protected
  47. public
  48. constructor Create;
  49. destructor Destroy; override;
  50. procedure Parse;
  51. property Help : boolean read fHelp;
  52. property Version : boolean read fVersion;
  53. property Verbose : boolean read fVerbose;
  54. property InputFiles : TStringList read fInputFiles;
  55. property OutputFile : string read fOutputFile write fOutputFile;
  56. property Target : TResTarget read fTarget;
  57. end;
  58. implementation
  59. uses
  60. msghandler;
  61. type
  62. { TConfFileParser }
  63. TConfFileParser = class
  64. private
  65. fConfFile : TStringList;
  66. fParList : TStringList;
  67. fInsPos : integer;
  68. procedure ParseLine(idx : integer);
  69. function GetParameter(pc : pchar; var i : integer) : string;
  70. function GetString(pc : pchar; var i : integer) : string;
  71. protected
  72. public
  73. constructor Create(aFileName : string; aParList : TStringList; aInsPos : integer);
  74. procedure Parse;
  75. destructor Destroy; override;
  76. end;
  77. { TConfFileParser }
  78. procedure TConfFileParser.ParseLine(idx: integer);
  79. var pc : pchar;
  80. tmp : string;
  81. i : integer;
  82. begin
  83. pc:=pchar(fConfFile[idx]);
  84. i:=0;
  85. while pc[i]<>#0 do
  86. begin
  87. case pc[i] of
  88. ' ',#9,#13,#10 : inc(i);
  89. '#' : break
  90. else
  91. begin
  92. tmp:=GetParameter(pc,i);
  93. if tmp<>'' then
  94. begin
  95. fParList.Insert(fInsPos,tmp);
  96. inc(fInsPos);
  97. end;
  98. end;
  99. end;
  100. end;
  101. end;
  102. function TConfFileParser.GetParameter(pc : pchar; var i : integer): string;
  103. begin
  104. Result:='';
  105. while pc[i]<>#0 do
  106. begin
  107. case pc[i] of
  108. ' ',#9,#13,#10 : exit;
  109. '#' : exit;
  110. '"' : Result:=Result+GetString(pc,i);
  111. else
  112. Result:=Result+pc[i];
  113. end;
  114. inc(i);
  115. end;
  116. end;
  117. function TConfFileParser.GetString(pc: pchar; var i: integer): string;
  118. begin
  119. Result:='';
  120. inc(i);
  121. while pc[i]<>#0 do
  122. begin
  123. if pc[i] = '"' then
  124. exit
  125. else
  126. Result:=Result+pc[i];
  127. inc(i);
  128. end;
  129. dec(i);
  130. end;
  131. constructor TConfFileParser.Create(aFileName: string; aParList: TStringList; aInsPos : integer);
  132. begin
  133. fInsPos:=aInsPos+1;
  134. fConfFile:=TStringList.Create;
  135. fParList:=aParList;
  136. try
  137. fConfFile.LoadFromFile(aFileName);
  138. except
  139. raise ECannotReadConfFile.Create(aFileName);
  140. end;
  141. end;
  142. procedure TConfFileParser.Parse;
  143. var i : integer;
  144. begin
  145. for i:=0 to fConfFile.Count-1 do
  146. ParseLine(i);
  147. end;
  148. destructor TConfFileParser.Destroy;
  149. begin
  150. fConfFile.Free;
  151. end;
  152. { TParameters }
  153. //for compatibility allow -i <inputfiles>
  154. procedure TParameters.ParseInputFiles(aList: TStringList; var index: integer;
  155. const parname : string);
  156. var tmp : string;
  157. begin
  158. tmp:=DoMandatoryArgument(aList,index+1);
  159. if tmp='' then
  160. raise EArgumentMissingException.Create(parname);
  161. while tmp<>'' do
  162. begin
  163. inc(index);
  164. fInputFiles.Add(tmp);
  165. tmp:=DoOptionalArgument(aList,index+1);
  166. end;
  167. end;
  168. procedure TParameters.ParseOutputFile(aList: TStringList; var index: integer;
  169. const parname : string);
  170. begin
  171. if fOutputFile<>'' then
  172. raise EOutputFileAlreadySetException.Create('');
  173. inc(index);
  174. fOutputFile:=DoMandatoryArgument(aList,index);
  175. if fOutputFile='' then
  176. raise EArgumentMissingException.Create(parname);
  177. end;
  178. procedure TParameters.ParseOutputFormat(aList: TStringList; var index: integer;
  179. const parname: string);
  180. var tmp : string;
  181. aFormat : TObjFormat;
  182. begin
  183. inc(index);
  184. tmp:=DoMandatoryArgument(aList,index);
  185. if tmp='' then
  186. raise EArgumentMissingException.Create(parname);
  187. for aFormat:=low(TObjFormat) to high(TObjFormat) do
  188. begin
  189. if ObjFormats[aFormat].name=tmp then
  190. begin
  191. fTarget.objformat:=aFormat;
  192. exit;
  193. end;
  194. end;
  195. raise EUnknownObjFormatException.Create(tmp);
  196. end;
  197. procedure TParameters.ParseArchitecture(aList: TStringList; var index: integer;
  198. const parname: string);
  199. var tmp : string;
  200. aMachine : TMachineType;
  201. begin
  202. inc(index);
  203. tmp:=DoMandatoryArgument(aList,index);
  204. if tmp='' then
  205. raise EArgumentMissingException.Create(parname);
  206. for aMachine:=low(TMachineType) to high(TMachineType) do
  207. begin
  208. if (Machines[aMachine].name=tmp) or (Machines[aMachine].alias = tmp) then
  209. begin
  210. fTarget.machine:=aMachine;
  211. fTarget.submachine:=GetDefaultSubMachineForMachine(fTarget.machine);
  212. exit;
  213. end;
  214. end;
  215. raise EUnknownMachineException.Create(tmp);
  216. end;
  217. procedure TParameters.ParseSubArchitecture(aList: TStringList; var index: integer; const parname: string);
  218. var tmp : string;
  219. aSubMachineArm : TSubMachineTypeArm;
  220. aSubMachineGeneric : TSubMachineTypeGeneric;
  221. begin
  222. inc(index);
  223. tmp:=DoMandatoryArgument(aList,index);
  224. if tmp='' then
  225. raise EArgumentMissingException.Create(parname);
  226. case fTarget.machine of
  227. mtarm,mtarmeb:
  228. for aSubMachineArm:=low(TSubMachineTypeArm) to high(TSubMachineTypeArm) do
  229. if SubMachinesArm[aSubMachineArm]=tmp then
  230. begin
  231. ftarget.submachine.subarm:=aSubMachineArm;
  232. exit;
  233. end;
  234. else
  235. for aSubMachineGeneric:=low(TSubMachineTypeGeneric) to high(TSubMachineTypeGeneric) do
  236. if SubMachinesGen[aSubMachineGeneric]=tmp then
  237. begin
  238. ftarget.submachine.subgen:=aSubMachineGeneric;
  239. exit;
  240. end;
  241. end;
  242. raise EUnknownSubMachineException.Create(tmp);
  243. end;
  244. procedure TParameters.ParseConfigFile(aList: TStringList; var index: integer;
  245. const parname : string);
  246. var tmp : string;
  247. cp : TConfFileParser;
  248. begin
  249. tmp:=copy(parname,2,length(parname)-1);
  250. if tmp='' then
  251. raise EArgumentMissingException.Create(parname);
  252. cp:=TConfFileParser.Create(tmp,aList,index);
  253. try
  254. cp.Parse;
  255. finally
  256. cp.Free;
  257. end;
  258. end;
  259. function TParameters.DoOptionalArgument(aList: TStringList; const i: integer
  260. ): string;
  261. begin
  262. Result:='';
  263. if aList.Count>i then
  264. begin
  265. if not IsParameter(aList[i]) then
  266. Result:=aList[i];
  267. end;
  268. end;
  269. function TParameters.DoMandatoryArgument(aList: TStringList; const i: integer
  270. ): string;
  271. begin
  272. Result:='';
  273. if aList.count>i then
  274. Result:=aList[i];
  275. end;
  276. function TParameters.IsParameter(const s: string): boolean;
  277. begin
  278. Result:=false;
  279. if length(s)<=1 then exit;
  280. if copy(s,1,1)='-' then Result:=true;
  281. end;
  282. function TParameters.ParamsToStrList: TStringList;
  283. var i : integer;
  284. begin
  285. Result:=TStringList.Create;
  286. try
  287. for i:=1 to ParamCount do
  288. Result.Add(ParamStr(i));
  289. except
  290. Result.Free;
  291. raise;
  292. end;
  293. end;
  294. procedure TParameters.Parse;
  295. var fList : TStringList;
  296. tmp : string;
  297. i : integer;
  298. begin
  299. fList:=ParamsToStrList;
  300. try
  301. i:=0;
  302. while i<fList.Count do
  303. begin
  304. tmp:=fList[i];
  305. Messages.DoVerbose(Format('parsing parameter ''%s''',[tmp]));
  306. if IsParameter(tmp) then
  307. begin
  308. if ((tmp='--help') or (tmp='-h') or (tmp='-?')) then
  309. fHelp:=true
  310. else if ((tmp='--version') or (tmp='-V')) then
  311. fVersion:=true
  312. else if ((tmp='--verbose') or (tmp='-v')) then
  313. fVerbose:=true
  314. else if ((tmp='-i') or (tmp='--input')) then
  315. ParseInputFiles(fList,i,tmp)
  316. else if ((tmp='-o') or (tmp='--output')) then
  317. ParseOutputFile(fList,i,tmp)
  318. else if (tmp='-of') then
  319. ParseOutputFormat(fList,i,tmp)
  320. else if ((tmp='-a') or (tmp='--arch')) then
  321. ParseArchitecture(fList,i,tmp)
  322. else if ((tmp='-s') or (tmp='--subarch')) then
  323. ParseSubArchitecture(fList,i,tmp)
  324. else
  325. raise EUnknownParameterException.Create(tmp);
  326. end
  327. else
  328. if copy(tmp,1,1)='@' then
  329. ParseConfigFile(fList,i,tmp)
  330. else
  331. fInputFiles.Add(tmp); //assume it is an input file
  332. inc(i);
  333. end;
  334. finally
  335. fList.Free;
  336. end;
  337. end;
  338. constructor TParameters.Create;
  339. begin
  340. fHelp:=false;
  341. fVersion:=false;
  342. fVerbose:=false;
  343. fInputFiles:=TStringList.Create;
  344. fOutputFile:='';
  345. fTarget.machine:=mtnone;
  346. GetDefaultSubMachineForMachine(fTarget.machine);
  347. fTarget.objformat:=ofnone;
  348. end;
  349. destructor TParameters.Destroy;
  350. begin
  351. fInputFiles.Free;
  352. end;
  353. end.