root/trunk/PascalCodeModifier.pas

Revision 158, 28.7 kB (checked in by sagrer, 5 months ago)
  1. Поправлены параметры запуска VerRevUpdater? через IDE
  2. Прикручена локализация в FlistFormat?.pas, IssFormat?.pas, SconfFormat.pas, PascalCodeModifier?.pas
  3. Прикручена локализация к IssBuilder?.
  4. Добавлен перевод на русский для IssBuilder?
  5. Выполнен #34
  • Property svnmailer:content-charset set to cp1251
Line 
1 ////////////////////////////////////////////////////////////
2 //            Класс для работы с файлом с кодом           //
3 //             на паскале - чтение и изменение            //
4 //                    элементов кода                      //
5 //                        v 0.1                           //
6 //                                                        //
7 //              Copyright (C) 2007 Sagrer                 //
8 //          Распространяется на условиях LGPL 2.1         //
9 //                  см. файл lgpl.txt                     //
10 //                                                        //
11 //                   sagrer@yandex.ru                     //
12 ////////////////////////////////////////////////////////////
13
14 //К работе над данным файлом приложили руки, ноги.... короче аффтары:
15 // 1) Sagrer (sagrer@yandex.ru)
16
17 ////////////////////////////////////////////////////////////////////////
18
19 unit PascalCodeModifier;
20
21 {$mode objfpc}{$H+}
22
23 interface
24
25 uses
26   Classes, SysUtils, LCLTextFileInString, CodeToolManager,
27   CodeTree, CodeCache, CodeAtom, TranslManager;
28  
29 type
30   RPascalConst = record      //Структура с инфой о константе.
31     ConstStart : LongInt;
32     ConstEnd : LongInt;
33     Name : AnsiString;
34     NameStart : LongInt;
35     NameEnd : LongInt;
36     Value : AnsiString;
37     ValueStart : LongInt;
38     ValueEnd : LongInt;
39   end;
40
41   APascalConsts = array of RPascalConst;    //Массив констант.
42
43   RPascalFunction = record       //Структура с инфой о функции.
44     FunctionStart : LongInt;
45     FunctionEnd : LongInt;
46     Name : AnsiString;
47     NameStart : LongInt;
48     NameEnd : LongInt;
49     IsProcedure : Boolean;
50     IsDeclaration : Boolean;
51   end;
52
53   APascalFunctions = array of RPascalFunction;    //Массив с функциями.
54
55   TPascalCodeModifier = class (TTextFileInString)
56   private
57     //Буффер и експлорер для кода.
58     CodeBuf : TCodeBuffer;                //Буффер.
59     ACodeTool : TCodeTool;                //Експлорер.
60     CodeToolsAreUnderControl : Boolean;    //Управляет ли уже ими какой-либо метод?
61   public
62     //Переменные.
63     //Переменные с инфой о блоках.
64     Consts : APascalConsts;              //Константы...
65     Functions : APascalFunctions;    //Функции...
66     //Служебные.
67     ErrorMessage : AnsiString;   //Для инфы про последнюю ошибку...
68     ErrorPosition : LongInt;     //Для инфы про номер символа последней ошибки.
69     ErrorLine : LongInt;         //Для инфы про номер строки последней ошибки.
70
71     //Конструкторы-деструкторы
72     constructor Create; override;                           //Конутруктор  %).
73     Destructor Destroy; override;                           //Типа деструктор.
74     //Открытые методы.
75     Function Load(const FName : AnsiString) : boolean; override; //Загрузить из файла.
76     Procedure MakNewFile; override;                              //"Создать новый файл" %).
77     Procedure GetErrorLineFromPos();                             //Получить номер строки по позиции ошибки в файле.
78     //--Блоки, чтение для них инфы--
79     procedure ResetConstsBlock();                                    //Обнулить инфу о блоке констант.
80     procedure ResetFunctionsBlock();                                 //Обнулить инфу о блоке функций.
81     procedure ResetBlocksInfo();                                     //Обнулить инфу о блоках кода.
82     procedure ResetConst(var ConstToReset : RPascalConst);           //Обнулить инфу о константе.
83     procedure ResetFunction(var FuncToReset : RPascalFunction);      //Обнулить инфу о функции.
84     function ParseConsts() : Boolean;                                //Пропарсить блок констант...
85     function ParseFunctions() : Boolean;                             //Пропарсить блок функций...
86     function ReParseFile() : Boolean;                                //Пропарсить текущий файл...
87     function GetPosForFirstFunction() : Integer;                     //Получить позицию в которую можно вписывать самую первую функцию.
88     //--Чтение и модификация элементов кода--
89     function ReadCodeConstValue(const ConstName : AnsiString) : AnsiString;   //Прочитать значение конкретной константы.
90     function WriteCodeConstValue(const ConstName, ConstValue : AnsiString) : Boolean;    //Записать значение конкретной константы.
91     function ReadFunctionName(const FullFunctionText : AnsiString) : AnsiString;   //Выпарсить имя функции из полного её кода.
92     function FunctionIsExists(const FunctionName : AnsiString) : Boolean;    //Существует ли функция?
93     function FunctionIsExistsByText(const FullFunctionText : AnsiString) : Boolean;    //Существует ли функция? Поиск идет по имени, которое берется из полного кода функции.
94     function GetFunctionIndex(const FunctionName : AnsiString) : Integer;    //Получить номер функции с таким именем в массиве с инфой.
95     function GetFullFunctionText(const FunctionIndex : Integer) : AnsiString;   //Получить полный код функции по её номеру в массиве.
96     function GetFullFunctionText(const FunctionName : AnsiString) : AnsiString;   //Получить полный код функции по её имени.
97     function WriteFunction(const FunctionIndex : Integer; const FullFunctionText : AnsiString) : Boolean;   //Записать функцию в код, если она уже есть - заменить.
98     function WriteFunction(const FunctionName, FullFunctionText : AnsiString) : Boolean;   //Записать функцию в код, если она уже есть - заменить.
99   end;
100
101 implementation
102
103 //////////////////////////////////////////////
104 //          TPascalCodeModifier             //
105 //////////////////////////////////////////////
106
107 //------------------------------------//
108 //      Конструкторы-деструкторы      //
109 //------------------------------------//
110
111 Constructor TPascalCodeModifier.Create;
112 //Конутруктор  %).
113 begin
114   inherited;       //Вызов родительского метода...
115
116   //Инициализовать пустые вложенные массивы в структурах.
117   SetLength(Self.Consts, 0);
118   SetLength(Self.Functions, 0);
119
120   //И прочиатим инфу объекта.
121   Self.MakNewFile;
122 end;
123
124 Destructor TPascalCodeModifier.Destroy;
125 //Типа деструктор.
126 begin
127   inherited;
128   Self.ResetBlocksInfo();
129 end;
130
131 //------------------------------------------//
132 //           Закрытые методы...             //
133 //------------------------------------------//
134
135 //------------------------------------------//
136 //            Открытые методы...            //
137 //------------------------------------------//
138
139 Function TPascalCodeModifier.Load(const FName : AnsiString) : boolean;
140 //Загрузить из файла.
141 begin
142   Self.MakNewFile;
143   Result := inherited;
144 end;
145
146 Procedure TPascalCodeModifier.MakNewFile;
147 //"Создать новый файл" %).
148 begin
149   inherited;
150   //Чистим инфу про ошибки.
151   Self.ErrorMessage := 'none';
152   Self.ErrorPosition := 0;
153   Self.ErrorLine := 0;
154   //Забиваем инфу в переменные.
155   Self.ACodeTool := nil;
156   Self.CodeBuf := nil;
157   Self.CodeToolsAreUnderControl := false;
158   //Чистим блоки с инфой про код.
159   Self.ResetBlocksInfo();
160 end;
161
162 Procedure TPascalCodeModifier.GetErrorLineFromPos();
163 //Получить номер строки по позиции ошибки в файле.
164 var
165   TempCursor, CurrLine : LongInt;
166 begin
167   if Self.ErrorPosition <= Self.Siz then begin
168     //Точка ошибки в пределах файла.
169     CurrLine := 1;
170     TempCursor := 0;
171     Self.ErrorLine := 0;
172     repeat
173       //Собсно бежим по строкам и определяем на какой строке курсор будет в точке ошибки.
174       TempCursor := TempCursor+1;
175       if Self.FileString[TempCursor] = #10 then begin
176         //Конец строки.
177         CurrLine := CurrLine+1;
178       end;
179       if Self.ErrorPosition = TempCursor then begin
180         //Нашли строку с ошибкой.
181         Self.ErrorLine := CurrLine;
182       end;
183     until (TempCursor = Self.Siz) or (Self.ErrorLine <> 0);
184   end
185   else begin
186     //Точка ошибки за пределами файла.
187     Self.ErrorLine := 0;
188   end;
189 end;
190
191 //---------------------------------------------//
192 //      --Блоки, чтение для них инфы--         //
193 //---------------------------------------------//
194
195 procedure TPascalCodeModifier.ResetConstsBlock();
196 //Обнулить инфу о константах.
197 begin
198   if Length(Self.Consts) > 0 then begin
199     SetLength(Self.Consts, 0);
200   end;
201 end;
202
203 procedure TPascalCodeModifier.ResetFunctionsBlock();
204 //Обнулить инфу о блоке функций.
205 begin
206   if Length(Self.Functions) > 0 then begin
207     SetLength(Self.Functions,0);
208   end;
209 end;
210
211 procedure TPascalCodeModifier.ResetBlocksInfo();
212 //Обнулить инфу о блоках кода.
213 begin
214   //Константы....
215   Self.ResetConstsBlock();
216   //Функции...
217   Self.ResetFunctionsBlock();
218 end;
219
220 procedure TPascalCodeModifier.ResetConst(var ConstToReset : RPascalConst);
221 //Обнулить инфу о константе.
222 begin
223   ConstToReset.ConstStart := 0;
224   ConstToReset.ConstEnd := 0;
225   ConstToReset.Name := '';
226   ConstToReset.NameStart := 0;
227   ConstToReset.NameEnd := 0;
228   ConstToReset.Value := '';
229   ConstToReset.ValueStart := 0;
230   ConstToReset.ValueEnd := 0;
231 end;
232
233 procedure TPascalCodeModifier.ResetFunction(var FuncToReset : RPascalFunction);
234 //Обнулить инфу о функции.
235 begin
236   FuncToReset.FunctionStart := 0;
237   FuncToReset.FunctionEnd := 0;
238   FuncToReset.Name := '';
239   FuncToReset.NameStart := 0;
240   FuncToReset.NameEnd := 0;
241   FuncToReset.IsProcedure := true;
242   FuncToReset.IsDeclaration := false;
243 end;
244
245 function TPascalCodeModifier.ParseConsts() : Boolean;
246 //Пропарсить блок констант...
247 var
248   IControlCodeTools : Boolean;
249   MemStream : TMemoryStream;
250   CurrTreeNode, ConstSectNode, ConstDefNode : TCodeTreeNode;
251   CurrConstNum : Integer;
252  
253 begin
254   //Инициализация.
255   Result := true;
256   //Смотрим - есть ли инфа в CodeTools ?
257   if Self.CodeToolsAreUnderControl = false then begin
258     //Надо закинуть инфу.
259     Self.CodeBuf := CodeToolBoss.CreateFile('tempfile.pas');
260     MemStream := TMemoryStream.Create;
261     MemStream.Write(Self.FileString[1], Length(Self.FileString));
262     Self.CodeBuf.LoadFromStream(MemStream);
263     MemStream.Free;
264     //И получить експлорера.
265     CodeToolBoss.Explore(Self.CodeBuf, Self.ACodeTool, true, false);
266     //Отметить на себя контроль CodeTools.
267     IControlCodeTools := true;
268     Self.CodeToolsAreUnderControl := true;
269   end
270   else begin
271     //Кто-то уже контроллирует объекты.
272     IControlCodeTools := false;
273   end;
274  
275   //Собсно поиск констант и забивка инфы.
276   //Строим дерево и получаем его корень.
277   Self.ACodeTool.BuildTree(false);
278   CurrTreeNode := Self.ACodeTool.Tree.Root;
279   //Смотрим чего из себя представляет корень. Это должна быть либо прога,
280   //либо юнит, либо пакайдж, либо лайбрари.
281   if (CurrTreeNode.Desc = ctnProgram) or
282      (CurrTreeNode.Desc = ctnPackage) or
283      (CurrTreeNode.Desc = ctnLibrary) or
284      (CurrTreeNode.Desc = ctnUnit) then
285   begin
286     //Собсно, это как раз та нода что нужно. Теперь лезем на уровень вниз...
287     CurrTreeNode := CurrTreeNode.FirstChild;
288     if CurrTreeNode <> nil then begin
289       //Ага, это первай чилд. Циклически просматриваем его и братьев (т.е. на том
290       //же уровне) - ищем секции с константами.
291       repeat
292         if CurrTreeNode.Desc = ctnConstSection then begin
293           //Ага, секция констант. Дальше в виде чилдов должна быть одна или
294           //несколько констант...
295           ConstSectNode := CurrTreeNode;  //Чтоб не потерять дерево.
296           CurrTreeNode := CurrTreeNode.FirstChild;
297           //И пробегаемся по секции.
298           repeat
299             //Ищем объявления констант.
300             if CurrTreeNode.Desc = ctnConstDefinition then begin
301               //Ага, это оно. Добавляем элемент в массив.
302               CurrConstNum := Length(Self.Consts);
303               SetLength(Self.Consts,CurrConstNum+1);
304               Self.ResetConst(Self.Consts[CurrConstNum]);
305               //Заполняем той инфой что есть сейчас.
306               Self.Consts[CurrConstNum].ConstStart := CurrTreeNode.StartPos;
307               Self.Consts[CurrConstNum].ConstEnd := CurrTreeNode.EndPos;
308               //Получаем имя константы. Выставляем курсор, берем атом, берем инфу.
309               Self.ACodeTool.CurPos.StartPos := CurrTreeNode.StartPos;
310               Self.ACodeTool.CurPos.EndPos := CurrTreeNode.StartPos;
311               Self.ACodeTool.CurPos.Flag := cafNone;
312               Self.ACodeTool.ReadNextAtom;
313               Self.Consts[CurrConstNum].Name := Self.ACodeTool.GetAtom;
314               Self.Consts[CurrConstNum].NameStart := Self.ACodeTool.CurPos.StartPos;
315               Self.Consts[CurrConstNum].NameEnd := Self.ACodeTool.CurPos.EndPos;
316               //Ищем значение константы...
317               ConstDefNode := CurrTreeNode;
318               CurrTreeNode := CurrTreeNode.FirstChild;
319               repeat
320                 if CurrTreeNode.Desc = ctnConstant then begin
321                   //Ага, вот значение.
322                   Self.Consts[CurrConstNum].Value := Copy(Self.FileString, CurrTreeNode.StartPos, CurrTreeNode.EndPos-CurrTreeNode.StartPos );
323                   Self.Consts[CurrConstNum].ValueStart := CurrTreeNode.StartPos;
324                   Self.Consts[CurrConstNum].ValueEnd := CurrTreeNode.EndPos;
325                 end;
326                 //Следующий!
327                 if Self.Consts[CurrConstNum].Value = '' then begin
328                   CurrTreeNode := CurrTreeNode.NextBrother;
329                 end
330                 else begin
331                   CurrTreeNode := nil;
332                 end;
333               until CurrTreeNode = nil;
334               //Закончилось объявление константы.
335               CurrTreeNode := ConstDefNode;
336             end;
337             //Следующий!
338             CurrTreeNode := CurrTreeNode.NextBrother;
339           until CurrTreeNode = nil;
340           //Закончилась секция.
341           CurrTreeNode := ConstSectNode;
342         end;
343         //На следующую ноду.
344         CurrTreeNode := CurrTreeNode.NextBrother;
345       until CurrTreeNode = nil;
346     end
347     else begin
348       //Гм.. пусто, нету деток... в прочем это не ошибка, останется 0 констант и все.
349     end;
350   end
351   else begin
352     //Ошибк.
353     Self.ErrorMessage := Self.ClassName+_(' can work only with full Programs, Units, Packages and Libraries.');
354     Self.ErrorPosition := CurrTreeNode.StartPos;
355     Self.GetErrorLineFromPos();
356     Result := false;
357   end;
358  
359   //Чистка мусора если это нужно.
360   if IControlCodeTools = true then begin
361     Self.CodeBuf := nil;
362     Self.ACodeTool := nil;
363     IControlCodeTools := false;
364     Self.CodeToolsAreUnderControl := false;
365   end;
366 end;
367
368 function TPascalCodeModifier.ParseFunctions() : Boolean;
369 //Пропарсить блок функций...
370 var
371   IControlCodeTools : Boolean;
372   MemStream : TMemoryStream;
373   CurrTreeNode, HeaderNode  : TCodeTreeNode;
374   CurrFuncNum : Integer;
375 begin
376   //Инициализация.
377   Result := true;
378   //Смотрим - есть ли инфа в CodeTools ?
379   if Self.CodeToolsAreUnderControl = false then begin
380     //Надо закинуть инфу.
381     Self.CodeBuf := CodeToolBoss.CreateFile('tempfile.pas');
382     MemStream := TMemoryStream.Create;
383     MemStream.Write(Self.FileString[1], Length(Self.FileString));
384     Self.CodeBuf.LoadFromStream(MemStream);
385     MemStream.Free;
386     //И получить експлорера.
387     CodeToolBoss.Explore(Self.CodeBuf, Self.ACodeTool, true, false);
388     //Отметить на себя контроль CodeTools.
389     IControlCodeTools := true;
390     Self.CodeToolsAreUnderControl := true;
391   end
392   else begin
393     //Кто-то уже контроллирует объекты.
394     IControlCodeTools := false;
395   end;
396  
397   //Строим дерево и получаем его корень.
398   Self.ACodeTool.BuildTree(false);
399   CurrTreeNode := Self.ACodeTool.Tree.Root;
400
401   //Смотрим чего из себя представляет корень. Это должна быть либо прога,
402   //либо юнит, либо пакайдж, либо лайбрари.
403   if (CurrTreeNode.Desc = ctnProgram) or
404      (CurrTreeNode.Desc = ctnPackage) or
405      (CurrTreeNode.Desc = ctnLibrary) or
406      (CurrTreeNode.Desc = ctnUnit) then
407   begin
408     //Собсно, это как раз та нода что нужно. Теперь лезем на уровень вниз...
409     CurrTreeNode := CurrTreeNode.FirstChild;
410     if CurrTreeNode <> nil then begin
411       //Ага, это первай чилд. Циклически просматриваем его и братьев (т.е. на том
412       //же уровне) - ищем функции.
413       repeat
414         if CurrTreeNode.Desc = ctnProcedure then begin
415           //Ага, функция. Добавляем элемент в массив.
416           CurrFuncNum := Length(Self.Functions);
417           SetLength(Self.Functions,Length(Self.Functions)+1);
418           Self.ResetFunction(Self.Functions[CurrFuncNum]);
419           Self.Functions[CurrFuncNum].FunctionStart := CurrTreeNode.StartPos;
420           Self.Functions[CurrFuncNum].FunctionEnd := CurrTreeNode.EndPos;
421           //Берем заголовок.
422           CurrTreeNode := CurrTreeNode.FirstChild;
423           //Смотрим - есть ли брат - если есть - значит нормальная процедура\функция, если нет - forward.
424           if CurrTreeNode.NextBrother = nil then begin
425             Self.Functions[CurrFuncNum].IsDeclaration := true;
426           end
427           else begin
428             Self.Functions[CurrFuncNum].IsDeclaration := false;
429           end;
430           //Получаем имя функции.
431           Self.ACodeTool.CurPos.StartPos := CurrTreeNode.StartPos;
432           Self.ACodeTool.CurPos.EndPos := CurrTreeNode.StartPos;
433           Self.ACodeTool.CurPos.Flag := cafNone;
434           Self.ACodeTool.ReadNextAtom;
435           Self.Functions[CurrFuncNum].Name := Self.ACodeTool.GetAtom;
436           Self.Functions[CurrFuncNum].NameStart := Self.ACodeTool.CurPos.StartPos;
437           Self.Functions[CurrFuncNum].NameEnd := Self.ACodeTool.CurPos.EndPos;
438           //Функция или процедура?
439           HeaderNode := CurrTreeNode;
440           CurrTreeNode := CurrTreeNode.FirstChild;
441           repeat
442             if CurrTreeNode <> nil then begin
443               if CurrTreeNode.Desc = ctnIdentifier then begin
444                 Self.Functions[CurrFuncNum].IsProcedure := false;
445               end;
446               //Следующий!
447               if Self.Functions[CurrFuncNum].IsProcedure = true then begin
448                 CurrTreeNode := CurrTreeNode.NextBrother;
449               end
450               else begin
451                 CurrTreeNode := nil;
452               end;
453             end;
454           until CurrTreeNode = nil;
455           //Вернуть ноду процедуры.
456           CurrTreeNode := HeaderNode.Parent;
457         end;
458         //Следующий!
459         CurrTreeNode := CurrTreeNode.NextBrother;
460       until CurrTreeNode = nil;
461     end;
462   end
463   else begin
464     //Ошибк.
465     Self.ErrorMessage := Self.ClassName+_(' can work only with full Programs, Units, Packages and Libraries.');
466     Self.ErrorPosition := CurrTreeNode.StartPos;
467     Self.GetErrorLineFromPos();
468     Result := false;
469   end;
470  
471   //Чистка мусора если это нужно.
472   if IControlCodeTools = true then begin
473     Self.CodeBuf := nil;
474     Self.ACodeTool := nil;
475     IControlCodeTools := false;
476     Self.CodeToolsAreUnderControl := false;
477   end;
478 end;
479
480 function TPascalCodeModifier.ReParseFile() : Boolean;
481 var
482   IControlCodeTools : Boolean;
483   MemStream : TMemoryStream;
484
485 begin
486   //Инициализация.
487   Result := true;
488   //Смотрим - есть ли инфа в CodeTools ?
489   if Self.CodeToolsAreUnderControl = false then begin
490     //Надо закинуть инфу.
491     Self.CodeBuf := CodeToolBoss.CreateFile('tempfile.pas');
492     MemStream := TMemoryStream.Create;
493     MemStream.Write(Self.FileString[1], Length(Self.FileString));
494     Self.CodeBuf.LoadFromStream(MemStream);
495     MemStream.Free;
496     //И получить експлорера.
497     CodeToolBoss.Explore(Self.CodeBuf, Self.ACodeTool, true, false);
498     //Отметить на себя контроль CodeTools.
499     IControlCodeTools := true;
500     Self.CodeToolsAreUnderControl := true;
501   end
502   else begin
503     //Кто-то уже контроллирует объекты.
504     IControlCodeTools := false;
505   end;
506  
507   //Чистим массивы с инфой....
508   Self.ResetBlocksInfo();
509  
510   //Просто вызываем функции парсинга конкретных блоков.
511   Result := Self.ParseConsts();
512   if Result = true then Result := Self.ParseFunctions();
513  
514   //Чистка мусора если это нужно.
515   if IControlCodeTools = true then begin
516     Self.CodeBuf := nil;
517     Self.ACodeTool := nil;
518     IControlCodeTools := false;
519     Self.CodeToolsAreUnderControl := false;
520   end;
521 end;
522
523 function TPascalCodeModifier.GetPosForFirstFunction() : Integer;
524 //Получить позицию в которую можно вписывать самую первую функцию.
525 var
526   IControlCodeTools : Boolean;
527   MemStream : TMemoryStream;
528   CurrTreeNode : TCodeTreeNode;
529  
530 begin
531   //Инициализация.
532   Result := -1;
533  
534   //Смотрим - есть ли инфа в CodeTools ?
535   if Self.CodeToolsAreUnderControl = false then begin
536     //Надо закинуть инфу.
537     Self.CodeBuf := CodeToolBoss.CreateFile('tempfile.pas');
538     MemStream := TMemoryStream.Create;
539     MemStream.Write(Self.FileString[1], Length(Self.FileString));
540     Self.CodeBuf.LoadFromStream(MemStream);
541     MemStream.Free;
542     //И получить експлорера.
543     CodeToolBoss.Explore(Self.CodeBuf, Self.ACodeTool, true, false);
544     //Отметить на себя контроль CodeTools.
545     IControlCodeTools := true;
546     Self.CodeToolsAreUnderControl := true;
547   end
548   else begin
549     //Кто-то уже контроллирует объекты.
550     IControlCodeTools := false;
551   end;
552
553   //Строим дерево и получаем его корень.
554   Self.ACodeTool.BuildTree(false);
555   CurrTreeNode := Self.ACodeTool.Tree.Root;
556  
557   //Смотрим чего из себя представляет корень.
558   //Пока умеет правильно работать только с Program
559   if CurrTreeNode.Desc = ctnProgram then begin
560     //Если Program - то найти где будет основной begin - функции можно писать выше него.
561     CurrTreeNode := CurrTreeNode.FirstChild;
562     if CurrTreeNode <> nil then begin
563       repeat
564         if CurrTreeNode.Desc = ctnBeginBlock then begin
565           //Аха, вот оно.
566           Result := CurrTreeNode.StartPos;
567           CurrTreeNode := nil;
568         end;
569         if CurrTreeNode <> nil then CurrTreeNode := CurrTreeNode.NextBrother;
570       until CurrTreeNode = nil;
571     end;
572   end
573   else begin
574     //Иначе - ныфэга нэзнайу %)
575     Self.ErrorMessage := _('TPascalCodeModifier.GetPosForFirstFunction can work only with Programs.');
576   end;
577  
578   //Чистка мусора если это нужно.
579   if IControlCodeTools = true then begin
580     Self.CodeBuf := nil;
581     Self.ACodeTool := nil;
582     IControlCodeTools := false;
583     Self.CodeToolsAreUnderControl := false;
584   end;
585 end;
586
587 //---------------------------------------------------//
588 //      --Чтение и модификация элементов кода--      //
589 //---------------------------------------------------//
590
591 function TPascalCodeModifier.ReadCodeConstValue(const ConstName : AnsiString) : AnsiString;
592 //Прочитать значение конкретной константы.
593 var
594   I : Integer;
595 begin
596   //Инициализация.
597   Result := '';
598  
599   //Ищем константу...
600   for I := 0 to Length(Self.Consts)-1 do begin
601     if LowerCase(Self.Consts[I].Name) = LowerCase(ConstName) then begin
602       //Нашли.
603       Result := Self.Consts[I].Value;
604       Break;
605     end;
606   end;
607 end;
608
609 function TPascalCodeModifier.WriteCodeConstValue(const ConstName, ConstValue : AnsiString) : Boolean;
610 //Записать значение конкретной константы.
611 var
612   I : Integer;
613 begin
614   //Инициализация.
615   Result := false;
616  
617   //Есть 2 варианта развития событий. Если константа уже есть - её значение просто перезаписывается.
618   //Если нет - константа полностью дописывается после последней существующей, в ту же секцию.
619  
620   //Ищем константу...
621   for I := 0 to Length(Self.Consts)-1 do begin
622     if LowerCase(Self.Consts[I].Name) = LowerCase(ConstName) then begin
623       //Нашли. Пишем новое значение.
624       Delete(Self.FileString, Self.Consts[I].ValueStart, Self.Consts[I].ValueEnd-Self.Consts[I].ValueStart);
625       Insert(ConstValue, Self.FileString, Self.Consts[I].ValueStart);
626       Result := true;
627       Break;
628     end;
629   end;
630  
631   //Если константа найдена не была - добавляем её целиком после последней.
632   if Result = false then begin
633     Insert(#13+#10+'  '+ConstName+' = '+ConstValue+';', Self.FileString, Self.Consts[Length(Self.Consts)-1].ConstEnd);
634     Result := true;
635   end;
636  
637   //Если константа была добавлена, а значит изменился код - его надо перепропарсить заново.
638   if Result = true then begin
639     Result := Self.ReParseFile();
640   end;
641 end;
642
643 function TPascalCodeModifier.ReadFunctionName(const FullFunctionText : AnsiString) : AnsiString;
644 //Выпарсить имя функции из полного её кода.
645 var
646   TempModifier : TPascalCodeModifier;
647   Parsed : Boolean;
648  
649 begin
650   //Инициализация.
651   Result := '';
652   TempModifier := TPascalCodeModifier.Create;
653   Parsed := true;
654  
655   //Формируем временный "текст проги" с внесением туда текста функции.
656   TempModifier.MakNewFile;
657   TempModifier.FileString := 'Program Temp;'+#13+#10+FullFunctionText+#13+#10+'begin end.';
658   //Парсим.
659   try
660     TempModifier.ReParseFile();
661   except
662     //Явно ошибка в FullFunctionText.
663     Parsed := false;
664     Self.ErrorMessage := _('Error, parsing FullFunctionText argument');
665   end;
666
667   //И получаем имя первой функции.
668   if Parsed = true then begin
669     if Length(TempModifier.Functions) > 0 then begin
670       Result := TempModifier.Functions[0].Name;
671     end;
672   end;
673  
674   //Чистка мусора.
675   TempModifier.Free;
676 end;
677
678 function TPascalCodeModifier.FunctionIsExists(const FunctionName : AnsiString) : Boolean;
679 //Существует ли функция?
680 var
681   I : Integer;
682 begin
683   //Инициализация.
684   Result := false;
685  
686   //Ищем функцию.
687   for I := 0 to Length(Self.Functions)-1 do begin
688     if Self.Functions[I].IsDeclaration = false then begin
689       //Проверка не forward ли это - т.к. форвард-декларации учитывать не надо.
690       if LowerCase(Self.Functions[I].Name) = LowerCase(FunctionName) then begin
691         //Нашли.
692         Result := true;
693         Break;
694       end;
695     end;
696   end;
697  
698 end;
699
700 function TPascalCodeModifier.FunctionIsExistsByText(const FullFunctionText : AnsiString) : Boolean;
701 //Существует ли функция? Поиск идет по имени, которое берется из полного кода функции.
702 begin
703   Result := Self.FunctionIsExists(Self.ReadFunctionName(FullFunctionText));
704 end;
705
706 function TPascalCodeModifier.GetFunctionIndex(const FunctionName : AnsiString) : Integer;
707 //Получить номер функции с таким именем в массиве с инфой.
708 var
709   I : Integer;
710 begin
711   //Инициализация.
712   Result := -1;
713  
714   //Ищем функцию.
715   for I := 0 to Length(Self.Functions)-1 do begin
716     if Self.Functions[I].IsDeclaration = false then begin
717       //Проверка не forward ли это - т.к. форвард-декларации учитывать не надо.
718       if LowerCase(Self.Functions[I].Name) = LowerCase(FunctionName) then begin
719         //Нашли.
720         Result := I;
721         Break;
722       end;
723     end;
724   end;
725  
726 end;
727
728 function TPascalCodeModifier.GetFullFunctionText(const FunctionIndex : Integer) : AnsiString;
729 //Получить полный код функции по её номеру в массиве.
730 begin
731   Result := Copy(Self.FileString, Self.Functions[FunctionIndex].FunctionStart, (Self.Functions[FunctionIndex].FunctionEnd-Self.Functions[FunctionIndex].FunctionStart)+1);
732 end;
733
734 function TPascalCodeModifier.GetFullFunctionText(const FunctionName : AnsiString) : AnsiString;
735 //Получить полный код функции по её имени.
736 var
737   FuncIndex : Integer;
738 begin
739   //Инициализация.
740   Result := '';
741  
742   //Если есть такая функция - то получить её индекс.
743   FuncIndex := Self.GetFunctionIndex(FunctionName);
744   //И собсно саму функцию.
745   if FuncIndex >= 0 then begin
746     Result := GetFullFunctionText(FuncIndex);
747   end;
748 end;
749
750 function TPascalCodeModifier.WriteFunction(const FunctionIndex : Integer; const FullFunctionText : AnsiString) : Boolean;
751 //Записать функцию в код, если она уже есть - заменить.
752 begin
753   //Инициализация.
754   Result := false;
755  
756   //Удаляем старый текст функции.
757   Delete(Self.FileString, Self.Functions[FunctionIndex].FunctionStart, (Self.Functions[FunctionIndex].FunctionEnd-Self.Functions[FunctionIndex].FunctionStart)+1);
758   //И собсно дописываем функцию.
759   Insert(FullFunctionText, Self.FileString, Self.Functions[FunctionIndex].FunctionStart);
760   //Код надо перепропарсить заново.
761   Result := Self.ReParseFile();
762 end;
763
764 function TPascalCodeModifier.WriteFunction(const FunctionName, FullFunctionText : AnsiString) : Boolean;
765 //Записать функцию в код, если она уже есть - заменить.
766 var
767   FuncIndex, InputPos : Integer;
768   TailToAdd : AnsiString;
769 begin
770   //Инициализация.
771   Result := false;
772
773   //Есть ли функция?
774   FuncIndex := Self.GetFunctionIndex(FunctionName);
775   if FuncIndex >= 0 then begin
776     //Есть такое дело. Вызываем функцию добавляющую по индексу.
777     Result := Self.WriteFunction(FuncIndex, FullFunctionText);
778   end
779   else begin
780     //Нету - бум дописывать после последней.
781     if Length(Self.Functions) > 0 then begin
782       //В коде есть как минимум 1 функция
783       InputPos := (Self.Functions[Length(Self.Functions)-1].FunctionEnd)+1;
784       TailToAdd := '';
785       //И добавиь дополнительный разделитель %).
786       Insert(#13+#10, Self.FileString, InputPos);
787       InputPos := InputPos+2;
788     end
789     else begin
790       //В коде нету ни одной функции.
791       InputPos := Self.GetPosForFirstFunction();
792       TailToAdd := #13+#10+#13+#10;
793     end;
794    
795     //Собсно вставляем функцию.
796     if InputPos > 0 then begin
797       Insert(#13+#10+FullFunctionText+TailToAdd, Self.FileString, InputPos);
798       //Код надо перепропарсить заново.
799       Result := Self.ReParseFile();
800     end;
801   end;
802 end;
803
804 end.
805
Note: See TracBrowser for help on using the browser.