source: trunk/NewView/CmdLineParameterUnit.pas@ 145

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

% file name handling to be more flexible for settings

  • Property svn:eol-style set to native
File size: 18.7 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
56 FUNCTION handleSwitchWithValue(const aSwitchString : String; const aSwitch : String; var aValue : String) : Boolean;
57 PROCEDURE parseSwitch(const aSwitchString : String);
58 PROPERTY getParsedFileNames : AnsiString read parsedFileNames;
59 PROPERTY getParsedSearchText : AnsiString read parsedSearchText;
60
61 public
62 PROPERTY isDebugEnabled : boolean read debugEnabled;
63 PROPERTY getShowUsageFlag : boolean read showUsageFlag;
64 PROPERTY getSearchFlag : boolean read searchFlag;
65 PROPERTY getGlobalSearchFlag : boolean read globalSearchFlag;
66 PROPERTY getLanguage : string read language;
67 PROPERTY getHelpManagerFlag : boolean read helpManagerFlag;
68 FUNCTION setHelpManagerFlag(const aNewValue : boolean) : boolean;
69 PROPERTY getHelpManagerWindow : HWND read helpManagerWindow;
70 PROPERTY getWindowPositionFlag : boolean read windowPositionFlag;
71 PROPERTY getWindowPosition : TWindowPosition read windowPosition;
72 PROPERTY getOwnerWindow : integer read ownerWindow;
73 PROPERTY getWindowTitle : AnsiString read windowTitle;
74 PROPERTY getSearchText : AnsiString read searchText;
75
76 FUNCTION getFileNames(const aShowNewViewHelpIfNoFileSpecifiedFlag : Boolean) : AnsiString;
77
78 PROCEDURE writeDetailsTo(aStrings : TStrings);
79 PROCEDURE logDetails;
80 PROCEDURE parseCmdLine(const aCmdLineString : AnsiString);
81 FUNCTION getOwnHelpFileName: String;
82 end;
83
84 // returns a string containing the whole
85 // command line parametes
86 FUNCTION nativeOS2GetCmdLineParameter : AnsiString;
87
88
89Implementation
90uses
91 DOS,
92 FileUtilsUnit;
93
94 PROCEDURE TCmdLineParameters.writeDetailsTo(aStrings : TStrings);
95 var
96 tmpWindowPosition : TWindowPosition;
97 begin
98 aStrings.Add('''' + commandLine + '''');
99 aStrings.Add('isDebugEnabled: ' + boolToStr(isDebugEnabled));
100
101 aStrings.Add('parsed infos:');
102 aStrings.Add(' showUsageFlag: ' + boolToStr(getShowUsageFlag));
103 aStrings.Add(' searchFlag: ' + boolToStr(getSearchFlag));
104 aStrings.Add(' fileNames(true): ' + getFileNames(true));
105 aStrings.Add(' fileNames(false): ' + getFileNames(false));
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));
114
115 tmpWindowPosition := getWindowPosition;
116 aStrings.Add(' windowPosition: '
117 + intToStr(tmpWindowPosition.left) + ', '
118 + intToStr(tmpWindowPosition.bottom) + ', '
119 + intToStr(tmpWindowPosition.width) + ', '
120 + intToStr(tmpWindowPosition.height)
121 );
122 aStrings.Add(' ownerWindow: ' + intToStr(getOwnerWindow));
123 aStrings.Add(' windowTitle: ' + getWindowTitle);
124 end;
125
126
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));
137 LogEvent(LogStartup, ' fileNames(true): ' + getFileNames(true));
138 LogEvent(LogStartup, ' fileNames(false): ' + getFileNames(false));
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
160 Function TCmdLineParameters.setHelpManagerFlag(const aNewValue : boolean) : boolean;
161 begin
162 helpManagerFlag := aNewValue;
163 result := helpManagerFlag;
164 end;
165
166
167 Procedure TCmdLineParameters.parseCmdLine(const aCmdLineString : AnsiString);
168 var
169 tmpState : (WHITESPACE, QUOTE, SWITCH, FILENAME, TEXT);
170 tmpCurrentParsePosition : integer;
171 tmpQuoted : boolean;
172 tmpCurrentChar : char;
173 tmpWhitespace : AnsiString;
174 tmpQuote : AnsiString;
175 tmpSwitch : AnsiString;
176 tmpEnvDebug : String;
177 begin
178 // first adjust logging
179 debugEnabled := false;
180 tmpEnvDebug := GetEnv(ENV_DEBUG);
181
182 if tmpEnvDebug <> '' then
183 begin
184 debugEnabled := true;
185 SetLogAspects(tmpEnvDebug);
186 end;
187
188 LogEvent(LogStartup, 'ParseCommandLine: "' + aCmdLineString + '"');
189
190 // store the original string for debugging
191 commandLine := aCmdLineString;
192
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 := '';
203 parsedSearchText := '';
204 parsedFileNames := '';
205 parsedRawFileNames := '';
206
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];
218
219 Case tmpCurrentChar of
220 ' ' :
221 begin
222 Case tmpState of
223
224 WHITESPACE :
225 begin
226 tmpWhitespace := tmpWhitespace + tmpCurrentChar;
227 end;
228
229 QUOTE :
230 begin
231 tmpQuote := tmpQuote + tmpCurrentChar;
232 end;
233
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;
247
248 FILENAME :
249 begin
250 if tmpQuoted then
251 begin
252 parsedFileNames := parsedFileNames + tmpCurrentChar;
253 parsedRawFileNames := parsedRawFileNames + tmpCurrentChar;
254 end
255 else
256 begin
257 tmpState := WHITESPACE;
258 tmpWhitespace := tmpCurrentChar;
259 end
260 end;
261
262 TEXT :
263 begin
264 if tmpQuoted then
265 begin
266 parsedSearchText := parsedSearchText + tmpCurrentChar;
267 end
268 else
269 begin
270 tmpState := WHITESPACE;
271 tmpWhitespace := tmpCurrentChar;
272 end
273 end;
274 end;
275 end;
276
277 '/', '-' :
278 begin
279 Case tmpState of
280 WHITESPACE :
281 begin
282 tmpState := SWITCH;
283 tmpSwitch := '';
284 end;
285
286 QUOTE :
287 begin
288 tmpState := SWITCH;
289 tmpSwitch := '';
290 end;
291
292 SWITCH :
293 begin
294 parseSwitch(tmpSwitch);
295 tmpSwitch := '';
296 end;
297
298 FILENAME :
299 begin
300 parsedFileNames := parsedFileNames + tmpCurrentChar;
301 parsedRawFileNames := parsedRawFileNames + tmpCurrentChar;
302 end;
303
304 TEXT :
305 begin
306 parsedSearchText := parsedSearchText + tmpCurrentChar;
307 end;
308 end;
309 end;
310
311 '"' :
312 begin
313 if tmpQuoted then
314 begin
315 tmpQuoted := false;
316 Case tmpState of
317 FILENAME :
318 begin
319 parsedRawFileNames := parsedRawFileNames + tmpCurrentChar;
320 end;
321 TEXT :
322 begin
323 parsedSearchText := parsedSearchText + tmpCurrentChar;
324 end;
325 end;
326 end
327 else
328 begin
329 tmpQuoted := true;
330 Case tmpState of
331 WHITESPACE :
332 begin
333 tmpState := QUOTE;
334 tmpQuote := tmpCurrentChar;
335 end;
336 FILENAME :
337 begin
338 parsedRawFileNames := parsedRawFileNames + tmpCurrentChar;
339 end;
340 end;
341 end;
342 end;
343
344 // any other char
345 else
346 begin
347 Case tmpState of
348
349 WHITESPACE :
350 begin
351 if length(parsedFileNames) > 0 then
352 begin
353 tmpState := TEXT;
354 parsedSearchText := parsedSearchText + tmpWhitespace + tmpCurrentChar;
355 end
356 else
357 begin
358 tmpState := FILENAME;
359 parsedFileNames := parsedFileNames + tmpCurrentChar;
360 parsedRawFileNames := parsedRawFileNames + tmpCurrentChar;
361 end;
362 end;
363
364 QUOTE :
365 begin
366 if length(parsedFileNames) > 0 then
367 begin
368 tmpState := TEXT;
369 parsedSearchText := parsedSearchText + tmpQuote + tmpCurrentChar;
370 end
371 else
372 begin
373 tmpState := FILENAME;
374 parsedFileNames := parsedFileNames + tmpCurrentChar;
375 parsedRawFileNames := parsedRawFileNames + tmpQuote + tmpCurrentChar;
376 end;
377 end;
378
379 SWITCH :
380 begin
381 tmpSwitch := tmpSwitch + tmpCurrentChar;
382 end;
383
384 FILENAME :
385 begin
386 parsedFileNames := parsedFileNames + tmpCurrentChar;
387 parsedRawFileNames := parsedRawFileNames + tmpCurrentChar;
388 end;
389
390 TEXT :
391 begin
392 parsedSearchText := parsedSearchText + tmpCurrentChar;
393 end;
394 end;
395 end;
396 end;
397 inc(tmpCurrentParsePosition);
398 end;
399
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;
406 end;
407 except
408 on e:EParsingFailed do
409 begin
410 showUsageFlag := true;
411 end;
412 end;
413
414 // remove blanks
415 fileNames := AnsiStrTrim(getParsedFileNames);
416 searchText := AnsiStrTrim(getParsedSearchText);
417
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
432 searchText := AnsiStrTrimChars(searchText, ['"']);
433 end;
434
435 LogEvent(LogStartup, 'Parameters parsed');
436 LogDetails;
437 end;
438
439
440 Function TCmdLineParameters.handleSwitchWithValue(const aSwitchString : String; const aSwitch : String; var aValue : String) : Boolean;
441 var
442 tmpText : String;
443 tmpValueStartPos : integer;
444 tmpSwitchLength : integer;
445 begin
446 tmpSwitchLength := Length(aSwitch);
447 tmpText := copy(aSwitchString, 1, tmpSwitchLength);
448 tmpText := lowercase(tmpText);
449
450 if (lowercase(aSwitch) = tmpText) then
451 begin
452 tmpValueStartPos := tmpSwitchLength;
453 inc(tmpValueStartPos);
454 if aSwitchString[tmpValueStartPos] = ':' then
455 begin
456 inc(tmpValueStartPos);
457 end;
458
459 aValue := copy(aSwitchString, tmpValueStartPos, Length(aSwitchString) - tmpValueStartPos+ 1);
460 result := true;
461 exit;
462 end;
463 result := false;
464 end;
465
466
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');
473
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');
479
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;
492
493 Function ParseWindowPosition(const aParamValue: String): TWindowPosition;
494 Var
495 tmpParts : TStringList;
496 Begin
497 tmpParts := TStringList.Create;
498 StrExtractStrings(tmpParts, aParamValue, [','], '\');
499
500 result.Left := ParseWindowPositionPart(tmpParts[0], WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN));
501 result.Bottom := ParseWindowPositionPart(tmpParts[1], WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN));
502
503 result.Width := ParseWindowPositionPart(tmpParts[2], WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN));
504 if result.Width < 50 then
505 result.Width := 50;
506
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;
512 end;
513
514
515 Procedure TCmdLineParameters.parseSwitch(const aSwitchString : String);
516 var
517 tmpCurrentChar : char;
518 tmpValue : String;
519 begin
520 // lang
521 if handleSwitchWithValue(aSwitchString, 'lang', tmpValue) then
522 begin
523 language := tmpValue;
524 exit;
525 end;
526
527 // title
528 if handleSwitchWithValue(aSwitchString, 'title', tmpValue) then
529 begin
530 windowTitle := tmpValue;
531 exit;
532 end;
533
534 // HM
535 if handleSwitchWithValue(aSwitchString, 'hm', tmpValue) then
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
550 if handleSwitchWithValue(aSwitchString, 'owner', tmpValue) then
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
564 if handleSwitchWithValue(aSwitchString, 'pos', tmpValue) then
565 begin
566 windowPosition := ParseWindowPosition(tmpValue);
567 windowPositionFlag := true;
568 exit;
569 end;
570
571 // check the next char
572 // TODO check for other invalid chars
573 tmpCurrentChar := aSwitchString[1];
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;
595 end;
596
597
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
622 FUNCTION TCmdLineParameters.getOwnHelpFileName: String;
623 var
624 tmpLanguage : String;
625 begin
626 tmpLanguage := getLanguage;
627 if tmpLanguage = '' then
628 begin
629 tmpLanguage := GetEnv(LanguageEnvironmentVar)
630 end;
631
632 result := FindDefaultLanguageHelpFile('NewView', tmpLanguage);
633 end;
634
635
636 FUNCTION nativeOS2GetCmdLineParameter : AnsiString;
637 VAR
638 tmpPtib : PTIB; // thread information block
639 tmpPpib : PPIB; // process information block
640 tmpCmd : PCHAR;
641 tmpParams : PCHAR;
642 tmpResult : AnsiString;
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
652 tmpParams := tmpCmd + StrLen(tmpCmd) + 1;
653
654 result := '';
655 AnsiSetString(result, tmpParams, StrLen(tmpParams));
656 END;
657END.
Note: See TracBrowser for help on using the repository browser.