| 1 |
//////////////////////////////////////////////////////////// |
|---|
| 2 |
// Класс для работы с *.ini // |
|---|
| 3 |
// v 1.5 // |
|---|
| 4 |
// // |
|---|
| 5 |
// Copyright (C) 2007-2008 Sagrer // |
|---|
| 6 |
// Распространяется на условиях LGPL 2.1 // |
|---|
| 7 |
// LCL-вариант. // |
|---|
| 8 |
// см. файл lgpl.txt // |
|---|
| 9 |
// // |
|---|
| 10 |
// sagrer@yandex.ru // |
|---|
| 11 |
//////////////////////////////////////////////////////////// |
|---|
| 12 |
|
|---|
| 13 |
//К работе над данным файлом приложили руки, ноги.... короче аффтары: |
|---|
| 14 |
// 1) Sagrer (sagrer@yandex.ru) |
|---|
| 15 |
|
|---|
| 16 |
//////////////////////////////////////////////////////////////////////// |
|---|
| 17 |
|
|---|
| 18 |
unit LCLAnIniFile; |
|---|
| 19 |
|
|---|
| 20 |
{$mode objfpc}{$H+} |
|---|
| 21 |
|
|---|
| 22 |
interface |
|---|
| 23 |
uses LCLTextFileInString, SysUtils, ExtraFunctionsLcl, Classes; |
|---|
| 24 |
|
|---|
| 25 |
type |
|---|
| 26 |
RIniValueListElement = record //Структура для значений ini записанных в виде строк в нестандартных секциях. |
|---|
| 27 |
Name : string; |
|---|
| 28 |
Value : string; |
|---|
| 29 |
end; |
|---|
| 30 |
|
|---|
| 31 |
AIniValueListElements = array of RIniValueListElement; //Тип одномерного массива - соответствует строке IniValueList |
|---|
| 32 |
|
|---|
| 33 |
AIniValueList = array of AIniValueListElements; //Тип двумерного динамического массива для хранения инфы из IniValueList - это содержимое нестандартной секции в которой элементы разделены точкой с запятой, а имена от значений двоеточием, в строке по нескольку элементов. |
|---|
| 34 |
|
|---|
| 35 |
TAnIniFile = class (TObject) //Самопальный класс для работы со стандартными и не очень (вроде *.iss) ini-файлами. |
|---|
| 36 |
Public |
|---|
| 37 |
//Переменные |
|---|
| 38 |
TextFil1 : TTextFileInString; |
|---|
| 39 |
|
|---|
| 40 |
//Конструкторы-деструкторы... |
|---|
| 41 |
Constructor Create; virtual; |
|---|
| 42 |
Destructor Destroy; override; |
|---|
| 43 |
|
|---|
| 44 |
//Другие методы... |
|---|
| 45 |
Function Load(const FileName : string) : boolean; //Загрузить файл в объект класса |
|---|
| 46 |
Function Save(const FileName : string) : boolean; //Сохранить инфу из объекта класса в файл |
|---|
| 47 |
Function SectionExists(const SectName : string) : boolean; //Существует ли секция |
|---|
| 48 |
Function ElementExists(const SectName, ElemName : string) : boolean; //Существует ли элемент |
|---|
| 49 |
Function ReadString(const SectName, ElemName : string) : string; //Прочитать строковое значение |
|---|
| 50 |
Function ReadInteger(const SectName, ElemName : string) : integer; //Прочитать целочисленное значение |
|---|
| 51 |
Function ReadFloat(const SectName, ElemName : string) : Extended; //Прочитать дробное значение |
|---|
| 52 |
Function ReadBool(const SectName, ElemName : string) : boolean; //Прочитать логическое значение |
|---|
| 53 |
Procedure WriteString(const SectName, ElemName, Str : string); //Записать строковое значение |
|---|
| 54 |
Procedure WriteInteger(const SectName, ElemName : string; Int : integer); //Записать целочисленное значение |
|---|
| 55 |
Procedure WriteFloat(const SectName, ElemName : string; Flt : Extended); //Записать дробное значение |
|---|
| 56 |
Procedure WriteBool(const SectName, ElemName : string; Bool : boolean); //Записать логическое значение |
|---|
| 57 |
Procedure MakNewFile(); virtual; //Создать "новый файл" |
|---|
| 58 |
Procedure CreateSection(const SectName : string); //Создать пустую секцию. |
|---|
| 59 |
Procedure RemoveSection(const SectName : string); virtual; //Полностью удалить секцию. |
|---|
| 60 |
Function ReadRawSection(const SectName : string) : string; //Прочитать все содержимое секции в одну строку. |
|---|
| 61 |
Function ReadSectionStrings(const SectName : string) : string; //Прочитать все содержимое секции в одну строку, но без строк - камментов. |
|---|
| 62 |
Procedure WriteRawSection(const SectName, SectContent : string); virtual; //Перезаписать всё содержимое секции из строки. |
|---|
| 63 |
Procedure StrToIniValueList(const InputStr : string; var IniValueList : AIniValueList); //Пропарсить строку и закинуть инфу в динамический массив. |
|---|
| 64 |
Function IniValueListToStr(var IniValueList : AIniValueList) : string; //Сгенерить строку из инфы динамического массива. |
|---|
| 65 |
Procedure ReadIniValueList(const SectName : string; var IniValueList : AIniValueList); //Прочитать IniValueList из секции. |
|---|
| 66 |
Procedure WriteIniValueList(const SectName : string; var IniValueList : AIniValueList); //Перезаписать инфу секции из IniValueList. |
|---|
| 67 |
Function CompareIniValueElements(var IniValueList1, IniValueList2 : AIniValueList; const List1Index, List2Index : Integer; const CaseSensitive : boolean; const ExceptValueNames : AnsiString) : Boolean; //Функция сравнивает 2 строки 2 списков значений, если они идентичны (с учетом условий каш-сенситив и исключенных элементов) - возвращает true, иначе false. Если первое из Except - "all" то все последующие - наоборот те что проверяются, остальные игнорируются. |
|---|
| 68 |
Function CompareIniValueLists(var IniValueList1, IniValueList2 : AIniValueList; const CaseSensitive : boolean; const ExceptValueNames : AnsiString) : Boolean; //Функция сравнивает 2 списка значений, если списки идентичны (с учетом условий каш-сенситив и исключенных элементов) - возвращает true, иначе false. Если первое из Except - "all" то все последующие - наоборот те что проверяются, остальные игнорируются. |
|---|
| 69 |
Function GetIniValueListValueIndex(var IniValueList : AIniValueList; const ValIndex : Integer; const ValueName : AnsiString) : Integer; //Вернуть индекс значения с указанным именем в указанной строке списка (элементе). |
|---|
| 70 |
Function GetIniValueListValue(var IniValueList : AIniValueList; const ValIndex : Integer; const ValueName : AnsiString) : AnsiString; //Функция возвращает содержимое значения с указанным именем в указанной строке списка. |
|---|
| 71 |
Function ChangeIniValueListValue(var IniValueList : AIniValueList; const ValIndex : Integer; const ValueName, ValueValue : AnsiString) : Boolean; //Функция записывает новое содержимое в значение с указанным именем в указанной строке списка. |
|---|
| 72 |
Function IniValueListValueExists(var IniValueList : AIniValueList; const ValIndex : Integer; const ValueName : AnsiString) : Boolean; //Если значение существует - возвращает true, иначе false. |
|---|
| 73 |
Function GetIniValueListIndexByValue(var IniValueList : AIniValueList; const ValueName, ValueValue : AnsiString) : Integer; //Возвращает индекс первого встреченного элемента (сверху) с указанным именем значения и собсно значением. Если ничего такого нема - вернет -1. |
|---|
| 74 |
Function CopyIniValueListElement(var From, Dest : AIniValueList; const FromIndex, DestIndex : Integer) : Boolean; //Скопировать содержимое одного элемента одного списка в другой элемент другого списка (в теории возможно и в рамкеах одного списка если оба указателя оставить на один и тот же список.). |
|---|
| 75 |
Function CopyIniValueList(var From, Dest : AIniValueList) : Boolean; //Скопировать содержимое одного списка в другой. |
|---|
| 76 |
Function AddIniValueList(var From, Dest : AIniValueList) : Boolean; //Скопировать содержимое одного списка в другой, добавив новые данные в конец целевого списка и сохранив все уже там присутствовавшее. |
|---|
| 77 |
Function RemoveIniValueListValue(var IniValueList : AIniValueList; const ValIndex : Integer; const ValueName : AnsiString) : Boolean; //Удалить значение с указанным именем в указанном элементе в IniValueList. Если значение такое не существовало - вернет false, иначе true. |
|---|
| 78 |
Function RemoveIniValueListElement(var IniValueList : AIniValueList; const ValIndex : Integer) : Boolean; //Удалить указанный элемент IniValueList. Если элемент не существовал - вернет false, в остальных случаях true. |
|---|
| 79 |
Private |
|---|
| 80 |
//Закрытые методы... |
|---|
| 81 |
Function GoToSection(const SectName : string; TypePos : byte) : boolean; //Перебросить курсор на ту или иную часть секции |
|---|
| 82 |
Function GoToElement(const SectName, ElemName : string) : boolean; //Перейти к определенному элементу секции |
|---|
| 83 |
Function NotComment(const Str : string) : boolean; //Проверялка - является ли строка комментом |
|---|
| 84 |
Function GetElemName(const Str : string) : string; //Получить имя элемента |
|---|
| 85 |
Function GetElemStr(const Str : string) : string; //Получить строковое значение элемента |
|---|
| 86 |
|
|---|
| 87 |
end; |
|---|
| 88 |
|
|---|
| 89 |
implementation |
|---|
| 90 |
|
|---|
| 91 |
///////////////////////////////////////////// |
|---|
| 92 |
// TAnIniFile // |
|---|
| 93 |
///////////////////////////////////////////// |
|---|
| 94 |
|
|---|
| 95 |
//-----------------------------------------// |
|---|
| 96 |
// Конструкторы-деструкторы... // |
|---|
| 97 |
//-----------------------------------------// |
|---|
| 98 |
|
|---|
| 99 |
Constructor TAnIniFile.Create; |
|---|
| 100 |
begin |
|---|
| 101 |
//Конструктор. Во избежание глюков. |
|---|
| 102 |
TextFil1 := TTextFileInString.Create; |
|---|
| 103 |
end; |
|---|
| 104 |
|
|---|
| 105 |
Destructor TAnIniFile.Destroy; |
|---|
| 106 |
begin |
|---|
| 107 |
//Типа деструктор. |
|---|
| 108 |
TextFil1.Free; |
|---|
| 109 |
inherited; |
|---|
| 110 |
end; |
|---|
| 111 |
|
|---|
| 112 |
//------------------------------------------// |
|---|
| 113 |
// Другие методы... // |
|---|
| 114 |
//------------------------------------------// |
|---|
| 115 |
|
|---|
| 116 |
Function TAnIniFile.Load(const FileName : string) : boolean; |
|---|
| 117 |
begin |
|---|
| 118 |
//Типа загружальник инишника в файло-строку. |
|---|
| 119 |
Result := TextFil1.Load(FileName); |
|---|
| 120 |
end; |
|---|
| 121 |
|
|---|
| 122 |
Function TAnIniFile.Save(const FileName : string) : boolean; |
|---|
| 123 |
begin |
|---|
| 124 |
//Типа савальник файло-строки в файло. |
|---|
| 125 |
TextFil1.Save(FileName); |
|---|
| 126 |
Result := true; |
|---|
| 127 |
end; |
|---|
| 128 |
|
|---|
| 129 |
Function TAnIniFile.SectionExists(const SectName : string) : boolean; |
|---|
| 130 |
var |
|---|
| 131 |
TempCur : Longint; |
|---|
| 132 |
begin |
|---|
| 133 |
//Проверяльщик, есть ли нужная секция. Курсор типа не изменится :) |
|---|
| 134 |
|
|---|
| 135 |
TempCur := TextFil1.Cursor; |
|---|
| 136 |
Result := GoToSection(SectName,1); |
|---|
| 137 |
TextFil1.Cursor := TempCur; |
|---|
| 138 |
|
|---|
| 139 |
end; |
|---|
| 140 |
|
|---|
| 141 |
Function TAnIniFile.ElementExists(const SectName, ElemName : string) : boolean; |
|---|
| 142 |
var |
|---|
| 143 |
TempCur : Longint; |
|---|
| 144 |
begin |
|---|
| 145 |
//Проверяльщик, есть ли нужный элемент. Курсор типа не изменится. |
|---|
| 146 |
|
|---|
| 147 |
TempCur := TextFil1.Cursor; |
|---|
| 148 |
Result := GoToElement(SectName,ElemName); |
|---|
| 149 |
TextFil1.Cursor := TempCur; |
|---|
| 150 |
end; |
|---|
| 151 |
|
|---|
| 152 |
Function TAnIniFile.ReadString(const SectName, ElemName : string) : string; |
|---|
| 153 |
begin |
|---|
| 154 |
//Вернуть значение нужного элемента в виде строки. |
|---|
| 155 |
Result := ''; //Типа по умолчанию пусто :) |
|---|
| 156 |
|
|---|
| 157 |
//Выйти на нужный элемент. |
|---|
| 158 |
If GoToElement(SectName,ElemName) = true then begin |
|---|
| 159 |
//Теперь - прочитать что там есть (ессно если элемент нашелся). |
|---|
| 160 |
Result := GetElemStr(TextFil1.ReadStrLn(TextFil1.Cursor)); |
|---|
| 161 |
end; |
|---|
| 162 |
end; |
|---|
| 163 |
|
|---|
| 164 |
Function TAnIniFile.ReadInteger(const SectName, ElemName : string) : integer; |
|---|
| 165 |
var |
|---|
| 166 |
TempStr : string; |
|---|
| 167 |
begin |
|---|
| 168 |
//Вернуть значение нужного элемента в виде интегера. |
|---|
| 169 |
TempStr := ReadString(SectName,ElemName); |
|---|
| 170 |
|
|---|
| 171 |
//Проверить, интегеровое число ли ето. |
|---|
| 172 |
If CheckStrInt(TempStr) = true then begin |
|---|
| 173 |
//Если какое-то число, то вернуть его... |
|---|
| 174 |
Result := StrToInt(TempStr); |
|---|
| 175 |
end |
|---|
| 176 |
else begin |
|---|
| 177 |
//Если там какая-то фигня, то вернуть ноль |
|---|
| 178 |
Result := 0; |
|---|
| 179 |
end; |
|---|
| 180 |
end; |
|---|
| 181 |
|
|---|
| 182 |
Function TAnIniFile.ReadFloat(const SectName, ElemName : string) : Extended; |
|---|
| 183 |
var |
|---|
| 184 |
TempStr : string; |
|---|
| 185 |
begin |
|---|
| 186 |
//Вернуть значение нужного элемента в виде флоата. |
|---|
| 187 |
TempStr := ReadString(SectName,ElemName); |
|---|
| 188 |
|
|---|
| 189 |
//Проверить, флоатовое число ли ето. |
|---|
| 190 |
If CheckStrFloat(TempStr) = true then begin |
|---|
| 191 |
//Если какое-то число, то вернуть его... |
|---|
| 192 |
Result :=StrToFloat(TempStr); |
|---|
| 193 |
end |
|---|
| 194 |
else begin |
|---|
| 195 |
//Если там какая-то фигня, то вернуть ноль |
|---|
| 196 |
Result := 0; |
|---|
| 197 |
end; |
|---|
| 198 |
end; |
|---|
| 199 |
|
|---|
| 200 |
Function TAnIniFile.ReadBool(const SectName, ElemName : string) : boolean; |
|---|
| 201 |
//Вернуть значение нужного элемента в виде буля. |
|---|
| 202 |
begin |
|---|
| 203 |
Result := StrToBool(ReadString(SectName,ElemName)); |
|---|
| 204 |
end; |
|---|
| 205 |
|
|---|
| 206 |
Procedure TAnIniFile.WriteString(const SectName, ElemName, Str : string); |
|---|
| 207 |
begin |
|---|
| 208 |
//Если элемент есть - переписать его заново, если элемента нет, |
|---|
| 209 |
//то создать его в конце секции. Если нет и секции, то создать |
|---|
| 210 |
//секцию, после чего в конец секции дописать элемент. |
|---|
| 211 |
//Писать элемент ессно в виде строки. Это базовая функа для |
|---|
| 212 |
//остальных писалок. Остальные (типа для интегеров и прочего) |
|---|
| 213 |
//будут работать через нее, просто преобразовывая типы... |
|---|
| 214 |
|
|---|
| 215 |
//Итак, в начале - проверить, существует ли элемент. |
|---|
| 216 |
If GoToElement(SectName,ElemName) = true then begin |
|---|
| 217 |
//Типа элемент существует. Просто переписать его заново... |
|---|
| 218 |
TextFil1.ReplaceString(TextFil1.Cursor,ElemName+'='+Str); |
|---|
| 219 |
end |
|---|
| 220 |
else begin |
|---|
| 221 |
//Типа элемента такого нет. Тогда проверить, есть ли секция под этот элемент... |
|---|
| 222 |
If GoToSection(SectName,3) = true then begin |
|---|
| 223 |
//В принципе, ниче делать не надо, курсор стоит в конце секции щас... |
|---|
| 224 |
end |
|---|
| 225 |
else begin |
|---|
| 226 |
//Если, типа и секции такой нету :). |
|---|
| 227 |
//То выставить курсор в самый низ файла |
|---|
| 228 |
//и создать эту секцию... |
|---|
| 229 |
|
|---|
| 230 |
If TextFil1.Siz <> 0 then begin |
|---|
| 231 |
//Типа, если вообще файл не пуст. |
|---|
| 232 |
TextFil1.Cursor := TextFil1.Siz+1; //курсор в конец файлы... |
|---|
| 233 |
If TextFil1.FileString[TextFil1.Cursor-1] = #10 then begin |
|---|
| 234 |
//Если конец файла - пустая новая строка |
|---|
| 235 |
//то сразу вставить имя секции |
|---|
| 236 |
//и еще 1 пустую новую строку, на которую и поставить курсор после всего. |
|---|
| 237 |
//Если же до этой пустой новой строки нету еще одной пустой строки |
|---|
| 238 |
//то вставить еще #13#10 чтоб был промежуток между секциями. |
|---|
| 239 |
If TextFil1.Siz > 3 then begin |
|---|
| 240 |
If TextFil1.FileString[TextFil1.Cursor-3] <> #10 then begin |
|---|
| 241 |
TextFil1.AddStr(''); |
|---|
| 242 |
end; |
|---|
| 243 |
end; |
|---|
| 244 |
TextFil1.AddStr('['+SectName+']'); |
|---|
| 245 |
TextFil1.Cursor := TextFil1.Siz+1; //курсор собсно в конец файла. |
|---|
| 246 |
end |
|---|
| 247 |
else begin |
|---|
| 248 |
//Конец файла - не пустая строка (чета есть) |
|---|
| 249 |
//тады - просто тоже самое, что выше, но немного по другому |
|---|
| 250 |
TextFil1.AddStr(#13+#10+#13+#10+'['+SectName+']'); //добавить еще и символ конца строки |
|---|
| 251 |
//в конец старой строки, собсно и создав новую строку |
|---|
| 252 |
TextFil1.Cursor := TextFil1.Siz+1; //курсор собсно в конец файла. |
|---|
| 253 |
end; |
|---|
| 254 |
end |
|---|
| 255 |
else begin |
|---|
| 256 |
//Если же файл пустой, то просто вставить сааамую первую секцию :)) |
|---|
| 257 |
TextFil1.AddStr('['+SectName+']'); |
|---|
| 258 |
TextFil1.Cursor := TextFil1.Siz+1; //курсор собсно в конец файла. |
|---|
| 259 |
end; |
|---|
| 260 |
end; |
|---|
| 261 |
|
|---|
| 262 |
//В общем так, выше есть несколько веток алгоритма, но в результате должно получится |
|---|
| 263 |
//одно и тоже - курсор стоит на пустой последней строке секции. |
|---|
| 264 |
//Теперь надо просто дописать туды нонвый элемент (т.к. эта ветка для того |
|---|
| 265 |
//случая, что элемента еще нету нифига... |
|---|
| 266 |
|
|---|
| 267 |
TextFil1.InsertString(TextFil1.Cursor,ElemName+'='+Str+#13+#10); |
|---|
| 268 |
|
|---|
| 269 |
end; |
|---|
| 270 |
end; |
|---|
| 271 |
|
|---|
| 272 |
Procedure TAnIniFile.WriteInteger(const SectName, ElemName : string; Int : integer); |
|---|
| 273 |
begin |
|---|
| 274 |
//Юзя запись в строку, записать туда строкой интегер. |
|---|
| 275 |
WriteString(SectName,ElemName,IntToStr(Int)); |
|---|
| 276 |
end; |
|---|
| 277 |
|
|---|
| 278 |
Procedure TAnIniFile.WriteFloat(const SectName, ElemName : string; Flt : Extended); |
|---|
| 279 |
begin |
|---|
| 280 |
//Юзя запись в строку, записать туда строкой флоат. |
|---|
| 281 |
WriteString(SectName,ElemName,FloatToStr(Flt)); |
|---|
| 282 |
end; |
|---|
| 283 |
|
|---|
| 284 |
Procedure TAnIniFile.WriteBool(const SectName, ElemName : string; Bool : boolean); |
|---|
| 285 |
var |
|---|
| 286 |
TempInt : Integer; |
|---|
| 287 |
begin |
|---|
| 288 |
//Записать |
|---|
| 289 |
WriteString(SectName,ElemName,BoolToStr(Bool)); |
|---|
| 290 |
end; |
|---|
| 291 |
|
|---|
| 292 |
Procedure TAnIniFile.MakNewFile(); |
|---|
| 293 |
begin |
|---|
| 294 |
//"Создавалка нового файла" ;) |
|---|
| 295 |
//на самом деле - нулит TextFil1 |
|---|
| 296 |
|
|---|
| 297 |
TextFil1.MakNewFile; |
|---|
| 298 |
end; |
|---|
| 299 |
|
|---|
| 300 |
Procedure TAnIniFile.CreateSection(const SectName : string); |
|---|
| 301 |
//Создать пустую секцию. |
|---|
| 302 |
begin |
|---|
| 303 |
|
|---|
| 304 |
if SectionExists(SectName) = false then begin |
|---|
| 305 |
//Если такой секции не существует - создаем. |
|---|
| 306 |
//Надо выставить курсор в самый конец файла. |
|---|
| 307 |
If TextFil1.Siz <> 0 then begin |
|---|
| 308 |
//Типа, если вообще файл не пуст. |
|---|
| 309 |
TextFil1.Cursor := TextFil1.Siz+1; //курсор в конец файлы... |
|---|
| 310 |
If TextFil1.FileString[TextFil1.Cursor-1] = #10 then begin |
|---|
| 311 |
//Если конец файла - пустая новая строка |
|---|
| 312 |
//то сразу вставить имя секции |
|---|
| 313 |
//и еще 1 пустую новую строку, на которую и поставить курсор после всего. |
|---|
| 314 |
//Если же до этой пустой новой строки нету еще одной пустой строки |
|---|
| 315 |
//то вставить еще #13#10 чтоб был промежуток между секциями. |
|---|
| 316 |
If TextFil1.Siz > 3 then begin |
|---|
| 317 |
If TextFil1.FileString[TextFil1.Cursor-3] <> #10 then begin |
|---|
| 318 |
TextFil1.AddStr(''); |
|---|
| 319 |
end; |
|---|
| 320 |
end; |
|---|
| 321 |
TextFil1.AddStr('['+SectName+']'); |
|---|
| 322 |
TextFil1.Cursor := TextFil1.Siz+1; //курсор собсно в конец файла. |
|---|
| 323 |
end |
|---|
| 324 |
else begin |
|---|
| 325 |
//Конец файла - не пустая строка (чета есть) |
|---|
| 326 |
//тады - просто тоже самое, что выше, но немного по другому |
|---|
| 327 |
TextFil1.AddStr(#13+#10+#13+#10+'['+SectName+']'); //добавить еще и символ конца строки |
|---|
| 328 |
//в конец старой строки, собсно и создав новую строку |
|---|
| 329 |
TextFil1.Cursor := TextFil1.Siz+1; //курсор собсно в конец файла. |
|---|
| 330 |
end; |
|---|
| 331 |
end |
|---|
| 332 |
else begin |
|---|
| 333 |
//Если же файл пустой, то просто вставить сааамую первую секцию :)) |
|---|
| 334 |
TextFil1.AddStr('['+SectName+']'); |
|---|
| 335 |
TextFil1.Cursor := TextFil1.Siz+1; //курсор собсно в конец файла. |
|---|
| 336 |
end; |
|---|
| 337 |
end; |
|---|
| 338 |
|
|---|
| 339 |
end; |
|---|
| 340 |
|
|---|
| 341 |
Procedure TAnIniFile.RemoveSection(const SectName : string); |
|---|
| 342 |
//Полностью удалить секцию. |
|---|
| 343 |
var |
|---|
| 344 |
TempCursor1 : LongInt; |
|---|
| 345 |
|
|---|
| 346 |
begin |
|---|
| 347 |
|
|---|
| 348 |
//Если только эта секция вообще существует.... |
|---|
| 349 |
if SectionExists(SectName) = true then begin |
|---|
| 350 |
//Ставим курсор на начало секции... |
|---|
| 351 |
GoToSection(SectName,1); |
|---|
| 352 |
TempCursor1 := TextFil1.Cursor; |
|---|
| 353 |
//Ставим курсор на конец секции... |
|---|
| 354 |
GoToSection(SectName,3); |
|---|
| 355 |
//Теперь удаляем нужное количество символов из строки... |
|---|
| 356 |
Delete(TextFil1.FileString, TempCursor1, TextFil1.Cursor-TempCursor1); |
|---|
| 357 |
end; |
|---|
| 358 |
|
|---|
| 359 |
//И типо полюбому курсор ставим на первый символ. |
|---|
| 360 |
TextFil1.Cursor := 1; |
|---|
| 361 |
|
|---|
| 362 |
end; |
|---|
| 363 |
|
|---|
| 364 |
Function TAnIniFile.ReadRawSection(const SectName : string) : string; |
|---|
| 365 |
//Прочитать все содержимое секции в одну строку. |
|---|
| 366 |
var |
|---|
| 367 |
TempCursor1, TempCursor2 : LongInt; |
|---|
| 368 |
|
|---|
| 369 |
begin |
|---|
| 370 |
//По умолчанию возвращается пустая строка... |
|---|
| 371 |
Result := ''; |
|---|
| 372 |
|
|---|
| 373 |
//Если только эта секция вообще существует.... |
|---|
| 374 |
if SectionExists(SectName) = true then begin |
|---|
| 375 |
//Запоминаем исходную позицию курсора... |
|---|
| 376 |
TempCursor2 := TextFil1.Cursor; |
|---|
| 377 |
//Ставим курсор на начало секции... |
|---|
| 378 |
GoToSection(SectName,2); |
|---|
| 379 |
TempCursor1 := TextFil1.Cursor; |
|---|
| 380 |
//Ставим курсор на конец секции... |
|---|
| 381 |
GoToSection(SectName,3); |
|---|
| 382 |
//Теперь копируем инфу в результирующую строку... |
|---|
| 383 |
//если только есть что копировать... |
|---|
| 384 |
if (TextFil1.Cursor-TempCursor1) > 0 then begin |
|---|
| 385 |
Result := Copy(TextFil1.FileString, TempCursor1, TextFil1.Cursor-TempCursor1); |
|---|
| 386 |
end; |
|---|
| 387 |
end; |
|---|
| 388 |
|
|---|
| 389 |
end; |
|---|
| 390 |
|
|---|
| 391 |
Function TAnIniFile.ReadSectionStrings(const SectName : string) : string; |
|---|
| 392 |
//Прочитать все содержимое секции в одну строку, но без строк - камментов. |
|---|
| 393 |
var |
|---|
| 394 |
TempStringList : TStringList; |
|---|
| 395 |
I : Integer; |
|---|
| 396 |
|
|---|
| 397 |
begin |
|---|
| 398 |
//Инициализация |
|---|
| 399 |
TempStringList := TStringList.Create; |
|---|
| 400 |
//По умолчанию возвращается пустая строка... |
|---|
| 401 |
Result := ''; |
|---|
| 402 |
|
|---|
| 403 |
//Если только эта секция вообще существует.... |
|---|
| 404 |
if SectionExists(SectName) = true then begin |
|---|
| 405 |
//Читаем содержимое секции... |
|---|
| 406 |
TempStringList.SetText(PChar(Self.ReadRawSection(SectName))); |
|---|
| 407 |
//Теперь идем построчно. |
|---|
| 408 |
For I := 0 to TempStringList.Count-1 do begin |
|---|
| 409 |
if Self.NotComment(TempStringList.Strings[I]) = true then begin |
|---|
| 410 |
//Строка не является комментом - копируем её в результат. |
|---|
| 411 |
if Result <> '' then Result := Result+#13+#10+TempStringList.Strings[I] |
|---|
| 412 |
else Result := TempStringList.Strings[I]; |
|---|
| 413 |
end; |
|---|
| 414 |
end; |
|---|
| 415 |
end; |
|---|
| 416 |
|
|---|
| 417 |
//Выбросить мусор. |
|---|
| 418 |
TempStringList.Free; |
|---|
| 419 |
end; |
|---|
| 420 |
|
|---|
| 421 |
Procedure TAnIniFile.WriteRawSection(const SectName, SectContent : string); |
|---|
| 422 |
//Перезаписать всё содержимое секции из строки. |
|---|
| 423 |
begin |
|---|
| 424 |
|
|---|
| 425 |
//Для начала удаляем всю секцию... |
|---|
| 426 |
RemoveSection(SectName); |
|---|
| 427 |
|
|---|
| 428 |
//Теперь создаем секцию заново... |
|---|
| 429 |
CreateSection(SectName); |
|---|
| 430 |
//И дописываем инфу в конец секции... курсор после CreateSection уже стоит на пустой строке в конце секции... |
|---|
| 431 |
TextFil1.FileString := TextFil1.FileString+SectContent; |
|---|
| 432 |
|
|---|
| 433 |
end; |
|---|
| 434 |
|
|---|
| 435 |
Procedure TAnIniFile.StrToIniValueList(const InputStr : string; var IniValueList : AIniValueList); |
|---|
| 436 |
//Пропарсить строку и закинуть инфу в динамический массив. |
|---|
| 437 |
var |
|---|
| 438 |
Strings, Elements, I, J, RealStrings, StrsAdded, ElementsAdded : Integer; |
|---|
| 439 |
SearchPChar : PChar; |
|---|
| 440 |
TrimmedStr, CurrStr, ElementStr, ValueStr : string; |
|---|
| 441 |
Done : boolean; |
|---|
| 442 |
|
|---|
| 443 |
begin |
|---|
| 444 |
//Инициализация |
|---|
| 445 |
Done := false; |
|---|
| 446 |
//Для начала - обтримать пробелы и переносы строк... |
|---|
| 447 |
TrimmedStr := TrimEx(InputStr,' '+#13+#10); |
|---|
| 448 |
|
|---|
| 449 |
//Проверяем есть ли что-то в строке... |
|---|
| 450 |
if Length(TrimmedStr) = 0 then begin |
|---|
| 451 |
//Строка пуста. Просто переводим массив в нуль и заканчиваем работу. |
|---|
| 452 |
SetLength(IniValueList,0,0); |
|---|
| 453 |
Done := true; |
|---|
| 454 |
end; |
|---|
| 455 |
|
|---|
| 456 |
//Едем дальше. |
|---|
| 457 |
if Done = false then begin |
|---|
| 458 |
|
|---|
| 459 |
//Подсчитать количество строк. |
|---|
| 460 |
Strings := 1; //Как минимум 1 строка там уже есть. |
|---|
| 461 |
I := 0; //Начинаем поиск с 1-го символа. |
|---|
| 462 |
repeat |
|---|
| 463 |
I := I+1; |
|---|
| 464 |
if TrimmedStr[I] = #10 then begin |
|---|
| 465 |
Strings := Strings+1; |
|---|
| 466 |
end; |
|---|
| 467 |
until I = Length(TrimmedStr); |
|---|
| 468 |
|
|---|
| 469 |
//Посчитали. Выделяем память в динамическом массиве (1-й уровень)... |
|---|
| 470 |
SetLength(IniValueList,Strings); |
|---|
| 471 |
|
|---|
| 472 |
//Терь построчно читаем инфу... |
|---|
| 473 |
//Начальные значения переменных... |
|---|
| 474 |
RealStrings := Strings; |
|---|
| 475 |
StrsAdded := 0; |
|---|
| 476 |
for I := 1 to Strings do begin |
|---|
| 477 |
//Выпарсиваем кусок от строки.... |
|---|
| 478 |
CurrStr := {TrimRight(}Parse(TrimmedStr,#13+#10){)}; |
|---|
| 479 |
//Подчищаем триманутую строку на всякий случай... |
|---|
| 480 |
TrimExLeft(TrimmedStr,' '+#13+#10); |
|---|
| 481 |
|
|---|
| 482 |
//Строчка есть. Теперь смотрим, не коммент ли она... |
|---|
| 483 |
if NotComment(CurrStr) = true then begin |
|---|
| 484 |
//не коммент - читаем. |
|---|
| 485 |
|
|---|
| 486 |
//Подсчитать количество элементов по точкам с запятой. |
|---|
| 487 |
Elements := 1; //Как минимум 1 штука уже должна быть. |
|---|
| 488 |
J := 0; //Поиск с 1-го символа. |
|---|
| 489 |
repeat |
|---|
| 490 |
J := J+1; |
|---|
| 491 |
if CurrStr[J] = ';' then begin |
|---|
| 492 |
//Найден разделитель элемента. |
|---|
| 493 |
Elements := Elements+1; |
|---|
| 494 |
end; |
|---|
| 495 |
until J = Length(CurrStr); |
|---|
| 496 |
|
|---|
| 497 |
//Выделить место в массиве... |
|---|
| 498 |
SetLength(IniValueList[StrsAdded],Elements); |
|---|
| 499 |
|
|---|
| 500 |
//Пропарсить элементы... |
|---|
| 501 |
ElementsAdded := -1; //Чтобы начать с 0-го элемента. |
|---|
| 502 |
repeat |
|---|
| 503 |
ElementsAdded := ElementsAdded+1; |
|---|
| 504 |
ElementStr := Trim(Parse(CurrStr,';')); //Прочитать очередной элемент... |
|---|
| 505 |
IniValueList[StrsAdded,ElementsAdded].Name := TrimRight(Parse(ElementStr,':')); //Имя элемента |
|---|
| 506 |
IniValueList[StrsAdded,ElementsAdded].Value := TrimLeft(ElementStr); //Значение элемента |
|---|
| 507 |
until Length(CurrStr) = 0; |
|---|
| 508 |
|
|---|
| 509 |
//Прибавить счетчик прочитанных строк. |
|---|
| 510 |
StrsAdded := StrsAdded+1; |
|---|
| 511 |
end |
|---|
| 512 |
else begin |
|---|
| 513 |
//Коммент - значит эта строка пуста, надо уменьшить размер массива... |
|---|
| 514 |
RealStrings := RealStrings-1; |
|---|
| 515 |
SetLength(IniValueList,RealStrings); |
|---|
| 516 |
end; |
|---|
| 517 |
|
|---|
| 518 |
end; |
|---|
| 519 |
|
|---|
| 520 |
end; |
|---|
| 521 |
|
|---|
| 522 |
end; |
|---|
| 523 |
|
|---|
| 524 |
Function TAnIniFile.IniValueListToStr(var IniValueList : AIniValueList) : string; |
|---|
| 525 |
//Сгенерить строку из инфы динамического массива. |
|---|
| 526 |
var |
|---|
| 527 |
I, J : Integer; |
|---|
| 528 |
begin |
|---|
| 529 |
//Элементарно пробежаться по массиву и вернуть строку... |
|---|
| 530 |
Result := ''; //Изначально пустая |
|---|
| 531 |
|
|---|
| 532 |
if Length(IniValueList) > 0 then begin |
|---|
| 533 |
|
|---|
| 534 |
for I := 0 to Length(IniValueList)-1 do begin |
|---|
| 535 |
|
|---|
| 536 |
//Добавить элементы |
|---|
| 537 |
for J := 0 to Length(IniValueList[I])-1 do begin |
|---|
| 538 |
Result := Result+IniValueList[I,J].Name+': '+IniValueList[I,J].Value; |
|---|
| 539 |
if J <> Length(IniValueList[I])-1 then begin |
|---|
| 540 |
//Если элемент не последний - добавить разделитель элементов |
|---|
| 541 |
Result := Result+'; '; |
|---|
| 542 |
end; |
|---|
| 543 |
end; |
|---|
| 544 |
|
|---|
| 545 |
//Если строка не последняя - добавить разделитель строк. |
|---|
| 546 |
if I <> Length(IniValueList)-1 then begin |
|---|
| 547 |
Result := Result+#13+#10; |
|---|
| 548 |
end; |
|---|
| 549 |
end; |
|---|
| 550 |
|
|---|
| 551 |
end; |
|---|
| 552 |
|
|---|
| 553 |
//Собсно - это все %). |
|---|
| 554 |
end; |
|---|
| 555 |
|
|---|
| 556 |
Procedure TAnIniFile.ReadIniValueList(const SectName : string; var IniValueList : AIniValueList); |
|---|
| 557 |
//Прочитать IniValueList из секции. |
|---|
| 558 |
begin |
|---|
| 559 |
StrToIniValueList(ReadRawSection(SectName),IniValueList); |
|---|
| 560 |
end; |
|---|
| 561 |
|
|---|
| 562 |
Procedure TAnIniFile.WriteIniValueList(const SectName : string; var IniValueList : AIniValueList); |
|---|
| 563 |
//Перезаписать инфу секции из IniValueList. |
|---|
| 564 |
begin |
|---|
| 565 |
WriteRawSection(SectName,IniValueListToStr(IniValueList)); |
|---|
| 566 |
end; |
|---|
| 567 |
|
|---|
| 568 |
Function TAnIniFile.CompareIniValueElements(var IniValueList1, IniValueList2 : AIniValueList; const List1Index, List2Index : Integer; const CaseSensitive : boolean; const ExceptValueNames : AnsiString) : Boolean; |
|---|
| 569 |
//Функция сравнивает 2 строки 2 списков значений, если они идентичны (с учетом условий каш-сенситив |
|---|
| 570 |
//и исключенных элементов) - возвращает true, иначе false. Если первое из Except - "all" то все |
|---|
| 571 |
//последующие - наоборот те что проверяются, остальные игнорируются. |
|---|
| 572 |
var |
|---|
| 573 |
I, J, I2, J2, ElI : Integer; |
|---|
| 574 |
ExceptsList : TStringList; |
|---|
| 575 |
ExceptAll, IdentElemFinded, CanCheck : Boolean; |
|---|
| 576 |
|
|---|
| 577 |
begin |
|---|
| 578 |
//Инициализация. |
|---|
| 579 |
Result := true; //По умолчанию считаем что значения идентичны. |
|---|
| 580 |
ExceptAll := false; //По умолчанию это вырублено. |
|---|
| 581 |
ExceptsList := TStringList.Create; |
|---|
| 582 |
|
|---|
| 583 |
//Заполняем список ексцептов... |
|---|
| 584 |
ExtractStrings([','],[' '],PChar(ExceptValueNames),ExceptsList); |
|---|
| 585 |
//Проверяем механьызьм екцзепта.... |
|---|
| 586 |
if ExceptsList.Count > 0 then begin |
|---|
| 587 |
if LowerCase(ExceptsList.Strings[0]) = 'all' then begin |
|---|
| 588 |
//Ага, есть такое дело. |
|---|
| 589 |
ExceptAll := true; |
|---|
| 590 |
//Удаляем элемент "all". |
|---|
| 591 |
ExceptsList.Delete(0); |
|---|
| 592 |
end; |
|---|
| 593 |
end; |
|---|
| 594 |
|
|---|
| 595 |
//Проверяем 1-й список... |
|---|
| 596 |
for I := 0 to Length(IniValueList1[List1Index])-1 do begin |
|---|
| 597 |
|
|---|
| 598 |
//Проверяем, проходит ли по екцептам. |
|---|
| 599 |
if ExceptAll = false then begin |
|---|
| 600 |
//Исключение по принципу "разрешено все, кроме..." |
|---|
| 601 |
CanCheck := true; |
|---|
| 602 |
for ElI := 0 to ExceptsList.Count-1 do begin |
|---|
| 603 |
if LowerCase(IniValueList1[List1Index,I].Name) = LowerCase(ExceptsList.Strings[ElI]) then begin |
|---|
| 604 |
//Нашли что элемент исключается. |
|---|
| 605 |
CanCheck := false; |
|---|
| 606 |
Break; |
|---|
| 607 |
end; |
|---|
| 608 |
end; |
|---|
| 609 |
end |
|---|
| 610 |
else begin |
|---|
| 611 |
//Исключение по принципу "запрещено все, кроме..." |
|---|
| 612 |
CanCheck := false; |
|---|
| 613 |
for ElI := 0 to ExceptsList.Count-1 do begin |
|---|
| 614 |
if LowerCase(IniValueList1[List1Index,I].Name) = LowerCase(ExceptsList.Strings[ElI]) then begin |
|---|
| 615 |
//Нашли что элемент _не_ исключается. |
|---|
| 616 |
CanCheck := true; |
|---|
| 617 |
Break; |
|---|
| 618 |
end; |
|---|
| 619 |
end; |
|---|
| 620 |
end; |
|---|
| 621 |
|
|---|
| 622 |
//Ок, если значение не попало под исключения - проверяем его... Надо обязательно найти аналогичное значение во втором списке, иначе считаем что списки не идентичны. |
|---|
| 623 |
if CanCheck = true then begin |
|---|
| 624 |
Result := false; //Задача цикла внизу - вернуть true. Иначе все вылетит с результатом false. |
|---|
| 625 |
for J := 0 to Length(IniValueList2[List2Index])-1 do begin |
|---|
| 626 |
//Сканим %). |
|---|
| 627 |
if LowerCase(IniValueList1[List1Index,I].Name) = LowerCase(IniValueList2[List2Index,J].Name) then begin |
|---|
| 628 |
//Ага, нашли значение с таким же именем. Теперь проверяем собсно значение. |
|---|
| 629 |
//Причем в зависимости от кейс-сенситива. |
|---|
| 630 |
if CaseSensitive = true then begin |
|---|
| 631 |
//Регистр учитывается. |
|---|
| 632 |
if IniValueList1[List1Index,I].Value = IniValueList2[List2Index,J].Value then begin |
|---|
| 633 |
//Ага, идентичны, true. |
|---|
| 634 |
Result := true; |
|---|
| 635 |
//И брякаем - вылетит в прямо на уровень внутри if CanCheck = true then begin |
|---|
| 636 |
Break; |
|---|
| 637 |
end; |
|---|
| 638 |
end |
|---|
| 639 |
else begin |
|---|
| 640 |
//Регистр не учитывается. |
|---|
| 641 |
if LowerCase(IniValueList1[List1Index,I].Value) = LowerCase(IniValueList2[List2Index,J].Value) then begin |
|---|
| 642 |
//Ага, идентичны, true. |
|---|
| 643 |
Result := true; |
|---|
| 644 |
//И брякаем - вылетит в прямо на уровень внутри if CanCheck = true then begin |
|---|
| 645 |
Break; |
|---|
| 646 |
end; |
|---|
| 647 |
end; |
|---|
| 648 |
end; |
|---|
| 649 |
end; |
|---|
| 650 |
//Просканили, смотрим - true оно или false. Если false то имеем бряк, что по факту приведет к завершению функции |
|---|
| 651 |
//и возвращению ей false. |
|---|
| 652 |
if Result = false then begin |
|---|
| 653 |
Break; |
|---|
| 654 |
end; |
|---|
| 655 |
end; |
|---|
| 656 |
|
|---|
| 657 |
end; |
|---|
| 658 |
|
|---|
| 659 |
//Ок, проверили 1-й список. Если Result все еще true - то проверяем 2-й, аналогично. |
|---|
| 660 |
if Result = true then begin |
|---|
| 661 |
for I := 0 to Length(IniValueList2[List2Index])-1 do begin |
|---|
| 662 |
|
|---|
| 663 |
//Проверяем, проходит ли по екцептам. |
|---|
| 664 |
if ExceptAll = false then begin |
|---|
| 665 |
//Исключение по принципу "разрешено все, кроме..." |
|---|
| 666 |
CanCheck := true; |
|---|
| 667 |
for ElI := 0 to ExceptsList.Count-1 do begin |
|---|
| 668 |
if LowerCase(IniValueList2[List2Index,I].Name) = LowerCase(ExceptsList.Strings[ElI]) then begin |
|---|
| 669 |
//Нашли что элемент исключается. |
|---|
| 670 |
CanCheck := false; |
|---|
| 671 |
Break; |
|---|
| 672 |
end; |
|---|
| 673 |
end; |
|---|
| 674 |
end |
|---|
| 675 |
else begin |
|---|
| 676 |
//Исключение по принципу "запрещено все, кроме..." |
|---|
| 677 |
CanCheck := false; |
|---|
| 678 |
for ElI := 0 to ExceptsList.Count-1 do begin |
|---|
| 679 |
if LowerCase(IniValueList2[List2Index,I].Name) = LowerCase(ExceptsList.Strings[ElI]) then begin |
|---|
| 680 |
//Нашли что элемент _не_ исключается. |
|---|
| 681 |
CanCheck := true; |
|---|
| 682 |
Break; |
|---|
| 683 |
end; |
|---|
| 684 |
end; |
|---|
| 685 |
end; |
|---|
| 686 |
|
|---|
| 687 |
//Ок, если значение не попало под исключения - проверяем его... Надо обязательно найти аналогичное значение во втором списке, иначе считаем что списки не идентичны. |
|---|
| 688 |
if CanCheck = true then begin |
|---|
| 689 |
Result := false; //Задача цикла внизу - вернуть true. Иначе все вылетит с результатом false. |
|---|
| 690 |
for J := 0 to Length(IniValueList1[List1Index])-1 do begin |
|---|
| 691 |
//Сканим %). |
|---|
| 692 |
if LowerCase(IniValueList2[List2Index,I].Name) = LowerCase(IniValueList1[List1Index,J].Name) then begin |
|---|
| 693 |
//Ага, нашли значение с таким же именем. Теперь проверяем собсно значение. |
|---|
| 694 |
//Причем в зависимости от кейс-сенситива. |
|---|
| 695 |
if CaseSensitive = true then begin |
|---|
| 696 |
//Регистр учитывается. |
|---|
| 697 |
if IniValueList2[List2Index,I].Value = IniValueList1[List1Index,J].Value then begin |
|---|
| 698 |
//Ага, идентичны, true. |
|---|
| 699 |
Result := true; |
|---|
| 700 |
//И брякаем - вылетит в прямо на уровень внутри if CanCheck = true then begin |
|---|
| 701 |
Break; |
|---|
| 702 |
end; |
|---|
| 703 |
end |
|---|
| 704 |
else begin |
|---|
| 705 |
//Регистр не учитывается. |
|---|
| 706 |
if LowerCase(IniValueList2[List2Index,I].Value) = LowerCase(IniValueList1[List1Index,J].Value) then begin |
|---|
| 707 |
//Ага, идентичны, true. |
|---|
| 708 |
Result := true; |
|---|
| 709 |
//И брякаем - вылетит в прямо на уровень внутри if CanCheck = true then begin |
|---|
| 710 |
Break; |
|---|
| 711 |
end; |
|---|
| 712 |
end; |
|---|
| 713 |
end; |
|---|
| 714 |
end; |
|---|
| 715 |
//Просканили, смотрим - true оно или false. Если false то имеем бряк, что по факту приведет к завершению функции |
|---|
| 716 |
//и возвращению ей false. |
|---|
| 717 |
if Result = false then begin |
|---|
| 718 |
Break; |
|---|
| 719 |
end; |
|---|
| 720 |
end; |
|---|
| 721 |
|
|---|
| 722 |
end; |
|---|
| 723 |
end; |
|---|
| 724 |
|
|---|
| 725 |
//Чистим мусор. |
|---|
| 726 |
ExceptsList.Free; |
|---|
| 727 |
end; |
|---|
| 728 |
|
|---|
| 729 |
Function TAnIniFile.CompareIniValueLists(var IniValueList1, IniValueList2 : AIniValueList; const CaseSensitive : boolean; const ExceptValueNames : AnsiString) : Boolean; |
|---|
| 730 |
//Функция сравнивает 2 списка значений, если списки идентичны (с учетом условий каш-сенситив и исключенных |
|---|
| 731 |
//элементов) - возвращает true, иначе false. Если первое из Except - "all" то все последующие - наоборот те |
|---|
| 732 |
//что проверяются, остальные игнорируются. |
|---|
| 733 |
var |
|---|
| 734 |
I, J : Integer; |
|---|
| 735 |
IdentElemFinded : Boolean; |
|---|
| 736 |
begin |
|---|
| 737 |
//Инициализация. |
|---|
| 738 |
Result := true; //По умолчанию считаем что списки идентичны... |
|---|
| 739 |
|
|---|
| 740 |
//Сверяем размер списков. |
|---|
| 741 |
if Length(IniValueList1) <> Length(IniValueList2) then begin |
|---|
| 742 |
Result := false; |
|---|
| 743 |
end; |
|---|
| 744 |
|
|---|
| 745 |
if (Result = true) and (Length(IniValueList1) > 0) then begin |
|---|
| 746 |
//Если в списках вообще что-то есть то сверяем их содержимое. |
|---|
| 747 |
for I := 0 to Length(IniValueList1)-1 do begin |
|---|
| 748 |
|
|---|
| 749 |
//Ищем во втором списке элемент, идентичный данному... |
|---|
| 750 |
IdentElemFinded := false; |
|---|
| 751 |
for J := 0 to Length(IniValueList2)-1 do begin |
|---|
| 752 |
IdentElemFinded := false; //Так надо на начало каждой интерации цикла. |
|---|
| 753 |
if CompareIniValueElements(IniValueList1, IniValueList2, I, J, CaseSensitive, ExceptValueNames) = true then begin |
|---|
| 754 |
//Нашли идентичный элемент. Оставляем отметку и брякаем цикл. |
|---|
| 755 |
IdentElemFinded := true; |
|---|
| 756 |
Break; |
|---|
| 757 |
end; |
|---|
| 758 |
end; |
|---|
| 759 |
|
|---|
| 760 |
//Смотрим - если идентичный элемент не найден - то Отмечаем false в результате, и опять же брякаем циклу... |
|---|
| 761 |
if IdentElemFinded = false then begin |
|---|
| 762 |
Result := false; |
|---|
| 763 |
Break; |
|---|
| 764 |
end; |
|---|
| 765 |
end; |
|---|
| 766 |
end; |
|---|
| 767 |
end; |
|---|
| 768 |
|
|---|
| 769 |
Function TAnIniFile.GetIniValueListValueIndex(var IniValueList : AIniValueList; const ValIndex : Integer; const ValueName : AnsiString) : Integer; |
|---|
| 770 |
//Вернуть индекс значения с указанным именем в указанной строке списка (элементе). |
|---|
| 771 |
var |
|---|
| 772 |
I : Integer; |
|---|
| 773 |
TempValName : AnsiString; |
|---|
| 774 |
|
|---|
| 775 |
begin |
|---|
| 776 |
//Инициализация. |
|---|
| 777 |
TempValName := LowerCase(ValueName); |
|---|
| 778 |
Result := -1; |
|---|
| 779 |
|
|---|
| 780 |
//Ищем значение и возвращаем результат. |
|---|
| 781 |
for I := 0 to Length(IniValueList[ValIndex])-1 do begin |
|---|
| 782 |
if LowerCase(IniValueList[ValIndex,I].Name) = TempValName then begin |
|---|
| 783 |
Result := I; |
|---|
| 784 |
Break; |
|---|
| 785 |
end; |
|---|
| 786 |
end; |
|---|
| 787 |
end; |
|---|
| 788 |
|
|---|
| 789 |
Function TAnIniFile.GetIniValueListValue(var IniValueList : AIniValueList; const ValIndex : Integer; const ValueName : AnsiString) : AnsiString; |
|---|
| 790 |
//Функция возвращает содержимое значения с указанным именем в указанной строке списка. |
|---|
| 791 |
var |
|---|
| 792 |
I : Integer; |
|---|
| 793 |
|
|---|
| 794 |
begin |
|---|
| 795 |
//Инициализация. |
|---|
| 796 |
Result := ''; |
|---|
| 797 |
|
|---|
| 798 |
//Ищем значение и возвращаем результат. |
|---|
| 799 |
I := Self.GetIniValueListValueIndex(IniValueList,ValIndex,ValueName); |
|---|
| 800 |
if I >= 0 then begin |
|---|
| 801 |
Result := IniValueList[ValIndex,I].Value; |
|---|
| 802 |
end; |
|---|
| 803 |
end; |
|---|
| 804 |
|
|---|
| 805 |
Function TAnIniFile.ChangeIniValueListValue(var IniValueList : AIniValueList; const ValIndex : Integer; const ValueName, ValueValue : AnsiString) : Boolean; |
|---|
| 806 |
//Функция записывает новое содержимое в значение с указанным именем в указанной строке списка. |
|---|
| 807 |
var |
|---|
| 808 |
I : Integer; |
|---|
| 809 |
TempValName : AnsiString; |
|---|
| 810 |
|
|---|
| 811 |
begin |
|---|
| 812 |
//Инициализация. |
|---|
| 813 |
TempValName := LowerCase(ValueName); |
|---|
| 814 |
Result := false; |
|---|
| 815 |
|
|---|
| 816 |
//Ищем значение. |
|---|
| 817 |
for I := 0 to Length(IniValueList)-1 do begin |
|---|
| 818 |
if LowerCase(IniValueList[ValIndex,I].Name) = TempValName then begin |
|---|
| 819 |
//Нашли, изменяем содержимое. |
|---|
| 820 |
IniValueList[ValIndex,I].Value := ValueValue; |
|---|
| 821 |
Result := true; |
|---|
| 822 |
Break; |
|---|
| 823 |
end; |
|---|
| 824 |
end; |
|---|
| 825 |
|
|---|
| 826 |
end; |
|---|
| 827 |
|
|---|
| 828 |
Function TAnIniFile.IniValueListValueExists(var IniValueList : AIniValueList; const ValIndex : Integer; const ValueName : AnsiString) : Boolean; |
|---|
| 829 |
//Если значение существует - возвращает true, иначе false. |
|---|
| 830 |
var |
|---|
| 831 |
I : Integer; |
|---|
| 832 |
TempValName : AnsiString; |
|---|
| 833 |
|
|---|
| 834 |
begin |
|---|
| 835 |
//Инициализация. |
|---|
| 836 |
TempValName := LowerCase(ValueName); |
|---|
| 837 |
Result := false; |
|---|
| 838 |
|
|---|
| 839 |
//Ищем значение. |
|---|
| 840 |
for I := 0 to Length(IniValueList)-1 do begin |
|---|
| 841 |
if LowerCase(IniValueList[ValIndex,I].Name) = TempValName then begin |
|---|
| 842 |
//Нашли, значит оно есть. Сообщаем об этом. |
|---|
| 843 |
Result := true; |
|---|
| 844 |
Break; |
|---|
| 845 |
end; |
|---|
| 846 |
end; |
|---|
| 847 |
end; |
|---|
| 848 |
|
|---|
| 849 |
Function TAnIniFile.GetIniValueListIndexByValue(var IniValueList : AIniValueList; const ValueName, ValueValue : AnsiString) : Integer; |
|---|
| 850 |
//Возвращает индекс первого встреченного элемента (сверху) с указанным именем значения и собсно значением. |
|---|
| 851 |
//Если ничего такого нема - вернет -1. |
|---|
| 852 |
var |
|---|
| 853 |
I, ValueNum : Integer; |
|---|
| 854 |
TempValueStr : AnsiString; |
|---|
| 855 |
|
|---|
| 856 |
begin |
|---|
| 857 |
//Инициализация. |
|---|
| 858 |
Result := -1; |
|---|
| 859 |
|
|---|
| 860 |
//Получить сверяемое значение в нижнем регистре. |
|---|
| 861 |
TempValueStr := LowerCase(ValueValue); |
|---|
| 862 |
//Пробежимся по списку в поисках подходящего элемента. |
|---|
| 863 |
for I := 0 to Length(IniValueList)-1 do begin |
|---|
| 864 |
//Смотрим - есть ли тут значение с нужным именем? |
|---|
| 865 |
ValueNum := Self.GetIniValueListValueIndex(IniValueList,I,ValueName); |
|---|
| 866 |
if ValueNum >= 0 then begin |
|---|
| 867 |
//Ага, есть тут такая фиговина. Смотрим - а то ли там собсно значение? |
|---|
| 868 |
if LowerCase(IniValueList[I,ValueNum].Value) = TempValueStr then begin |
|---|
| 869 |
//Вахъ, и в самом деле оно. Поиск завершен, возвращаем результат. |
|---|
| 870 |
Result := I; |
|---|
| 871 |
Break; |
|---|
| 872 |
end; |
|---|
| 873 |
end; |
|---|
| 874 |
end; |
|---|
| 875 |
|
|---|
| 876 |
end; |
|---|
| 877 |
|
|---|
| 878 |
Function TAnIniFile.CopyIniValueListElement(var From, Dest : AIniValueList; const FromIndex, DestIndex : Integer) : Boolean; |
|---|
| 879 |
//Скопировать содержимое одного элемента одного списка в другой элемент другого списка (в теории возможно |
|---|
| 880 |
//и в рамкеах одного списка если оба указателя оставить на один и тот же список.). |
|---|
| 881 |
var |
|---|
| 882 |
I : Integer; |
|---|
| 883 |
begin |
|---|
| 884 |
//Инициализация. |
|---|
| 885 |
Result := false; |
|---|
| 886 |
|
|---|
| 887 |
//Выставляем размер элемента... |
|---|
| 888 |
SetLength(Dest[DestIndex],Length(From[FromIndex])); |
|---|
| 889 |
//Собсно копируем... |
|---|
| 890 |
for I := 0 to Length(From[FromIndex])-1 do begin |
|---|
| 891 |
Dest[DestIndex,I].Name := From[FromIndex,I].Name; |
|---|
| 892 |
Dest[DestIndex,I].Value := From[FromIndex,I].Value; |
|---|
| 893 |
end; |
|---|
| 894 |
//И вернуть результат. |
|---|
| 895 |
Result := true; |
|---|
| 896 |
end; |
|---|
| 897 |
|
|---|
| 898 |
Function TAnIniFile.CopyIniValueList(var From, Dest : AIniValueList) : Boolean; |
|---|
| 899 |
//Скопировать содержимое одного списка в другой. |
|---|
| 900 |
var |
|---|
| 901 |
I : Integer; |
|---|
| 902 |
begin |
|---|
| 903 |
//Инициализация. |
|---|
| 904 |
Result := true; |
|---|
| 905 |
|
|---|
| 906 |
//Чистим целевой массив... |
|---|
| 907 |
SetLength(Dest, 0, 0); |
|---|
| 908 |
//Собсно поехали. Выставить размер массива первого уровня... |
|---|
| 909 |
SetLength(Dest, Length(From)); |
|---|
| 910 |
//Поехали по этому массиву... |
|---|
| 911 |
for I := 0 to Length(From)-1 do begin |
|---|
| 912 |
//Копируем собсно элемент. |
|---|
| 913 |
if Self.CopyIniValueListElement(From, Dest, I, I) = false then begin |
|---|
| 914 |
//Если при этом была какая-то ошибка - вываливаемся из цикла, возвращая false. |
|---|
| 915 |
Result := false; |
|---|
| 916 |
Break; |
|---|
| 917 |
end; |
|---|
| 918 |
end; |
|---|
| 919 |
end; |
|---|
| 920 |
|
|---|
| 921 |
Function TAnIniFile.AddIniValueList(var From, Dest : AIniValueList) : Boolean; |
|---|
| 922 |
//Скопировать содержимое одного списка в другой, добавив новые данные в конец |
|---|
| 923 |
//целевого списка и сохранив все уже там присутствовавшее. |
|---|
| 924 |
var |
|---|
| 925 |
I, OldDestLength : Integer; |
|---|
| 926 |
begin |
|---|
| 927 |
//Инициализация. |
|---|
| 928 |
Result := true; |
|---|
| 929 |
|
|---|
| 930 |
//Меняем размер целевого массива... |
|---|
| 931 |
OldDestLength := Length(Dest); |
|---|
| 932 |
SetLength(Dest, Length(Dest)+Length(From)); |
|---|
| 933 |
//Поехали по этому массиву... |
|---|
| 934 |
for I := 0 to Length(From)-1 do begin |
|---|
| 935 |
//Копируем собсно элемент. |
|---|
| 936 |
if Self.CopyIniValueListElement(From, Dest, I, OldDestLength+I) = false then begin |
|---|
| 937 |
//Если при этом была какая-то ошибка - вываливаемся из цикла, возвращая false. |
|---|
| 938 |
Result := false; |
|---|
| 939 |
Break; |
|---|
| 940 |
end; |
|---|
| 941 |
end; |
|---|
| 942 |
end; |
|---|
| 943 |
|
|---|
| 944 |
Function TAnIniFile.RemoveIniValueListValue(var IniValueList : AIniValueList; const ValIndex : Integer; const ValueName : AnsiString) : Boolean; |
|---|
| 945 |
//Удалить значение с указанным именем в указанном элементе в IniValueList. |
|---|
| 946 |
//Если значение такое не существовало - вернет false, иначе true. |
|---|
| 947 |
var |
|---|
| 948 |
I, ValuesNum : Integer; |
|---|
| 949 |
DeletingValue, DummyValue : RIniValueListElement; |
|---|
| 950 |
|
|---|
| 951 |
begin |
|---|
| 952 |
//Инициализация. |
|---|
| 953 |
Result := false; |
|---|
| 954 |
ValuesNum := Length(IniValueList[ValIndex]); |
|---|
| 955 |
|
|---|
| 956 |
//Существует ли нужное значение? И заодно номер его получить. |
|---|
| 957 |
I := Self.GetIniValueListValueIndex(IniValueList,ValIndex,ValueName); |
|---|
| 958 |
if I >= 0 then begin |
|---|
| 959 |
//Итак, значение для удаления найдено. |
|---|
| 960 |
//Если это значение не последнее - то двигаем значения в массиве чтобы таки стало последним. |
|---|
| 961 |
if I <> ValuesNum-1 then begin |
|---|
| 962 |
Move(IniValueList[ValIndex,I],DeletingValue,SizeOf(RIniValueListElement)); //Временно копируем инфу удаляемого значения. |
|---|
| 963 |
Move(IniValueList[ValIndex,I+1],IniValueList[ValIndex,I],SizeOf(RIniValueListElement)*(ValuesNum-(I+1))); //Переносим инфу других значений. |
|---|
| 964 |
Move(DeletingValue,IniValueList[ValIndex,ValuesNum-1],SizeOf(RIniValueListElement)); //Копируем удаляемое значение в конец массива чтоб его прочистило при смене размера массива (во избежание утечков памяти). |
|---|
| 965 |
Move(DummyValue,DeletingValue,SizeOf(RIniValueListElement)); //Копируем во временное значение инфу значения заглушки - чтобы тупой сборщег мусора не полез по ссылкам и не заховал последнее значение массива раньше или позже (т.е. еще раз на пустое место) правильного времени. |
|---|
| 966 |
end; |
|---|
| 967 |
//Почистить удаляемое значение. |
|---|
| 968 |
IniValueList[ValIndex,ValuesNum-1].Name := ''; |
|---|
| 969 |
IniValueList[ValIndex,ValuesNum-1].Value := ''; |
|---|
| 970 |
//И почистить массив. |
|---|
| 971 |
ValuesNum := ValuesNum-1; |
|---|
| 972 |
SetLength(IniValueList[ValIndex],ValuesNum); |
|---|
| 973 |
//Done. |
|---|
| 974 |
Result := true; |
|---|
| 975 |
end; |
|---|
| 976 |
end; |
|---|
| 977 |
|
|---|
| 978 |
Function TAnIniFile.RemoveIniValueListElement(var IniValueList : AIniValueList; const ValIndex : Integer) : Boolean; |
|---|
| 979 |
//Удалить указанный элемент IniValueList. Если элемент не существовал - вернет false, в остальных случаях true. |
|---|
| 980 |
var |
|---|
| 981 |
I, ValuesNum, ElementsNum : Integer; |
|---|
| 982 |
DeletingElement, DummyElement : AIniValueListElements; |
|---|
| 983 |
|
|---|
| 984 |
begin |
|---|
| 985 |
//Инициализация. |
|---|
| 986 |
Result := false; |
|---|
| 987 |
DeletingElement := nil; //Чтобы убедиться что в памяти под этот массив ничего не выделено. |
|---|
| 988 |
SetLength(DummyElement,0); |
|---|
| 989 |
|
|---|
| 990 |
if Length(IniValueList) >= ValIndex then begin |
|---|
| 991 |
//т.е. если в массиве есть элемент с таким индексом. |
|---|
| 992 |
//Для начала - очистить содержимое элемента. |
|---|
| 993 |
ValuesNum := Length(IniValueList[ValIndex]); |
|---|
| 994 |
for I := 0 to ValuesNum-1 do begin |
|---|
| 995 |
IniValueList[ValIndex,I].Name := ''; |
|---|
| 996 |
IniValueList[ValIndex,I].Value := ''; |
|---|
| 997 |
end; |
|---|
| 998 |
SetLength(IniValueList[ValIndex],0); |
|---|
| 999 |
//Теперь надо удалить собсно сам элемент. |
|---|
| 1000 |
ElementsNum := Length(IniValueList); |
|---|
| 1001 |
//Если это значение не последнее - то двигаем значения в массиве чтобы таки стало последним. |
|---|
| 1002 |
if ValIndex <> ElementsNum-1 then begin |
|---|
| 1003 |
Move(IniValueList[ValIndex],DeletingElement,SizeOf(AIniValueListElements)); //Временно копируем инфу удаляемого элемента. |
|---|
| 1004 |
Move(IniValueList[ValIndex+1],IniValueList[ValIndex],SizeOf(AIniValueListElements)*(ElementsNum-(ValIndex+1))); //Переносим инфу других элементов. |
|---|
| 1005 |
Move(DeletingElement,IniValueList[ElementsNum-1],SizeOf(AIniValueListElements)); //Копируем удаляемый элемент в конец массива чтоб его прочистило при смене размера массива (во избежание утечков памяти). |
|---|
| 1006 |
Move(DummyElement,DeletingElement,SizeOf(AIniValueListElements)); //Копируем во временный элемент инфу значение заглушки - чтобы тупой сборщег мусора не полез по ссылкам и не заховал последний элемент массива раньше или позже (т.е. еще раз на пустое место) правильного времени. |
|---|
|