source: trunk/NewView/CmdLineParameterUnit.pas@ 69

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

fixed melpmanager parameter handling
more unit tests

  • Property svn:eol-style set to native
File size: 16.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,
14 BseTib,
15 BseDos,
16 SysUtils,
17 Classes,
18 PMWIN,
19 StringUtilsUnit,
20 DebugUnit;
21
22 CONST
23 SUCCESS = 0;
24 ERROR_UNMATCHED_QUOTE = -1;
25
26 TYPE EParsingFailed=CLASS(Exception);
27
28 TYPE
29 TWindowPosition = record
30 left: longint;
31 bottom: longint;
32 width: longint;
33 height: longint;
34 end;
35 TYPE
36 TCmdLineParameters = class
37 private
38 commandLine : String;
39 showUsageFlag : boolean;
40 searchFlag : boolean;
41 globalSearchFlag : boolean;
42 language : string;
43 helpManagerFlag : boolean;
44 helpManagerWindow : HWND;
45 windowPositionFlag: boolean;
46 windowPosition: TWindowPosition;
47 ownerWindow : integer;
48 windowTitle : string;
49 fileNames : string;
50 fileNamesRaw : string;
51 searchText : string;
52
53// FUNCTION ReadNextPart(const aParseString : String; const aSetOfDelimiterChars : TSetOfChars): String;
54 FUNCTION handleSwitchWithValue(const aSwitchString : String; const aSwitch : String; var aValue : String) : Boolean;
55 PROCEDURE parseSwitch(aSwitchString : String);
56 PROPERTY getFileNames : string read fileNames;
57 PROPERTY getSearchText : string read searchText;
58
59 public
60 PROPERTY getCommandLine : String read commandLine;
61 PROPERTY getShowUsageFlag : boolean read showUsageFlag;
62 PROPERTY getSearchFlag : boolean read searchFlag;
63 PROPERTY getGlobalSearchFlag : boolean read globalSearchFlag;
64 PROPERTY getLanguage : string read language;
65 PROPERTY getHelpManagerFlag : boolean read helpManagerFlag;
66 FUNCTION setHelpManagerFlag(aNewValue : boolean) : boolean;
67 PROPERTY getHelpManagerWindow : HWND read helpManagerWindow;
68 PROPERTY getWindowPositionFlag : boolean read windowPositionFlag;
69 PROPERTY getWindowPosition : TWindowPosition read windowPosition;
70 PROPERTY getOwnerWindow : integer read ownerWindow;
71 PROPERTY getWindowTitle : string read windowTitle;
72 PROPERTY getFileNamesRaw : string read fileNamesRaw;
73
74 PROCEDURE writeDetailsTo(aStrings : TStrings);
75 PROCEDURE parseCmdLine(aCmdLineString : String);
76
77 FUNCTION getInterpretedFileNames: String;
78 FUNCTION getInterpretedSearchText: String;
79 end;
80
81 FUNCTION getOwnHelpFileName: String;
82
83 // returns a string containing the whole
84 // command line parametes
85 FUNCTION nativeOS2GetCmdLineParameter : String;
86
87
88Implementation
89uses
90 ACLFileUtility;
91
92 PROCEDURE TCmdLineParameters.writeDetailsTo(aStrings : TStrings);
93 var
94 tmpWindowPosition : TWindowPosition;
95 begin
96 aStrings.Add('''' + getCommandLine + '''');
97 aStrings.Add('parsed infos:');
98
99 aStrings.Add('getShowUsageFlag: ' + boolToStr(getShowUsageFlag));
100 aStrings.Add('getSearchFlag: ' + boolToStr(getSearchFlag));
101 aStrings.Add('getSearchText: ' + getSearchText);
102 aStrings.Add('getGlobalSearchFlag: ' + boolToStr(getGlobalSearchFlag));
103 aStrings.Add('getLanguage: ' + getLanguage);
104 aStrings.Add('getHelpManagerFlag: ' + boolToStr(getHelpManagerFlag));
105 aStrings.Add('getHelpManagerWindow: ' + LongWordToStr(getHelpManagerWindow));
106 aStrings.Add('getWindowPositionFlag: ' + boolToStr(getWindowPositionFlag));
107 aStrings.Add('getFileNames: ' + getFileNames);
108 aStrings.Add('getInterpretedSearchText: ' + getInterpretedSearchText);
109 aStrings.Add('getInterpretedFileNames: ' + getInterpretedFileNames);
110
111 tmpWindowPosition := getWindowPosition;
112 aStrings.Add('getWindowPosition: '
113 + intToStr(tmpWindowPosition.left) + ', '
114 + intToStr(tmpWindowPosition.bottom) + ', '
115 + intToStr(tmpWindowPosition.width) + ', '
116 + intToStr(tmpWindowPosition.height)
117 );
118 aStrings.Add('getOwnerWindow: ' + intToStr(getOwnerWindow));
119 aStrings.Add('getWindowTitle: ' + getWindowTitle);
120 end;
121
122
123 Function TCmdLineParameters.getInterpretedFileNames: String;
124 var
125 tmpOwnHelpFileName : String;
126 begin
127 result := getFileNames;
128
129 if getGlobalSearchFlag
130 AND (getSearchText = '')
131 then
132 begin
133 result := '';
134 exit;
135 end;
136
137
138 tmpOwnHelpFileName := FindDefaultLanguageHelpFile('NewView');
139 if (result = '') AND
140 FileExists(tmpOwnHelpFileName)
141 then
142 result := tmpOwnHelpFileName;
143 end;
144
145
146 Function TCmdLineParameters.getInterpretedSearchText: String;
147 begin
148 result := getSearchText;
149
150 if getGlobalSearchFlag
151 AND (result = '')
152 then
153 result := getFileNamesRaw;
154
155 if not getGlobalSearchFlag
156 AND (not getSearchFlag)
157 then
158 begin
159 result := StrTrim(result);
160 result := StrTrimChars(result, ['"']);
161 end;
162
163 end;
164
165
166 Function TCmdLineParameters.setHelpManagerFlag(aNewValue : boolean) : boolean;
167 begin
168 helpManagerFlag := aNewValue;
169 result := helpManagerFlag;
170 end;
171
172
173 Procedure TCmdLineParameters.parseCmdLine(aCmdLineString : String);
174 var
175 tmpState : (WHITESPACE, QUOTE, SWITCH, FILENAME, TEXT);
176 tmpCurrentParsePosition : integer;
177 tmpQuoted : boolean;
178 tmpCurrentChar : char;
179 tmpWhitespace : String;
180 tmpQuote : String;
181 tmpSwitch : String;
182 begin
183 LogEvent(LogStartup, 'ParseCommandLine: "' + aCmdLineString + '"');
184
185 // store the original string for debugging
186 commandLine := aCmdLineString;
187
188 // reset the whole object
189 showUsageFlag := false;
190 searchFlag := false;
191 globalSearchFlag := false;
192 language := '';
193 helpManagerFlag := false;
194 helpManagerWindow := 0;
195 windowPositionFlag := false;
196 ownerWindow := 0;
197 windowTitle := '';
198 searchText := '';
199 fileNames := '';
200 fileNamesRaw := '';
201
202 try
203 // start parsing
204 tmpState := WHITESPACE;
205 tmpWhitespace := '';
206 tmpSwitch := '';
207 tmpQuote := '';
208 tmpQuoted := false;
209 tmpCurrentParsePosition := 1;
210 while tmpCurrentParsePosition <= length(aCmdLineString) do
211 begin
212 tmpCurrentChar := aCmdLineString[tmpCurrentParsePosition];
213
214 Case tmpCurrentChar of
215 ' ' :
216 begin
217 Case tmpState of
218
219 WHITESPACE :
220 begin
221 tmpWhitespace := tmpWhitespace + tmpCurrentChar;
222 end;
223
224 QUOTE :
225 begin
226 tmpQuote := tmpQuote + tmpCurrentChar;
227 end;
228
229 SWITCH :
230 begin
231 if tmpQuoted then
232 begin
233 tmpSwitch := tmpSwitch + tmpCurrentChar;
234 end
235 else
236 begin
237 parseSwitch(tmpSwitch);
238 tmpState := WHITESPACE;
239 tmpWhitespace := tmpCurrentChar;
240 end
241 end;
242
243 FILENAME :
244 begin
245 if tmpQuoted then
246 begin
247 fileNames := fileNames + tmpCurrentChar;
248 fileNamesRaw := fileNamesRaw + tmpCurrentChar;
249 end
250 else
251 begin
252 tmpState := WHITESPACE;
253 tmpWhitespace := tmpCurrentChar;
254 end
255 end;
256
257 TEXT :
258 begin
259 if tmpQuoted then
260 begin
261 searchText := searchText + tmpCurrentChar;
262 end
263 else
264 begin
265 tmpState := WHITESPACE;
266 tmpWhitespace := tmpCurrentChar;
267 end
268 end;
269 end;
270 end;
271
272 '/', '-' :
273 begin
274 Case tmpState of
275 WHITESPACE :
276 begin
277 tmpState := SWITCH;
278 tmpSwitch := '';
279 end;
280
281 QUOTE :
282 begin
283 tmpState := SWITCH;
284 tmpSwitch := '';
285 end;
286
287 SWITCH :
288 begin
289 parseSwitch(tmpSwitch);
290 tmpSwitch := '';
291 end;
292
293 FILENAME :
294 begin
295 fileNames := fileNames + tmpCurrentChar;
296 fileNamesRaw := fileNamesRaw + tmpCurrentChar;
297 end;
298
299 TEXT :
300 begin
301 searchText := searchText + tmpCurrentChar;
302 end;
303 end;
304 end;
305
306 '"' :
307 begin
308 if tmpQuoted then
309 begin
310 tmpQuoted := false;
311 Case tmpState of
312 FILENAME :
313 begin
314 fileNamesRaw := fileNamesRaw + tmpCurrentChar;
315 end;
316 end;
317 end
318 else
319 begin
320 Case tmpState of
321 WHITESPACE :
322 begin
323 tmpState := QUOTE;
324 tmpQuote := tmpCurrentChar;
325 end;
326 FILENAME :
327 begin
328 fileNamesRaw := fileNamesRaw + tmpCurrentChar;
329 end;
330 end;
331 tmpQuoted := true;
332 end;
333 end;
334
335 // any other char
336 else
337 begin
338 Case tmpState of
339
340 WHITESPACE :
341 begin
342 if length(fileNames) > 0 then
343 begin
344 tmpState := TEXT;
345 searchText := searchText + tmpWhitespace + tmpCurrentChar;
346 end
347 else
348 begin
349 tmpState := FILENAME;
350 fileNames := fileNames + tmpCurrentChar;
351 fileNamesRaw := fileNamesRaw + tmpCurrentChar;
352 end;
353 end;
354
355 QUOTE :
356 begin
357 if length(fileNames) > 0 then
358 begin
359 tmpState := TEXT;
360 searchText := searchText + tmpWhitespace + tmpCurrentChar;
361 end
362 else
363 begin
364 tmpState := FILENAME;
365 fileNames := fileNames + tmpCurrentChar;
366 fileNamesRaw := fileNamesRaw + tmpQuote + tmpCurrentChar;
367 end;
368 end;
369
370 SWITCH :
371 begin
372 tmpSwitch := tmpSwitch + tmpCurrentChar;
373 end;
374
375 FILENAME :
376 begin
377 fileNames := fileNames + tmpCurrentChar;
378 fileNamesRaw := fileNamesRaw + tmpCurrentChar;
379 end;
380
381 TEXT :
382 begin
383 searchText := searchText + tmpCurrentChar;
384 end;
385 end;
386 end;
387 end;
388 inc(tmpCurrentParsePosition);
389 end;
390
391 // ok all chars are processed, but maybe we have something to do
392 Case tmpState of
393 SWITCH :
394 begin
395 parseSwitch(tmpSwitch);
396 end;
397 end;
398
399
400 // TODO remove interpreted
401
402 except
403 on e:EParsingFailed do
404 begin
405 showUsageFlag := true;
406 end;
407 end;
408
409 // remove leading blanks from search text
410 searchText := StrTrim(searchText);
411
412 LogEvent(LogStartup, 'Parameters parsed');
413 LogEvent(LogStartup, ' Filename(s): "' + fileNames + '"');
414 LogEvent(LogStartup, ' Search Text: "' + searchText + '"');
415 end;
416
417
418{
419 FUNCTION TCmdLineParameters.ReadNextPart(const aParseString : String; const aSetOfDelimiterChars : TSetOfChars): String;
420 VAR
421 i : integer;
422 tmpChar : char;
423 BEGIN
424 result := '';
425 for i:= currentParsePosition to length(aParseString) do
426 begin
427 tmpChar := aParseString[i];
428 if tmpChar in aSetOfDelimiterChars then
429 begin
430 i := length(aParseString); // stop parsing
431 end
432 else
433 begin
434 result := result + tmpChar;
435 end;
436 end;
437 END;
438}
439
440
441 Function TCmdLineParameters.handleSwitchWithValue(const aSwitchString : String; const aSwitch : String; var aValue : String) : Boolean;
442 var
443 tmpText : String;
444 tmpValueStartPos : integer;
445 tmpSwitchLength : integer;
446 begin
447 tmpSwitchLength := Length(aSwitch);
448 tmpText := copy(aSwitchString, 1, tmpSwitchLength);
449 tmpText := lowercase(tmpText);
450
451 if (lowercase(aSwitch) = tmpText) then
452 begin
453 tmpValueStartPos := tmpSwitchLength;
454 inc(tmpValueStartPos);
455 if aSwitchString[tmpValueStartPos] = ':' then
456 begin
457 inc(tmpValueStartPos);
458 end;
459
460 aValue := copy(aSwitchString, tmpValueStartPos, Length(aSwitchString) - tmpValueStartPos+ 1);
461 result := true;
462 exit;
463 end;
464 result := false;
465 end;
466
467
468 Function ParseWindowPositionPart(const aPart: String; const aScreenDimension: longint): longint;
469 Var
470 tmpPart : String;
471 Begin
472 if aPart = '' then
473 raise EParsingFailed.Create('Missing position element');
474
475 if StrEndsWithIgnoringCase(aPart, 'P') then
476 begin
477 tmpPart := copy(aPart, 1, length(aPart)-1);
478 if tmpPart = '' then
479 raise EParsingFailed.Create('Missing position element');
480
481 Result := StrToInt(tmpPart);
482 if Result < 0 then
483 Result := 0;
484 if Result > 100 then
485 Result := 100;
486 Result := Round(Result / 100 * aScreenDimension);
487 end
488 else
489 begin
490 Result := StrToInt(aPart);
491 end;
492 end;
493
494 Function ParseWindowPosition(const aParamValue: String): TWindowPosition;
495 Var
496 tmpParts : TStringList;
497 Begin
498 tmpParts := TStringList.Create;
499 StrExtractStrings(tmpParts, aParamValue, [','], '\');
500
501 result.Left := ParseWindowPositionPart(tmpParts[0], WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN));
502 result.Bottom := ParseWindowPositionPart(tmpParts[1], WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN));
503
504 result.Width := ParseWindowPositionPart(tmpParts[2], WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN));
505 if result.Width < 50 then
506 result.Width := 50;
507
508 result.Height := ParseWindowPositionPart(tmpParts[3], WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN));
509 if result.Height < 50 then
510 result.Height := 50;
511
512 tmpParts.Destroy;
513 end;
514
515
516 Procedure TCmdLineParameters.parseSwitch(aSwitchString : String);
517 var
518 tmpCurrentChar : char;
519 tmpText : String;
520 tmpValue : String;
521 begin
522 // lang
523 if handleSwitchWithValue(aSwitchString, 'lang', tmpValue) then
524 begin
525 language := tmpValue;
526 exit;
527 end;
528
529 // title
530 if handleSwitchWithValue(aSwitchString, 'title', tmpValue) then
531 begin
532 windowTitle := tmpValue;
533 exit;
534 end;
535
536 // HM
537 if handleSwitchWithValue(aSwitchString, 'hm', tmpValue) then
538 begin
539 try
540 helpManagerWindow := StrToInt(tmpValue);
541 helpManagerFlag := true;
542 except
543 on e:Exception do
544 begin
545 showUsageFlag := true;
546 end;
547 end;
548 exit;
549 end;
550
551 // owner
552 if handleSwitchWithValue(aSwitchString, 'owner', tmpValue) then
553 begin
554 try
555 ownerWindow := StrToInt(tmpValue);
556 except
557 on e:Exception do
558 begin
559 showUsageFlag := true;
560 end;
561 end;
562 exit;
563 end;
564
565 // pos
566 if handleSwitchWithValue(aSwitchString, 'pos', tmpValue) then
567 begin
568 windowPosition := ParseWindowPosition(tmpValue);
569 windowPositionFlag := true;
570 exit;
571 end;
572
573 // check the next char
574 // TODO check for other invalid chars
575 tmpCurrentChar := aSwitchString[1];
576 Case tmpCurrentChar of
577 'h', 'H', '?' :
578 begin
579 showUsageFlag := true;
580
581 // check for 'help'
582// tmpText := copy(aCmdLineString, 2, 3);
583// tmpText := lowercase(tmpText);
584
585// if ('elp' = tmpText) then
586// begin
587// end;
588 end;
589
590 's', 'S' :
591 begin
592 searchFlag := true;
593 end;
594
595 'g', 'G' :
596 begin
597 globalSearchFlag := true;
598 end;
599
600 else
601 begin
602 raise EParsingFailed.Create('Unsupported switch');
603 end;
604 end;
605 end;
606
607
608 FUNCTION getOwnHelpFileName: String;
609 begin
610 result := FindDefaultLanguageHelpFile('NewView');
611 end;
612
613
614 FUNCTION nativeOS2GetCmdLineParameter : STRING;
615 VAR
616 tmpPtib : PTIB; // thread information block
617 tmpPpib : PPIB; // process information block
618 tmpCmd : PCHAR;
619 tmpResult : PCHAR;
620
621 BEGIN
622 // ask the system
623 DosGetInfoBlocks(tmpPtib, tmpPpib);
624 tmpCmd := tmpPpib^.pib_pchcmd;
625 // the fist element (null terminated) is the
626 // called command itself
627 // skip to the next null terminated string
628 // these are the parameters
629 tmpResult := tmpCmd + StrLen(tmpCmd) + 1;
630 result := StrPas(tmpResult);
631 END;
632END.
Note: See TracBrowser for help on using the repository browser.