Subversion Repositories fastphp

Rev

Rev 4 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. unit Functions;
  2.  
  3. interface
  4.  
  5. uses
  6.   Windows, Messages, SysUtils, StrUtils, IniFiles, Classes, Forms, Variants, MsHTML,
  7.   SHDocVw, StdCtrls;
  8.  
  9. function GetDosOutput(CommandLine: string; Work: string = ''): string;
  10. function StrIPos(const SubStr, S: string): Integer;
  11. procedure WaitForBrowser(WB: TWebbrowser);
  12. function LoadFileToStr(const FileName: TFileName): AnsiString;
  13. function LastPos(const SubStr, S: string): integer;
  14. function ParseCHM(chmFile: string): boolean;
  15. procedure BrowseURL(WebBrowser1: TWebBrowser; url: string);
  16. procedure BrowseContent(WebBrowser1: TWebBrowser; html: string);
  17. function IsTextHTML(s: string): boolean;
  18. function GetWordUnderCaret(AMemo: TMemo): string;
  19. function IsValidPHPExe(const exeFile: string): boolean;
  20.  
  21. implementation
  22.  
  23. function GetDosOutput(CommandLine: string; Work: string = ''): string;
  24. var
  25.   SA: TSecurityAttributes;
  26.   SI: TStartupInfo;
  27.   PI: TProcessInformation;
  28.   StdOutPipeRead, StdOutPipeWrite: THandle;
  29.   WasOK: Boolean;
  30.   Buffer: array[0..255] of AnsiChar;
  31.   BytesRead: Cardinal;
  32.   WorkDir: string;
  33.   Handle: Boolean;
  34. begin
  35.   if Work = '' then Work := ExtractFilePath(ParamStr(0));
  36.  
  37.   Result := '';
  38.   with SA do begin
  39.     nLength := SizeOf(SA);
  40.     bInheritHandle := True;
  41.     lpSecurityDescriptor := nil;
  42.   end;
  43.   CreatePipe(StdOutPipeRead, StdOutPipeWrite, @SA, 0);
  44.   try
  45.     with SI do
  46.     begin
  47.       FillChar(SI, SizeOf(SI), 0);
  48.       cb := SizeOf(SI);
  49.       dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
  50.       wShowWindow := SW_HIDE;
  51.       hStdInput := GetStdHandle(STD_INPUT_HANDLE); // don't redirect stdin
  52.       hStdOutput := StdOutPipeWrite;
  53.       hStdError := StdOutPipeWrite;
  54.     end;
  55.     WorkDir := Work;
  56.     Handle := CreateProcess(nil, PChar('cmd.exe /C "' + CommandLine + '"'),
  57.                             nil, nil, True, 0, nil,
  58.                             PChar(WorkDir), SI, PI);
  59.     CloseHandle(StdOutPipeWrite);
  60.     if Handle then
  61.       try
  62.         repeat
  63.           WasOK := ReadFile(StdOutPipeRead, Buffer, 255, BytesRead, nil);
  64.           if BytesRead > 0 then
  65.           begin
  66.             Buffer[BytesRead] := #0;
  67.             Result := Result + Buffer;
  68.           end;
  69.         until not WasOK or (BytesRead = 0);
  70.         WaitForSingleObject(PI.hProcess, INFINITE);
  71.       finally
  72.         CloseHandle(PI.hThread);
  73.         CloseHandle(PI.hProcess);
  74.       end;
  75.   finally
  76.     CloseHandle(StdOutPipeRead);
  77.   end;
  78. end;
  79.  
  80. function StrIPos(const SubStr, S: string): Integer;
  81. begin
  82.   Result := Pos(UpperCase(SubStr), UpperCase(S));
  83. end;
  84.  
  85. procedure WaitForBrowser(WB: TWebbrowser);
  86. begin
  87.   while (WB.Busy)
  88.     and not (Application.Terminated) do
  89.   begin
  90.     Application.ProcessMessages;
  91.     Sleep(100);
  92.   end;
  93. end;
  94.  
  95. function LoadFileToStr(const FileName: TFileName): AnsiString;
  96. var
  97.   FileStream : TFileStream;
  98.  
  99. begin
  100.   Result:= '';
  101.   FileStream:= TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
  102.   try
  103.     if FileStream.Size>0 then begin
  104.       SetLength(Result, FileStream.Size);
  105.       FileStream.Read(Result[1], FileStream.Size);
  106.     end;
  107.   finally
  108.     FileStream.Free;
  109.   end;
  110. end;
  111.  
  112. function LastPos(const SubStr, S: string): integer;
  113. var
  114.   I, J, K: integer;
  115. begin
  116.   Result := 0;
  117.   I := Length(S);
  118.   K := Length(SubStr);
  119.   if (K = 0) or (K > I) then
  120.     Exit;
  121.   while (Result = 0) and (I >= K) do
  122.   begin
  123.     J := K;
  124.     if S[I] = SubStr[J] then
  125.     begin
  126.       while (J > 1) and (S[I + J - K - 1] = SubStr[J - 1]) do
  127.         Dec(J);
  128.       if J = 1 then
  129.         Result := I - K + 1;
  130.     end;
  131.     Dec(I);
  132.   end;
  133. end;
  134.  
  135. function ParseCHM(chmFile: string): boolean;
  136. var
  137.   test, candidate, candidate2: string;
  138.   p, p2, q: integer;
  139.   i: integer;
  140.   good: Boolean;
  141.   ini: TMemIniFile;
  142.   domain: string;
  143.   sl: TStringList;
  144.   symbolCount: Integer;
  145.   sl2: TStrings;
  146.   outFile: string;
  147. begin
  148.   // TODO: problem:  mysqli::commit has /res/mysqli.commit.html -> keyword is NOT commit alone
  149.  
  150.   outFile := ChangeFileExt(chmFile, '.ini');
  151.   DeleteFile(outFile);
  152.   test := LoadFileToStr(chmFile);
  153.   if Pos('/php_manual_', test) = -1 then
  154.   begin
  155.     result := false;
  156.     exit;
  157.   end;
  158.   p := 0;
  159.   ini := TMemIniFile.Create(outFile);
  160.   try
  161.     ini.WriteString('_Info_', 'Source', chmFile);
  162.     ini.WriteString('_Info_', 'Generated', DateTimeToStr(Now));
  163.     ini.WriteString('_Info_', 'GeneratorVer', '1.0');
  164.     ini.WriteString('_Info_', 'Signature', '$ViaThinkSoft$');
  165.     {$REGION 'Excludes'}
  166.     // TODO: more excludes
  167.     ini.WriteBool('_HelpExclude_', 'about', true);
  168.     ini.WriteBool('_HelpExclude_', 'apache', true);
  169.     {$ENDREGION}
  170.     while true do
  171.     begin
  172.       Application.ProcessMessages;
  173.  
  174.       p := PosEx('/res/', Test, p+1);
  175.       if p = 0 then break;
  176.       p2 := PosEx('.html', Test, p);
  177.       if p = 0 then break;
  178.       candidate := copy(Test, p+5, p2-p-5);
  179.       if candidate = '' then continue;
  180.       if Length(candidate) > 50 then continue;
  181.       good := true;
  182.       for i := p+5 to p2-1 do
  183.       begin
  184.         if ord(test[i]) < 32 then
  185.         begin
  186.           good := false;
  187.           break;
  188.         end;
  189.         if not (test[i] in ['a'..'z', 'A'..'Z', '.', '-', '_', '0'..'9']) then
  190.         begin
  191.           ini.WriteInteger('_Errors_', 'Contains unexpected character! ' + candidate, ini.ReadInteger('_Errors_', 'Contains unexpected character! ' + candidate, 0)+1);
  192.           good := false;
  193.           break;
  194.         end;
  195.       end;
  196.       if good then
  197.       begin
  198.         candidate2 := LowerCase(StringReplace(candidate, '-', '_', [rfReplaceAll]));
  199.         q := LastPos('.', candidate2);
  200.         domain := copy(candidate2, 1, q-1);
  201.         if domain = '' then continue;
  202.         candidate2 := copy(candidate2, q+1, Length(candidate2)-q);
  203.         ini.WriteInteger('_Category_', domain, ini.ReadInteger('_Category_', domain, 0)+1);
  204.         ini.WriteString(domain, candidate2, '/res/'+candidate+'.html');
  205.         if not ini.ReadBool('_HelpExclude_', domain, false)
  206.            and (candidate2 <> 'configuration')
  207.            and (candidate2 <> 'constants')
  208.            and (candidate2 <> 'installation')
  209.            and (candidate2 <> 'requirements')
  210.            and (candidate2 <> 'resources')
  211.            and (candidate2 <> 'setup') then
  212.         begin
  213.           if ini.ReadString('_HelpWords_', candidate2, '') <> '' then
  214.           begin
  215.             ini.WriteInteger('_Conflicts_', candidate2, ini.ReadInteger('_Conflicts_', candidate2, 0)+1);
  216.           end;
  217.  
  218.           ini.WriteString('_HelpWords_', candidate2, '/res/'+candidate+'.html');
  219.         end;
  220.       end;
  221.     end;
  222.  
  223.     sl := TStringList.Create;
  224.     sl2 := TStringList.Create;
  225.     try
  226.       ini.ReadSections(sl);
  227.       ini.WriteInteger('_Info_', 'TotalDomains', sl.Count);
  228.       symbolCount := 0;
  229.       for domain in sl do
  230.       begin
  231.         ini.ReadSection(domain, sl2);
  232.         Inc(symbolCount, sl2.Count)
  233.       end;
  234.       ini.WriteInteger('_Info_', 'TotalSymbols', symbolCount);
  235.     finally
  236.       sl.Free;
  237.       sl2.Free;
  238.     end;
  239.  
  240.     ini.UpdateFile;
  241.     result := true;
  242.   finally
  243.     ini.Free;
  244.   end;
  245. end;
  246.  
  247. procedure BrowseURL(WebBrowser1: TWebBrowser; url: string);
  248. var
  249.   BrowserFlags : olevariant;
  250.   MyTargetFrameName : olevariant;
  251.   MyPostaData : olevariant;
  252.   MyHeaders : olevariant;
  253. begin
  254. { Flags:
  255. Constant            Value Meaning
  256. NavOpenInNewWindow  $01  Open the resource or file in a new window.
  257. NavNoHistory        $02  Do not add the resource or file to the history list. The new page replaces the current page in the list.
  258. NavNoReadFromCache  $04  Do not read from the disk cache for this navigation.
  259. NavNoWriteToCache   $08  Do not write the results of this navigation to the disk cache.
  260. NavAllowAutosearch  $10  If the navigation fails, the Web browser attempts to navigate common root domains (.com, .org, and so on). If this still fails, the URL is passed to a search engine.
  261. }
  262.   BrowserFlags := $02;
  263.   MyTargetFrameName := null;
  264.   MyPostaData := null;
  265.   MyHeaders := null;
  266.   WebBrowser1.Silent := true; // no JavaScript errors
  267.   Webbrowser1.Navigate(url, BrowserFlags,MyTargetFrameName,MyPostaData,MyHeaders);
  268.   WaitForBrowser(WebBrowser1);
  269. end;
  270.  
  271. procedure BrowseContent(WebBrowser1: TWebBrowser; html: string);
  272. var
  273.   BrowserFlags : olevariant;
  274.   MyTargetFrameName : olevariant;
  275.   MyPostaData : olevariant;
  276.   MyHeaders : olevariant;
  277.   Doc: Variant;
  278. begin
  279. { Flags:
  280. Constant            Value Meaning
  281. NavOpenInNewWindow  $01  Open the resource or file in a new window.
  282. NavNoHistory        $02  Do not add the resource or file to the history list. The new page replaces the current page in the list.
  283. NavNoReadFromCache  $04  Do not read from the disk cache for this navigation.
  284. NavNoWriteToCache   $08  Do not write the results of this navigation to the disk cache.
  285. NavAllowAutosearch  $10  If the navigation fails, the Web browser attempts to navigate common root domains (.com, .org, and so on). If this still fails, the URL is passed to a search engine.
  286. }
  287.   if WebBrowser1.Document = nil then
  288.   begin
  289.     BrowserFlags := $02 + $04 + $08 + $10;
  290.     MyTargetFrameName := null;
  291.     MyPostaData := null;
  292.     MyHeaders := null;
  293.     Webbrowser1.Navigate('about:blank', BrowserFlags,MyTargetFrameName,MyPostaData,MyHeaders);
  294.     WaitForBrowser(WebBrowser1);
  295.   end;
  296.  
  297.   Doc := WebBrowser1.Document;
  298.   Doc.Clear;
  299.   Doc.Write(html);
  300.   Doc.Close;
  301.   WaitForBrowser(WebBrowser1);
  302. end;
  303.  
  304. function IsTextHTML(s: string): boolean;
  305.  
  306.   function _Tag(const tag: string): integer;
  307.   begin
  308.     result := 0;
  309.     if (StrIPos('<'+tag+'>', s) > 0) then Inc(result);
  310.     if (StrIPos('</'+tag+'>', s) > 0) then Inc(result);
  311.     if (StrIPos('<'+tag+' />', s) > 0) then Inc(result);
  312.     if (StrIPos('<'+tag+' ', s) > 0) then Inc(result);
  313.   end;
  314.  
  315. var
  316.   score: integer;
  317. begin
  318.   score := _Tag('html') + _Tag('body') + _Tag('p') + _Tag('a') + _Tag('b') +
  319.            _Tag('i') + _Tag('u') + _Tag('li') + _Tag('ol') + _Tag('ul') +
  320.            _Tag('img') + _Tag('div') + _Tag('hr') + _Tag('code') +
  321.            _Tag('pre') + _Tag('blockquote') + _Tag('span');
  322.   result := score >= 2;
  323. end;
  324.  
  325. // Template: http://stackoverflow.com/questions/6339446/delphi-get-the-whole-word-where-the-caret-is-in-a-memo
  326. function GetWordUnderCaret(AMemo: TMemo): string;
  327.  
  328.   function ValidChar(c: char): boolean;
  329.   begin
  330.     result := c in ['a'..'z', 'A'..'Z', '0'..'9', '_'];
  331.   end;
  332.  
  333. var
  334.    Line    : Integer;
  335.    Column  : Integer;
  336.    LineText: string;
  337.    InitPos : Integer;
  338.    EndPos  : Integer;
  339. begin
  340.    //Get the caret position
  341.    Line   := AMemo.Perform(EM_LINEFROMCHAR,AMemo.SelStart, 0) ;
  342.    Column := AMemo.SelStart - AMemo.Perform(EM_LINEINDEX, Line, 0) ;
  343.    //Validate the line number
  344.    if AMemo.Lines.Count-1 < Line then Exit;
  345.  
  346.    //Get the text of the line
  347.    LineText := AMemo.Lines[Line];
  348.  
  349.    // Column zeigt auf das Zeichen LINKS vom Cursor!
  350.  
  351.    InitPos := Column;
  352.    if not ValidChar(LineText[InitPos]) then Inc(InitPos);
  353.    while (InitPos-1 >= 1) and ValidChar(LineText[InitPos-1]) do Dec(InitPos);
  354.  
  355.    EndPos := Column;
  356.    while (EndPos+1 <= Length(LineText)) and ValidChar(LineText[EndPos+1]) do Inc(EndPos);
  357.  
  358.    //Get the text
  359.    Result := Copy(LineText, InitPos, EndPos - InitPos + 1);
  360. end;
  361.  
  362. function IsValidPHPExe(const exeFile: string): boolean;
  363. var
  364.   cont: string;
  365. begin
  366.   cont := LoadFileToStr(exeFile);
  367.   result := (Pos('php://stdout', cont) >= 0) or
  368.             (Pos('PHP_SELF', cont) >= 0);
  369. end;
  370.  
  371. end.
  372.