source: trunk/NewView/CmdLineParameterUnit.pas@ 433

Last change on this file since 433 was 168, checked in by RBRi, 18 years ago

warning fixes

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