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
RevLine 
[23]1Unit CmdLineParameterUnit;
2
3// NewView - a new OS/2 Help Viewer
4// Copyright 2006 Ronald Brill (rbri at rbri dot de)
[42]5// This software is released under the GNU Public License - see readme.txt
[23]6
7// Helper functions to address the command line parameters newview
8// is started with
9
10Interface
11
12uses
[32]13 Os2Def,
14 BseTib,
15 BseDos,
[23]16 SysUtils,
17 Classes,
18 PMWIN,
[42]19 StringUtilsUnit,
20 DebugUnit;
[23]21
22 CONST
23 SUCCESS = 0;
24 ERROR_UNMATCHED_QUOTE = -1;
25
[42]26 TYPE EParsingFailed=CLASS(Exception);
27
[23]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
[42]38 commandLine : String;
[23]39 showUsageFlag : boolean;
[42]40 searchFlag : boolean;
41 globalSearchFlag : boolean;
[23]42 language : string;
43 helpManagerFlag : boolean;
[69]44 helpManagerWindow : HWND;
[23]45 windowPositionFlag: boolean;
46 windowPosition: TWindowPosition;
47 ownerWindow : integer;
48 windowTitle : string;
[25]49 fileNames : string;
[45]50 fileNamesRaw : string;
[42]51 searchText : string;
[23]52
[67]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);
[65]56 PROPERTY getFileNames : string read fileNames;
57 PROPERTY getSearchText : string read searchText;
[42]58
[23]59 public
[42]60 PROPERTY getCommandLine : String read commandLine;
[32]61 PROPERTY getShowUsageFlag : boolean read showUsageFlag;
[42]62 PROPERTY getSearchFlag : boolean read searchFlag;
63 PROPERTY getGlobalSearchFlag : boolean read globalSearchFlag;
[32]64 PROPERTY getLanguage : string read language;
65 PROPERTY getHelpManagerFlag : boolean read helpManagerFlag;
[25]66 FUNCTION setHelpManagerFlag(aNewValue : boolean) : boolean;
[69]67 PROPERTY getHelpManagerWindow : HWND read helpManagerWindow;
[32]68 PROPERTY getWindowPositionFlag : boolean read windowPositionFlag;
69 PROPERTY getWindowPosition : TWindowPosition read windowPosition;
70 PROPERTY getOwnerWindow : integer read ownerWindow;
71 PROPERTY getWindowTitle : string read windowTitle;
[45]72 PROPERTY getFileNamesRaw : string read fileNamesRaw;
[42]73
[65]74 PROCEDURE writeDetailsTo(aStrings : TStrings);
[42]75 PROCEDURE parseCmdLine(aCmdLineString : String);
[54]76
77 FUNCTION getInterpretedFileNames: String;
78 FUNCTION getInterpretedSearchText: String;
[23]79 end;
80
[54]81 FUNCTION getOwnHelpFileName: String;
82
[42]83 // returns a string containing the whole
84 // command line parametes
[54]85 FUNCTION nativeOS2GetCmdLineParameter : String;
[23]86
87
88Implementation
[54]89uses
90 ACLFileUtility;
[23]91
[65]92 PROCEDURE TCmdLineParameters.writeDetailsTo(aStrings : TStrings);
93 var
94 tmpWindowPosition : TWindowPosition;
95 begin
[67]96 aStrings.Add('''' + getCommandLine + '''');
[65]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));
[69]105 aStrings.Add('getHelpManagerWindow: ' + LongWordToStr(getHelpManagerWindow));
[65]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
[67]123 Function TCmdLineParameters.getInterpretedFileNames: String;
[54]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
[67]146 Function TCmdLineParameters.getInterpretedSearchText: String;
[54]147 begin
148 result := getSearchText;
149
150 if getGlobalSearchFlag
151 AND (result = '')
152 then
153 result := getFileNamesRaw;
[65]154
155 if not getGlobalSearchFlag
156 AND (not getSearchFlag)
157 then
158 begin
159 result := StrTrim(result);
160 result := StrTrimChars(result, ['"']);
161 end;
162
[54]163 end;
164
165
[67]166 Function TCmdLineParameters.setHelpManagerFlag(aNewValue : boolean) : boolean;
[25]167 begin
168 helpManagerFlag := aNewValue;
169 result := helpManagerFlag;
170 end;
171
172
[67]173 Procedure TCmdLineParameters.parseCmdLine(aCmdLineString : String);
[23]174 var
[67]175 tmpState : (WHITESPACE, QUOTE, SWITCH, FILENAME, TEXT);
176 tmpCurrentParsePosition : integer;
177 tmpQuoted : boolean;
[42]178 tmpCurrentChar : char;
[67]179 tmpWhitespace : String;
180 tmpQuote : String;
181 tmpSwitch : String;
[23]182 begin
[42]183 LogEvent(LogStartup, 'ParseCommandLine: "' + aCmdLineString + '"');
[25]184
[42]185 // store the original string for debugging
186 commandLine := aCmdLineString;
[23]187
[42]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 := '';
[45]199 fileNames := '';
200 fileNamesRaw := '';
[23]201
[42]202 try
203 // start parsing
[67]204 tmpState := WHITESPACE;
205 tmpWhitespace := '';
206 tmpSwitch := '';
207 tmpQuote := '';
208 tmpQuoted := false;
209 tmpCurrentParsePosition := 1;
210 while tmpCurrentParsePosition <= length(aCmdLineString) do
[42]211 begin
[67]212 tmpCurrentChar := aCmdLineString[tmpCurrentParsePosition];
[23]213
[42]214 Case tmpCurrentChar of
215 ' ' :
[67]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
[42]232 begin
[67]233 tmpSwitch := tmpSwitch + tmpCurrentChar;
234 end
235 else
[42]236 begin
[67]237 parseSwitch(tmpSwitch);
238 tmpState := WHITESPACE;
239 tmpWhitespace := tmpCurrentChar;
240 end
241 end;
242
243 FILENAME :
244 begin
245 if tmpQuoted then
[42]246 begin
[45]247 fileNames := fileNames + tmpCurrentChar;
248 fileNamesRaw := fileNamesRaw + tmpCurrentChar;
[67]249 end
250 else
[42]251 begin
[67]252 tmpState := WHITESPACE;
253 tmpWhitespace := tmpCurrentChar;
254 end
255 end;
256
257 TEXT :
258 begin
259 if tmpQuoted then
260 begin
[42]261 searchText := searchText + tmpCurrentChar;
[67]262 end
263 else
264 begin
265 tmpState := WHITESPACE;
266 tmpWhitespace := tmpCurrentChar;
267 end
[23]268 end;
[42]269 end;
[67]270 end;
[25]271
[42]272 '/', '-' :
[67]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
[42]309 begin
[67]310 tmpQuoted := false;
[23]311 Case tmpState of
[42]312 FILENAME :
[23]313 begin
[45]314 fileNamesRaw := fileNamesRaw + tmpCurrentChar;
[23]315 end;
316 end;
[67]317 end
318 else
[42]319 begin
[23]320 Case tmpState of
[67]321 WHITESPACE :
[23]322 begin
[67]323 tmpState := QUOTE;
324 tmpQuote := tmpCurrentChar;
[23]325 end;
[42]326 FILENAME :
[23]327 begin
[45]328 fileNamesRaw := fileNamesRaw + tmpCurrentChar;
[23]329 end;
[42]330 end;
[67]331 tmpQuoted := true;
[42]332 end;
[67]333 end;
[42]334
[67]335 // any other char
[42]336 else
[67]337 begin
338 Case tmpState of
339
340 WHITESPACE :
341 begin
342 if length(fileNames) > 0 then
[23]343 begin
[67]344 tmpState := TEXT;
345 searchText := searchText + tmpWhitespace + tmpCurrentChar;
346 end
347 else
[23]348 begin
[67]349 tmpState := FILENAME;
[42]350 fileNames := fileNames + tmpCurrentChar;
[45]351 fileNamesRaw := fileNamesRaw + tmpCurrentChar;
[23]352 end;
[67]353 end;
354
355 QUOTE :
356 begin
357 if length(fileNames) > 0 then
[23]358 begin
[67]359 tmpState := TEXT;
360 searchText := searchText + tmpWhitespace + tmpCurrentChar;
361 end
362 else
363 begin
364 tmpState := FILENAME;
[45]365 fileNames := fileNames + tmpCurrentChar;
[67]366 fileNamesRaw := fileNamesRaw + tmpQuote + tmpCurrentChar;
[23]367 end;
[67]368 end;
369
370 SWITCH :
[42]371 begin
[67]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
[42]383 searchText := searchText + tmpCurrentChar;
[23]384 end;
[42]385 end;
386 end;
387 end;
[67]388 inc(tmpCurrentParsePosition);
[42]389 end;
[23]390
[67]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
[42]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
[67]418{
[42]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;
[23]437 END;
[67]438}
[23]439
440
[67]441 Function TCmdLineParameters.handleSwitchWithValue(const aSwitchString : String; const aSwitch : String; var aValue : String) : Boolean;
[42]442 var
443 tmpText : String;
[67]444 tmpValueStartPos : integer;
[42]445 tmpSwitchLength : integer;
446 begin
447 tmpSwitchLength := Length(aSwitch);
[67]448 tmpText := copy(aSwitchString, 1, tmpSwitchLength);
[42]449 tmpText := lowercase(tmpText);
[23]450
[42]451 if (lowercase(aSwitch) = tmpText) then
452 begin
[67]453 tmpValueStartPos := tmpSwitchLength;
454 inc(tmpValueStartPos);
455 if aSwitchString[tmpValueStartPos] = ':' then
[42]456 begin
[67]457 inc(tmpValueStartPos);
[42]458 end;
[23]459
[67]460 aValue := copy(aSwitchString, tmpValueStartPos, Length(aSwitchString) - tmpValueStartPos+ 1);
[42]461 result := true;
462 exit;
463 end;
464 result := false;
465 end;
[23]466
467
[42]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');
[23]474
[42]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');
[23]480
[42]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;
[23]493
[42]494 Function ParseWindowPosition(const aParamValue: String): TWindowPosition;
495 Var
496 tmpParts : TStringList;
497 Begin
498 tmpParts := TStringList.Create;
499 StrExtractStrings(tmpParts, aParamValue, [','], '\');
[23]500
[42]501 result.Left := ParseWindowPositionPart(tmpParts[0], WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN));
502 result.Bottom := ParseWindowPositionPart(tmpParts[1], WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN));
[23]503
[42]504 result.Width := ParseWindowPositionPart(tmpParts[2], WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN));
505 if result.Width < 50 then
506 result.Width := 50;
[23]507
[42]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;
[23]513 end;
514
515
[67]516 Procedure TCmdLineParameters.parseSwitch(aSwitchString : String);
[42]517 var
518 tmpCurrentChar : char;
519 tmpText : String;
520 tmpValue : String;
521 begin
522 // lang
[67]523 if handleSwitchWithValue(aSwitchString, 'lang', tmpValue) then
[42]524 begin
525 language := tmpValue;
526 exit;
527 end;
528
529 // title
[67]530 if handleSwitchWithValue(aSwitchString, 'title', tmpValue) then
[42]531 begin
532 windowTitle := tmpValue;
533 exit;
534 end;
535
536 // HM
[67]537 if handleSwitchWithValue(aSwitchString, 'hm', tmpValue) then
[42]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
[67]552 if handleSwitchWithValue(aSwitchString, 'owner', tmpValue) then
[42]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
[67]566 if handleSwitchWithValue(aSwitchString, 'pos', tmpValue) then
[42]567 begin
568 windowPosition := ParseWindowPosition(tmpValue);
569 windowPositionFlag := true;
570 exit;
571 end;
572
573 // check the next char
[67]574 // TODO check for other invalid chars
575 tmpCurrentChar := aSwitchString[1];
[42]576 Case tmpCurrentChar of
577 'h', 'H', '?' :
578 begin
579 showUsageFlag := true;
580
581 // check for 'help'
[67]582// tmpText := copy(aCmdLineString, 2, 3);
583// tmpText := lowercase(tmpText);
[42]584
[67]585// if ('elp' = tmpText) then
586// begin
587// end;
[42]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;
[23]605 end;
606
[25]607
[54]608 FUNCTION getOwnHelpFileName: String;
609 begin
610 result := FindDefaultLanguageHelpFile('NewView');
611 end;
612
613
[42]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;
[23]632END.
Note: See TracBrowser for help on using the repository browser.