1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
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 +{&} quoteIfContainsWhite(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.
|