Subversion Repositories fastphp

Rev

Rev 4 | Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 daniel-mar 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.