source: branches/2.19_branch/NewView/CmdLineParameterUnit.pas@ 331

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

warning fixes

  • Property svn:eol-style set to native
File size: 19.5 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 helpManagerFlag : boolean;
44 helpManagerWindow : HWND;
45 windowPositionFlag: boolean;
46 windowPosition: TWindowPosition;
47 ownerWindow : integer;
48 windowTitle : AnsiString;
49 parsedFileNames : AnsiString;
50 parsedRawFileNames : AnsiString;
51 fileNames : AnsiString;
52 parsedSearchText : AnsiString;
53 searchText : AnsiString;
54 debugEnabled : boolean;
55 nhmDebugMessages : TStringList; // for better debugging strange situations
56
57 FUNCTION handleSwitchWithValue(const aSwitchString : String; const aSwitch : String; var aValue : String) : Boolean;
58 PROCEDURE parseSwitch(const aSwitchString : String);
59 PROPERTY getParsedFileNames : AnsiString read parsedFileNames;
60 PROPERTY getParsedSearchText : AnsiString read parsedSearchText;
61
62 public
63 PROPERTY isDebugEnabled : boolean read debugEnabled;
64 PROPERTY getShowUsageFlag : boolean read showUsageFlag;
65 PROPERTY getSearchFlag : boolean read searchFlag;
66 PROPERTY getGlobalSearchFlag : boolean read globalSearchFlag;
67 PROPERTY getLanguage : string read language;
68 PROPERTY getHelpManagerFlag : boolean read helpManagerFlag;
69 FUNCTION setHelpManagerFlag(const aNewValue : boolean) : boolean;
70 PROPERTY getHelpManagerWindow : HWND read helpManagerWindow;
71 PROPERTY getWindowPositionFlag : boolean read windowPositionFlag;
72 PROPERTY getWindowPosition : TWindowPosition read windowPosition;
73 PROPERTY getOwnerWindow : integer read ownerWindow;
74 PROPERTY getWindowTitle : AnsiString read windowTitle;
75 PROPERTY getSearchText : AnsiString read searchText;
76
77 FUNCTION getFileNames(const aShowNewViewHelpIfNoFileSpecifiedFlag : Boolean) : AnsiString;
78
79 PROCEDURE writeDetailsTo(aStrings : TStrings);
80 PROCEDURE logDetails;
81 PROCEDURE parseCmdLine(const aCmdLineString : AnsiString);
82 FUNCTION getOwnHelpFileName: String;
83 PROCEDURE addNhmDebugMessage(const aString : String);
84 end;
85
86 // returns a string containing the whole
87 // command line parametes
88 FUNCTION nativeOS2GetCmdLineParameter : AnsiString;
89
90
91Implementation
92uses
93 DOS,
94 FileUtilsUnit,
95 VersionUnit;
96
97 PROCEDURE TCmdLineParameters.writeDetailsTo(aStrings : TStrings);
98 var
99 tmpWindowPosition : TWindowPosition;
100 i : integer;
101 begin
102 aStrings.Add('---- Version ----');
103 aStrings.Add(' ' + GetAppVersion);
104 aStrings.Add('');
105
106 aStrings.Add('---- Command Line ----');
107 aStrings.Add('''' + commandLine + '''');
108 aStrings.Add('isDebugEnabled: ' + boolToStr(isDebugEnabled));
109
110 aStrings.Add('parsed infos:');
111 aStrings.Add(' showUsageFlag: ' + boolToStr(getShowUsageFlag));
112 aStrings.Add(' searchFlag: ' + boolToStr(getSearchFlag));
113 aStrings.Add(' fileNames(true): ' + getFileNames(true));
114 aStrings.Add(' fileNames(false): ' + getFileNames(false));
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));
123
124 tmpWindowPosition := getWindowPosition;
125 aStrings.Add(' windowPosition: '
126 + intToStr(tmpWindowPosition.left) + ', '
127 + intToStr(tmpWindowPosition.bottom) + ', '
128 + intToStr(tmpWindowPosition.width) + ', '
129 + intToStr(tmpWindowPosition.height)
130 );
131 aStrings.Add(' ownerWindow: ' + intToStr(getOwnerWindow));
132 aStrings.Add(' windowTitle: ' + getWindowTitle);
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
144 end;
145
146
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));
157 LogEvent(LogStartup, ' fileNames(true): ' + getFileNames(true));
158 LogEvent(LogStartup, ' fileNames(false): ' + getFileNames(false));
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
180 Function TCmdLineParameters.setHelpManagerFlag(const aNewValue : boolean) : boolean;
181 begin
182 helpManagerFlag := aNewValue;
183 result := helpManagerFlag;
184 end;
185
186
187 Procedure TCmdLineParameters.parseCmdLine(const aCmdLineString : AnsiString);
188 var
189 tmpState : (WHITESPACE, QUOTE, SWITCH, FILENAME, TEXT);
190 tmpCurrentParsePosition : integer;
191 tmpQuoted : boolean;
192 tmpCurrentChar : char;
193 tmpWhitespace : AnsiString;
194 tmpQuote : AnsiString;
195 tmpSwitch : AnsiString;
196 tmpEnvDebug : String;
197 begin
198 // first adjust logging
199 debugEnabled := false;
200 tmpEnvDebug := GetEnv(ENV_DEBUG);
201
202 if tmpEnvDebug <> '' then
203 begin
204 debugEnabled := true;
205 SetLogAspects(tmpEnvDebug);
206 end;
207
208 LogEvent(LogStartup, 'ParseCommandLine: "' + aCmdLineString + '"');
209
210 // store the original string for debugging
211 commandLine := aCmdLineString;
212
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 := '';
223 parsedSearchText := '';
224 parsedFileNames := '';
225 parsedRawFileNames := '';
226
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];
238
239 Case tmpCurrentChar of
240 ' ' :
241 begin
242 Case tmpState of
243
244 WHITESPACE :
245 begin
246 tmpWhitespace := tmpWhitespace + tmpCurrentChar;
247 end;
248
249 QUOTE :
250 begin
251 tmpQuote := tmpQuote + tmpCurrentChar;
252 end;
253
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;
267
268 FILENAME :
269 begin
270 if tmpQuoted then
271 begin
272 parsedFileNames := parsedFileNames + tmpCurrentChar;
273 parsedRawFileNames := parsedRawFileNames + tmpCurrentChar;
274 end
275 else
276 begin
277 tmpState := WHITESPACE;
278 tmpWhitespace := tmpCurrentChar;
279 end
280 end;
281
282 TEXT :
283 begin
284 if tmpQuoted then
285 begin
286 parsedSearchText := parsedSearchText + tmpCurrentChar;
287 end
288 else
289 begin
290 tmpState := WHITESPACE;
291 tmpWhitespace := tmpCurrentChar;
292 end
293 end;
294 end;
295 end;
296
297 '/', '-' :
298 begin
299 Case tmpState of
300 WHITESPACE :
301 begin
302 tmpState := SWITCH;
303 tmpSwitch := '';
304 end;
305
306 QUOTE :
307 begin
308 tmpState := SWITCH;
309 tmpSwitch := '';
310 end;
311
312 SWITCH :
313 begin
314 parseSwitch(tmpSwitch);
315 tmpSwitch := '';
316 end;
317
318 FILENAME :
319 begin
320 parsedFileNames := parsedFileNames + tmpCurrentChar;
321 parsedRawFileNames := parsedRawFileNames + tmpCurrentChar;
322 end;
323
324 TEXT :
325 begin
326 parsedSearchText := parsedSearchText + tmpCurrentChar;
327 end;
328 end;
329 end;
330
331 '"' :
332 begin
333 if tmpQuoted then
334 begin
335 tmpQuoted := false;
336 Case tmpState of
337 FILENAME :
338 begin
339 parsedRawFileNames := parsedRawFileNames + tmpCurrentChar;
340 end;
341 TEXT :
342 begin
343 parsedSearchText := parsedSearchText + tmpCurrentChar;
344 end;
345 end;
346 end
347 else
348 begin
349 tmpQuoted := true;
350 Case tmpState of
351 WHITESPACE :
352 begin
353 tmpState := QUOTE;
354 tmpQuote := tmpCurrentChar;
355 end;
356 FILENAME :
357 begin
358 parsedRawFileNames := parsedRawFileNames + tmpCurrentChar;
359 end;
360 end;
361 end;
362 end;
363
364 // any other char
365 else
366 begin
367 Case tmpState of
368
369 WHITESPACE :
370 begin
371 if length(parsedFileNames) > 0 then
372 begin
373 tmpState := TEXT;
374 parsedSearchText := parsedSearchText + tmpWhitespace + tmpCurrentChar;
375 end
376 else
377 begin
378 tmpState := FILENAME;
379 parsedFileNames := parsedFileNames + tmpCurrentChar;
380 parsedRawFileNames := parsedRawFileNames + tmpCurrentChar;
381 end;
382 end;
383
384 QUOTE :
385 begin
386 if length(parsedFileNames) > 0 then
387 begin
388 tmpState := TEXT;
389 parsedSearchText := parsedSearchText + tmpQuote + tmpCurrentChar;
390 end
391 else
392 begin
393 tmpState := FILENAME;
394 parsedFileNames := parsedFileNames + tmpCurrentChar;
395 parsedRawFileNames := parsedRawFileNames + tmpQuote + tmpCurrentChar;
396 end;
397 end;
398
399 SWITCH :
400 begin
401 tmpSwitch := tmpSwitch + tmpCurrentChar;
402 end;
403
404 FILENAME :
405 begin
406 parsedFileNames := parsedFileNames + tmpCurrentChar;
407 parsedRawFileNames := parsedRawFileNames + tmpCurrentChar;
408 end;
409
410 TEXT :
411 begin
412 parsedSearchText := parsedSearchText + tmpCurrentChar;
413 end;
414 end;
415 end;
416 end;
417 inc(tmpCurrentParsePosition);
418 end;
419
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;
426 end;
427 except
428 on e:EParsingFailed do
429 begin
430 showUsageFlag := true;
431 end;
432 end;
433
434 // remove blanks
435 fileNames := AnsiStrTrim(getParsedFileNames);
436 searchText := AnsiStrTrim(getParsedSearchText);
437
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
452 searchText := AnsiStrTrimChars(searchText, ['"']);
453 end;
454
455 LogEvent(LogStartup, 'Parameters parsed');
456 LogDetails;
457 end;
458
459
460 Function TCmdLineParameters.handleSwitchWithValue(const aSwitchString : String; const aSwitch : String; var aValue : String) : Boolean;
461 var
462 tmpText : String;
463 tmpValueStartPos : integer;
464 tmpSwitchLength : integer;
465 begin
466 tmpSwitchLength := Length(aSwitch);
467 tmpText := copy(aSwitchString, 1, tmpSwitchLength);
468 tmpText := lowercase(tmpText);
469
470 if (lowercase(aSwitch) = tmpText) then
471 begin
472 tmpValueStartPos := tmpSwitchLength;
473 inc(tmpValueStartPos);
474 if aSwitchString[tmpValueStartPos] = ':' then
475 begin
476 inc(tmpValueStartPos);
477 end;
478
479 aValue := copy(aSwitchString, tmpValueStartPos, Length(aSwitchString) - tmpValueStartPos+ 1);
480 result := true;
481 exit;
482 end;
483 result := false;
484 end;
485
486
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');
493
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');
499
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;
512
513 Function ParseWindowPosition(const aParamValue: String): TWindowPosition;
514 Var
515 tmpParts : TStringList;
516 tmpScreenWidth : longint;
517 tmpScreenHeight : longint;
518 Begin
519 tmpParts := TStringList.Create;
520 StrExtractStrings(tmpParts, aParamValue, [','], '\');
521
522 tmpScreenWidth := WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN);
523 tmpScreenHeight := WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN);
524
525 result.Left := ParseWindowPositionPart(tmpParts[0], tmpScreenWidth);
526 result.Bottom := ParseWindowPositionPart(tmpParts[1], tmpScreenHeight);
527
528 result.Width := ParseWindowPositionPart(tmpParts[2], tmpScreenWidth);
529 if result.Width < 50 then
530 result.Width := 50;
531
532 result.Height := ParseWindowPositionPart(tmpParts[3], tmpScreenHeight);
533 if result.Height < 50 then
534 result.Height := 50;
535
536 tmpParts.Destroy;
537 end;
538
539
540 Procedure TCmdLineParameters.parseSwitch(const aSwitchString : String);
541 var
542 tmpCurrentChar : char;
543 tmpValue : String;
544 begin
545 // lang
546 if handleSwitchWithValue(aSwitchString, 'lang', tmpValue) then
547 begin
548 language := tmpValue;
549 exit;
550 end;
551
552 // title
553 if handleSwitchWithValue(aSwitchString, 'title', tmpValue) then
554 begin
555 windowTitle := tmpValue;
556 exit;
557 end;
558
559 // HM
560 if handleSwitchWithValue(aSwitchString, 'hm', tmpValue) then
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
575 if handleSwitchWithValue(aSwitchString, 'owner', tmpValue) then
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
589 if handleSwitchWithValue(aSwitchString, 'pos', tmpValue) then
590 begin
591 windowPosition := ParseWindowPosition(tmpValue);
592 windowPositionFlag := true;
593 exit;
594 end;
595
596 // check the next char
597 // TODO check for other invalid chars
598 tmpCurrentChar := aSwitchString[1];
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;
620 end;
621
622
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
647 FUNCTION TCmdLineParameters.getOwnHelpFileName: String;
648 var
649 tmpLanguage : String;
650 begin
651 tmpLanguage := getLanguage;
652 if tmpLanguage = '' then
653 begin
654 tmpLanguage := GetEnv(LanguageEnvironmentVar)
655 end;
656
657 result := FindDefaultLanguageHelpFile('NewView', tmpLanguage);
658 end;
659
660
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
672 FUNCTION nativeOS2GetCmdLineParameter : AnsiString;
673 VAR
674 tmpPtib : PTIB; // thread information block
675 tmpPpib : PPIB; // process information block
676 tmpCmd : PCHAR;
677 tmpParams : PCHAR;
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
687 tmpParams := tmpCmd + StrLen(tmpCmd) + 1;
688
689 result := '';
690 AnsiSetString(result, tmpParams, StrLen(tmpParams));
691 END;
692
693
694END.
Note: See TracBrowser for help on using the repository browser.