root/trunk/ExtraFunctionsLcl.pas

Revision 164, 34.5 kB (checked in by sagrer, 5 months ago)

Добавил новый класс TListOfStringLists - что-то вроде двумерного массива - список списков строк - будет использоваться в некоторых местах. Тест класса добавлен в тестовую прогу, вроде как все протестировано.

  • Property svnmailer:content-charset set to cp1251
Line 
1 ///////////////////////////////////////////////////////////
2 //                   ExtraFunctionsFcl                   //
3 //    Модуль с самопальными функциями и прочим общего    //
4 //                   назначения под LCL.                 //
5 //                Copyright (C) 2007 Sagrer              //
6 //              Распространяется на условиях             //
7 //                      LGPL v2.1                        //
8 //                                                       //
9 //                  версия модуля 0.1                    //
10 //                                                       //
11 //                  sagrer@yandex.ru                     //
12 ///////////////////////////////////////////////////////////
13
14 //К работе над данным файлом приложили руки, ноги.... короче аффтары:
15 // 1) Sagrer (sagrer@yandex.ru)
16
17 ////////////////////////////////////////////////////////////////////////
18
19 unit ExtraFunctionsLcl;
20
21 {$mode objfpc}{$H+}
22
23 interface
24
25 uses
26   Classes, SysUtils, Windows, Registry, crc;
27  
28 const
29   DoDebugOutput = true;            //Выводить ли дебажные мессаги.
30
31   //Типо идентификаторы...
32  
33   //EnvPathAdd
34   EnvPathAdd_User = 0;
35   EnvPathAdd_Global = 1;
36  
37 type
38   TListOfStringLists = class        //Класс для списка списков строк %).
39   private
40     //Закрытые переменные
41     StringLists : array of TStringList;
42   protected
43   public
44     //Конструкторы-деструкторы...
45     constructor Create; virtual;
46     destructor Destroy; override;
47
48     //Открытые методы...
49     procedure SetCount(const NewCount : Integer);   //Выставляет длину массива списков, если нужно создает, если нужно - удаляет объекты.
50     function AddList : Integer;       //Добавляет элемент в конец списка, возвращает его индекс.
51     function InsertList(const Index : Integer) : Integer;   //Вставляет элемент в указанную позицию. Возвращает реальный индекс в который добавлен элемент.
52     procedure RemoveList(const Index : Integer);   //Удаляет элемент в указанной позиции.
53     function Count : Integer;      //Возвращает количество элементов.
54     function GetList(const Index : Integer) : TStringList;   //Вернуть элемент с указанным индексом.
55   end;
56
57 //Глобальные функции.
58 Function StrRPos(str1,str2 : pchar) : pchar;  //На основе функции из FPC. Ищет первое вхождение str2 в str1, но с конца строки.
59 Function Parse( var S : AnsiString; const Separators : AnsiString ) : AnsiString;   //Функция для парсинга строк, сделано на основе функции из KOL.
60 Function ParseTail( var S : AnsiString; const Separators : AnsiString ) : AnsiString;   //Анологично тому что выше, но работает с хвоста.
61 Function ParseNumericHead(var S : AnsiString) : AnsiString;    //Парсит считая за разделитель первый попавшийся символ не-цифру.
62 Function IsNumericStr (Str : string) : boolean;      //А эта функа должна определять, состоит ли строка только из цифр.
63 Function IsVersionStr (Str : string) : boolean;      //Является ли строка номером версии.
64 Function IsNewVersion(OldVer, NewVer : string) : boolean;     //Функа должна проверять, новее ли версия.
65 Procedure ParsePathString(const PathString : string; var PathStringList : TStringList);  //Парсит строку с путями и загоняет инфу в TStringList.
66 Function CombinePathString(const PathStringList : TStringList) : string;  //Генерит из TStringList строку типа Path.
67 Function EnvPathExists(const PathStr : string; const CheckUser, CheckGlobal : boolean) : boolean;   //Проверяет, существует ли такой path в указанных переменных.
68 Function EnvPathRemove(const PathStr : string; const CheckUser, CheckGlobal : boolean) : boolean;   //Удаляет строку пути из указанных PATH. Результат - true если чего-то было удалено.
69 Function EnvPathAdd(const PathStr : string; const Target : integer; const ForceRemoveDoubles : boolean = true; const ForceCreateLocal : boolean = false) : boolean;     //Добавляет путь в указанные PATH.
70 Function TrimExLeft(const InputStr, TrimChars : string) : string;   //Тримает символы слева.
71 Function TrimExRight(const InputStr, TrimChars : string) : string;   //Тримает символы справа.
72 Function TrimEx(const InputStr, TrimChars : string) : string;   //Тримает символы со всех сторон.
73 Function FileToCRC32(const FileName : string; const ConsoleOutput : boolean = false) : cardinal;   //Вычислить CRC32 для файла, если надо с индикацией процесса в консоль.
74 Function CheckCharNum(const Ch : char) : boolean;    //Проверить - является ли символ цифрой
75 Function CheckStrInt(const St : string) : boolean;    //Проверить - является ли строка представлением целочисленного значения
76 Function CheckStrFloat(const St : string) : boolean;   //Проверить - является ли строка представлением дробного значения
77 Function IntToBool(const InputInt : Integer) : boolean;   //Превратить Integer в Boolean
78 Function StrToBool(const InputStr : AnsiString) : boolean;  //Превратить String в Boolean
79 Function BoolToInt(const InputBool : boolean) : Integer;  //Превратить Boolean в Integer
80 Function BoolToStr(const InputBool : boolean) : AnsiString;   //Превратить Boolean в String
81 Function ReadFirstLineFromStr(const InputStr : AnsiString) : AnsiString;  //Элементарно скопировать строку от начала до байта #13 или #10 если #13 не обнаружится.
82
83 implementation
84
85 uses
86   ExtraFileUtilsLCL;
87  
88 /////////////////////////////////////////////
89 //            TListOfStringLists           //
90 /////////////////////////////////////////////
91
92 //Класс для списка списков строк %).
93
94 //-----------------------------------------//
95 //        Конструкторы-деструкторы...      //
96 //-----------------------------------------//
97
98 constructor TListOfStringLists.Create;
99 begin
100   //Нужно инициализировать массив, точнее определиться что он пустой.
101   SetLength(Self.StringLists,0);
102 end;
103
104 destructor TListOfStringLists.Destroy;
105 var
106   I : Integer;
107 begin
108   //Выкидываем мусор
109   for I := 0 to Length(Self.StringLists)-1 do begin
110     //Чистим массив, разрушая вложенные в него объекты.
111     Self.StringLists[i].Free;
112   end;
113   //И выставляем длину самого массива в нуль.
114   SetLength(Self.StringLists,0);
115
116   //Выполнить унаследованный деструктор
117   inherited;
118 end;
119
120 //------------------------------------------//
121 //            Открытые методы...            //
122 //------------------------------------------//
123
124 procedure TListOfStringLists.SetCount(const NewCount : Integer);
125 //Выставляет длину массива списков, если нужно создает, если нужно - удаляет объекты.
126 var
127   I, J : Integer;
128 begin
129   //Тут смотря как - если нужно уменьшить массив - действуем одним способом, иначе другим.
130   if NewCount < Length(Self.StringLists) then begin
131     //Нужно уменьшать массив. Удаляем лишние элементы.
132     for I := NewCount to Length(Self.StringLists)-1 do begin
133       //Чистим массив, разрушая вложенные в него объекты.
134       Self.StringLists[I].Free;
135     end;
136     //И выставляем новую длину массива.
137     SetLength(Self.StringLists,NewCount);
138   end
139   else if NewCount > Length(Self.StringLists) then begin
140     //Нужно увеличивать массив. Сначала выставим новую длину.
141     J := Length(Self.StringLists);
142     SetLength(Self.StringLists,NewCount);
143     //Теперь добавим новых элементов.
144     for I := J to NewCount-1 do begin
145       Self.StringLists[I] := TStringList.Create;
146     end;
147   end;
148  
149   //Особо наблюдательные заметят, что тут не обрабатывается вариант когда Length = GetLength(Self.StringLists).
150   //Особо понятливые при этом сообразят что делать в таком случае ничего не надо.
151 end;
152
153 function TListOfStringLists.AddList : Integer;
154 //Добавляет элемент в конец списка, возвращает его индекс.
155 begin
156   //Увеличиваем количество элементов на 1 штука.
157   Result := Length(Self.StringLists);      //Это вернет индекс нового элемента.
158   SetLength(Self.StringLists,Result+1);
159   //Создаем объект.
160   Self.StringLists[Result] := TStringList.Create;
161 end;
162
163 function TListOfStringLists.InsertList(const Index : Integer) : Integer;
164 //Вставляет элемент в указанную позицию. Возвращает реальный индекс в который добавлен элемент.
165 var
166   TempPointer : TStringList;
167   I : Integer;
168  
169 begin
170   //+1 элемент массива...
171   Result := Self.AddList;
172   //Смотрим, если Index меньше, чем индекс новосозданного элемента - требуется его переместить в нужную позицию.
173   if Index < Result then begin
174     //Копируем указатель нового элемента...
175     TempPointer := Self.StringLists[Result];
176     //В цикле предвигаем элементы так чтобы в Index "освободить" место...
177     for I := Result downto Index+1 do begin
178       Self.StringLists[I] := Self.StringLists[I-1];
179     end;
180     //И записываем указатель в "освободившийся" элемент...
181     Self.StringLists[Index] := TempPointer;
182   end;
183 end;
184
185 procedure TListOfStringLists.RemoveList(const Index : Integer);
186 //Удаляет элемент в указанной позиции.
187 var
188   I : Integer;
189 begin
190   //Тут несколько проще. Разрушаем указанный объект, затем передвигаем все на его место.
191   if Length(Self.StringLists) > Index then begin
192     //Если указанный Index-ом объект существует - удаляем.
193     Self.StringLists[Index].Free;
194     //Если нужно - сдвигаем элементы...
195     if Length(Self.StringLists)-1 > Index then begin
196       for I := Index to Length(Self.StringLists)-2 do begin
197         Self.StringLists[I] := Self.StringLists[I+1];
198       end;
199     end;
200     //И уменьшаем размер массива.
201     SetLength(Self.StringLists,Length(Self.StringLists)-1);
202   end;
203 end;
204
205 function TListOfStringLists.Count : Integer;
206 //Возвращает количество элементов.
207 begin
208   Result := Length(Self.StringLists);    //От так вот.
209 end;
210
211 function TListOfStringLists.GetList(const Index : Integer) : TStringList;
212 //Вернуть элемент с указанным индексом.
213 begin
214   Result := Self.StringLists[Index];
215 end;
216  
217 /////////////////////////////////////////////
218 //            Глобальные функции           //
219 /////////////////////////////////////////////
220
221 Function StrRPos(str1,str2 : pchar) : pchar;
222 //На основе функции из FPC.
223 //Ищет первое вхождение str2 в str1, но с конца строки.
224 var
225    p : pchar;
226    lstr2 : SizeInt;
227 begin
228    StrRPos:=nil;
229    if (str1 = nil) or (str2 = nil) then
230      exit;
231    p:=strrscan(str1,str2^);
232    if p=nil then
233      exit;
234    lstr2:=strlen(str2);
235    while p<>nil do
236      begin
237         if strlcomp(p,str2,lstr2)=0 then
238           begin
239              StrRPos:=p;
240              exit;
241           end;
242         dec(p);
243         p:=strrscan(p,str2^);
244      end;
245 end;
246
247 Function Parse( var S : AnsiString; const Separators : AnsiString ) : AnsiString;
248 //Функция для парсинга строк, сделано на основе функции из KOL.
249 var Pos : Integer;
250
251 begin
252   Pos := Longint( StrPos( PChar(S), PChar(Separators) ) - LongInt(S) + 1 ) ;
253   if Pos <= 0 then
254      Pos := Length( S ) + Length(Separators);
255   Result := S;
256   S := Copy( Result, Pos + Length(Separators), MaxInt );
257   Result := Copy( Result, 1, Pos - 1 );
258 end;
259
260 Function ParseTail( var S : AnsiString; const Separators : AnsiString ) : AnsiString;
261 //Анологично тому что выше, но работает с хвоста.
262 var Pos : Integer;
263
264 begin
265   Pos := Longint( StrRPos( PChar(S), PChar(Separators) ) - LongInt(S) + 1 ) ;
266   Result := S;
267   S := Copy(Result, 1, Pos-1);
268   Result := Copy(Result, Pos+Length(Separators), Length(Result)-(Pos+Length(Separators))+1);
269 end;
270
271 Function ParseNumericHead(var S : AnsiString) : AnsiString;
272 //Парсит считая за разделитель первый попавшийся символ не-цифру.
273 var
274   Pos : Integer;
275   Finded : Boolean;
276
277 begin
278   //Инициализация.
279   Pos := 0;
280   Finded := false;
281  
282   //Ищем первую "не-цифру"
283   repeat
284     Pos := Pos+1;
285     if Pos <= Length(S) then begin
286       if IsNumericStr(S[Pos]) = false then begin
287         //Нашли.
288         Finded := true;
289         Pos := Pos-1;
290       end;
291     end;
292   until (Pos = Length(S)) or (Finded = true);
293  
294   //Ну и, собсно парсенг.
295   Result := Copy(S,1,Pos);
296   Delete(S,1,Pos);
297 end;
298
299 Function IsNumericStr (Str : string) : boolean;
300 var
301   I, StrLength : integer;
302   FindedChar : boolean;
303 begin
304   //А эта функа должна определять, состоит ли строка только из цифр.
305
306   Result := true;  //Умолчальный результат.
307
308   StrLength := Length(Str);
309   If StrLength > 0 then begin
310     //Если в строке чета есть то можно приступать.
311     For I := 1 to StrLength do begin
312       FindedChar := true;
313       If Str[I] = '1' then FindedChar := false;  //Достаточно выполнится 1 проверке - и чар будет не найден :)
314       If Str[I] = '2' then FindedChar := false;
315       If Str[I] = '3' then FindedChar := false;
316       If Str[I] = '4' then FindedChar := false;
317       If Str[I] = '5' then FindedChar := false;
318       If Str[I] = '6' then FindedChar := false;
319       If Str[I] = '7' then FindedChar := false;
320       If Str[I] = '8' then FindedChar := false;
321       If Str[I] = '9' then FindedChar := false;
322       If Str[I] = '0' then FindedChar := false;
323
324       //И если был обнаружен символ-не цифра - обломить все нафиг.
325       If FindedChar = true then Result := false;
326     end;
327   end
328   else begin
329     Result := false;  //Типа строка пустая.
330   end;
331 end;
332
333 Function IsVersionStr (Str : string) : boolean;
334 var
335   I, StrLength : integer;
336   FindedChar, WasPoint : boolean;
337 begin
338   //Является ли строка номером версии.
339
340   Result := true;  //Умолчальный результат.
341
342   StrLength := Length(Str);
343   If StrLength > 0 then begin
344     //Если в строке чета есть то можно приступать.
345     WasPoint := false;
346     For I := 1 to StrLength do begin
347       FindedChar := true;
348       If Str[I] = '1' then begin
349         FindedChar := false;
350         WasPoint := false;
351       end;
352       If Str[I] = '2' then begin
353         FindedChar := false;
354         WasPoint := false;
355       end;
356       If Str[I] = '3' then begin
357         FindedChar := false;
358         WasPoint := false;
359       end;
360       If Str[I] = '4' then begin
361         FindedChar := false;
362         WasPoint := false;
363       end;
364       If Str[I] = '5' then begin
365         FindedChar := false;
366         WasPoint := false;
367       end;
368       If Str[I] = '6' then begin
369         FindedChar := false;
370         WasPoint := false;
371       end;
372       If Str[I] = '7' then begin
373         FindedChar := false;
374         WasPoint := false;
375       end;
376       If Str[I] = '8' then begin
377         FindedChar := false;
378         WasPoint := false;
379       end;
380       If Str[I] = '9' then begin
381         FindedChar := false;
382         WasPoint := false;
383       end;
384       If Str[I] = '0' then begin
385         FindedChar := false;
386         WasPoint := false;
387       end;
388       If Str[I] = '.' then begin
389         FindedChar := false;
390         If WasPoint = true then begin
391           //Если до этого уже была точка - то аблооом.
392           FindedChar := true;
393         end;
394         WasPoint := true;
395       end;
396
397       //И если был обнаружен символ-не цифра и не точка - обломить все нафиг.
398       If FindedChar = true then Result := false;
399     end;
400   end
401   else begin
402     Result := false;  //Типа строка пустая.
403   end;
404 end;
405
406 Function IsNewVersion(OldVer, NewVer : string) : boolean;
407 var
408   CurrVerLevels, I,
409   OldVerLevels, MaxLevel : integer;
410   TempStr, TempStr2,
411   OldVerTemp, NewVerTemp : string;
412 begin
413   //Функа должна проверять, новее ли версия.
414
415   Result := false;  //Типа умолчальное значение.
416   OldVerTemp := OldVer;
417   NewVerTemp := NewVer;
418
419
420   If (IsVersionStr(OldVer) = true) and (IsVersionStr(NewVer) = true) then begin
421     //Только если в обоих строках - версии.
422
423     //Для начала - посмотреть сколько уровней версии в старой версии.
424     TempStr := NewVerTemp;
425     TempStr2 := '';      //Переменная инициализируется чисто чтоб не вылазил хинт при Parse от компилера.
426     CurrVerLevels := 1;  //Есть как минимум 1 уровень.
427     repeat
428       If Pos('.',TempStr) <> 0 then begin
429         CurrVerLevels := CurrVerLevels + 1;   //Есть минимум еще 1 уровень.
430         TempStr2 := Parse(TempStr,'.');
431       end;
432     until Pos('.',TempStr) = 0;
433
434     //И в новой.
435     TempStr := OldVerTemp;
436     OldVerLevels := 1;  //Есть как минимум 1 уровень.
437     repeat
438       If Pos('.',TempStr) <> 0 then begin
439         OldVerLevels := OldVerLevels + 1;   //Есть минимум еще 1 уровень.
440         TempStr2 := Parse(TempStr,'.');
441       end;
442     until Pos('.',TempStr) = 0;
443
444     //Теперь вычислить максимальный уровень.
445     If CurrVerLevels > OldVerLevels then begin
446       MaxLevel := CurrVerLevels;
447     end
448     else begin
449       MaxLevel := OldVerLevels;
450     end;
451
452     //Теперь - к той версии что самая малоуровневая - добавить нулей.
453     If CurrVerLevels < MaxLevel then begin
454       For I := 1 to MaxLevel - CurrVerLevels do begin
455         NewVerTemp := NewVerTemp+'.0';
456       end;
457     end;
458     If OldVerLevels < MaxLevel then begin
459       For I := 1 to MaxLevel - OldVerLevels do begin
460         OldVerTemp := OldVerTemp+'.0';
461       end;
462     end;
463
464     //Ну а теперь - собсно сравнение наконецто.
465     I := 0;
466     repeat
467       I := I+1;
468       TempStr := Parse(OldVerTemp,'.');
469       TempStr2 := Parse(NewVerTemp,'.');
470       If StrToInt(TempStr2) > StrToInt(TempStr) then Result := true;
471     until (I = MaxLevel) or (Result = true);
472   end;
473 end;
474
475
476
477 Procedure ParsePathString(const PathString : string; var PathStringList : TStringList);
478 //Парсит строку с путями и загоняет инфу в TStringList.
479 begin
480
481   //Чистим список.
482   PathStringList.Clear;
483  
484   //Парсим...
485   ExtractStrings([';'], [' '], PChar(PathString), PathStringList);
486 end;
487
488 Function CombinePathString(const PathStringList : TStringList) : string;
489 //Генерит из TStringList строку типа Path.
490 var
491   I : integer;
492 begin
493
494   Result := '';
495  
496   if PathStringList.Count > 0 then begin
497     for I := 0 to PathStringList.Count-1 do begin
498       //Добавить строку...
499       Result := Result+PathStringList.Strings[I];
500       //И если надо - разделитель.
501       if I < PathStringList.Count-1 then begin
502         Result := Result+';';
503       end;
504     end;
505   end;
506  
507 end;
508
509 Function EnvPathExists(const PathStr : string; const CheckUser, CheckGlobal : boolean) : boolean;
510 //Проверяет, существует ли такой path в указанных переменных.
511 var
512   Registr : TRegistry;
513   PathVar : string;
514   PathVarList : TStringList;
515   I : Integer;
516
517   Function SearcherCode : boolean;
518   begin
519     Result := false;
520
521     //Получаем путь...
522     PathVar := Registr.ReadString('PATH');
523     //Парсим строчку...
524     ParsePathString(PathVar,PathVarList);
525     if PathVarList.Count > 0 then begin
526       //Ищем там все наши пути. Только если есть где искать ессно.
527       I := -1;
528       repeat
529         I := I+1;
530         if UpperCase(DelLastSlash(PathVarList.Strings[I])) = UpperCase(DelLastSlash(PathStr)) then begin
531           Result := true;   //Чета нашли % ).
532         end;
533       until (I >= PathVarList.Count-1) or (Result = true);
534     end;
535   end;
536
537 begin
538
539   //Инициализация..
540   Registr := TRegistry.Create;
541   PathVarList := TStringList.Create;
542   Result := false;
543
544   //Чистим
545   //Юзверя...
546   If CheckUser = true then begin
547     Registr.RootKey := HKEY_CURRENT_USER;
548     Registr.OpenKey('\Environment',false);
549     Result := SearcherCode();
550   end;
551
552   //Глобально...
553   If CheckGlobal = true then begin
554     Registr.RootKey := HKEY_LOCAL_MACHINE;
555     Registr.OpenKey('\SYSTEM\CurrentControlSet\Control\Session Manager\Environment',false);
556     Result := Result or SearcherCode();
557   end;
558
559   //Чистим мусор...
560   Registr.Free;
561   PathVarList.Free;
562
563 end;
564
565 Function EnvPathRemove(const PathStr : string; const CheckUser, CheckGlobal : boolean) : boolean;
566 //Удаляет строку пути из указанных PATH. Результат - true если чего-то было удалено.
567 var
568   Registr : TRegistry;
569   PathVar : string;
570   PathVarList : TStringList;
571   I : Integer;
572   Finded : boolean;
573  
574   Function RemoverCode : boolean;
575   begin
576     Result := false;
577
578     //Получаем путь...
579     PathVar := Registr.ReadString('PATH');
580     //Парсим строчку...
581     ParsePathString(PathVar,PathVarList);
582     if PathVarList.Count > 0 then begin
583       //Ищем там все наши пути и удаляем. Только если есть где искать ессно.
584       I := -1;
585       Finded := false;    //Нашли ли мы там нужный путь...
586       repeat
587         I := I+1;
588         if UpperCase(DelLastSlash(PathVarList.Strings[I])) = UpperCase(DelLastSlash(PathStr)) then begin
589           PathVarList.Delete(I);
590           I := I-1;
591           Finded := true;   //Чета нашли % ).
592         end;
593       until I >= PathVarList.Count-1;
594
595       //Вернем строчку обратно в переменную...
596       //Ессно это сработает только если в переменной хоть что-то было и тем более если
597       //там удалось найти искомое...
598       if Finded = true then begin
599         //Генерим строчку...
600         PathVar := CombinePathString(PathVarList);
601         if DoDebugOutput = true then begin
602           //Writeln('New path will be: '+PathVar);
603         end;
604         //И собсно записываем новое значение...
605         Registr.WriteString('PATH',PathVar);           //Временно закомменчено - на время отладки.
606         //Результат.
607         Result := true;
608       end;
609
610     end;
611   end;
612  
613 begin
614
615   //Инициализация..
616   Registr := TRegistry.Create;
617   PathVarList := TStringList.Create;
618   Result := false;
619  
620   //Чистим
621   //Юзверя...
622   If CheckUser = true then begin
623     Registr.RootKey := HKEY_CURRENT_USER;
624     Registr.OpenKey('\Environment',false);
625     Result := RemoverCode();
626     Registr.CloseKey;
627   end;
628  
629   //Глобально...
630   If CheckGlobal = true then begin
631     Registr.RootKey := HKEY_LOCAL_MACHINE;
632     Registr.OpenKey('\SYSTEM\CurrentControlSet\Control\Session Manager\Environment',false);
633     Result := Result or RemoverCode();
634     Registr.CloseKey;
635   end;
636  
637   //Сообщаем другим прогам что щей-то поменялось...
638   if Result = true then begin
639     SendMessage( HWND_BROADCAST, WM_SETTINGCHANGE, 0, LPARAM(LPCSTR('Environment')) );
640   end;
641  
642   //Чистим мусор...
643   Registr.Free;
644   PathVarList.Free;
645
646 end;
647
648 Function EnvPathAdd(const PathStr : string; const Target : integer; const ForceRemoveDoubles : boolean = true; const ForceCreateLocal : boolean = false) : boolean;
649 //Добавляет путь в указанные PATH.
650 var
651   Registr : TRegistry;
652   UserPathVar, GlobalPathVar : string;
653   UserPathVarList, GlobalPathVarList : TStringList;
654   Finded : boolean;
655  
656 begin
657   //Инициализация..
658   Registr := TRegistry.Create;
659   Result := false;
660  
661   //Итак, в зависимости от того куда собираемся добавлять...
662   if Target = EnvPathAdd_Global then begin
663     //В глобалку добавляем
664    
665     //Ищем есть ли этот путь в локалке. Если есть - удаляем.
666     EnvPathRemove(PathStr, true, false);
667    
668     //Теперь проверим - есть ли в глобалке такой путь уже...
669     Finded := EnvPathExists(PathStr, false, true);
670    
671     //Если нифига не нашли - добавляем переменную. Если нашли - ниче трогать не надо %).
672     if Finded = false then begin
673       Registr.RootKey := HKEY_LOCAL_MACHINE;
674       Registr.OpenKey('\SYSTEM\CurrentControlSet\Control\Session Manager\Environment',true);
675       //Получаем путь...
676       GlobalPathVar := Registr.ReadString('PATH');
677       //Парсим строчку...
678       GlobalPathVarList := TStringList.Create;
679       ParsePathString(GlobalPathVar,GlobalPathVarList);
680       //Добавляем значение...
681       GlobalPathVarList.Add(PathStr);
682       GlobalPathVar := CombinePathString(GlobalPathVarList);
683       //Пишем все обратно.
684       if DoDebugOutput = true then begin
685         //Writeln('New global path will be: '+GlobalPathVar);
686       end;
687       //И собсно записываем новое значение...
688       Registr.WriteString('PATH',GlobalPathVar);           //Временно закомменчено - на время отладки.
689       Registr.CloseKey;
690       //Сообщаем другим прогам что щей-то поменялось...
691       SendMessage( HWND_BROADCAST, WM_SETTINGCHANGE, 0, LPARAM(LPCSTR('Environment')) );
692       //Чистим мусор...
693       GlobalPathVarList.Free;
694     end;
695   end
696   else if Target = EnvPathAdd_User then begin
697     //В локалку добавляем
698
699     //Проверяем, есть ли в глобалке такой путь (если не форсим добавление в локалку),
700     //либо если сказано удалять в глобалке - удаляем.
701     Finded := false;
702     if ForceRemoveDoubles = true then begin
703       //Удаляем глобалку
704       EnvPathRemove(PathStr, false, true);
705     end
706     else if ForceCreateLocal = false then begin
707       //Проверяем есть ли что-то в глобалке - если есть то в локалку добавляться не будет.
708       Finded := EnvPathExists(PathStr, false, true);
709     end;
710    
711     //Если пока есть причины продолжать - проверяем, есть ли в локалке такой путь...
712     if Finded = false then begin
713       Finded := EnvPathExists(PathStr, true, false);
714     end;
715    
716     //И теперь, если таки нужно добавить новое значение в переменную - добавляем.
717     Registr.RootKey := HKEY_CURRENT_USER;
718     Registr.OpenKey('\Environment',true);
719     //Получаем путь...
720     UserPathVar := Registr.ReadString('PATH');
721     //Парсим строчку...
722     UserPathVarList := TStringList.Create;
723     ParsePathString(UserPathVar,UserPathVarList);
724     //Добавляем значение...
725     UserPathVarList.Add(PathStr);
726     UserPathVar := CombinePathString(UserPathVarList);
727     //Пишем все обратно.
728     if DoDebugOutput = true then begin
729       //Writeln('New user path will be: '+UserPathVar);
730     end;
731     //И собсно записываем новое значение...
732     Registr.WriteString('PATH',UserPathVar);           //Временно закомменчено - на время отладки.
733     Registr.CloseKey;
734     //Сообщаем другим прогам что щей-то поменялось...
735     SendMessage( HWND_BROADCAST, WM_SETTINGCHANGE, 0, LPARAM(LPCSTR('Environment')) );
736     //Чистим мусор...
737     UserPathVarList.Free;
738   end;
739
740   //Чистим мусор...
741   Registr.Free;
742 end;
743
744 Function TrimExLeft(const InputStr, TrimChars : string) : string;
745 //Тримает символы слева.
746 var
747   FindedTrimChar, FindedNoTrimChar : boolean;
748   I, J : Integer;
749  
750 begin
751
752   //Умолчальное возвращаемое значение.
753   Result := '';
754  
755   //Есть ли во входной строке хоть что-то....
756   if Length(InputStr) > 0 then begin
757     //Есть. Значит считаем количество символов с начала строки совпадающие с TrimChars...
758     I := 0;
759     FindedNoTrimChar := false;
760     repeat
761       //Цикл собственно подсчета количества тримаемых символов.
762       //Щелкаем счетчиком и обнуляем индикатор проверки символа.
763       I := I+1;
764       FindedTrimChar := false;
765      
766       //Проверяем символ
767       for J := 1 to Length(TrimChars) do begin
768         //Цикл проверки является ли символ тримаемым %).
769         if InputStr[I] = TrimChars[J] then begin
770           FindedTrimChar := true;     //Нашли такой символ.
771         end;
772       end;
773      
774       //Смотрим результат проверки.
775       if FindedTrimChar = false then begin
776         //Таки символ оказался не тримаемым - подсчет завершен, отмечаем что первый не-трим символ найден.
777         FindedNoTrimChar := true;
778       end;
779      
780     until (I = Length(InputStr)) or (FindedNoTrimChar = true);
781    
782     //Теперь в зависимости от того что нашли...
783     If FindedNoTrimChar = true then begin
784       //Если в строке есть что-то помимо тримаемых символов - будем тримы удалять.
785       //Если бы там были только они - можно было бы вообще ничего не делать - вернется пустая строка.
786       Result := RightStr(InputStr,Length(InputStr)-I+1);
787     end;
788   end;
789  
790 end;
791
792 Function TrimExRight(const InputStr, TrimChars : string) : string;
793 //Тримает символы справа.
794 var
795   FindedTrimChar, FindedNoTrimChar : boolean;
796   I, J : Integer;
797
798 begin
799
800   //Умолчальное возвращаемое значение.
801   Result := '';
802
803   //Есть ли во входной строке хоть что-то....
804   if Length(InputStr) > 0 then begin
805     //Есть. Значит считаем количество символов с конца строки совпадающие с TrimChars...
806     I := Length(InputStr)+1;
807     FindedNoTrimChar := false;
808     repeat
809       //Цикл собственно подсчета количества тримаемых символов.
810       //Щелкаем счетчиком и обнуляем индикатор проверки символа.
811       I := I-1;
812       FindedTrimChar := false;
813
814       //Проверяем символ
815       for J := 1 to Length(TrimChars) do begin
816         //Цикл проверки является ли символ тримаемым %).
817         if InputStr[I] = TrimChars[J] then begin
818           FindedTrimChar := true;     //Нашли такой символ.
819         end;
820       end;
821
822       //Смотрим результат проверки.
823       if FindedTrimChar = false then begin
824         //Таки символ оказался не тримаемым - подсчет завершен, отмечаем что первый не-трим символ найден.
825         FindedNoTrimChar := true;
826       end;
827
828     until (I = 1) or (FindedNoTrimChar = true);
829
830     //Теперь в зависимости от того что нашли...
831     If FindedNoTrimChar = true then begin
832       //Если в строке есть что-то помимо тримаемых символов - будем тримы удалять.
833       //Если бы там были только они - можно было бы вообще ничего не делать - вернется пустая строка.
834       Result := LeftStr(InputStr,I);
835     end;
836   end;
837
838 end;
839
840 Function TrimEx(const InputStr, TrimChars : string) : string;
841 //Тримает символы со всех сторон.
842 begin
843   //Просто вызываем обе отдельные функции.
844   Result := TrimExLeft(TrimExRight(InputStr, TrimChars), TrimChars);
845 end;
846
847 Function FileToCRC32(const FileName : string; const ConsoleOutput : boolean = false) : cardinal;
848 //Вычислить CRC32 для файла, если надо с индикацией процесса в консоль.
849 const
850   ReadBuffSize = 500000;              //По 500 кб - думаю такой буффер пойдет даже на самой древней вендовой системе...
851                                       //... или на виртуальном linux-хосте с wine.
852 var
853   CurrStream : TFileStream;
854   //Buffer : array [0..ReadBuffSize-1] of byte;    //Изза бага, возможно в fpc (в дельфе все пашет) - приходится юзать динамический массив.
855   Buffer : array of byte;
856   Readed, FullReaded : LongInt;
857  
858 begin
859
860   //Инициализируем значение CRC
861   Result := crc32(0, nil, 0);
862   //и выделяем память под буффер...
863   SetLength(Buffer,ReadBuffSize-1);
864
865   //Существует ли файлег...
866   if FileExists(FileName) = true then begin
867     //Если есть что высчитывать - считаем...
868    
869     //Счетчики чтения...
870     Readed := 0;
871     FullReaded := 0;
872    
873     //Открываем файл...
874     CurrStream := TFileStream.Create(FileName,fmOpenRead);
875    
876     //Если надо - выводим инфу о прогрессе в консоль.
877     if ConsoleOutput = true then begin
878       Write('CRC32: '+FileName+' -> ');
879     end;
880    
881     //Собсно считаем. Читаем файл по кусочкам пока файл не кончится.
882     repeat
883       Readed := CurrStream.Read(buffer[0],ReadBuffSize);
884       FullReaded := FullReaded+Readed;
885       Result := crc32(Result, @buffer[0], Readed);
886     until Readed = 0;
887    
888     //Готово. Закрыть прочитанный файл.
889     CurrStream.Free;
890     //И если надо сообщить новую CRC в консоль...
891     if ConsoleOutput = true then begin
892       Writeln(IntToHex(Result,8));
893     end;
894    
895   end;
896  
897   //Чистим мусор
898   SetLength(Buffer,0);
899 end;
900
901 Function CheckCharNum(const Ch : char) : boolean;
902 //Проверить - является ли символ цифрой
903 begin
904   result := false;
905   if Ch = '0' then result := true;
906   if Ch = '1' then result := true;
907   if Ch = '2' then result := true;
908   if Ch = '3' then result := true;
909   if Ch = '4' then result := true;
910   if Ch = '5' then result := true;
911   if Ch = '6' then result := true;
912   if Ch = '7' then result := true;
913   if Ch = '8' then result := true;
914   if Ch = '9' then result := true;
915 end;
916
917 Function CheckStrInt(const St : string) : boolean;
918 //Проверить - является ли строка представлением целочисленного значения
919 var
920   ch : char;
921   I : integer;
922  
923 begin
924   If (st <> '') and (st<>'-') then begin
925     result := true;
926     I := 0;
927     If St[I+1] = '-' then I := I+1;
928     repeat
929       I := I+1;
930       Ch := St[I];
931       if ch <> #0 then if CheckCharNum(Ch) = false then result := false;
932     until Ch = #0;
933   end
934   else result := false;
935 end;
936
937 Function CheckStrFloat(const St : string) : boolean;
938 //Проверить - является ли строка представлением дробного значения
939 var
940   zapatih, I : integer;
941   ch : char;
942  
943 begin
944   If (st <> '') and (st <> 'NAN') and (st<>'-') then begin
945     result := true;
946     zapatih := 1;
947     I := 0;
948     If St[I+1] = '-' then I := I+1;
949     repeat
950       I := I+1;
951       Ch := St[I];
952       If ch = '.' then zapatih := zapatih-1
953       else if ch <> #0 then if CheckCharNum(Ch) = false then result := false;
954     until Ch = #0;
955     if zapatih < 0 then result := false;
956   end
957   else begin
958     If St = 'NAN' then result := true
959     else Result := false;
960   end;
961 end;
962
963 Function IntToBool(const InputInt : Integer) : boolean;
964 //Превратить Integer в Boolean
965 begin
966   If InputInt = 1 then begin
967     Result := true;
968   end
969   else begin
970     Result := false;
971   end;
972 end;
973
974 Function StrToBool(const InputStr : AnsiString) : boolean;
975 //Превратить String в Boolean
976 begin
977   //Проверить, интегеровое число ли ето.
978   If CheckStrInt(InputStr) = true then begin
979     //Если какое-то число, то вернуть его значение...
980     Result := IntToBool(StrToInt(InputStr));
981   end
982   else begin
983     //Если там какая-то фигня, то вернуть false
984     Result := false;
985   end;
986 end;
987
988 Function BoolToInt(const InputBool : boolean) : Integer;
989 //Превратить Boolean в Integer
990 begin
991   If InputBool = true then begin
992     //true
993     Result := 1;
994   end
995   else begin
996     //false
997     Result := 0;
998   end;
999 end;
1000
1001 Function BoolToStr(const InputBool : boolean) : AnsiString;
1002 //Превратить Boolean в String
1003 begin
1004   Result := IntToStr(BoolToInt(InputBool));
1005 end;
1006
1007 Function IsLocalPath(const PathStr : string) : boolean;
1008 //Возвращает true если путь локальный, и false если нет.
1009 //Под локальным понимается путь начинающийся с точки.
1010 begin
1011   Result := false;   //По умолчанию считаем что путь глобален.
1012  
1013   if Length(PathStr) >= 1 then begin
1014     if PathStr[1] = '.' then begin
1015       Result := true;
1016     end;
1017   end;
1018 end;
1019
1020 Function ReadFirstLineFromStr(const InputStr : AnsiString) : AnsiString;
1021 //Элементарно скопировать строку от начала до байта #13 или #10 если #13 не обнаружится.
1022 var
1023   EndStrPos13, EndStrPos10, EndStrPos : Integer;
1024 begin
1025   //Инициализация.
1026   Result := '';
1027
1028   //Определяем позицию конца строки по #13.
1029   EndStrPos13 := Longint( StrPos( PChar(InputStr), PChar(#13) ) - LongInt(InputStr) + 1 ) ;
1030   if EndStrPos13 <= 0 then begin
1031     EndStrPos13 := Length( InputStr )+1;
1032   end;
1033   //И по #10
1034   EndStrPos10 := Longint( StrPos( PChar(InputStr), PChar(#10) ) - LongInt(InputStr) + 1 ) ;
1035   if EndStrPos10 <= 0 then begin
1036     EndStrPos10 := Length( InputStr )+1;
1037   end;
1038   //Определяем реальный конец строки.
1039   if EndStrPos10 < EndStrPos13 then begin
1040     EndStrPos := EndStrPos10;
1041   end
1042   else begin
1043     EndStrPos := EndStrPos13;
1044   end;
1045
1046   //И собсно копируем результат.
1047   Result := Copy(InputStr,1,EndStrPos-1);
1048 end;
1049
1050 // добаляет расширение если его еще нет.
1051 function AddExtensionIfAbsent(const path, extension :String) :String;
1052 var
1053   ex :AnsiString;
1054 begin
1055   Result := path;
1056   ex := ExtractFileExt(path);
1057   if (ex = '') then begin
1058     Result := path + extension;
1059   end;
1060 end;
1061
1062 // чистое имя файла, без расширения
1063 function GetFileNameWithoutExtension(const path :String) :String;
1064 var
1065   fileName :String;
1066   i        :Integer;
1067 begin
1068   fileName := ExtractFileName(path);
1069   i := Length(FileName);
1070   while (i > 0) and (FileName[i] <> '.') do Dec(i);
1071
1072   if (i > 0) then
1073     Result := Copy(FileName, 1, i - 1)
1074   else
1075     Result := fileName;
1076
1077
1078 end;
1079
1080 end.
1081
Note: See TracBrowser for help on using the browser.