source: trunk/NewView/CmdLineParameterUnit.pas@ 259

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

support -i option

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