1 (изменено: Freeman, 14.06.2020 в 17:09)

Тема: ParamStr и ParamCount

Сделал пример, использующий функции ParamCount и ParamStr.
Вроде как эти функции должны быть в System.
А вот насчёт остального(константы, типы, переменные) точно не знаю, где это должно быть расположено.
Ещё есть вспомогательная процедура ProcessArgs, она по идее должна вызываться при старте приложения.
Эта процедура подсчитывает ArgCount и заполняет ArgValues.

Исходный код
program ParamTest;

uses
  CRT;

const
  AppPath: PPAnsiChar = PPAnsiChar(32);
  CmdLine: PPAnsiChar = PPAnsiChar(28);
  MAX_PARAMS = 128;

type
  TArgValues = array[0..MAX_PARAMS - 1] of PAnsiChar;

var
  ArgCount: LongWord = 1; // at least program path
  ArgValues: TArgValues;

function ParamCount: LongWord;
begin
  if ArgCount > 1 then
    Result := ArgCount - 1
  else
    Result := 0;
end;

function ParamStr(Idx: LongWord): PAnsiChar;
begin
  if Idx < ArgCount then
    Result := ArgValues[Idx]
  else
    Result := '';
end;

procedure ProcessArgs;
asm
        PUSH   EBX
        PUSH   ESI
        PUSH   EDI
        MOV    ESI, CmdLine
        MOV    ESI, [ESI]
        LEA    EDI, ArgValues
        MOV    EAX, AppPath
        MOV    EAX, [EAX]
        MOV    [EDI], EAX
        ADD    EDI, 4
        XOR    EBX, EBX
        XOR    ECX, ECX
@next:
        MOV    CL, [ESI]
        JECXZ  @done
        INC    ESI
        CMP    CL, ' '
        JE     @next
        MOV    AL, '"'
        INC    EBX
        CMP    AL, CL
        MOV    EDX, ESI
        JE     @quote
        DEC    EDX
        MOV    AL, ' '
@quote:
        MOV    [EDI], EDX
@parse:
        MOV    CL, [ESI]
        JECXZ  @done
        INC    ESI
        CMP    AL, CL
        JNE    @parse
        ADD    EDI, 4
        MOV    BYTE PTR [ESI - 1], 0
        JMP    @next
@done:
        ADD    ArgCount, EBX // ArgCount  already contains at least 1
        POP    EDI
        POP    ESI
        POP    EBX
end;

var
  i: LongWord;

begin
  InitConsole('Test ParamStr', True);
  ProcessArgs;
  WriteLn('ParamCount = %u', [ParamCount]);
  for i := 0 to ParamCount do
    WriteLn('ParamStr(%u) = "%s"', [i, ParamStr(i)]);
  ReadKey;
end.
Результат

misc.php?action=pun_attachment&amp;item=37&amp;download=0

Добавлено 2020-06-13 в 19:37

Вместе с ParamCount и ParamStr для работы с командной строкой также будет полезной функция FindCmdLineSwitch.
Но для неё необходима функция сравнения строк.

У меня она такая
function StrCmp(const Str1, Str2: PAnsiChar): Boolean;
asm
  PUSH ESI
  PUSH EDI
  MOV ESI, Str1
  MOV EDI, Str2
  XOR ECX, ECX
  XOR EAX, EAX // EAX = False
@next:
  MOV CH, [ESI]
  MOV CL, [EDI]
  CMP CH, CL   // if Str1[i] <> Str2[i] then Result := False;
  JNE @done
  JECXZ @equal // if Str1[i] = #0 and Str2[i] = #0 then Result := True;
  INC ESI
  INC EDI
  JMP @next
@equal:
  INC EAX      // EAX = True
@done:
  POP EDI
  POP ESI
end;
Функция FindCmdLineSwitch(предполагается, что ключи командной строки начинаются с символа '-')
function FindCmdLineSwitch(const Switch: PAnsiChar): Boolean;
var
  Index: LongWord;
  Param: PAnsiChar;
