source: trunk/NewView/CmdLineParameterUnit.pas@ 82

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

file util refactoring and many more unit tests

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