source: trunk/NewView/CmdLineParameterUnit.pas@ 23

Last change on this file since 23 was 23, checked in by RBRi, 19 years ago

rewritten command line parser + unit tests

  • Property svn:eol-style set to native
File size: 13.8 KB
Line 
1Unit CmdLineParameterUnit;
2
3// NewView - a new OS/2 Help Viewer
4// Copyright 2006 Ronald Brill (rbri at rbri dot de)
5// This software is released under the Gnu Public License - see readme.txt
6
7// Helper functions to address the command line parameters newview
8// is started with
9
10Interface
11
12uses
13 Os2Def, BseTib, BseDos,
14 SysUtils,
15 Classes,
16
17 PMWIN,
18
19 ACLStringUtility,
20 ACLProfile,
21 ACLFileUtility;
22
23 CONST
24 SUCCESS = 0;
25 ERROR_UNMATCHED_QUOTE = -1;
26
27 TYPE
28 TWindowPosition = record
29 left: longint;
30 bottom: longint;
31 width: longint;
32 height: longint;
33 end;
34 TYPE
35 TCmdLineParameters = class
36 private
37 showUsageFlag : boolean;
38 searchTextFlag : boolean;
39 searchText : string;
40 globalSearchTextFlag : boolean;
41 globalSearchText : string;
42 language : string;
43 helpManagerFlag : boolean;
44 helpManagerWindow : integer;
45 windowPositionFlag: boolean;
46 windowPosition: TWindowPosition;
47 ownerWindow : integer;
48 windowTitle : string;
49 fileName : string;
50 topic : string;
51 {
52 TopicParam: string;
53 FilenamesParam: TAString;
54 }
55
56 public
57 FUNCTION getShowUsageFlag : boolean;
58 FUNCTION getSearchTextFlag : boolean;
59 FUNCTION getSearchText : string;
60 FUNCTION getGlobalSearchTextFlag : boolean;
61 FUNCTION getGlobalSearchText : string;
62 FUNCTION getLanguage : string;
63 FUNCTION getHelpManagerFlag : boolean;
64 FUNCTION getHelpManagerWindow : integer;
65 FUNCTION getWindowPositionFlag : boolean;
66 FUNCTION getWindowPosition : TWindowPosition;
67 FUNCTION getOwnerWindow : integer;
68 FUNCTION getWindowTitle : string;
69 FUNCTION getFileName : string;
70 FUNCTION getTopic : string;
71 PROCEDURE parseCmdLine(aSplittedCmdLine : TStringList);
72 end;
73
74 // returns a string containing the whole
75 // command line parametes
76 FUNCTION nativeOS2GetCmdLineParameter : STRING;
77
78 // returns a string containing the whole
79 // command line parametes
80 FUNCTION splitCmdLineParameter(aCmdLineString : String; var aRC : Integer) : TStringList;
81
82 // Return true if param matches the form
83 // /Flag:value
84 // dash (-) can be used instead of slash (/)
85 // colon can be omitted
86 FUNCTION MatchValueParam( const aParam: string; const aFlag: string; var aValue: string): boolean;
87
88 // Return true if param matches the form
89 // /Flag
90 // dash (-) can be used instead of slash (/)
91 FUNCTION MatchFlagParam( const aParam: string; const aFlag: string): boolean;
92
93 // Extract a single element of a window position spec
94 // - take a value from comma-separated list
95 // - convert to numeric
96 // - if the number ends with P then take as
97 // a percentage of given dimension
98 FUNCTION ExtractPositionElement(Var aParamValue: string; aScreenDimension: longint) : longint;
99
100 // Extract a specified window position:
101 // X,Y,W,H
102 FUNCTION ExtractPositionSpec(aParamValue: string; Var aPosition: TWindowPosition ): boolean;
103Implementation
104
105 FUNCTION TCmdLineParameters.getShowUsageFlag : boolean;
106 begin
107 result := showUsageFlag;
108 end;
109
110
111 FUNCTION TCmdLineParameters.getSearchTextFlag : boolean;
112 begin
113 result := searchTextFlag;
114 end;
115
116
117 FUNCTION TCmdLineParameters.getSearchText : string;
118 begin
119 result := searchText;
120 end;
121
122
123 FUNCTION TCmdLineParameters.getGlobalSearchTextFlag : boolean;
124 begin
125 result := globalSearchTextFlag;
126 end;
127
128
129 FUNCTION TCmdLineParameters.getGlobalSearchText : string;
130 begin
131 result := globalSearchText;
132 end;
133
134
135 FUNCTION TCmdLineParameters.getLanguage : string;
136 begin
137 result := language;
138 end;
139
140
141 FUNCTION TCmdLineParameters.getHelpManagerFlag : boolean;
142 begin
143 result := helpManagerFlag;
144 end;
145
146
147 FUNCTION TCmdLineParameters.getHelpManagerWindow : integer;
148 begin
149 result := helpManagerWindow;
150 end;
151
152
153 FUNCTION TCmdLineParameters.getWindowPositionFlag : boolean;
154 begin
155 result := windowPositionFlag;
156 end;
157
158
159 FUNCTION TCmdLineParameters.getWindowPosition : TWindowPosition;
160 begin
161 result := windowPosition;
162 end;
163
164
165 FUNCTION TCmdLineParameters.getOwnerWindow : integer;
166 begin
167 result := ownerWindow;
168 end;
169
170
171 FUNCTION TCmdLineParameters.getWindowTitle : string;
172 begin
173 result := windowTitle;
174 end;
175
176
177 FUNCTION TCmdLineParameters.getFileName : string;
178 begin
179 result := fileName;
180 end;
181
182
183 FUNCTION TCmdLineParameters.getTopic : string;
184 begin
185 result := topic;
186 end;
187
188
189 procedure TCmdLineParameters.parseCmdLine(aSplittedCmdLine : TStringList);
190 var
191 tmpParamIndex : integer;
192 tmpParameter : string;
193 tmpParameterValue : string;
194 begin
195 // reset the whole object
196 showUsageFlag := false;
197 searchTextFlag := false;
198 searchText := '';
199 globalSearchTextFlag := false;
200 globalSearchText := '';
201 language := '';
202 helpManagerFlag := false;
203 helpManagerWindow := 0;
204 windowPositionFlag := false;
205 // windowPosition;
206 ownerWindow := 0;
207 windowTitle := '';
208
209 filename := '';
210 topic := '';
211
212 // start parsing
213 for tmpParamIndex := 0 to aSplittedCmdLine.Count -1 do
214 begin
215 tmpParameter := aSplittedCmdLine[tmpParamIndex];
216
217 if MatchFlagParam(tmpParameter, '?')
218 or MatchFlagParam(tmpParameter, 'H')
219 or MatchFlagParam(tmpParameter, 'HELP') then
220 begin
221 showUsageFlag := true
222 end
223 else if MatchValueParam(tmpParameter, 'G', globalSearchText) then
224 begin
225 globalSearchTextFlag := true;
226 end
227 else if MatchValueParam(tmpParameter, 'S', searchText) then
228 begin
229 searchTextFlag := true;
230 end
231 else if MatchValueParam(tmpParameter, 'LANG', language) then
232 begin
233 // nothing to do
234 end
235 else if MatchValueParam(tmpParameter, 'HM', tmpParameterValue) then
236 begin
237 try
238 helpManagerWindow := StrToInt(tmpParameterValue);
239 helpManagerFlag := true;
240 except
241 // ignore invalid window value
242 end;
243 end
244 else if MatchValueParam(tmpParameter, 'OWNER', tmpParameterValue) then
245 begin
246 try
247 ownerWindow := StrToInt(tmpParameterValue);
248 except
249 // ignore invalid owner value
250 end;
251 end
252 else if MatchValueParam(tmpParameter, 'TITLE', windowTitle) then
253 begin
254 // nothing to do
255 end
256 else if MatchFlagParam(tmpParameter, 'PROFILE') then
257 begin
258 StartProfile(GetLogFilesDir + 'newview.prf' );
259 end
260 else if MatchValueParam(tmpParameter, 'POS', tmpParameterValue ) then
261 begin
262 // set window position/size
263 if ExtractPositionSpec(tmpParameterValue, windowPosition) then
264 begin
265 windowPositionFlag := true;
266 end
267 else
268 begin
269 // invalid...
270 showUsageFlag := true;
271 end;
272 end
273 else
274 begin
275 if length(filename) = 0 then
276 begin
277 // filename
278 fileName := tmpParameter;
279 end
280 else
281 begin
282 // search (topic) parameter... append all remaining thingies
283 if topic <> '' then
284 begin
285 topic := topic + ' ';
286 end;
287 topic := topic + tmpParameter;
288 end;
289 end;
290 end;
291 end;
292
293
294FUNCTION nativeOS2GetCmdLineParameter : STRING;
295 VAR
296 tmpPtib : PTIB; /* thread information block */
297 tmpPpib : PPIB; /* process information block */
298 tmpCmd : PCHAR;
299 tmpResult : PCHAR;
300
301 BEGIN
302 DosGetInfoBlocks(tmpPtib, tmpPpib);
303 tmpCmd := tmpPpib^.pib_pchcmd;
304 tmpResult := tmpCmd + StrLen(tmpCmd) + 1;
305 nativeOS2GetCmdLineParameter := StrPas(tmpResult);
306 END;
307
308
309FUNCTION splitCmdLineParameter(aCmdLineString : String; var aRC : Integer) : TStringList;
310 CONST
311 STATE_BEFORE = 0;
312 STATE_INSIDE = 1;
313 STATE_START_QUOTE = 2;
314 STATE_INSIDE_QUOTED = 3;
315 STATE_INSIDE_QUOTED_START_QUOTE = 4;
316 VAR
317 i : Integer;
318 tmpCurrentChar : char;
319 tmpState : INTEGER;
320 tmpCurrentCommand : String;
321 tmpResult : TStringList;
322
323 BEGIN
324 aRC := SUCCESS;
325 tmpResult := TStringList.Create;
326 tmpState := 0;
327 tmpCurrentCommand := '';
328 for i:=1 to length(aCmdLineString) do
329 begin
330 tmpCurrentChar := aCmdLineString[i];
331
332 Case tmpCurrentChar of
333 ' ' :
334 begin
335 Case tmpState of
336 STATE_BEFORE : {do nothing};
337 STATE_INSIDE :
338 begin
339 tmpResult.add(tmpCurrentCommand);
340 tmpCurrentCommand := '';
341 tmpState := STATE_BEFORE;
342 end;
343 STATE_INSIDE_QUOTED_START_QUOTE :
344 begin
345 tmpResult.add(tmpCurrentCommand);
346 tmpCurrentCommand := '';
347 tmpState := STATE_BEFORE;
348 end;
349 ELSE
350 begin
351 tmpCurrentCommand := tmpCurrentCommand + tmpCurrentChar;
352 end;
353 end;
354 end;
355
356 '"' :
357 begin
358 Case tmpState of
359 STATE_START_QUOTE :
360 begin
361 tmpState := STATE_INSIDE;
362 tmpCurrentCommand := tmpCurrentCommand + tmpCurrentChar;
363 end;
364 STATE_INSIDE_QUOTED :
365 tmpState := STATE_INSIDE_QUOTED_START_QUOTE;
366 STATE_INSIDE_QUOTED_START_QUOTE :
367 begin
368 tmpState := STATE_INSIDE_QUOTED;
369 tmpCurrentCommand := tmpCurrentCommand + tmpCurrentChar;
370 end;
371 ELSE
372 tmpState := STATE_START_QUOTE;
373 end;
374 end;
375 ELSE
376 begin
377 Case tmpState of
378 STATE_BEFORE :
379 begin
380 tmpState := STATE_INSIDE;
381 tmpCurrentCommand := tmpCurrentCommand + tmpCurrentChar;
382 end;
383 STATE_INSIDE :
384 begin
385 tmpState := STATE_INSIDE;
386 tmpCurrentCommand := tmpCurrentCommand + tmpCurrentChar;
387 end;
388 STATE_START_QUOTE :
389 begin
390 tmpState := STATE_INSIDE_QUOTED;
391 tmpCurrentCommand := tmpCurrentCommand + tmpCurrentChar;
392 end;
393 STATE_INSIDE_QUOTED :
394 begin
395 tmpCurrentCommand := tmpCurrentCommand + tmpCurrentChar;
396 end;
397 STATE_INSIDE_QUOTED_START_QUOTE :
398 begin
399 tmpState := STATE_INSIDE;
400 tmpCurrentCommand := tmpCurrentCommand + tmpCurrentChar;
401 end;
402 end;
403 end;
404 end;
405 end;
406
407 Case tmpState of
408 STATE_BEFORE : { nothing to do};
409 STATE_INSIDE :
410 begin
411 tmpResult.add(tmpCurrentCommand);
412 end;
413 STATE_INSIDE_QUOTED_START_QUOTE :
414 begin
415 tmpResult.add(tmpCurrentCommand);
416 end;
417 ELSE
418 begin
419 aRC := ERROR_UNMATCHED_QUOTE;
420 tmpResult.add(tmpCurrentCommand);
421 end;
422 end;
423 splitCmdLineParameter:= tmpResult;
424 END;
425
426
427FUNCTION MatchValueParam( const aParam: string; const aFlag: string; var aValue: string ): boolean;
428begin
429 Result := false;
430
431 if aParam = '' then
432 exit;
433
434 if ( aParam[ 1 ] <> '/' )
435 and ( aParam[ 1 ] <> '-' ) then
436 exit;
437
438 if CompareText(copy(aParam, 2, length(aFlag)), aFlag) <> 0 then
439 exit;
440
441 Result := true;
442
443 aValue := copy(aParam, 2 + length(aFlag), length(aParam));
444 if aValue <> '' then
445 if aValue[ 1 ] = ':' then
446 delete(aValue, 1, 1 );
447end;
448
449
450FUNCTION MatchFlagParam(const aParam: string; const aFlag: string ): boolean;
451begin
452 Result := false;
453
454 if aParam = '' then
455 exit;
456
457 if (aParam[ 1 ] <> '/' )
458 and (aParam[ 1 ] <> '-' ) then
459 exit;
460 Result := CompareText(copy(aParam, 2, length(aParam)-1), aFlag) = 0;
461end;
462
463
464FUNCTION ExtractPositionElement(Var aParamValue: string; aScreenDimension: longint ): longint;
465var
466 tmpElement: string;
467begin
468 tmpElement := ExtractNextValue(aParamValue, ',' );
469 if tmpElement = '' then
470 raise Exception.Create('Missing position element');
471 if StrEnds('P', tmpElement) then
472 begin
473 Delete(tmpElement, length(tmpElement), 1);
474 if tmpElement = '' then
475 raise Exception.Create('Missing position element');
476 Result := StrToInt(tmpElement);
477 if Result < 0 then
478 Result := 0;
479 if Result > 100 then
480 Result := 100;
481 Result := Round(Result / 100 * aScreenDimension);
482 end
483 else
484 begin
485 Result := StrToInt(tmpElement);
486 end;
487end;
488
489FUNCTION SystemMetrics(aSystemMetric : LONG) : LongInt;
490Begin
491 Result := WinQuerySysValue(HWND_DESKTOP, aSystemMetric);
492end;
493
494FUNCTION ExtractPositionSpec(aParamValue: string; Var aPosition: TWindowPosition ): boolean;
495begin
496 try
497 aPosition.Left := ExtractPositionElement(aParamValue, SystemMetrics(SV_CXSCREEN));
498 aPosition.Bottom := ExtractPositionElement(aParamValue, SystemMetrics(SV_CYSCREEN));
499 aPosition.Width := ExtractPositionElement(aParamValue, SystemMetrics(SV_CXSCREEN));
500 if aPosition.Width < 50 then
501 aPosition.Width := 50;
502 aPosition.Height := ExtractPositionElement(aParamValue, SystemMetrics(SV_CYSCREEN));
503 if aPosition.Height < 50 then
504 aPosition.Height := 50;
505 Result := true;
506 except
507 Result := false;
508 end;
509end;
510
511END.
Note: See TracBrowser for help on using the repository browser.