paramparser.pas 8.5 KB

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