custapp.pp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2003 by the Free Pascal development team
  4. CustomApplication class.
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {$mode objfpc}
  12. {$h+}
  13. unit CustApp;
  14. Interface
  15. uses SysUtils,Classes;
  16. Type
  17. TExceptionEvent = Procedure (Sender : TObject; E : Exception) Of Object;
  18. TCustomApplication = Class(TComponent)
  19. Private
  20. FOnException: TExceptionEvent;
  21. FTerminated : Boolean;
  22. FHelpFile,
  23. FTitle : String;
  24. FOptionChar : Char;
  25. FCaseSensitiveOptions : Boolean;
  26. FStopOnException : Boolean;
  27. function GetEnvironmentVar(VarName : String): String;
  28. function GetExeName: string;
  29. Function GetLocation : String;
  30. function GetTitle: string;
  31. Protected
  32. procedure SetTitle(const AValue: string); Virtual;
  33. Function GetConsoleApplication : boolean; Virtual;
  34. Procedure DoRun; Virtual;
  35. Function GetParams(Index : Integer) : String;virtual;
  36. function GetParamCount: Integer;Virtual;
  37. Public
  38. constructor Create(AOwner: TComponent); override;
  39. destructor Destroy; override;
  40. // Some Delphi methods.
  41. procedure HandleException(Sender: TObject); virtual;
  42. procedure Initialize; virtual;
  43. procedure Run;
  44. procedure ShowException(E: Exception);virtual;
  45. procedure Terminate; virtual;
  46. // Extra methods.
  47. function FindOptionIndex(Const S : String; Var Longopt : Boolean) : Integer;
  48. Function GetOptionValue(Const S : String) : String;
  49. Function GetOptionValue(Const C: Char; Const S : String) : String;
  50. Function HasOption(Const S : String) : Boolean;
  51. Function HasOption(Const C : Char; Const S : String) : Boolean;
  52. Function CheckOptions(Const ShortOptions : String; Const Longopts : TStrings; Opts,NonOpts : TStrings) : String;
  53. Function CheckOptions(Const ShortOptions : String; Const Longopts : TStrings) : String;
  54. Function CheckOptions(Const ShortOptions : String; Const LongOpts : Array of string) : String;
  55. Function CheckOptions(Const ShortOptions : String; Const LongOpts : String) : String;
  56. Procedure GetEnvironmentList(List : TStrings;NamesOnly : Boolean);
  57. Procedure GetEnvironmentList(List : TStrings);
  58. // Delphi properties
  59. property ExeName: string read GetExeName;
  60. property HelpFile: string read FHelpFile write FHelpFile;
  61. property Terminated: Boolean read FTerminated;
  62. property Title: string read FTitle write SetTitle;
  63. property OnException: TExceptionEvent read FOnException write FOnException;
  64. // Extra properties
  65. Property ConsoleApplication : Boolean Read GetConsoleApplication;
  66. Property Location : String Read GetLocation;
  67. Property Params [Index : integer] : String Read GetParams;
  68. Property ParamCount : Integer Read GetParamCount;
  69. Property EnvironmentVariable[envName : String] : String Read GetEnvironmentVar;
  70. Property OptionChar : Char Read FoptionChar Write FOptionChar;
  71. Property CaseSensitiveOptions : Boolean Read FCaseSensitiveOptions Write FCaseSensitiveOptions;
  72. Property StopOnException : Boolean Read FStopOnException Write FStopOnException;
  73. end;
  74. Implementation
  75. { TCustomApplication }
  76. function TCustomApplication.GetExeName: string;
  77. begin
  78. Result:=Paramstr(0);
  79. end;
  80. Procedure SysGetEnvironmentList(List : TStrings;NamesOnly : Boolean);
  81. var
  82. s : string;
  83. i,l,j,count : longint;
  84. begin
  85. count:=GetEnvironmentVariableCount;
  86. if count>0 then
  87. for j:=1 to count do
  88. begin
  89. s:=GetEnvironmentString(j);
  90. l:=Length(s);
  91. If NamesOnly then
  92. begin
  93. I:=pos('=',s);
  94. If (I>0) then
  95. S:=Copy(S,1,I-1);
  96. end;
  97. List.Add(S);
  98. end;
  99. end;
  100. function TCustomApplication.GetEnvironmentVar(VarName : String): String;
  101. begin
  102. Result:=GetEnvironmentVariable(VarName);
  103. end;
  104. Procedure TCustomApplication.GetEnvironmentList(List : TStrings;NamesOnly : Boolean);
  105. begin
  106. // Routine must be in custapp.inc
  107. SysGetEnvironmentList(List,NamesOnly);
  108. end;
  109. Procedure TCustomApplication.GetEnvironmentList(List : TStrings);
  110. begin
  111. GetEnvironmentList(List,False);
  112. end;
  113. function TCustomApplication.GetLocation: String;
  114. begin
  115. Result:=ExtractFilePath(GetExeName);
  116. end;
  117. function TCustomApplication.GetParamCount: Integer;
  118. begin
  119. Result:=System.ParamCount;
  120. end;
  121. function TCustomApplication.GetTitle: string;
  122. begin
  123. Result:=FTitle;
  124. end;
  125. function TCustomApplication.GetParams(Index: Integer): String;
  126. begin
  127. Result:=ParamStr(Index);
  128. end;
  129. procedure TCustomApplication.SetTitle(const AValue: string);
  130. begin
  131. FTitle:=AValue;
  132. end;
  133. function TCustomApplication.GetConsoleApplication: boolean;
  134. begin
  135. Result:=IsConsole;
  136. end;
  137. procedure TCustomApplication.DoRun;
  138. begin
  139. // Do nothing. Override in descendent classes.
  140. end;
  141. constructor TCustomApplication.Create(AOwner: TComponent);
  142. begin
  143. inherited Create(AOwner);
  144. FOptionChar:='-';
  145. FCaseSensitiveOptions:=True;
  146. FStopOnException:=False;
  147. end;
  148. destructor TCustomApplication.Destroy;
  149. begin
  150. inherited Destroy;
  151. end;
  152. procedure TCustomApplication.HandleException(Sender: TObject);
  153. begin
  154. If Not (ExceptObject is Exception) then
  155. SysUtils.showexception(ExceptObject,ExceptAddr)
  156. else
  157. begin
  158. If Not Assigned(FOnexception) then
  159. ShowException(Exception(ExceptObject))
  160. else
  161. FOnException(Sender,Exception(ExceptObject));
  162. end;
  163. If FStopOnException then
  164. FTerminated:=True;
  165. end;
  166. procedure TCustomApplication.Initialize;
  167. begin
  168. FTerminated:=False;
  169. end;
  170. procedure TCustomApplication.Run;
  171. begin
  172. Repeat
  173. Try
  174. DoRun;
  175. except
  176. HandleException(Self);
  177. end;
  178. Until FTerminated;
  179. end;
  180. procedure TCustomApplication.ShowException(E: Exception);
  181. begin
  182. Sysutils.ShowException(E,ExceptAddr)
  183. end;
  184. procedure TCustomApplication.Terminate;
  185. begin
  186. FTerminated:=True;
  187. end;
  188. function TCustomApplication.GetOptionValue(Const S: String): String;
  189. begin
  190. Result:=GetoptionValue(#255,S);
  191. end;
  192. function TCustomApplication.GetOptionValue(Const C: Char; Const S: String): String;
  193. Var
  194. B : Boolean;
  195. I,P : integer;
  196. O : String;
  197. begin
  198. Result:='';
  199. I:=FindOptionIndex(C,B);
  200. If (I=-1) then
  201. I:=FindoptionIndex(S,B);
  202. If (I<>-1) then
  203. begin
  204. If B then
  205. begin // Long options have form --option=value
  206. O:=Params[I];
  207. P:=Pos('=',O);
  208. If (P=0) then
  209. P:=Length(O);
  210. Delete(O,1,P);
  211. Result:=O;
  212. end
  213. else
  214. begin // short options have form '-o value'
  215. If (I<ParamCount) then
  216. Result:=Params[I+1];
  217. end;
  218. end;
  219. end;
  220. function TCustomApplication.HasOption(Const S: String): Boolean;
  221. Var
  222. B : Boolean;
  223. begin
  224. Result:=FindOptionIndex(S,B)<>-1;
  225. end;
  226. function TCustomApplication.FindOptionIndex(Const S : String; Var Longopt : Boolean) : Integer;
  227. Var
  228. SO,O : String;
  229. I,P : Integer;
  230. begin
  231. If Not CaseSensitiveOptions then
  232. SO:=UpperCase(S)
  233. else
  234. SO:=S;
  235. Result:=-1;
  236. I:=ParamCount;
  237. While (Result=-1) and (I>0) do
  238. begin
  239. O:=Params[i];
  240. If (Length(O)>0) and (O[1]=FOptionChar) then
  241. begin
  242. Delete(O,1,1);
  243. LongOpt:=(Length(O)>0) and (O[1]=FOptionChar);
  244. If LongOpt then
  245. begin
  246. Delete(O,1,1);
  247. P:=Pos('=',O);
  248. If (P<>0) then
  249. O:=Copy(O,1,P-1);
  250. end;
  251. If Not CaseSensitiveOptions then
  252. O:=UpperCase(O);
  253. If (O=SO) then
  254. Result:=i;
  255. end;
  256. Dec(i);
  257. end;
  258. end;
  259. function TCustomApplication.HasOption(Const C: Char; Const S: String): Boolean;
  260. Var
  261. B : Boolean;
  262. begin
  263. Result:=(FindOptionIndex(C,B)<>-1) or (FindOptionIndex(S,B)<>-1);
  264. end;
  265. Function TCustomApplication.CheckOptions(Const ShortOptions : String; Const Longopts : TStrings) : String;
  266. begin
  267. Result:=CheckOptions(ShortOptions,LongOpts,Nil,Nil);
  268. end;
  269. ResourceString
  270. SErrInvalidOption = 'Invalid option at position %d: "%s"';
  271. SErrNoOptionAllowed = 'Option at position %d does not allow an argument: %s';
  272. SErrOptionNeeded = 'Option at position %d needs an argument : %s';
  273. Function TCustomApplication.CheckOptions(Const ShortOptions : String; Const Longopts : TStrings; Opts,NonOpts : TStrings) : String;
  274. Var
  275. I,J,L,P : Integer;
  276. O,OV,SO : String;
  277. HaveArg : Boolean;
  278. Function FindLongOpt(S : String) : boolean;
  279. Var
  280. I : integer;
  281. begin
  282. If CaseSensitiveOptions then
  283. begin
  284. I:=LongOpts.Count-1;
  285. While (I>=0) and (LongOpts[i]<>S) do
  286. Dec(i);
  287. end
  288. else
  289. begin
  290. S:=UpperCase(S);
  291. I:=LongOpts.Count-1;
  292. While (I>=0) and (UpperCase(LongOpts[i])<>S) do
  293. Dec(i);
  294. end;
  295. Result:=(I<>-1);
  296. end;
  297. begin
  298. If CaseSensitiveOptions then
  299. SO:=Shortoptions
  300. else
  301. SO:=LowerCase(Shortoptions);
  302. Result:='';
  303. I:=1;
  304. While (I<=ParamCount) and (Result='') do
  305. begin
  306. O:=Paramstr(I);
  307. If (Length(O)=0) or (O[1]<>FOptionChar) then
  308. begin
  309. If Assigned(NonOpts) then
  310. NonOpts.Add(O)
  311. end
  312. else
  313. begin
  314. If (Length(O)<2) then
  315. Result:=Format(SErrInvalidOption,[i,O])
  316. else
  317. begin
  318. HaveArg:=False;
  319. OV:='';
  320. // Long option ?
  321. If (O[2]=FOptionChar) then
  322. begin
  323. Delete(O,1,2);
  324. J:=Pos('=',O);
  325. If J<>0 then
  326. begin
  327. HaveArg:=true;
  328. OV:=O;
  329. Delete(OV,1,J);
  330. O:=Copy(O,1,J-1);
  331. end;
  332. // Switch Option
  333. If FindLongopt(O) then
  334. begin
  335. If HaveArg then
  336. Result:=Format(SErrNoOptionAllowed,[I,O])
  337. end
  338. else
  339. begin // Required argument
  340. If FindLongOpt(O+':') then
  341. begin
  342. If Not HaveArg then
  343. Result:=Format(SErrOptionNeeded,[I,O]);
  344. end
  345. else
  346. begin // Optional Argument.
  347. If not FindLongOpt(O+'::') then
  348. Result:=Format(SErrInvalidOption,[I,O]);
  349. end;
  350. end;
  351. end
  352. else // Short Option.
  353. begin
  354. HaveArg:=(I<ParamCount) and (Length(ParamStr(I+1))>0) and (ParamStr(I+1)[i]<>FOptionChar);
  355. If HaveArg then
  356. OV:=Paramstr(I+1);
  357. If Not CaseSensitiveOptions then
  358. O:=LowerCase(O);
  359. L:=Length(O);
  360. J:=2;
  361. While (result='') and (J<=L) do
  362. begin
  363. P:=Pos(O[J],ShortOptions);
  364. If (P=0) or (O[j]=':') then
  365. Result:=Format(SErrInvalidOption,[I,O[J]])
  366. else
  367. begin
  368. If (P<Length(ShortOptions)) and (Shortoptions[P+1]=':') then
  369. begin
  370. // Required argument
  371. Writeln('P ',P,' J ',J,' ',O[J],' ',l,' Havearg ',HaveArg);
  372. If ((P+1)=Length(ShortOptions)) or (Shortoptions[P+2]<>':') Then
  373. If (J<L) or not haveArg then // Must be last in multi-opt !!
  374. Result:=Format(SErrOptionNeeded,[I,O[J]]);
  375. O:=O[j]; // O is added to arguments.
  376. end;
  377. end;
  378. Inc(J);
  379. end;
  380. If HaveArg then
  381. begin
  382. Inc(I); // Skip argument.
  383. O:=O[Length(O)]; // O is added to arguments !
  384. end;
  385. end;
  386. If HaveArg and (Result='') then
  387. If Assigned(Opts) then
  388. Opts.Add(O+'='+OV);
  389. end;
  390. end;
  391. Inc(I);
  392. end;
  393. end;
  394. Function TCustomApplication.CheckOptions(Const ShortOptions : String; Const LongOpts : Array of string) : String;
  395. Var
  396. L : TStringList;
  397. I : Integer;
  398. begin
  399. L:=TStringList.Create;
  400. Try
  401. For I:=0 to High(LongOpts) do
  402. L.Add(LongOpts[i]);
  403. Result:=CheckOptions(ShortOptions,L);
  404. Finally
  405. L.Free;
  406. end;
  407. end;
  408. Function TCustomApplication.CheckOptions(Const ShortOptions : String; Const LongOpts : String) : String;
  409. Const
  410. SepChars = ' '#10#13#9;
  411. Var
  412. L : TStringList;
  413. Len,I,J : Integer;
  414. begin
  415. L:=TStringList.Create;
  416. Try
  417. I:=1;
  418. Len:=Length(LongOpts);
  419. While I<=Len do
  420. begin
  421. While Isdelimiter(SepChars,LongOpts,I) do
  422. Inc(I);
  423. J:=I;
  424. While (J<=Len) and Not IsDelimiter(SepChars,LongOpts,J) do
  425. Inc(J);
  426. If (I<=J) then
  427. L.Add(Copy(LongOpts,I,(J-I)));
  428. I:=J+1;
  429. end;
  430. Result:=CheckOptions(Shortoptions,L);
  431. Finally
  432. L.Free;
  433. end;
  434. end;
  435. end.