forked from c9/cloud9
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathparser.js
More file actions
287 lines (259 loc) · 11 KB
/
Copy pathparser.js
File metadata and controls
287 lines (259 loc) · 11 KB
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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
/*
termlib_parser.js v.1.1
command line parser for termlib.js
(c) Norbert Landsteiner 2005-2010
mass:werk - media environments
<http://www.masswerk.at>
you are free to use this parser under the "termlib.js" license.
Synopsis:
var parser = new Parser();
parser.parseLine("a line with command");
var command = parser.argv[parser.argc++];
Usage:
Call method "parseLine('a line with command')" from inside of your Terminal-handler.
This will parse the current command line to chunks separated by any amount of
white space (see property whiteSpace).
"parseLine" will inject the following properties into the Terminal instance:
this.argv: Array of parsed chunks (words, arguments)
this.argQL: Array of quoting level per argument
This array will contain the according quote character or an
empty string for each element of argv with the same index
this.argc: A pointer to this.argv and this.argQL
(initially set to 0; used by method getopt)
E.g.: For the string: This is "quoted".
argv will result to ['this', 'is', 'quoted', '.']
and argQL will result to ['', '', '"', '']
if '"' is defined as a quote character (default: ', ", and `)
getopt(this, "<options>")
Call this method from inside of your handler to parse any options from the
next chunk in this.argv that this.argc points to.
Options are considered any arguments preceded by an option character in the
property optionChars (default: "-"). The second argument is a string
containing all characters to be considered legal option flags.
The method returns an object with a property of type object for any option
flag (defined as a character in the options-string) found in argv.
argc will be advanced to the first element of argv that is not an option.
Each of the flag-objects will contain the property `value'.
In case that the option flag was immediately followed by a number
(unsigned float value), this will be stored as a number in the value,
otherwise the value will be set to -1.
Any flags that were not defined in the options-string will be stored as
an array of chars in the property `illegals' of the returned object.
E.g.:
parser.argv: ["test", "-en7a", "-f", "next"]
parser.argc: set initially to 0
var command = parser.argv[parser.argc++]; // parser.argc now points to 2nd chunk
var options = parser.getopt("en");
getopt will return the following object:
{
'e': { value: -1 },
'n': { value: 7 },
'illegals': ['a', 'f']
}
and parser.argc will be set to 3, pointing to "next".
Escape expressions:
The parser can handle escape sequences, e.g.: hexdecimal notations of
characters that are preceded by an escape character. (default: parse any
2-byte hex expressions preceded by "%" as a character, e.g. "%41" => "A")
Escape characters are defined in the property escapeExpressions with the
according method as their value. (The given function or method must be present
at creation and takes four arguments: terminal instance, current char-position,
the escape character found, and the current quoting level. The method or function
is expected to strip any escape sequence of the lineBuffer and to return a string
to be inserted at the current parsing position.)
The result of an escape expression will allways add to the current chunk and will
never result in parsed white space.
Configuration: you may want to overide the follow objects (or add properties):
parser.whiteSpace: chars to be parsed as white space
parser.quoteChars: chars to be parsed as quotes
parser.singleEscapes: chars to escape a quote or escape expression
parser.optionChars: chars that start an option
parser.escapeExpressions: chars that start escape expressions
v. 1.1: Parser is now a function with a constructor.
Configurations can be handled at a per-instance basis.
Parser is now a single, self-contained object in the global name space.
Note: we are not storing the terminal instance in order to avoid memory leakage.
*/
require.def("ext/console/parser", [], function() {
function Parser() {
this.lineBuffer = "";
// config:
// chars to be parsed as white space
this.whiteSpace = {
' ': true,
'\t': true
};
// chars to be parsed as quotes
this.quoteChars = {
'"': true,
"'": true,
'`': true
};
// chars to be parsed as escape char
this.singleEscapes = {
'\\': true
};
// chars that mark the start of an option-expression
// for use with getopt
this.optionChars = {
'-': true
};
// chars that start escape expressions (value = handler)
// plugin handlers for ascii escapes or variable substitution
this.escapeExpressions = {
'%': Parser.prototype.plugins.hexExpression
};
}
Parser.prototype = {
version: '1.1',
plugins: {
hexExpression: function(charindex, escapechar, quotelevel) {
/* example for a plugin for Parser.escapeExpressions
params:
charindex: position in parser.lineBuffer (escapechar)
escapechar: escape character found
quotelevel: current quoting level (quote char or empty)
(quotelevel is not used here, but this is a general approach to plugins)
the character in position charindex will be ignored
the return value is added to the current argument
*/
// convert hex values to chars (e.g. %20 => <SPACE>)
if(!this.lineBuffer)
return null;
if (this.lineBuffer.length > charindex+2) {
// get next 2 chars
var hi = this.lineBuffer.charAt(charindex+1);
var lo = this.lineBuffer.charAt(charindex+2);
lo = lo.toUpperCase();
hi = hi.toUpperCase();
// check for valid hex digits
if ((((hi>='0') && (hi<='9')) || ((hi>='A') && ((hi<='F')))) &&
(((lo>='0') && (lo<='9')) || ((lo>='A') && ((lo<='F'))))) {
// next 2 chars are valid hex, so strip them from lineBuffer
Parser.prototype.plugins._escExprStrip(this, charindex+1, charindex+3);
// and return the char
return String.fromCharCode(parseInt(hi+lo, 16));
}
}
// if not handled return the escape character (=> no conversion)
return escapechar;
},
_escExprStrip: function(termref, from, to) {
// strip characters from termref.lineBuffer (for use with escape expressions)
termref.lineBuffer =
termref.lineBuffer.substring(0, from) +
termref.lineBuffer.substring(to);
}
},
getopt: function(optsstring) {
// scans argv form current position of argc for opts
// arguments in argv must not be quoted
// returns an object with a property for every option flag found
// option values (absolute floats) are stored in Object.<opt>.value (default -1)
// the property "illegals" contains an array of all flags found but not in optstring
// argc is set to first argument that is not an option
var opts = { 'illegals':[] };
while ((this.argc < this.argv.length) && (this.argQL[this.argc]=='')) {
var a = this.argv[this.argc];
if ((a.length>0) && (this.optionChars[a.charAt(0)])) {
var i = 1;
while (i<a.length) {
var c=a.charAt(i);
var v = '';
while (i<a.length-1) {
var nc=a.charAt(i+1);
if ((nc=='.') || ((nc>='0') && (nc<='9'))) {
v += nc;
i++;
}
else {
break;
}
}
if (optsstring.indexOf(c)>=0) {
opts[c] = (v == '')? {value:-1} : (isNaN(v))? {value:0} : {value:parseFloat(v)};
}
else {
opts.illegals[opts.illegals.length]=c;
}
i++;
}
this.argc++;
}
else {
break;
}
}
return opts;
},
parseLine: function(lineBuffer) {
this.lineBuffer = lineBuffer || "";
// stand-alone parser, takes a Terminal instance as argument
// parses the command line and stores results as instance properties
// argv: list of parsed arguments
// argQL: argument's quoting level (<empty> or quote character)
// argc: cursur for argv, set initinally to zero (0)
// open quote strings are not an error but automatically closed.
var argv = ['']; // arguments vector
var argQL = ['']; // quoting level
var argc = 0; // arguments cursor
var escape = false ; // escape flag
for (var i=0; i<this.lineBuffer.length; i++) {
var ch= this.lineBuffer.charAt(i);
if (escape) {
argv[argc] += ch;
escape = false;
}
else if (this.escapeExpressions[ch]) {
var v = this.escapeExpressions[ch](this, i, ch, argQL[argc]);
if (typeof v != 'undefined') argv[argc] += v;
}
else if (this.quoteChars[ch]) {
if (argQL[argc]) {
if (argQL[argc] == ch) {
argc ++;
argv[argc] = argQL[argc] = '';
}
else {
argv[argc] += ch;
}
}
else {
if (argv[argc] != '') {
argc ++;
argv[argc] = '';
argQL[argc] = ch;
}
else {
argQL[argc] = ch;
}
}
}
else if (this.whiteSpace[ch]) {
if (argQL[argc]) {
argv[argc] += ch;
}
else if (argv[argc] != '') {
argc++;
argv[argc] = argQL[argc] = '';
}
}
else if (this.singleEscapes[ch]) {
escape = true;
}
else {
argv[argc] += ch;
}
}
if ((argv[argc] == '') && (!argQL[argc])) {
argv.length--;
argQL.length--;
}
this.argv = argv;
this.argQL = argQL;
this.argc = 0;
}
}
return Parser;
});
// eof