📄 uparse.pas
字号:
{Gets the list of files to parse only if they are used by other files. }
procedure TParserManager.GetLibList;
var Paths :TStringList; //list of paths of all found files
i :Integer; //counter through the list
Name :String; //an entry in the list
FileInfo :TSearchRec; //data to get long name of files
begin
Paths := TStringList.Create; //create list of all found files
try
Paths.Sorted := True;
Paths.Duplicates := dupIgnore;
for i := 0 to FLibs.Count - 1 do //for each entry in the list
begin
Name := FLibs[i]; //get it
//remove trailing PathSeparators
if (Name <> '') and (Name[length(Name)] in ['\', '/']) then
Delete(Name, length(Name), 1);
if FileExists(Name)
{$IFDEF LINUX}
and not DirectoryExists(Name)
{$ENDIF}
then //it is a file?
//add to the list of files
Paths.add(ExtractShortPathName(ExpandFileName(Name)))
else
//search directory and add files to the list
FindPasFiles(ExtractShortPathName(ExpandFileName(Name)), Paths,
Boolean(FLibs.Objects[i]));
end;
for i := 0 to Paths.Count - 1 do //for each found file
if FindFirst(Paths[i], //get its long name = internal name
{$IFNDEF LINUX}
{$IFDEF conditionalexpressions}
{$WARN SYMBOL_PLATFORM OFF}
{$ENDIF}
faHidden
{$IFDEF conditionalexpressions}
{$WARN SYMBOL_PLATFORM ON}
{$ENDIF}
{$ELSE}
0
{$ENDIF}
, FileInfo) = 0 then //file found?
try
//is a simple unit (not a program etc.)?
if LowerCase(ExtractFileExt(FileInfo.Name)) = '.pas' then
begin
//get base name of file; this should also be the internal name
Name := ChangeFileExt(FileInfo.Name, ''); //in Delphi
if FLibFileNames.IndexOf(Name) = -1 then //no file with that name yet?
//add it (register it) to the lists
FLibFilePaths.Insert(FLibFileNames.Add(Name), Paths[i])
else
//generate a warning message
AddWarning('Libs: Several files with the name "' + Name +
'", ignoring file: ' + Paths[i], nil);
end;
finally
FindClose(FileInfo); //end the "search"
end;
finally
Paths.Free; //free list of found files
end;
end;
{Sorts the list of files depending on their usage, i.e. the files not using
other files will be first and project files and packages will be last.
~param List the list to sort }
procedure TParserManager.SortFileList(List: TFileList);
type TAdded = ( //if files are already added
aNo, //no, still have to
aYes, //yes, already added
aAdding); //currently adding (detecting cross-references)
//the list of files in original order
var OrgList :array of TPascalFile;
//if the files are already added; same order as in ~[link OrgList]
Added :array of TAdded;
//new sorted list of the files
NewList :array of TPascalFile;
//insertion point of new files in NewList
NewItem :Integer;
{Returns the index of the file in the original list.
~param AFile the file to search
~result the index of the file in the original list }
function Find(AFile: TPascalFile): Integer;
begin
Result := Length(OrgList) - 1;
while OrgList[Result] <> AFile do
begin
dec(Result);
assert(Result >= 0);
end;
end;
{Adds the file to the list after all used files have been added.
~param Index the index of the file to add in the original list }
procedure Add(Index: Integer);
var List :TStrings; //used files (in interface)
i :Integer; //counter though used units
ind :Integer; //index of unit in original list
begin
assert(Added[Index] = aNo);
Added[Index] := aAdding; //file is being added at the moment
//list of used files (in interface)
List := OrgList[Index].UsedUnitList[fpInterface];
for i := 0 to List.Count - 1 do //for each used unit
begin
assert(assigned(List.Objects[i]));
ind := Find(TPascalFile(List.Objects[i])); //get index of file
if Added[ind] = aNo then //file not added yet?
Add(ind) //add it
else
if (Added[ind] = aAdding) then //cross-referencing of units?
AddWarning('Cross-using of units ' +
TPascalFile(List.Objects[i]).InternalFileName + ' and ' +
OrgList[Index].InternalFileName + '!', nil);
end;
Added[Index] := aYes; //file is now added
NewList[NewItem] := OrgList[Index];
inc(NewItem); //move insertion point in new list
end;
var Count :Integer; //number of files in list
i :Integer; //counter through the list
begin
Count := List.Count; //get number of files
if Count > 1 then //need to be sorted?
begin
SetLength(OrgList, Count); //create original list to sort
for i := 0 to Count - 1 do //fill original list
OrgList[i] := List[i];
SetLength(Added, Count);
FillChar(Added[0], Count * SizeOf(Added[0]), aNo); //no file added so far
SetLength(NewList, Count); //create new sorted list
NewItem := 0; //NewList is empty so far
{$IFOPT C+}
//no file added so far
FillChar(NewList[0], Count * SizeOf(NewList[0]), Integer(nil));
{$ENDIF}
//now sort the files by their usage of each other
for i := 0 to Count - 1 do //for each file in original list
begin
assert(Added[i] in [aNo, aYes]);
if Added[i] = aNo then //if not already added
Add(i); //add it
end;
assert(NewItem = Count); //same number of files added
{$IFOPT C+}
for i := 0 to Count - 1 do //check:
assert(Added[i] = aYes); //all files have been added
{$ENDIF}
List.RemoveAll(False); //clear list
for i := 0 to Count - 1 do //for each (now sorted) file
begin
assert(assigned(NewList[i]));
assert(not List.IsIn(NewList[i]));
List.AddFileToThisList(NewList[i]); //add it again to list
end;
end; //if Count > 1
end;
{Generates a warning-message if the internal (pascal) name of the file differs
from the name of the file in the file-system.
~param TheFile the file, whose name should be tested, if its names differ }
procedure TParserManager.TestFileName(TheFile: TPascalFile);
var SearchRec :TSearchRec; //to obtain the long name of the file
begin
//get long name of the file
if FindFirst(TheFile.FilePath, faAnyFile, SearchRec) = 0 then
try
if LowerCase(ChangeFileExt(SearchRec.Name, '')) <> //are they different?
LowerCase(TheFile.InternalFileName) then
AddWarning(Format('Name of file "%s" differs: %s', //add a warning
[TheFile.InternalFileName, SearchRec.Name]), nil);
finally
FindClose(SearchRec);
end;
end;
{$IFOPT C+}
{Tests the inheritance-hierarchy-linking between record-like types; this is for
debugging purposes only.
~param Kind the kind of record-like types to check
~param List list of all files that contain all record-like types
~result if the linking is correct }
function TParserManager.TestRecordLikeLinks(Kind: TRecordKind;
List: TFileList): Boolean;
{Deletes all inherited classes (children) of the given class from the list.
All children of the children and so on will also be deleted recursively.
~param Parent the class, whose children should be removed from the list
~param Children the list in which to search and remove the children }
procedure DeleteAllChildren(Parent: TIdentifier; Children: TIdentifierList);
var Ident :TIdentifier; //a record-like identifier
i :Integer; //counter through the list
Count :Integer; //number of identifiers left
begin
i := Children.Count - 1; //run through the whole list
while i >= 0 do
begin
Ident := Children[i]; //get an identifier
if TRecordType(Ident).GetParent = Parent then //it's a child?
begin
Children.Remove(i, False); //delete this child
DeleteAllChildren(Ident, Children); //delete all children of it
dec(i); //and next identifier
Count := Children.Count - 1; //test, if sub-children have been
if Count < i then //deleted and end of list moved
i := Count; //make sure, it's a valid index
end
else
dec(i); //next identifier
end;
end;
var AllList :TIdentifierList; //list of all identifiers
ParentsList :TIdentifierList; //list of all without a parent
i, j :Integer; //general counters
FileD :TPascalFile; //each file
Ident :TIdentifier; //each identifier
Count :Integer; //number of identifiers in AllList
begin
AllList := TIdentifierList.Create; //create list for all identifiers
try
//search all identifiers of that kind of record-like types
for i := 0 to List.Count - 1 do //for each file
begin
FileD := List[i]; //get the file
for j := 0 to FileD.Idents.Count - 1 do //for each identifier
begin
Ident := FileD.Idents[j]; //get the identifier
//if it is a record-like type of thet kind
if (Ident is TRecordType) and (TRecordType(Ident).Kind = Kind) then
AllList.AddIdent(Ident); //add it to the list
end;
end;
Count := AllList.Count; //get number of found identifiers
if Count > 0 then //any identifiers there?
begin
ParentsList := TIdentifierList.Create; //create list for all parents
try
for i := Count - 1 downto 0 do //for each identifier
begin
Ident := AllList[i]; //get it
assert(Ident is TRecordType);
//if it has no parent it is a top-level parent
if not assigned(TRecordType(Ident).GetParent()) then
begin
ParentsList.AddIdent(Ident); //add it to the list of parents
AllList.RemoveIdent(Ident, False); //& remove it from the other list
end;
end;
//for each parent remove all known children (and their children ...)
for i := 0 to ParentsList.Count - 1 do
DeleteAllChildren(ParentsList[i], AllList);
finally
ParentsList.RemoveAll(False); //free the list of parents
ParentsList.Free;
end;
Count := AllList.Count; //number of remaining identifiers
end; //if Count > 0
//all identifiers have to be linked or be a parent; no remaining allowed
Result := Count = 0;
finally
AllList.RemoveAll(False); //free the list of identifiers
AllList.Free;
end;
end;
{$ENDIF}
{Parses the specified new files. }
procedure TParserManager.ParseNewFiles;
{Splits the list of files and directories into two. All files will be added
to Files, all directories to Dir.
~param List list of files and directories to add to the others lists
~param Files list to add the files of List to
~param Dirs list to add the directories of List to }
procedure SplitLists(List, Files, Dirs: TStrings);
var i :Integer; //counter through the list
Name :String; //an entry in the list
begin
for i := 0 to List.Count - 1 do //for each entry in the list
begin
Name := List[i]; //get it
//remove trailing PathSeparators
if (Name <> '') and (Name[length(Name)] in ['\', '/']) then
Delete(Name, length(Name), 1);
if FileExists(Name)
{$IFDEF LINUX}
and not DirectoryExists(Name)
{$ENDIF}
then //is it a file?
Files.AddObject(ExtractShortPathName(ExpandFileName(Name)),
List.Objects[i]) //add to list of files
else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -