#path #compare #inno-setup #pascalscript
#путь #Сравнить #inno-setup #pascalscript
Вопрос:
Есть ли встроенный способ сравнения двух строк, представляющих пути в Inno Setup Pascal? Если не с помощью одной функции, то, возможно, с помощью некоторой нормализации пути.
Наивное сравнение строк, очевидно, некорректно, даже если мы игнорируем регистр с SameText()
(согласно правилам Windows).
Как минимум, корректное сравнение должно
- Трактуют
/
как идентичные - Игнорируйте несколько разделителей, например
\
(используйте их как один, как ОС) - Игнорировать конечные разделители (для правильного сравнения путей к каталогам, для чего это в основном необходимо)
- Разрешать пути (
foo..bar
равныеbar
, по крайней мере, еслиfoo
они существуют) - и т.д. (правила хорошо известны)
- Не требуется, чтобы пути действительно существовали в файловой системе.
Разрешение абсолютных и относительных путей является бонусом, но для этого требуется указать текущий путь. Возможно, CWD — это нормально, но я не уверен, что Inno в любом случае принимает относительные пути установки.
Это, должно быть, довольно распространенная задача для установщика, но я удивлен, что не нашел простого, но правильного решения…
Ответ №1:
Объединить ExpandFileName
, AddBackslash
и SameText
:
function SamePath(P1, P2: string): Boolean;
begin
P1 := AddBackslash(ExpandFileName(P1));
P2 := AddBackslash(ExpandFileName(P2));
Result := SameText(P1, P2);
end;
The ExpandFileName
:
- Преобразует
/
в - Нормализует последовательность любых косых черт до одной обратной косой черты (за исключением ведущих обратных косых черт в UNC-путях).
- Разрешает относительные пути.
AddBackslash
Заботится об игнорировании конечных разделителей.
Тесты:
procedure TestSamePath(P: string);
begin
if not SamePath(P, 'C:mypathMyProg.exe') then
RaiseException('Test failed: ' P);
end;
function InitializeSetup(): Boolean;
begin
TestSamePath('C:mypathMyProg.exe');
TestSamePath('C:mypathMYPROG.exe');
TestSamePath('C:mypath\MyProg.exe');
TestSamePath('C:/my/path/MyProg.exe');
TestSamePath('C:my/path//MyProg.exe');
TestSamePath('C:mypathMyProg.exe');
TestSamePath('C:my..mypathMyProg.exe');
SetCurrentDir('C:');
TestSamePath('mypathMyProg.exe');
TestSamePath('mypathMyProg.exe');
SetCurrentDir('C:my');
TestSamePath('pathMyProg.exe');
TestSamePath('.pathMyProg.exe');
Result := True;
end;
Комментарии:
1. Да, похоже, это так… (
RemoveBackslashUnlessRoot()
также будет работать). Я все еще нахожу удивительным, что для этого нет встроенной функции даже в таком специализированном инструменте (не говоря уже о .NET).ExpandFileName()
выполняет 90% работы, но в идеале сравнение должно определить, как использовать регистр символов переносимым способом…