summary refs log tree commit diff stats
path: root/nim/parseopt.pas
diff options
context:
space:
mode:
Diffstat (limited to 'nim/parseopt.pas')
-rw-r--r--nim/parseopt.pas153
1 files changed, 153 insertions, 0 deletions
diff --git a/nim/parseopt.pas b/nim/parseopt.pas
new file mode 100644
index 000000000..d543b998e
--- /dev/null
+++ b/nim/parseopt.pas
@@ -0,0 +1,153 @@
+//
+//
+//            Nimrod's Runtime Library
+//        (c) Copyright 2008 Andreas Rumpf
+//
+//    See the file "copying.txt", included in this
+//    distribution, for details about the copyright.
+//
+unit parseopt;
+
+// A command line parser; the Nimrod version of this file
+// will become part of the standard library.
+
+interface
+
+{$include 'config.inc'}
+
+uses
+  nsystem, charsets, nos, strutils;
+
+type
+  TCmdLineKind = (
+    cmdEnd,          // end of command line reached
+    cmdArgument,     // argument detected
+    cmdLongoption,   // a long option ``--option`` detected
+    cmdShortOption   // a short option ``-c`` detected
+  );
+  TOptParser = object(NObject)
+    cmd: string;
+    pos: int;
+    inShortState: bool;
+    kind: TCmdLineKind;
+    key, val: string;
+  end;
+
+function init(const cmdline: string = ''): TOptParser;
+procedure next(var p: TOptParser);
+
+function getRestOfCommandLine(const p: TOptParser): string;
+
+implementation
+
+function init(const cmdline: string = ''): TOptParser;
+var
+  i: int;
+begin
+  result.pos := strStart;
+  result.inShortState := false;
+  if cmdline <> '' then
+    result.cmd := cmdline
+  else begin
+    result.cmd := '';
+    for i := 1 to ParamCount() do
+      result.cmd := result.cmd +{&} quoteIfSpaceExists(paramStr(i)) +{&} ' ';
+  {@ignore}
+    result.cmd := result.cmd + #0;
+  {@emit}
+  end;
+  result.kind := cmdEnd;
+  result.key := '';
+  result.val := '';
+end;
+
+function parseWord(const s: string; const i: int; var w: string;
+          const delim: TCharSet = {@set}[#9, ' ', #0]): int;
+begin
+  result := i;
+  if s[result] = '"' then begin
+    inc(result);
+    while not (s[result] in [#0, '"']) do begin
+      addChar(w, s[result]);
+      inc(result);
+    end;
+    if s[result] = '"' then inc(result)
+  end
+  else begin
+    while not (s[result] in delim) do begin
+      addChar(w, s[result]);
+      inc(result);
+    end
+  end
+end;
+
+procedure handleShortOption(var p: TOptParser);
+var
+  i: int;
+begin
+  i := p.pos;
+  p.kind := cmdShortOption;
+  addChar(p.key, p.cmd[i]);
+  inc(i);
+  p.inShortState := true;
+  while p.cmd[i] in [#9, ' '] do begin
+    inc(i);
+    p.inShortState := false;
+  end;
+  if p.cmd[i] in [':', '='] then begin
+    inc(i); p.inShortState := false;
+    while p.cmd[i] in [#9, ' '] do inc(i);
+    i := parseWord(p.cmd, i, p.val);
+  end;
+  if p.cmd[i] = #0 then p.inShortState := false;
+  p.pos := i;
+end;
+
+procedure next(var p: TOptParser);
+var
+  i: int;
+begin
+  i := p.pos;
+  while p.cmd[i] in [#9, ' '] do inc(i);
+  p.pos := i;
+  setLength(p.key, 0);
+  setLength(p.val, 0);
+  if p.inShortState then begin
+    handleShortOption(p); exit
+  end;
+  case p.cmd[i] of
+    #0: p.kind := cmdEnd;
+    '-': begin
+      inc(i);
+      if p.cmd[i] = '-' then begin
+        p.kind := cmdLongOption;
+        inc(i);
+        i := parseWord(p.cmd, i, p.key, {@set}[#0, ' ', #9, ':', '=']);
+        while p.cmd[i] in [#9, ' '] do inc(i);
+        if p.cmd[i] in [':', '='] then begin
+          inc(i);
+          while p.cmd[i] in [#9, ' '] do inc(i);
+          p.pos := parseWord(p.cmd, i, p.val);
+        end
+        else
+          p.pos := i;
+      end
+      else begin
+        p.pos := i;
+        handleShortOption(p)
+      end
+    end;
+    else begin
+      p.kind := cmdArgument;
+      p.pos := parseWord(p.cmd, i, p.key);
+    end
+  end
+end;
+
+function getRestOfCommandLine(const p: TOptParser): string;
+begin
+  result := strip(ncopy(p.cmd, p.pos+strStart, length(p.cmd)-1))
+  // always -1, because Pascal version uses a trailing zero here
+end;
+
+end.