source: trunk/NewView/CmdLineParameterUnit.pas@ 128

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

% file name handling to be more flexible for settings

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