begin
  Result := False;
  for Index := 1 to ParamCount do
  begin
    Param := ParamStr(Index);
    if (Param[0] = '-') and StrCmp(@Param[1], Switch) then
    begin
      Result := True;
      Break;
    end;
  end;
end;
Post's attachments

Иконка вложений ParamStr.PNG 26.17 Кб, 68 скачиваний с 2020-06-13 

2

Re: ParamStr и ParamCount

Параметры командной строки - одна из базовых вещей в любом приложении. По мне, ей самое место в System. Программа может вообще ничего не отобразить, но параметры обработать. Вспомогательной функции ProcessArgs - то же там место. Единственное, её нужно сделать скрытой (убрать из интерфейсной части). Так же, добавить её вызов в секцию инициализации модуля System. Я не вижу смысла разделять ProcessArgs и ParamStr. В противном случаи,мы получим не рабочий ParamStr. Тут два пути: или ProcessArgs, ParamStr,  ParamCount в отдельном модуле (тогда это гарантированный гемор для пользователей и вопросы на форумах: а где это?) или всё в System, как базовая вещь любого приложения.

3

Re: ParamStr и ParamCount

Предлагаю добавить эти функции в System.

interface
......................................
const
  MAX_PARAMS = 128;

type
  TArgValues = array[0..MAX_PARAMS - 1] of PAnsiChar;

var
  ArgCount: LongInt = 1; // at least program path
  ArgValues: TArgValues;
  
function ParamCount: LongInt;
function ParamStr(Idx: LongInt): PAnsiChar;  
......................................
implementation
......................................
function ParamCount: LongInt;
begin
  if ArgCount > 1 then
    Result := ArgCount - 1
  else
    Result := 0;
end;

function ParamStr(Idx: LongInt): PAnsiChar;
begin
  if Idx < ArgCount then
    Result := ArgValues[Idx]
  else
    Result := '';
end;

procedure ProcessArgs;
asm
        PUSH   EBX
        PUSH   ESI
        PUSH   EDI
        MOV    ESI, CmdLine
        LEA    EDI, ArgValues
        MOV    EAX, AppPath
        MOV    [EDI], EAX
        ADD    EDI, 4
        XOR    EBX, EBX
        XOR    ECX, ECX
@next:
        MOV    CL, [ESI]
        JECXZ  @done
        INC    ESI
        CMP    CL, ' '
        JE     @next
        MOV    AL, '"'
        INC    EBX
        CMP    AL, CL
        MOV    EDX, ESI
        JE     @quote
        DEC    EDX
        MOV    AL, ' '
@quote:
        MOV    [EDI], EDX
@parse:
        MOV    CL, [ESI]
        JECXZ  @done
        INC    ESI
        CMP    AL, CL
        JNE    @parse
        ADD    EDI, 4
        MOV    BYTE PTR [ESI - 1], 0
        JMP    @next
@done:
        ADD    ArgCount, EBX // ArgCount  already contains at least 1
        POP    EDI
        POP    ESI
        POP    EBX
end;
......................................
initialization
......................................
  AppPath := PPKolibriChar(32)^;
  CmdLine := PPKolibriChar(28)^;
  
  ProcessArgs;

а также тестовый пример

program ParamTest;

{$APPTYPE CONSOLE}

uses
  CRT;

var
  i: LongInt;

begin
  WriteLn('ParamCount = ', ParamCount);
  for i := 0 to ParamCount do
    WriteLn('ParamStr(', i, ') = ', ParamStr(i));
end.

Кстати, есть такое предложение: держать эти функции не в System, а в отдельном модуле и подключать их только по необходимости(по аналогии с менеджером памяти).
Ведь не все программы принимают параметры в командной строке, а для файлового пути к самой программе у нас есть AppPath.