// RFC 3629 https://tools.ietf.org/html/rfc3629
{$MODE FPC}
{$MODESWITCH DEFAULTPARAMETERS}
{$MODESWITCH OUT}
{$MODESWITCH RESULT}
unit dformat;

interface

type
// %[flags][width][.precision][length]specifier
TFormatItem = record
  // for ' '
  PlainStart: PAnsiChar;
  PlainLength: LongInt;
  // other specifiers
  Flags: LongInt;
  Width: LongInt; // >0 for 'number', 0 for '*'
  Precision: LongInt; // >0 for '.number', 0 for '.*', -1 for unspecified
  Length: AnsiChar;
end;

//
//  FormatNext
//
//      Parses next item of c-like format string.
//
//  Parameters:
//
//      Cursor: pointer to current item
//      CursorEnd: end of format string
//
//  Returns:
//
//      Result: letter of parsed format item
//      Cursor: cursor to next format item
//      Item: arguments of parsed format item
//
function FormatNext(var Cursor: PAnsiChar; CursorEnd: PAnsiChar; out Item: TFormatItem): AnsiChar;

implementation

function _FormatNextItemSpecifier(var Cursor: PAnsiChar; CursorEnd: PAnsiChar; out Item: TFormatItem): AnsiChar; inline;
begin
  Inc(Cursor, 2);
  Exit('s');
end;

function _FormatNextItemText(var Cursor: PAnsiChar; CursorEnd: PAnsiChar; out Item: TFormatItem): AnsiChar; inline;
var
  L: LongInt;
begin
  Item.PlainStart := Cursor;
  L := IndexByte(Cursor^, CursorEnd - Cursor, Ord('%'));
  if L <> -1 then begin
    Item.PlainLength := L;
    Inc(Cursor, L);
  end else begin
    Item.PlainLength := CursorEnd - Cursor;
    Cursor := CursorEnd;
  end;
  Exit(' ');
end;

function FormatNext(var Cursor: PAnsiChar; CursorEnd: PAnsiChar; out Item: TFormatItem): AnsiChar;
begin
  if Cursor >= CursorEnd then
    Exit(#0);
  if Cursor^ = '%' then begin
    Result := _FormatNextItemSpecifier(Cursor, CursorEnd, Item);
  end else begin
    Result := _FormatNextItemText(Cursor, CursorEnd, Item);
  end;
end;

end.
